summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryi chen <[email protected]>2026-07-09 11:49:33 +0800
committerRbb666 <[email protected]>2026-07-22 21:50:12 +0800
commit4fbdf331d12a820feaa7b5724c28bd78b651074a (patch)
tree7063ee28365637fdd5f7b51d07d4a8453c460ded
parent69b66ad4112103f83328b1729b6b586efb5a6da1 (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.c13
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);