diff options
| author | yi chen <[email protected]> | 2026-07-09 11:49:33 +0800 |
|---|---|---|
| committer | Rbb666 <[email protected]> | 2026-07-22 21:50:12 +0800 |
| commit | 4fbdf331d12a820feaa7b5724c28bd78b651074a (patch) | |
| tree | 7063ee28365637fdd5f7b51d07d4a8453c460ded | |
| parent | 69b66ad4112103f83328b1729b6b586efb5a6da1 (diff) | |
lwp: copy timeout into kernel space in sys_select()
sys_select() passed the raw user-space timeout pointer straight
through to select(), unlike readfds/writefds/exceptfds which are
all validated with lwp_user_accessable() and copied into kernel
memory first. A malicious or buggy user thread could pass a
timeout pointing at unmapped or otherwise invalid memory, which
select() would then dereference directly (timeout->tv_sec /
timeout->tv_usec) without any check, from kernel context.
Validate and copy it into a kernel-local struct timeval the same
way the fd_set arguments already are, before it reaches select().
Fixes #10298
Signed-off-by: yi chen <[email protected]>
| -rw-r--r-- | components/lwp/lwp_syscall.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index de147d5f09..f3538c2cb4 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -970,6 +970,7 @@ sysret_t sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptf #ifdef ARCH_MM_MMU int ret = -1; fd_set *kreadfds = RT_NULL, *kwritefds = RT_NULL, *kexceptfds = RT_NULL; + struct timeval ktimeout, *ptimeout = RT_NULL; if (readfds) { @@ -1016,8 +1017,18 @@ sysret_t sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptf } lwp_get_from_user(kexceptfds, exceptfds, sizeof *kexceptfds); } + if (timeout) + { + if (!lwp_user_accessable((void *)timeout, sizeof *timeout)) + { + SET_ERRNO(EFAULT); + goto quit; + } + lwp_get_from_user(&ktimeout, timeout, sizeof ktimeout); + ptimeout = &ktimeout; + } - ret = select(nfds, kreadfds, kwritefds, kexceptfds, timeout); + ret = select(nfds, kreadfds, kwritefds, kexceptfds, ptimeout); if (kreadfds) { lwp_put_to_user(readfds, kreadfds, sizeof *kreadfds); |
