Affected versions: OpenBSD 7.4

πŸ“– ~4 min read  β€’  Source: OpenBSD 7.4 errata 015_expat

Errata topic: Security: expat (All architectures)

Issued: March 18, 2024

Related CVEs: CVE-2024-28757

Upstream summary: In libexpat fix billion laughs attack vulnerability CVE-2024-28757.

Table of contents
  1. Symptom & Impact
  2. Environment & Reproduction
  3. Root Cause Analysis
  4. Quick Triage
  5. Step-by-Step Diagnosis
  6. Solution – Primary Fix
  7. Solution – Alternative Approaches
  8. Verification & Acceptance Criteria
  9. Rollback Plan
  10. Prevention & Hardening
  11. Related Errors & Cross-Refs
  12. References & Further Reading

Symptom & Impact

On OpenBSD 7.4 hosts the OpenBSD 7.4 errata 015_expat entry covers expat. Until doas syspatch applies the signed binary patch (or the operator builds and installs the upstream source diff), the running kernel and userland on the affected architectures keep the unfixed code paths in place. Defence-in-depth from pledge(2) and unveil(2) (maintained by upstream, not user-tuned) reduces blast radius but does not retire the underlying defect. Edge boxes, firewall hosts under pf(4), and mail relays running smtpd(8) are the typical impact surface.

Environment & Reproduction

Reproduction targets OpenBSD 7.4. Confirm release, kernel build, and currently applied patches:

uname -a
sysctl kern.version
cat /etc/motd
doas syspatch -l               # patches already applied to base
doas syspatch -c               # patches still pending for this release
pkg_info expat 2>/dev/null || true   # only meaningful for ports-side names

Trigger the workflow that exposes expat β€” errata 015_expat β€” security advisory β€” syspatch and remediation while collecting log evidence from syslogd(8):

tail -200 /var/log/messages
tail -200 /var/log/daemon
tail -200 /var/log/authlog
dmesg | tail -200

Root Cause Analysis

Root cause is tracked at OpenBSD 7.4 errata 015_expat. The OpenBSD release engineers shipped a signed patch (015_expat) against the 7.4 base tree; hosts that have not yet run doas syspatch for this release remain exposed. Correlate the timeline of the failure with the patch issue date and with kernel / daemon state:

doas syspatch -l               # already applied
doas syspatch -c               # pending
sysctl kern.version
sysctl kern.osrelease kern.osrevision
tail -500 /var/log/messages
tail -500 /var/log/daemon

Quick Triage

Run these checks on OpenBSD 7.4 to confirm the failure mode and current state of expat / errata 015_expat:

doas syspatch -c               # is THIS errata still pending?
doas syspatch -l               # has it already been applied?
pkg_info -Q expat              # search ports/packages catalogue
pkg_info expat 2>/dev/null     # info on installed port (if any)
tail -100 /var/log/messages
tail -100 /var/log/daemon
dmesg | tail -100
doas pfctl -sr                 # current pf rules, if exposure is network-side
doas pfctl -ss                 # active state table
# If expat maps to an rc(8) service, the script name may differ from the errata tag
# (e.g. 'unbound', 'smtpd', 'httpd'); list and probe with rcctl:
doas rcctl ls started
doas rcctl get expat 2>/dev/null || true

Step-by-Step Diagnosis

  1. List started and enabled services with rcctl(8) β€” the OpenBSD service manager.

    doas rcctl ls started
    doas rcctl ls on
  2. Follow live system, daemon and auth logs.

    tail -F /var/log/messages
    tail -F /var/log/daemon
    tail -F /var/log/authlog
  3. Validate pf(4) rules and state if exposure is network-facing.

    doas pfctl -sr
    doas pfctl -ss
    doas pfctl -si
  4. Inspect kernel and process state.

    dmesg | tail -200
    vmstat 1 5
    systat -b vmstat 1
    fstat | head
    pstat -f | head
  5. Snapshot live packets on the affected interface (replace em0 as needed).

    doas tcpdump -ni em0 -c 200
  6. Confirm the errata is still pending and correlate with the upstream entry.

    doas syspatch -c
  7. Cross-reference findings against OpenBSD 7.4 errata 015_expat to pin the commit that introduced expat β€” errata 015_expat β€” security advisory β€” syspatch and remediation.

