When syscalling on i386, the kernel copies in the sycall args with a special function [1]. The third argument is the size of the userland area. In x86_copyargs, however, you can see [2] that the area is copied by two chunks of 16 and 20 bytes, which means that if a syscall has a 4-byte-sized argument, the kernel still copies 16 bytes.
The problem is that the VM_MAXUSER_ADDRESS check (in charge of making sure we don't start reading kernel space) is done on the third argument, and not the real copied size. It is easy to create a condition where %esp+4+arg_size <= VM_MAXUSER_ADDRES and %esp+4+roundup(arg_size, 16) > VM_MAXUSER_ADDRESS. In such a case, the userland check succeeds, and the kernel starts copying its own memory. Without going into terrible details, it is possible for userland to make sure VM_MAXUSER_ADDRESS+delta is readable, and therefore, x86_copyargs will succeed, and some args will contain some slots of the page tree. This bug seems harmless, but I guess it is still possible to leak kernel data to userland. I wrote [3] quickly, which triggers such a condition and goes unseen. x86_copyargs is supposed to be an 'optimized' copyin. While the design of this function is obviously wrong, I would simply suggest rounding up the size of the third argument [4]. Just sayin [1] https://nxr.netbsd.org/xref/src/sys/arch/x86/x86/syscall.c#150 [2] https://nxr.netbsd.org/xref/src/sys/arch/i386/i386/copy.S#679 [3] http://m00nbsd.net/garbage/sysover/sysover.c [4] http://m00nbsd.net/garbage/sysover/syscall.diff
