Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <jannh@google.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20230105134403.754986-1-jannh@google.com

authored by

Jann Horn and committed by
Thomas Gleixner
9f76d591 b7bfaa76

+6
+2
kernel/time/hrtimer.c
··· 2126 2126 if (!timespec64_valid(&tu)) 2127 2127 return -EINVAL; 2128 2128 2129 + current->restart_block.fn = do_no_restart_syscall; 2129 2130 current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE; 2130 2131 current->restart_block.nanosleep.rmtp = rmtp; 2131 2132 return hrtimer_nanosleep(timespec64_to_ktime(tu), HRTIMER_MODE_REL, ··· 2148 2147 if (!timespec64_valid(&tu)) 2149 2148 return -EINVAL; 2150 2149 2150 + current->restart_block.fn = do_no_restart_syscall; 2151 2151 current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE; 2152 2152 current->restart_block.nanosleep.compat_rmtp = rmtp; 2153 2153 return hrtimer_nanosleep(timespec64_to_ktime(tu), HRTIMER_MODE_REL,
+2
kernel/time/posix-stubs.c
··· 147 147 return -EINVAL; 148 148 if (flags & TIMER_ABSTIME) 149 149 rmtp = NULL; 150 + current->restart_block.fn = do_no_restart_syscall; 150 151 current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE; 151 152 current->restart_block.nanosleep.rmtp = rmtp; 152 153 texp = timespec64_to_ktime(t); ··· 241 240 return -EINVAL; 242 241 if (flags & TIMER_ABSTIME) 243 242 rmtp = NULL; 243 + current->restart_block.fn = do_no_restart_syscall; 244 244 current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE; 245 245 current->restart_block.nanosleep.compat_rmtp = rmtp; 246 246 texp = timespec64_to_ktime(t);
+2
kernel/time/posix-timers.c
··· 1270 1270 return -EINVAL; 1271 1271 if (flags & TIMER_ABSTIME) 1272 1272 rmtp = NULL; 1273 + current->restart_block.fn = do_no_restart_syscall; 1273 1274 current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE; 1274 1275 current->restart_block.nanosleep.rmtp = rmtp; 1275 1276 ··· 1298 1297 return -EINVAL; 1299 1298 if (flags & TIMER_ABSTIME) 1300 1299 rmtp = NULL; 1300 + current->restart_block.fn = do_no_restart_syscall; 1301 1301 current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE; 1302 1302 current->restart_block.nanosleep.compat_rmtp = rmtp; 1303 1303