Solution – Primary Fix

Apply the signed base-system binary patch with syspatch(8). Patches are signify(1)-verified against /etc/signify/openbsd-74-base.pub before they install:

doas syspatch -c               # list pending patches for this release
doas syspatch                  # apply all pending base patches
doas syspatch -l               # confirm the new patch is in the applied list
# Some patches require restarting a daemon rather than rebooting;
# use rcctl(8) β€” the OpenBSD service manager:
doas rcctl restart expat 2>/dev/null || true
# Patches that touch the kernel or libc require a reboot:
doas shutdown -r now

If the affected component is a port/package rather than base (check with pkg_info expat), upgrade via pkg_add(1) β€” note OpenBSD uses pkg_add/pkg_delete, not pkg:

doas pkg_add -u expat          # upgrade this single package
doas pkg_add -u                # upgrade every installed package
pkg_info expat                 # confirm the new version

Manually verify the signed patch tarball if you do not trust the in-tree mirror selection:

cd /tmp && ftp https://ftp.openbsd.org/pub/OpenBSD/7.4/SHA256.sig
signify -Cp /etc/signify/openbsd-74-base.pub -x SHA256.sig

Need help rolling syspatch across a fleet of OpenBSD edge / firewall / mail-relay boxes? Our IT Solutions & Services team supports OpenBSD edge / firewall / mail relay deployments with signify-verified syspatch automation. Get in touch for a free consultation.

Solution – Alternative Approaches

If syspatch is not viable (unsupported architecture β€” syspatch only ships binary patches for amd64, i386 and arm64; or fully custom kernels) choose from these alternatives:

  • Fetch and apply the upstream source diff, then rebuild the affected subsystem against the release branch (the canonical OpenBSD route on sparc64/powerpc64/riscv64):

    cd /tmp && ftp https://ftp.openbsd.org/pub/OpenBSD/patches/7.4/common/015_expat.patch.sig
    signify -Vep /etc/signify/openbsd-74-base.pub -m 015_expat.patch.sig -x 015_expat.patch.sig
    cd /usr/src && doas patch -p0 < /tmp/015_expat.patch
    # Then rebuild the affected component per the patch header instructions
    # (typical kernel rebuild):
    cd /sys/arch/$(uname -m)/compile/GENERIC.MP && doas make obj && doas make config && doas make && doas make install
    doas shutdown -r now
  • Move to a snapshot (-current) build with sysupgrade when the release branch lags behind a fast-moving fix:

    doas sysupgrade -s             # jump to the current snapshot
    # or to the next release point:
    doas sysupgrade
  • Constrain the exposure window with stricter pf(4) rules until syspatch can run. Edit /etc/pf.conf and reload:

    # /etc/pf.conf β€” minimal hardening snippet
    block return
    pass out quick inet proto { tcp udp icmp }
    pass in quick on egress proto tcp from <trusted> to (egress) port { ssh }
    # then reload:
    doas pfctl -nf /etc/pf.conf    # dry-run / syntax check
    doas pfctl -f  /etc/pf.conf
  • Disable the affected service with rcctl until the patch is rolled (note: some operators install sudo as a port, but OpenBSD ships doas(1) as the default and uses /etc/doas.conf):

    doas rcctl stop  expat 2>/dev/null || true
    doas rcctl disable expat 2>/dev/null || true
  • If the affected component is a port, pin to a known-good build by reinstalling from a saved tarball with pkg_add -D installed.

Verification & Acceptance Criteria

All of these should pass after the fix:

doas syspatch -c               # MUST list no pending patches for this errata
doas syspatch -l               # MUST include this errata id
# If expat is a port/package, confirm the version moved forward:
pkg_info expat 2>/dev/null
tail -50 /var/log/messages    # no new errors after the reboot/restart
tail -50 /var/log/daemon
doas rcctl check expat 2>/dev/null || true

