Skip to content

[rtsan] Intercept various file system functions #118183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ void OSSpinLockLock(volatile OSSpinLock *__lock);
#include <stdarg.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>

Expand Down Expand Up @@ -358,6 +359,31 @@ INTERCEPTOR(int, dup2, int oldfd, int newfd) {
return REAL(dup2)(oldfd, newfd);
}

INTERCEPTOR(int, chmod, const char *path, mode_t mode) {
__rtsan_notify_intercepted_call("chmod");
return REAL(chmod)(path, mode);
}

INTERCEPTOR(int, fchmod, int fd, mode_t mode) {
__rtsan_notify_intercepted_call("fchmod");
return REAL(fchmod)(fd, mode);
}

INTERCEPTOR(int, mkdir, const char *path, mode_t mode) {
__rtsan_notify_intercepted_call("mkdir");
return REAL(mkdir)(path, mode);
}

INTERCEPTOR(int, rmdir, const char *path) {
__rtsan_notify_intercepted_call("rmdir");
return REAL(rmdir)(path);
}

INTERCEPTOR(mode_t, umask, mode_t cmask) {
__rtsan_notify_intercepted_call("umask");
return REAL(umask)(cmask);
}

// Concurrency
#if SANITIZER_APPLE
#pragma clang diagnostic push
Expand Down Expand Up @@ -818,6 +844,11 @@ void __rtsan::InitializeInterceptors() {
RTSAN_MAYBE_INTERCEPT_LSEEK64;
INTERCEPT_FUNCTION(dup);
INTERCEPT_FUNCTION(dup2);
INTERCEPT_FUNCTION(chmod);
INTERCEPT_FUNCTION(fchmod);
INTERCEPT_FUNCTION(mkdir);
INTERCEPT_FUNCTION(rmdir);
INTERCEPT_FUNCTION(umask);
INTERCEPT_FUNCTION(ioctl);

#if SANITIZER_APPLE
Expand Down
55 changes: 55 additions & 0 deletions compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>

Expand Down Expand Up @@ -442,6 +443,60 @@ TEST_F(RtsanOpenedFileTest, Dup2DiesWhenRealtime) {
ExpectNonRealtimeSurvival(Func);
}

TEST_F(RtsanFileTest, ChmodDiesWhenRealtime) {
auto Func = [this]() { chmod(GetTemporaryFilePath(), 0777); };
ExpectRealtimeDeath(Func, "chmod");
ExpectNonRealtimeSurvival(Func);
}

TEST_F(RtsanOpenedFileTest, FchmodDiesWhenRealtime) {
auto Func = [this]() { fchmod(GetOpenFd(), 0777); };
ExpectRealtimeDeath(Func, "fchmod");
ExpectNonRealtimeSurvival(Func);
}

TEST(TestRtsanInterceptors, UmaskDiesWhenRealtime) {
auto Func = []() { umask(0); };
ExpectRealtimeDeath(Func, "umask");
ExpectNonRealtimeSurvival(Func);
}

class RtsanDirectoryTest : public ::testing::Test {
protected:
void SetUp() override {
const ::testing::TestInfo *const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
directory_path_ = std::string("/tmp/rtsan_temp_dir_") + test_info->name();
RemoveTemporaryDirectory();
}

const char *GetTemporaryDirectoryPath() const {
return directory_path_.c_str();
}

void TearDown() override { RemoveTemporaryDirectory(); }

private:
void RemoveTemporaryDirectory() const {
std::remove(GetTemporaryDirectoryPath());
}
std::string directory_path_;
};

TEST_F(RtsanDirectoryTest, MkdirDiesWhenRealtime) {
auto Func = [this]() { mkdir(GetTemporaryDirectoryPath(), 0777); };
ExpectRealtimeDeath(Func, "mkdir");
ExpectNonRealtimeSurvival(Func);
}

TEST_F(RtsanDirectoryTest, RmdirDiesWhenRealtime) {
// We don't actually create this directory before we try to remove it
// Thats OK - we are just making sure the call gets intercepted
auto Func = [this]() { rmdir(GetTemporaryDirectoryPath()); };
ExpectRealtimeDeath(Func, "rmdir");
ExpectNonRealtimeSurvival(Func);
}

TEST_F(RtsanOpenedFileTest, FreadDiesWhenRealtime) {
auto Func = [this]() {
char c{};
Expand Down