In the Linux world, since syscalls are exposed by libc, other non-C runtimes (for example, Go) end up needing to make system calls on their own without the libc wrappers. Is such a system just not a thing in Windows?
In the Linux world, since syscalls are exposed by libc, other non-C runtimes (for example, Go) end up needing to make system calls on their own without the libc wrappers. Is such a system just not a thing in Windows?
They didn't need to, they wanted to, and it can break at any moment on any platform other than Linux. In fact a few versions back they finally back-pedalled and started going through libSystem on OSX.
> Is such a system just not a thing in Windows?
It's not a thing anywhere other than Linux. Go's developers were told time and again that they were supposed to dynamically link to and go through the platform's libc on OSX and BSDs.
They finally relented on OSX after Go broke multiple times during the Sierra beta, but IIRC that's not the case yet for other BSDs (I was thinking it was also the reason why Go 1.11 is required on OpenBSD 6.4, it is but not entirely: OpenBSD requires that stack memory be mapped with MAP_STACK or syscalls will terminate the calling process, so that's an artefact of Go doing userland stacks / threads rather than doing raw syscalls).
Linux is pretty much the only operating system that considers the actual system call ABI to be stable. The BSDs and OS X all want you to use the platform libc instead to access system calls, while Windows uses kernel32.dll et al. as its stable interface.
What about MS-DOS? :P
Yeah, it's not a thing. You just import functions from ntdll the same way you import from anything else. The OS program loader reads your program's import table and loads them for you.
> does ntdll expose any other functionality? Functionality that may want to be overridden by a different implementation, etc?
It exposes lots of other stuff (DLL loading, memory heap, etc.) that you may want to do differently, but you can hook those at runtime if you really want to. It's not as convenient as just linking another library, but on the other hand, it makes it easier to replace them at runtime instead of at compile-time -- say, if you want a shared library to override a syscall.
No, making system call interposition harder isn't a security feature. A user who can LD_PRELOAD you can already do arbitrary things to your program.
Can you elaborate on this? I'm aware of things like LD_PRELOAD, but if an adversary controls the environment, he could just change PATH to point to a rooted version of chrome anyway. That also has to do with the capabilities of the system linker, not glibc.
>the LGPL effectively forbids many projects from using static linking as an escape hatch
The LGPL explicitly allows static linking, that's the main difference versus the GPL.
LGPL allows dynamic linking. Only way it'll allow static is if your releases are accompanied by tools for decompiling and recompiling your binaries with the LGPL bits interchanged. But that actually might not be allowed either, since GCC 4.3+ headers and runtimes (e.g. libstdc++) kind of prohibit you from changing binaries on your own, after they've been compiled.
Can you elaborate on this?
The difference is that calls between dynamic libraries are on the same side of the "airtight hatchway" (as explained by Raymond Chen at https://devblogs.microsoft.com/oldnewthing/20060508-22/?p=31...), while there's a security boundary at the network connection.
What specific threat is bypassing libc supposed to protect against? I don't think you have an argument here. As the poster to whom you're replying mentioned, anyone who can do symbol interposition already has full control over your program.
I consider symbolic interposition to be one of those things. Linux users might not feel comfortable about the fact that glibc currently makes it so easy to intercept system calls to Linux Kernel's RNG, that your upstream dependencies might actually compromise your key generator unintentionally.
Don't you think that's worth discussing? We could also talk about the concerns surrounding Layered Service Providers, which is another great example of userspace libraries misrepresenting APIs that are generally believed to be talking to the operating system.
Users get to control how programs execute. They can interpose symbols. They can disassemble programs. They can run programs under a debugger. They can modify the kernel. They can run programs in a VM. A program can't detect this intermediation; nor does it have any right to do so. A program has no business breaking random OS visibility and control features. We generally call the ones that try malware.
Bypassing libc when making system calls doesn't give a program any insurance against environmental changes. It just inconveniences users while providing no "safety" guarantees. If you want full control over a program's execution environment, ship an appliance.
syscall(SYS_getcpu, &cpu, &node, NULL);AFAIK, there is: Go likes using tiny stacks, while libc expects normal-sized stacks. Switching to a reasonably-sized stack and back has a cost, which the Go developers want to avoid.