The original reproduction for expat β€” errata 015_expat β€” security advisory β€” syspatch and remediation must not trigger across two consecutive runs.

Rollback Plan

OpenBSD syspatch keeps the pre-patch binaries; rolling back a single base patch is a one-liner. Capture the pre-state first:

doas syspatch -l > /root/syspatch-pre.txt
pkg_info -m > /root/pkg-pre.txt

To revert this specific erratum if the new build misbehaves:

doas syspatch -r               # revert the most recent patch
# If multiple patches landed in the same run and you need an earlier one:
doas syspatch -r               # repeat until syspatch -l matches /root/syspatch-pre.txt
doas shutdown -r now           # reboot if the rollback touched the kernel

For port-side reverts, reinstall the saved binary package:

doas pkg_add -D installed -F update /var/cache/pkg/expat-<previous-version>.tgz

There is no LVM/BE concept on OpenBSD; for full-host rollback take a dump(8) of the affected filesystems before any change and restore from restore(8) if needed.

Prevention & Hardening

Prevent recurrence on OpenBSD 7.4 hosts running expat:

  • Schedule syspatch from cron(8) so signed patches land within hours of publication:

    # /var/cron/tabs/root β€” append:
    ~ * * * *    -ns /usr/sbin/syspatch && /usr/sbin/syspatch -c | grep -q . && logger -t syspatch 'patches pending'
  • Subscribe to [email protected] and to the per-release errata RSS / page at openbsd.org/errata74.html.

  • Pair syspatch with sysupgrade for major version jumps; never let a host drift more than one release behind:

    doas sysupgrade                # next release
    doas sysupgrade -s             # current snapshot (-current)
  • Verify every downloaded SHA256 manifest with signify(1) before trusting it (this is what syspatch does internally β€” replicate it for manual installs):

    signify -Cp /etc/signify/openbsd-74-base.pub -x SHA256.sig
  • Tighten pf(4) with a default-deny ruleset, anchors per service, and rate-limiting on edge interfaces. Reload safely with the dry-run flag:

    doas pfctl -nf /etc/pf.conf    # syntax check only
    doas pfctl -f  /etc/pf.conf    # commit
    doas pfctl -sr | head          # show loaded rules
  • Enable W^X enforcement and rely on upstream-shipped pledge(2) / unveil(2) annotations as defence-in-depth. These are not user-tuned β€” they are baked into each base binary by the OpenBSD developers and reduce the blast radius if a future bug like expat β€” errata 015_expat β€” security advisory β€” syspatch and remediation reappears.

  • If you run expat as an internet-facing service, consider running it under OpenBSD’s built-in daemons β€” httpd(8), relayd(8) and smtpd(8) ship in base and are kept current by the same release-engineering cycle that produces these errata.

  • Manage doas(1) rules carefully in /etc/doas.conf (no sudo by default β€” some shops add the sudo port but doas is the supported tool):

    permit nopass keepenv root
    permit persist :wheel

Issues that commonly surface alongside expat β€” errata 015_expat β€” security advisory β€” syspatch and remediation: stale signify public keys after a release jump, syspatch hanging on a half-applied update, pf rule drift across reboots, and ksh(1) completion mismatches after libc patches. Triage with:

uname -a
doas syspatch -l
doas syspatch -c
doas pfctl -sr
ls -la /etc/signify/

View all openbsd-7-4 tutorials on the Tutorials Hub →

Browse all common problems & solutions on the Tutorials Hub.

References & Further Reading

Primary reference: OpenBSD 7.4 errata 015_expat. Useful manual pages on OpenBSD 7.4:

man syspatch
man sysupgrade
man signify
man pkg_add
man pkg_info
man rcctl
man pf
man pf.conf
man doas
man doas.conf

Other resources: the OpenBSD FAQ at openbsd.org/faq, the per-release errata index at openbsd.org/errata74.html, and the signed release manifest at ftp.openbsd.org/pub/OpenBSD/7.4/SHA256.sig for expat β€” errata 015_expat β€” security advisory β€” syspatch and remediation.


View all OpenBSD 7.4 tutorials on the Tutorials Hub →