3 ms·
There's a pretty clear explanation in https://lore.kernel.org/patchwork/patch/506101/ https://lore.kernel.org/patchwork/patch/506101/ : MIPS floating point sup
by geofft 8y ago
There's a pretty clear explanation in https://lore.kernel.org/patchwork/patch/506101/ https://lore.kernel.org/patchwork/patch/506101/ :
MIPS floating point support requires that any instruction that cannot be directly executed by the FPU, be emulated by the kernel. Part of this emulation involves executing non-FPU instructions that fall in the delay slots of FP branch instructions. Since the beginning of MIPS/Linux time, this has been done by placing the instructions on the userspace thread stack, and executing them there, as the instructions must be executed in the MM context of the thread receiving the emulation.
i.e., the kernel needs to find some place in the userspace process to stick the emulation code, because the emulation code needs to happen in the context of the userspace process (e.g., memory access permissions etc.), and ~20 years ago a convenient place the kernel could write to in the userspace process was to push things onto the stack and nobody realized that was weird. Historically the stack was executable everywhere, and when we realized that was a bad idea because exploits can put shellcode on the stack and stopped doing it on most architectures, we weren't able to stop on MIPS because of this reason.
If we were rearchitecting this from scratch today I bet there would be something like a vDSO for this, i.e., the kernel maps a read-only executable page at a random address when the process starts, and when you try to execute a floating-point instruction it sets some registers (or pushes data and only data onto the stack) and updates the instruction pointer to point to that page. But the simplest fix to the existing architecture was apparently to specify a non-stack area for the kernel to use, which still involves a W|X segment, but at least it isn't the stack.
- saagarjha 8y ago> If we were rearchitecting this from scratch today I bet there would be something like a vDSO for this This is what I was getting at with my question. There is a way to do this; sure, branch-delay slots are annoying but they’re not impossible to work around. > But the simplest fix to the existing architecture was apparently to specify a non-stack area for the kernel to use, which still involves a W|X segment, but at least it isn't the stack. I mean, you protect yourself against trivial buffer overflows, but a good write primitive is still enough to get code execution. It’s more of a band-aid than an actual fix.
- geofft 8y agoIf I'm reading the patch right, you allocate a buffer at a random address and pass a pointer to the kernel, and then you don't have to hold on to a pointer to that address any more, right? So unlike with the stack, it should be hard for an attacker who can only writes to figure out where to write. (Maybe this isn't true in a 2 GB address space given enough attempts?)
- saagarjha 8y agoYeah, I missed the part where the address is given by the user space thread to the kernel instead of the other way around. That being said, I’m not sure as to the amount of entropy the address can have: it might end up being bruteforceable on 32-bit without having to query the full address space (the memory region might be a whole page?). The best solution, of course, is to not have any RWX segments at all.