
OpenBSD system-call-origin verification - swills
https://lwn.net/Articles/806776/
======
quotemstr
I strongly support this policy not only for security, but also for general
operating system robustness. Linux is pretty much the only system that places
the ABI compatibility boundary and the machine privilege level boundary in the
same place in the stack. I think that's the wrong place: it pushes a lot of
complexity that could be in userspace into the kernel, because the kernel is
the first place past the ABI break. Linux would be better if nobody except
libc were allowed to make system calls and we just made libc (or a giant VDSO)
the ABI support boundary.

We should at the very least have a VDSO for every system call. There should be
_some_ opportunity to run code in userspace before a privilege transition.
Doing so would give us a lot more flexibility than we have now.

For example, consider socketcall(2): for a long time, all Linux socket system
calls (like recvmsg) were multiplexed through a single system call. A few
years ago, the kernel community realized that this multiplexing was a bad idea
and made individual system calls for all the traditional socket operations.
But since we have to support old programs, we have socketcall(2) _and_ the new
system calls in the kernel. Why should we?

If the ABI support level had been libc all along, we could have changed the
system call strategy (from multiplexing to fine-grained calls) transparently
without bloating the kernel with compatibility code.

~~~
saagarjha
> We should have a VDSO for every system call.

This doesn't really make sense; the vDSO only works for system calls that do
nothing but read a value from the kernel and return it to userspace.

~~~
quotemstr
Not the case. Some VDSOs just forward to regular system calls. Try
clock_gettime with CLOCK_BOOTTIME sometime. (I need to send a patch to fix
this. Maybe over Christmas.)

Requiring that every system call go through a VDSO would be great because it
would give us a "hook" for changing system behavior before entering the
kernel, which is a good thing, because in the age of speculative execution
mitigations, entering the kernel is expensive, just like in the days of yore.

~~~
saagarjha
On my computer I ended up going through a rdtsc instead of a syscall…

------
gok
This is a pretty weak security mitigation since any ROP attack will typically
achieve return-to-libc anyway, but yelling at people who make syscalls
directly is good.

~~~
nineteen999
> but yelling at people who make syscalls directly is good.

Why though? Doesn't this mean that all non-C based languages are going to be
treated somewhat as second class citizens, having to link the standard C
library (eg. as Go is doing on some platforms) in order to call into the
kernel?

While languages such as Go and Rust are aiming to replace/displace C due to it
being designed in an age where security was considered less of an issue, it
seems counter-intuitive to me that we should insist that they should link in
the apparent attack surface of the standard C library. The syscall boundary
seems an ideal place to make the delineation between the kernel and userland
via an established API, and I would have expected that languages that want to
displace C be able to use that interface directly in order to bypass the
standard C library. That would seem to allow userlands to be built that
include no C code whatsoever. But I'm very obviously no expert.

~~~
gok
It's totally acceptable to write to libc in something other than C, or in fact
to write libc itself in something other than C.

~~~
pjmlp
Example, Microsoft has rewritten their C standard library in C++ with extern
"C" entry points.

~~~
nineteen999
Yes. Microsoft have made a number of silly mistakes with respect to OS design,
which has cost them the server space outside of authentication for your and my
lifetime. Bloat is not the answer to either security or performance problems.

~~~
pjmlp
Quite the contrary, I admire Microsoft for being one of the first companies to
start driving C away from our IT stacks.

Thankfully Apple, Google, IBM and Unisys seem to be on the same boat.

