$RodHat_
MOTD

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

Published by

OpenBSD 7.10: pledge coverage, a W^X gap closed, and DES finally gone
Photo: AI-generated — no human photographer / RodHat AI Cover

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

  1. OpenBSD 7.10 (OpenBSD Project)
  2. OpenBSD 7.10 release notes (OpenBSD Project)