From d8cd4e49028c3b99425d1c799706911d37000d4f Mon Sep 17 00:00:00 2001 From: Ben Wiederhake Date: Sat, 7 Mar 2020 23:38:47 +0100 Subject: [PATCH] Kernel: Fix race in select This is similar to 28e1da344d1de4fb80ce9e9c8da9127fa8606dc7 and 4dd4dd2f3c067eca446d9513e814ae9aaa648882. The crux is that select verifies that the filedescriptor sets are writable *before* blocking, and writes to them *after* blocking. In the meantime, a concurrent thread can make the output buffer unwritable, e.g. by deallocating it. --- Kernel/Process.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index eb156b0731..e1feeb6f52 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -2815,6 +2815,17 @@ int Process::sys$select(const Syscall::SC_select_params* params) if (!timeout || select_has_timeout) { if (Thread::current->block(computed_timeout, select_has_timeout, rfds, wfds, efds) != Thread::BlockResult::WokeNormally) return -EINTR; + // While we blocked, the process lock was dropped. This gave other threads + // the opportunity to mess with the memory. For example, it could free the + // region, and map it to a region to which it has no write permissions. + // Therefore, we need to re-validate all pointers. + if (writefds && !validate_write_typed(writefds)) + return -EFAULT; + if (readfds && !validate_write_typed(readfds)) + return -EFAULT; + // See the fixme below. + if (exceptfds && !validate_write_typed(exceptfds)) + return -EFAULT; } int marked_fd_count = 0;