deniz.in

Markets

Weather

Loading weather

· via Hacker News – Front Page (native)

OpenBSD root exploit traced to 37-year-old shared memory bug from original BSD

Security researchers at Calif turned a shared-memory counter flaw dating back roughly 37 years to the original BSD sources into a local root exploit on OpenBSD, combined with an out-of-bounds kernel write fixed in errata 026 and 018.

OpenBSD root exploit traced to 37-year-old shared memory bug from original BSD

Security researchers at Calif have published a write-up, currently on the Hacker News front page, demonstrating a local privilege escalation to root on OpenBSD that relies on a kernel bug traceable roughly 37 years back to the original BSD source tree. According to Calif, the exploit reaches a root shell even with OpenBSD's KARL kernel relinking, SMAP and SMEP enabled, and without relying on a separate information disclosure vulnerability.

A 16-bit counter with a long memory

Calif says the root of the problem is a shared memory attachment counter, declared as a signed 16-bit short in code inherited from the original BSD. By keeping shared memory attachment records alive while forking processes over and over, an attacker can push that counter past its maximum value of 32,767 and force it to wrap negative. The researchers report reaching -32,643 by mapping 127 SysV shared memory segments, releasing them with munmap(), and forking 259 processes.

That integer overflow can then be converted into a use-after-free through a race condition: one process calls IPC_RMID while a helper process attaches a size-confused shared memory segment. Calif reported the issue, along with suggested patches, to OpenBSD; the overflow was addressed in errata 026, while the separate out-of-bounds kernel write used in the chain was fixed in errata 018.

From counter wrap to kernel code execution

The write-up walks the entire path. The researchers groomed the kernel heap while watching metrics from sysctl(KERN_MALLOCSTATS), such as kb_total and kb_totalfree, to track when fresh pages were allocated. They then aligned IP socket allocations and set IP_MULTICAST_TTL to a non-default value of 2, forcing the allocation of a persistent 16-byte struct ip_moptions whose final word packs two 16-bit counters. The conditional -1 out-of-bounds write was aimed at that structure, overwriting both the current and maximum membership fields. Closing the socket traverses the group members and triggers atomic decrements that modify the self-referential page table mapping twice, switching it from user-accessible to supervisor-accessible and thereby neutralizing SMAP and SMEP. From there, overwriting a predictable kernel pointer yielded kernel code execution, after which the researchers cleaned up shared memory accounting and restored the pointer to obtain a root shell.

Calif characterizes the end result as a write-what-where primitive: the write came from a TAILQ_REMOVE, the "what" was a userland mapping made supervisor-accessible, and the "where" was a predictable kernel pointer location.

KARL does not cover the allocators

The research also explains why OpenBSD's relinking did not stop the attack. KARL randomizes function and data addresses in the kernel binary, but according to Calif the kernel's memory allocators remain deterministic: neither the boot-time allocator nor the best-fit allocator randomizes its base address, so early boot allocations land at predictable locations across reboots on identical hardware. Structures allocated at those addresses that contain function pointers become attractive targets. The exploit, for instance, reliably targeted the lo0 and enc0 ioctl handlers, overwriting one for control flow and using the other to restore the original value.

Proposed hardening

Beyond the errata fixes, Calif outlines several defenses. Safe-unlinking would verify doubly linked list invariants before performing unlink writes and abort or panic on violation; FreeBSD and NetBSD already implement this in sys/queue.h. The self-referential PTE mapping slot could be randomized at boot, or the PTE marked read-only and only made writable during modification. The kernel allocator could be made non-deterministic by randomizing its base address and the runtime allocation order. Compiler defenses also factor in: Calif has proposed the array bounds sanitizer to FreeBSD as a release-build mitigation and privately reported 21 issues it would have caught, some with local privilege escalation impact, while the upcoming Alloc Tokens feature could isolate pointer-containing allocations to blunt heap overflows and use-after-free exploitation.

Why it matters

OpenBSD has spent decades building its reputation on source auditing, insecure API replacement, privilege separation and memory safety mitigations, yet this bug survived all of it for 37 years, inherited from ancestral BSD code. That is a sobering reminder that even the most audited codebases can carry long-lived flaws, and that heritage code remains a quiet liability. The work also shows that hardening one layer, such as the kernel binary itself, can be undermined by deterministic subsystems elsewhere, so defenses need to cover allocators and data structures too. With Calif noting that AI-assisted vulnerability discovery is lowering the cost of finding bugs, neutralizing entire classes of exploitation primitives, rather than patching bugs one at a time, looks like the more durable strategy. For OpenBSD operators, the immediate action is straightforward: apply errata 026 and 018.

  • #openbsd
  • #kernel-security
  • #privilege-escalation
  • #integer-overflow
  • #exploit