Skip to content

Commit 2e2d3ee

Browse files
authored
Merge pull request #493 from totoroyyb/master
[DRAFT] fix: unhandled futex-related syscall
2 parents 3f6467d + fa731ed commit 2e2d3ee

1 file changed

Lines changed: 105 additions & 0 deletions

File tree

src/libfaketime.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4186,6 +4186,90 @@ pid_t getpid() {
41864186
#endif
41874187

41884188
#ifdef INTERCEPT_SYSCALL
4189+
#ifdef INTERCEPT_FUTEX
4190+
long handle_futex_syscall(long number, uint32_t* uaddr, int futex_op, uint32_t val, struct timespec* timeout, uint32_t* uaddr2, uint32_t val3) {
4191+
if (timeout == NULL) {
4192+
// not timeout related, just call the real syscall
4193+
goto futex_fallback;
4194+
}
4195+
4196+
// if ((futex_op & FUTEX_CMD_MASK) == FUTEX_WAIT_BITSET) {
4197+
if (1) {
4198+
clockid_t clk_id = CLOCK_MONOTONIC;
4199+
if (futex_op & FUTEX_CLOCK_REALTIME)
4200+
clk_id = CLOCK_REALTIME;
4201+
4202+
struct timespec real_tp, fake_tp;
4203+
4204+
DONT_FAKE_TIME((*real_clock_gettime)(clk_id, &real_tp));
4205+
fake_tp = real_tp;
4206+
if (fake_clock_gettime(clk_id, &fake_tp) == -1) {
4207+
goto futex_fallback;
4208+
}
4209+
// Create a corrected timeout by adjusting with the difference between
4210+
// real and fake timestamps
4211+
struct timespec adjusted_timeout, time_diff;
4212+
timespecsub(&fake_tp, &real_tp, &time_diff);
4213+
timespecsub(timeout, &time_diff, &adjusted_timeout);
4214+
// fprintf(stdout, "libfaketime: adjusted timeout: %ld.%09ld\n", adjusted_timeout.tv_sec, adjusted_timeout.tv_nsec);
4215+
long result;
4216+
result = real_syscall(number, uaddr, futex_op, val, &adjusted_timeout, uaddr2, val3);
4217+
if (result != 0) {
4218+
return result;
4219+
}
4220+
4221+
// Check if the futex timeout has already passed according to fake time
4222+
struct timespec now_fake;
4223+
if (fake_clock_gettime(clk_id, &now_fake) != 0) {
4224+
return result;
4225+
}
4226+
4227+
// If the timeout is already passed in fake time, return 0.
4228+
while (!timespeccmp(&now_fake, timeout, >=)) {
4229+
// Calculate how much real time we need to wait
4230+
struct timespec real_now, fake_now, wait_time;
4231+
DONT_FAKE_TIME((*real_clock_gettime)(clk_id, &real_now));
4232+
fake_clock_gettime(clk_id, &fake_now);
4233+
4234+
// Calculate how much fake time is left until the timeout
4235+
struct timespec fake_time_left;
4236+
timespecsub(timeout, &fake_now, &fake_time_left);
4237+
4238+
// Scale the fake time left by the user rate if set
4239+
if (user_rate_set && !dont_fake) {
4240+
timespecmul(&fake_time_left, 1.0 / user_rate, &wait_time);
4241+
} else {
4242+
wait_time = fake_time_left;
4243+
}
4244+
4245+
// Calculate the real timeout by adding the wait time to the current real time
4246+
struct timespec real_timeout;
4247+
timespecadd(&real_now, &wait_time, &real_timeout);
4248+
4249+
// fprintf(stdout, "libfaketime: recalculated real timeout: %ld.%09ld\n",
4250+
// real_timeout.tv_sec, real_timeout.tv_nsec);
4251+
4252+
// Call the real syscall with the recalculated timeout
4253+
result = real_syscall(number, uaddr, futex_op, val, &real_timeout, uaddr2, val3);
4254+
if (result != 0) {
4255+
return result;
4256+
}
4257+
4258+
// Check if the futex timeout has already passed according to fake time
4259+
if (fake_clock_gettime(clk_id, &now_fake) != 0) {
4260+
return result;
4261+
}
4262+
}
4263+
return 0;
4264+
} else {
4265+
return real_syscall(number, uaddr, futex_op, val, timeout, uaddr2, val3);
4266+
}
4267+
4268+
futex_fallback:
4269+
return real_syscall(number, uaddr, futex_op, val, timeout, uaddr2, val3);
4270+
}
4271+
#endif
4272+
41894273
/* see https://github.com/wolfcw/libfaketime/issues/301 */
41904274
long syscall(long number, ...) {
41914275
va_list ap;
@@ -4211,6 +4295,27 @@ long syscall(long number, ...) {
42114295
va_end(ap);
42124296
return clock_gettime(clk_id, tp);
42134297
}
4298+
4299+
#ifdef INTERCEPT_FUTEX
4300+
if (number == __NR_futex) {
4301+
uint32_t *uaddr;
4302+
int futex_op;
4303+
uint32_t val;
4304+
struct timespec *timeout; /* or: uint32_t val2 */
4305+
uint32_t* uaddr2;
4306+
uint32_t val3;
4307+
4308+
uaddr = va_arg(ap, uint32_t*);
4309+
futex_op = va_arg(ap, int);
4310+
val = va_arg(ap, uint32_t);
4311+
timeout = va_arg(ap, struct timespec*);
4312+
uaddr2 = va_arg(ap, uint32_t*);
4313+
val3 = va_arg(ap, uint32_t);
4314+
va_end(ap);
4315+
4316+
return handle_futex_syscall(number, uaddr, futex_op, val, timeout, uaddr2, val3);
4317+
}
4318+
#endif
42144319

42154320
variadic_promotion_t a[syscall_max_args];
42164321
for (int i = 0; i < syscall_max_args; i++)

0 commit comments

Comments
 (0)