From my reading, when your code starts up, it calls pinsyscall indicating “my execve stub is at N..N+P” - which means any attempt to hijack into execve from a vulnerability (which won’t be in the N..N+P range) will get you a SIGKILL. i.e. you can still call execve from your code all you want because you bounce through the known stub.
Sure, I just don’t know if this is intended to be called from usercode (fine) or from pre-main libc entrypoint code, which would prevent manual execve syscalls.
At least, that would break every compiled program that invokes execve on its own, right? … Unless it static links libc, I guess.
This might be a difference, since I’m used to Linux. Does OpenBSD see syscalls or libc library calls as the “official kernel interface”? It sounds like libc?
Yep, it’s libc is the official interface that remains stable between releases (well, at the source level anyway; OpenBSD doesn’t guarantee binary compatibility between successive releases)
As I understand it, Linux is the outlier in having the official ABI at the syscall level. macOS, Windows, *BSD, illumos, etc. all treat libc (or equivalently libSystem on macOS, and win32.dll on Windows), as the official interface with to the kernel.
That’s only sort of true. It allows running binaries compiled for earlier versions using it’s COMPAT_FREEBSD layers (that are optional). These compatibility layers exist precisely because the ABI is allowed to break between major releases.
If you wrote an assembly program that manually made syscalls back on FreeBSD 11, you could run the binaries that were compiled for FreeBSD 11 fine on modern FreeBSD as it would properly detect that it needs a compatibility layer. But if you were to recompile it on the latest FreeBSD version, there’s no guarantee that it would work.
I can’t quite tell from your comment but it seems like you might be thinking about the syscall at too high of a level. Programs that call execve are doing it via the libc wrapper while this works at the next level down. So a program can call libc’s wrapper all they want, regardless of which code pins the program to that particular wrapper for the syscall. What they can’t do is implement their own syscalls, at the instruction level.
I believe this was already the case with msyscall(2). That’s scoped to all syscalls though, where pinsyscall(2) appears to further narrow the scope for specific syscalls (the example here being execve(2).
I remember in the security lab I was briefly interning at in 2011 that we were always talking about how at least at a theoretical level, the interesting control flow attacks were basically solved by control flow graph validators and that the grunt work to make them practical was “just around the corner” so we shifted focus to non-control data attacks that required far more detailed invariant detection and enforcement to address. While I think we were a bit too optimistic about the timeline for control graph validation, it’s nice to see stuff like this starting to make shallow aspects of it practical.
Why would you call it poorly worded? It seems like a fairly level-headed assessment of OpenBSD’s security features. There’s praise and disapproval given based on the merits of each, comparing to other platforms as well.
If your takeaway from reading that website is a fairly level-headed assessment of anything then I’m not sure what to tell you. It’s my personal opinion that it’s anything but that.
The person who’s maintaining the website is one of the persons who’s doing the talk but not walking the walk, i.e. a blabbermouth.
Qualys on the other hand is actively trying to exploit the latest OpenSSH vulnerability and found some valid shortcomings in OpenBSD’s malloc. otto@ who wrote otto-malloc, acknowledged them and is already working on an improved version.
Does this mean that programs cannot perform those syscalls from outside the libc at all anymore?
From my reading, when your code starts up, it calls
pinsyscall
indicating “myexecve
stub is atN..N+P
” - which means any attempt to hijack intoexecve
from a vulnerability (which won’t be in theN..N+P
range) will get you aSIGKILL
. i.e. you can still callexecve
from your code all you want because you bounce through the known stub.Sure, I just don’t know if this is intended to be called from usercode (fine) or from pre-main libc entrypoint code, which would prevent manual execve syscalls.
At least, that would break every compiled program that invokes
execve
on its own, right? … Unless it static links libc, I guess.You, the programmer, do not need to do anything:
ld.so(1)
will callpinsyscall
for dynamically linked binaries. For static binaries, some of the initialization code will do it.This might be a difference, since I’m used to Linux. Does OpenBSD see syscalls or libc library calls as the “official kernel interface”? It sounds like libc?
edit: Ah, the LWN article supports this.
Yep, it’s libc is the official interface that remains stable between releases (well, at the source level anyway; OpenBSD doesn’t guarantee binary compatibility between successive releases)
As I understand it, Linux is the outlier in having the official ABI at the syscall level. macOS, Windows, *BSD, illumos, etc. all treat libc (or equivalently libSystem on macOS, and win32.dll on Windows), as the official interface with to the kernel.
Freebsd has a stable syscall interface.
That’s only sort of true. It allows running binaries compiled for earlier versions using it’s COMPAT_FREEBSD layers (that are optional). These compatibility layers exist precisely because the ABI is allowed to break between major releases.
If you wrote an assembly program that manually made syscalls back on FreeBSD 11, you could run the binaries that were compiled for FreeBSD 11 fine on modern FreeBSD as it would properly detect that it needs a compatibility layer. But if you were to recompile it on the latest FreeBSD version, there’s no guarantee that it would work.
I can’t quite tell from your comment but it seems like you might be thinking about the syscall at too high of a level. Programs that call
execve
are doing it via the libc wrapper while this works at the next level down. So a program can call libc’s wrapper all they want, regardless of which code pins the program to that particular wrapper for the syscall. What they can’t do is implement their own syscalls, at the instruction level.That’s been the case for 3-4 years now.
See https://www.mail-archive.com/tech@openbsd.org/msg54429.html and a 3rd party writeup on it at https://lwn.net/Articles/806776/
I believe this was already the case with msyscall(2). That’s scoped to all syscalls though, where
pinsyscall(2)
appears to further narrow the scope for specific syscalls (the example here beingexecve(2)
.I remember in the security lab I was briefly interning at in 2011 that we were always talking about how at least at a theoretical level, the interesting control flow attacks were basically solved by control flow graph validators and that the grunt work to make them practical was “just around the corner” so we shifted focus to non-control data attacks that required far more detailed invariant detection and enforcement to address. While I think we were a bit too optimistic about the timeline for control graph validation, it’s nice to see stuff like this starting to make shallow aspects of it practical.
Seems isopenbsdsecu.re is already on it.
Yeah, they’re obsessed with doling out poorly worded opinions about everything OpenBSD does.
Why would you call it poorly worded? It seems like a fairly level-headed assessment of OpenBSD’s security features. There’s praise and disapproval given based on the merits of each, comparing to other platforms as well.
If your takeaway from reading that website is a fairly level-headed assessment of anything then I’m not sure what to tell you. It’s my personal opinion that it’s anything but that.
The person who’s maintaining the website is one of the persons who’s doing the talk but not walking the walk, i.e. a blabbermouth.
Qualys on the other hand is actively trying to exploit the latest OpenSSH vulnerability and found some valid shortcomings in OpenBSD’s malloc. otto@ who wrote otto-malloc, acknowledged them and is already working on an improved version.