------
blinskey
Folks interested in this sort of news might also enjoy the OpenBSD Journal,
which covered this recently, albeit more succinctly:
[https://undeadly.org/cgi?action=article;sid=20191202105849](https://undeadly.org/cgi?action=article;sid=20191202105849)

~~~
claudiawerner
Totally off-topic, but it's interesting how the URL uses ; as the GET
parameter separator rather than &.

~~~
pas
The internal syntax and semantics of the query part is not really defined by
HTTP.
([https://tools.ietf.org/html/rfc3986#section-3.4](https://tools.ietf.org/html/rfc3986#section-3.4))

Also:

"Historic RFC 1866 (obsoleted by RFC 2854) encourages CGI authors to support
';' in addition to '&'"

[https://en.wikipedia.org/wiki/URL#cite_note-23](https://en.wikipedia.org/wiki/URL#cite_note-23)

------
gpvos
_> Since OpenBSD is largely in control of its user-space applications, it can
enforce restrictions that would be difficult to enact in a more loosely
coupled system like Linux, however._

In which ways is OpenBSD more in control of userspace applications, and in
which ways is Linux more loosely coupled?

 _> Switching Go to use the libc wrappers (as is already done on Solaris and
macOS)_

Did Solaris and macOS also do that for security reasons? (A linked article
mentions ABI instability as the reason, but maybe there's more to it.)

~~~
merlincorey
> In which ways is OpenBSD more in control of userspace applications, and in
> which ways is Linux more loosely coupled?

One of the major differences between Unix and Linux is which parts of the
system are in the source tree.

Linux is technically just the kernel, and a Linux distribution will put
together the base libraries and userland programs and kernel along with
various tools for installing and managing.

Kernel space programs are generally the kernel itself and device drivers.

Base userland programs are things like `cat` and `ls` and more that allow for
manipulating and inspecting parts of the system. User-space programs are any
userland program which is not in kernel-space, including third party packages
and custom software written by the user.

Userland programs need to be linked against libraries, which is where libc
comes in.

In most BSD Unix systems, the source tree will include the kernel and the base
userland programs together.

That means that OpenBSD's versions of `libc` and `ls` are maintained in the
same source tree as the kernel, allowing for much tighter coupling and
integration for changes.

By contrast, the Linux distributions are generally using some versions of GNU
C and GNU Coreutils, perhaps with patches downstream.

So a core change to the Linux kernel must make its way upstream to the user
space application and then downstream from that, the distribution must
integrate both.

This is much more loosely coupled and should hopefully illustrate the
difficulty in coordinating such a change in Linux.

~~~
saagarjha
The coupling here is specifically the lockstep of the kernel syscall ABI and
libc.

------
Animats
This effectively treats libc as a trusted interface. Checking should be at the
protection boundary, the system call. This just makes attacks more
complicated, not less successful.

~~~
miohtama
In a long run the non-complicated solution is to get rid of anything that can
compile to something with a buffer overflow.

Just half trolling.

~~~
jacquesm
There goes Rust I guess...

~~~
pjmlp
I doubt we will ever see a UNIX clone written in Rust.

An OS that happens to expose some support for POSIX, yeah (e.g. Redox), but
anything else wouldn't be an UNIX clone per se.

~~~
clarry
And that's all good, we don't need more people cloning an OS that was good 50
years ago.

Modern software is sidestepping the UNIX way left and right. Rightly so, as
anyone who's tried to write anything serious in shell would know. Or anyone
who realizes that non-blocking I/O was an afterthought (look into the history
of select(2) and why libraries like libev exist and what problems they run
into on unix derivatives..) and that there's still nothing like a standard,
robust, well designed async I/O API.

~~~
pjmlp
UNIX was good, for an OS given away with source code and an almost free
license (versus what other mainframe OS were asking for).

History would be quite different if AT&T was allowed to sell it from day one.

------
haecceity
So what's stopping the attacker from searching the libc export table for the
right syscall wrapper?

~~~
saagarjha
ASLR, for one.

~~~
haecceity
Can't they use dlopen to find libc?

~~~
asveikau
dlopen is a dynamically linked function, so they would have to find that too.
Its location will also be randomized.

Note we are talking about exploit code here, i.e. you have just exploited a
buffer overflow, not ELF code loaded in a well behaved fashion.

------
jedisct1
And then WebAssembly will ruin all these efforts.

~~~
saagarjha
WebAssembly should not be making direct system calls anyways.

