Skip to content

wp_seed_src: read /dev/urandom via raw fd to avoid seccomp SIGSYS#440

Open
ColtonWilley wants to merge 1 commit into
wolfSSL:masterfrom
ColtonWilley:seed-src-seccomp-sigsys-fix
Open

wp_seed_src: read /dev/urandom via raw fd to avoid seccomp SIGSYS#440
ColtonWilley wants to merge 1 commit into
wolfSSL:masterfrom
ColtonWilley:seed-src-seccomp-sigsys-fix

Conversation

@ColtonWilley

Copy link
Copy Markdown
Contributor

Problem

SEED-SRC read /dev/urandom through a buffered stdio FILE* (XFOPEN). That breaks OpenSSH's privsep preauth child:

  1. sshd primes its RNG (seed_rng -> RAND_status) before the privsep fork, so the first fread pulls a block of read-ahead into the stdio buffer.
  2. The child inherits the buffered FILE* and its fd.
  3. On child exit, glibc stdio cleanup calls lseek() to discard the unread read-ahead.
  4. lseek() is not in OpenSSH's preauth seccomp allow-list, so the child is killed with SIGSYS (audit shows sig=31 syscall=8).

Stock OpenSSL reads the device with a raw fd and never hits this; the buffered FILE* was the defect. Separately, re-initializing SEED-SRC (a second provider load) orphaned the previous buffered handle.

Fix

  • Read /dev/urandom with a raw fd (open/read/close, O_CLOEXEC). No stdio buffer, so no read-ahead and no exit-time lseek.
  • Share the fd and the wolfSSL seed callback across provider contexts, reference counted. The last unload closes the fd and restores the seed callback to wc_GenerateSeed — not NULL, which would make a later wc_InitRng fail DRBG_NO_SEED_CB under FIPS.
  • SEED-SRC now depends on wolfSSL file support; NO_WOLFSSL_DIR builds #error rather than silently falling back.

Tests

  • test_seccomp_sandbox — runs under the verbatim OpenSSH 9.9p1 preauth filter: single-context (the original crash), re-init, and multi-context survivor. Compiled in with -DWP_TEST_SECCOMP_SANDBOX (enabled by the seed-src CI job; a skip stub otherwise, since it needs PR_SET_SECCOMP).
  • test_seed_src_refcount — multi-context refcount; the first unload must not close the shared fd.
  • test_seed_src_reload — drives the refcount to zero (fd close + seed-callback restore) and reloads; re-exec'd so the count actually reaches zero, which the main suite's own reference otherwise prevents.

SEED-SRC opened /dev/urandom with XFOPEN (buffered fopen). The first
fread pulls read-ahead into the stdio buffer. sshd primes its RNG before
the privsep fork, so the preauth child inherits that buffered FILE*; at
child exit glibc stdio cleanup calls lseek() to drop the unread
read-ahead. lseek() isn't in OpenSSH's preauth seccomp filter, so the
child is killed with SIGSYS.

Use a raw fd (open/read/close, O_CLOEXEC) instead: no buffer, no
read-ahead, no exit-time lseek, matching OpenSSL's own device seeding.
The fd and wolfSSL seed callback are shared and reference counted across
provider contexts; the last unload closes the fd and restores the seed
callback to wc_GenerateSeed (not NULL, which fails wc_InitRng with
DRBG_NO_SEED_CB under FIPS). Also fixes a re-init leak that orphaned the
prior buffered handle.
@ColtonWilley ColtonWilley added the ci:all PR OSP toggle: run all label Jul 10, 2026

@padelsbach padelsbach left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good improvement. Couple nits

Comment thread src/wp_seed_src.c

(void)os;

if (WP_URANDOM_LOCK() != 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to the lock, should probably check that the refcount >= 1 just to make sure the file is still open

Comment thread src/wp_seed_src.c
{
if (g_urandom_fd == XBADFD) {
do {
g_urandom_fd = open(URANDOM_PATH, O_RDONLY | O_CLOEXEC);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use XOPEN here for consistency?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:all PR OSP toggle: run all

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants