OpenBSD 7.10: pledge coverage, a W^X gap closed, and DES finally gone
Published by RodHat

OpenBSD ships every six months. October, April, repeat, since 1996. Whatever else is happening in the industry, whatever conference was just held and whatever thing someone’s calling “cloud-native security” this week, OpenBSD ships on schedule, the release notes land on openbsd.org, and the Theo de Raadt email list post reads like it always has. If you don’t run OpenBSD, you should still read those notes. The project documents things Linux vendors shipped broken for fifteen years and called fine.
7.10 has three changes worth pulling apart.
pledge(2) coverage for httpd and bgpd
pledge(2) is OpenBSD’s syscall restriction interface. A process calls it early in
startup, names the set of system calls it legitimately needs, and from that point
forward any syscall outside that set kills the process. Not the request. The process.
Hard.
7.10 extends pledge coverage to httpd and bgpd. Both daemons have been in the base
system for years. httpd has had privilege separation since 2015 and bgpd since
2004. What they did not have was a formal pledge declaration that would catch a syscall
the daemon has no business making, even from within a privilege-separated worker.
The distinction matters. Privilege separation splits a daemon into a privileged parent and an unprivileged worker, so that if the worker gets compromised the attacker lands in a box with minimal rights. Pledge layers on top of that by restricting which syscalls even the privileged parent is allowed to make. Privsep limits blast radius. Pledge shrinks the attack surface of the allowed code itself.
If you run bgpd, you are running software that accepts untrusted route advertisements
from the internet’s full collection of AS operators, some of whom are incompetent and
some of whom are adversarial. The bgpd pledge coverage means a bug in route
advertisement parsing that somehow reaches exec-class syscall territory now kills the
process rather than running the attacker’s code. That is the correct behavior.
Linux has seccomp-bpf for the same purpose. It has been in the kernel since 3.5,
released 2012. Fourteen years on, default pledge coverage across base daemons is still
not a thing Linux distros do. Landlock has been upstream for five years and almost
nobody is deploying it. OpenBSD
ships it as table stakes for a daemon that handles routing.
W^X enforcement in the dynamic linker
Write XOR Execute is OpenBSD’s memory permission policy: no page is simultaneously
writable and executable. It has been policy for a very long time. The practical
enforcement is per-page at the mmap(2)/mprotect(2) boundary, and the kernel
enforces it.
7.10 closes a gap in ld.so, the dynamic linker. During library loading, ld.so was
briefly mapping pages with write and execute permissions simultaneously to relocate PLT
entries before switching to execute-only. The window was narrow: just the relocation
phase of library loading. But it was a real W^X violation, and on a system where the
threat model includes attacker-controlled libraries or attacker-influenced load order,
a window during dlopen(3) is an exploitable window.
The fix is not clever. ld.so now does the work in two passes: write first, then
separately transition to execute. The pages are never simultaneously W+X. The PLT
relocation still happens, it just doesn’t violate the invariant to do it.
This is the kind of thing that takes years to find because the enforcement is kernel-side
and ld.so is trusted code running before your process has a chance to set any of its
own policies. The kernel trusts ld.so. An attacker who can influence library loading
is standing in that trust relationship. The fix removes the trust gap rather than
auditing who’s standing in it.
DES gone
The base system’s last DES-based authentication code is removed in 7.10. This includes
the legacy crypt(3) DES path and the des_crypt support in pam compat shims.
DES is a 56-bit block cipher from 1977. It is not slow to break. It has not been slow to break since the late 1990s. Every modern password hashing scheme uses bcrypt, scrypt, or Argon2id, all of which have been in OpenBSD’s base for longer than most current sysadmins have been running systems. There is no deployment that legitimately needs DES-based password hashing in 2026.
The argument for keeping compatibility code is “someone might have it.” The argument against is that compatibility code for a broken algorithm is exactly the code that gets called when an attacker needs it to be. OpenBSD’s answer is to remove it and let whoever “might” need it file a bug explaining why.
The OpenSSH DSA removal followed the same logic: keep old broken crypto around long enough for legitimate users to migrate, then cut it. The base system is not a museum.
Why you should read this even on Linux
Rod runs FreeBSD. He is not about to tell you to swap your entire userland for an operating system with different design goals. But there is a real habit worth cultivating: read every OpenBSD release’s notes on the day they drop.
The pledge coverage improvements describe syscall restriction patterns that work on any
Unix with seccomp or similar. The W^X enforcement work describes a class of linker-phase
vulnerability that exists everywhere ld.so runs. The DES removal is a reminder of
how long “legacy compatibility” outlives any reason for it to exist.
OpenBSD externalizes the threat model that most Linux distros keep implicit. The prctl hardening options that achieve partial pledge-equivalent behavior on Linux exist specifically because the threat models OpenBSD documented are real. Read the release notes. Then go check whether your daemons have equivalent coverage on whatever you’re actually running.
If they don’t, that’s your next week’s work.
Sources
- OpenBSD 7.10 (OpenBSD Project)
- OpenBSD 7.10 release notes (OpenBSD Project)