Skip to content

Commit

Permalink
Reland "[Sanitizers] Intercept timer_create" (#113710) (#116717)
Browse files Browse the repository at this point in the history
Original commit 2ec5c69 only
intercepted timer_create.

Because of how versioned libc symbols work, this could cause problems
where a newer `timer_create`
was used, and the result would be used by an older version. This would
cause crashes. This is why we
need to intercept all of the related functions.

Addresses #111847
  • Loading branch information
fmayer authored Nov 19, 2024
1 parent 2e0a3c2 commit 0488d17
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 0 deletions.
3 changes: 3 additions & 0 deletions compiler-rt/lib/hwasan/hwasan_platform_interceptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@
#undef SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID
#define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID 0

#undef SANITIZER_INTERCEPT_TIMER_CREATE
#define SANITIZER_INTERCEPT_TIMER_CREATE 0

#undef SANITIZER_INTERCEPT_GETITIMER
#define SANITIZER_INTERCEPT_GETITIMER 0

Expand Down
28 changes: 28 additions & 0 deletions compiler-rt/lib/msan/tests/msan_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4881,4 +4881,32 @@ TEST(MemorySanitizer, throw_catch) {
// pass
}
}

#if defined(__GLIBC__)
TEST(MemorySanitizer, timer_create) {
timer_t timer;
EXPECT_POISONED(timer);
int res = timer_create(CLOCK_REALTIME, nullptr, &timer);
ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(timer);

// Make sure the timer is usable.
struct itimerspec cur_value {};
cur_value.it_value.tv_sec = 1;
EXPECT_EQ(0, timer_settime(timer, 0, &cur_value, nullptr));

struct itimerspec read_value;
EXPECT_POISONED(read_value);
EXPECT_EQ(0, timer_gettime(timer, &read_value));
EXPECT_NOT_POISONED(read_value);

timer_t timer2;
EXPECT_POISONED(timer2);
// Use an invalid clock_id to make timer_create fail.
res = timer_create(INT_MAX, nullptr, &timer2);
ASSERT_EQ(-1, res);
EXPECT_POISONED(timer2);
timer_delete(timer);
}
#endif
} // namespace
56 changes: 56 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
Original file line number Diff line number Diff line change
Expand Up @@ -2289,6 +2289,61 @@ INTERCEPTOR(int, pthread_getcpuclockid, uptr thread,
#define INIT_CLOCK_GETCPUCLOCKID
#endif

#if SANITIZER_INTERCEPT_TIMER_CREATE
INTERCEPTOR(int, timer_create, __sanitizer_clockid_t clockid, void *sevp,
__sanitizer_timer_t *timer) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, timer_create, clockid, sevp, timer);
int res = REAL(timer_create)(clockid, sevp, timer);
if (!res && timer) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, timer, sizeof *timer);
}
return res;
}

INTERCEPTOR(int, timer_delete, __sanitizer_timer_t timer) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, timer_delete, timer);
int res = REAL(timer_delete)(timer);
return res;
}

INTERCEPTOR(int, timer_gettime, __sanitizer_timer_t timer,
struct __sanitizer_itimerspec *curr_value) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, timer_gettime, timer, curr_value);
int res = REAL(timer_gettime)(timer, curr_value);
if (!res && curr_value) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, sizeof *curr_value);
}
return res;
}

INTERCEPTOR(int, timer_settime, __sanitizer_timer_t timer, int flags,
const struct __sanitizer_itimerspec *new_value,
struct __sanitizer_itimerspec *old_value) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, timer_settime, timer, flags, new_value,
old_value);
int res = REAL(timer_settime)(timer, flags, new_value, old_value);
if (!res) {
if (new_value)
COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, sizeof *new_value);
if (old_value)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, sizeof *old_value);
}
return res;
}

# define INIT_TIMER_CREATE \
COMMON_INTERCEPT_FUNCTION_GLIBC_VER_MIN(timer_create, "GLIBC_2.3.3"); \
COMMON_INTERCEPT_FUNCTION_GLIBC_VER_MIN(timer_delete, "GLIBC_2.3.3"); \
COMMON_INTERCEPT_FUNCTION_GLIBC_VER_MIN(timer_gettime, "GLIBC_2.3.3"); \
COMMON_INTERCEPT_FUNCTION_GLIBC_VER_MIN(timer_settime, "GLIBC_2.3.3");
#else
# define INIT_TIMER_CREATE
#endif

#if SANITIZER_INTERCEPT_GETITIMER
INTERCEPTOR(int, getitimer, int which, void *curr_value) {
void *ctx;
Expand Down Expand Up @@ -10266,6 +10321,7 @@ static void InitializeCommonInterceptors() {
INIT_SETPWENT;
INIT_CLOCK_GETTIME;
INIT_CLOCK_GETCPUCLOCKID;
INIT_TIMER_CREATE;
INIT_GETITIMER;
INIT_TIME;
INIT_GLOB;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
(SI_FREEBSD || SI_NETBSD || SI_LINUX || SI_SOLARIS)
#define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID \
(SI_LINUX || SI_FREEBSD || SI_NETBSD)
// TODO: This should be SI_POSIX, adding glibc first until I have time
// to verify all timer_t typedefs on other platforms.
#define SANITIZER_INTERCEPT_TIMER_CREATE SI_GLIBC
#define SANITIZER_INTERCEPT_GETITIMER SI_POSIX
#define SANITIZER_INTERCEPT_TIME SI_POSIX
#define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS)
Expand Down
14 changes: 14 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,16 @@ typedef long __sanitizer_time_t;

typedef long __sanitizer_suseconds_t;

struct __sanitizer_timespec {
__sanitizer_time_t tv_sec; /* seconds */
u64 tv_nsec; /* nanoseconds */
};

struct __sanitizer_itimerspec {
struct __sanitizer_timespec it_interval; /* timer period */
struct __sanitizer_timespec it_value; /* timer expiration */
};

struct __sanitizer_timeval {
__sanitizer_time_t tv_sec;
__sanitizer_suseconds_t tv_usec;
Expand Down Expand Up @@ -1517,6 +1527,10 @@ extern const int si_SEGV_ACCERR;

#define SIGACTION_SYMNAME sigaction

# if SANITIZER_LINUX
typedef void *__sanitizer_timer_t;
# endif

#endif // SANITIZER_LINUX || SANITIZER_APPLE

#endif

0 comments on commit 0488d17

Please sign in to comment.