4 ms·
Since calling syscalls directly instead of through the wrapper dll is unsupported, I wouldn't be surprised if MS prevented syscalls from outside the expected li
by CodesInChaos 6y ago
Since calling syscalls directly instead of through the wrapper dll is unsupported, I wouldn't be surprised if MS prevented syscalls from outside the expected libraries at some point.
OpenBSD already does this to improve security: https://marc.info/?l=openbsd-tech&m=157488907117170&w=2 https://marc.info/?l=openbsd-tech&m=157488907117170&w=2
- guenthert 6y agoI'm a bit at loss how this improves security or why it is necessary. If the kernel needs an external library as gatekeeper, something fundamentally went wrong. And why would, say a Lisp compiler use the C library (or to use a more popular example, why would a Java VM do the same)? It might be common practice (to ease FFI/JNI), but making this a requirement seems heading the wrong direction.
- saagarjha 6y agoI believe libc is the only stable way to ask the kernel to do something for you.
- kazinator 6y agoGNU Libc is only stable at the source code level, and tries fairly hard at the binary level with approaches like symbol versioning and whatnot. Linux syscalls are more stable at the actual binary level. Some "int $0x80" code you wrote in 1996 in x86 assembly language will work today, provided the binary format (like a.out) will load. The libc which was used then is not even around any more.
- saagarjha 6y agoAh, I was talking about OpenBSD's kernel interface. Linux is ABI stable at the syscall level, of course–I know it tries to be binary compatible, but I have never actually tested this much.
- trasz 6y agoIt's pretty common to run FreeBSD jails with old userspace (say, 8.0) on top of up to date FreeBSD kernel (say, 12.1). This works because to the stable syscall interface.
- kazinator 6y agoIt isn't an external gatekeeper. The kernel receives a syscall. The kernel looks at the user space instruction pointer to determine where the sycall came from. The instruction pointer is not in a blessed area; the syscall is declined. That's all internal to the kernel. User space perhaps just arranges it; it informs the kernel about the restricted area. That's essentially the same as any other limit, like setting a limit on stack size, core file size, execution time, whether the stack is executable, ...
- CodesInChaos 6y ago> I'm a bit at loss how this improves security or why it is necessary. If the kernel needs an external library as gatekeeper, something fundamentally went wrong. It's not about defending the kernel from the user mode process. It's a mitigation to make exploiting usermode RCEs like buffer overflows a bit harder by possibly preventing some forms of ASLR bypass. MS might do it in part for security, but likely aloo to prevent people from relying on unstable implementation details, which makes changing those details harder for MS because they try to avoid breaking popular applications. > And why would, say a Lisp compiler use the C library On unix based systems libc doubles as (part of) the OS's API. BSD in particular has no stable syscall interface, code must go through libc. Its libc doesn't even have a stable ABI across major versions, which is annoying if you're not using C. Non C languages are clearly second class citizens on BSD. Linux on the other hand does have a stable documented syscall interface, so you are allowed to call the kernel directly, without relying on any OS provided usermode libraries. On Windows it's similar to BSD, but you have to go through different OS provided libraries (at minimum ntdll, usually the Win32 API). At least these have a stable ABI. On Windows libc is little more than just another dll. > but making this a requirement seems heading the wrong direction. I disagree. IMO an OS provided dynamically linked library is a great abstraction boundary. It allows the OS to change its kernel interface or even turn operations that previously needed to transition into the kernel into purely usermode functions. For example the OS might provide a mutex which in the first version transitions to the kernel on every lock attempt, while later it's replaced by a futex based implementation which only transitions on contented locks. Or more relevant to the linked article, it allows implementing the same API on a completely different kernel (like Wine does), without increasing the kernel's API surface.
- rstuart4133 6y ago> IMO an OS provided dynamically linked library is a great abstraction boundary. In theory, yes that's true. In practice it's a question of whether it actually reduces anybodies work load. If everybody respected the boundary I sure it would reduce Microsofts work load. But as has been reported repeatedly here, that's isn't how it's worked out in practice. Not only do applications not respect it, Microsoft finds itself in the position of having to ensure some of those applications keep working on newer kernel versions despite the fact they've wilfully violated the rules. So we end up the Windows GUI having to expose with "compatibility levels", and users having to deal with it. That doesn't sound like a win to me. There are other ways of doing it that wouldn't suffer from that fate. Trampolines (a page the kernel creates in user space that intercepts some syscalls) is one way that Linux uses. I don't think Linux does, but it wouldn't be hard to insist that any syscall come from those pages. Do that and you have your cake (low overhead user space mediating some calls), and get to eat it to (you can safely assume every one uses it).
- saagarjha 6y agoOpenBSD's technique doesn't really stop any actual attacks, nobody really targets syscall instructions in binaries because most of them don't have them anyways (especially on OpenBSD, where as I understand they aren't stable). You're going to ret2libc and this doesn't do anything to fix that.
- wahern 6y agoTo ret2libc you first need to break ASLR. The point of the OpenBSD mitigation is to address JIT compiler exploits, which permit circumventing ASLR by injecting code to make syscalls directly.
- saagarjha 6y agoGenerally, if you have enough control that you can influence the JIT compiler to emit arbitrary instructions you either already have an address leak or could make one fairly trivially.