Skip to content

Commit 9f76d59

Browse files
thejhKAGA-KOKO
authored andcommitted
timers: Prevent union confusion from unexpected restart_syscall()
The nanosleep syscalls use the restart_block mechanism, with a quirk: The `type` and `rmtp`/`compat_rmtp` fields are set up unconditionally on syscall entry, while the rest of the restart_block is only set up in the unlikely case that the syscall is actually interrupted by a signal (or pseudo-signal) that doesn't have a signal handler. If the restart_block was set up by a previous syscall (futex(..., FUTEX_WAIT, ...) or poll()) and hasn't been invalidated somehow since then, this will clobber some of the union fields used by futex_wait_restart() and do_restart_poll(). If userspace afterwards wrongly calls the restart_syscall syscall, futex_wait_restart()/do_restart_poll() will read struct fields that have been clobbered. This doesn't actually lead to anything particularly interesting because none of the union fields contain trusted kernel data, and futex(..., FUTEX_WAIT, ...) and poll() aren't syscalls where it makes much sense to apply seccomp filters to their arguments. So the current consequences are just of the "if userspace does bad stuff, it can damage itself, and that's not a problem" flavor. But still, it seems like a hazard for future developers, so invalidate the restart_block when partly setting it up in the nanosleep syscalls. Signed-off-by: Jann Horn <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent b7bfaa7 commit 9f76d59

File tree

3 files changed

+6
-0
lines changed

3 files changed

+6
-0
lines changed

kernel/time/hrtimer.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,6 +2126,7 @@ SYSCALL_DEFINE2(nanosleep, struct __kernel_timespec __user *, rqtp,
21262126
if (!timespec64_valid(&tu))
21272127
return -EINVAL;
21282128

2129+
current->restart_block.fn = do_no_restart_syscall;
21292130
current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
21302131
current->restart_block.nanosleep.rmtp = rmtp;
21312132
return hrtimer_nanosleep(timespec64_to_ktime(tu), HRTIMER_MODE_REL,
@@ -2147,6 +2148,7 @@ SYSCALL_DEFINE2(nanosleep_time32, struct old_timespec32 __user *, rqtp,
21472148
if (!timespec64_valid(&tu))
21482149
return -EINVAL;
21492150

2151+
current->restart_block.fn = do_no_restart_syscall;
21502152
current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
21512153
current->restart_block.nanosleep.compat_rmtp = rmtp;
21522154
return hrtimer_nanosleep(timespec64_to_ktime(tu), HRTIMER_MODE_REL,

kernel/time/posix-stubs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
147147
return -EINVAL;
148148
if (flags & TIMER_ABSTIME)
149149
rmtp = NULL;
150+
current->restart_block.fn = do_no_restart_syscall;
150151
current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
151152
current->restart_block.nanosleep.rmtp = rmtp;
152153
texp = timespec64_to_ktime(t);
@@ -240,6 +241,7 @@ SYSCALL_DEFINE4(clock_nanosleep_time32, clockid_t, which_clock, int, flags,
240241
return -EINVAL;
241242
if (flags & TIMER_ABSTIME)
242243
rmtp = NULL;
244+
current->restart_block.fn = do_no_restart_syscall;
243245
current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
244246
current->restart_block.nanosleep.compat_rmtp = rmtp;
245247
texp = timespec64_to_ktime(t);

kernel/time/posix-timers.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
12701270
return -EINVAL;
12711271
if (flags & TIMER_ABSTIME)
12721272
rmtp = NULL;
1273+
current->restart_block.fn = do_no_restart_syscall;
12731274
current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
12741275
current->restart_block.nanosleep.rmtp = rmtp;
12751276

@@ -1297,6 +1298,7 @@ SYSCALL_DEFINE4(clock_nanosleep_time32, clockid_t, which_clock, int, flags,
12971298
return -EINVAL;
12981299
if (flags & TIMER_ABSTIME)
12991300
rmtp = NULL;
1301+
current->restart_block.fn = do_no_restart_syscall;
13001302
current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
13011303
current->restart_block.nanosleep.compat_rmtp = rmtp;
13021304

0 commit comments

Comments
 (0)