Skip to content

fix(security): harden conntrack, console and process memory boundaries - #49

Merged
YUZHEthefool merged 8 commits into
mainfrom
fix/security-audit-20261031
Nov 1, 2026
Merged

YUZHEthefool merged 8 commits into
mainfrom
fix/security-audit-20261031

Conversation

@YUZHEthefool

@YUZHEthefool YUZHEthefool commented Oct 31, 2026 •

Copy link
Copy Markdown
Member

Problem and outcome

This change repairs six retained October 31 audit candidates: recoverable conntrack admission, ingress TCP control-state handling, namespace-init signal authority, physical console input ownership, COW heap-shrink invalidation and OOM memory accounting. It is based on 7548e73 after the UID quota work merged. Gracefully closed TCP connections also recover admission capacity, and futex requeue preserves sleeping waiters that arrive during target preparation.

Closes #48.

Design and scope

  • Prefer ordinary conntrack victims, then the oldest UDP stream under capacity pressure. Preserve established TCP, pending egress, namespace shares, the root reserve and transactional rollback. Ingress FIN flags cannot shorten tracking lifetimes; local FIN transitions still commit only after successful egress. Socket-confirmed terminal closure uses a globally unique generation token and settles any final FIN acknowledgement before making the flow replaceable. Half-closed connections remain protected, and stale tokens cannot retire reused tuples or another namespace.
  • Revalidate futex mover counts under the source lock after preparing the target. A late arrival triggers bounded preparation retries before any wake or move. Keep allocation outside metadata locks and retain the existing resource-pressure fallback.
  • Require host-mapped DAC for ancestor-PID-namespace supervision. Share the credential check between syscall preflight and delivery, reject matches between unmapped identities, and preserve self/thread-group authority plus explicitly scoped administrator supervision.
  • Give physical console input to the Ring-0 shell when enabled, otherwise to global init's thread group. Standard input, reopened /dev/console, duplicated descriptors and poll use the same policy. Unauthorized reads return EPERM; read polling reports POLLERR.
  • Flush every removed brk leaf across the address space before releasing frames, including leaves retained by another COW owner. The syscall-test fixture checks completion before page-table pruning.
  • Include committed brk, executable/stack and page-table charges in allocation-free OOM scoring. Exclude sparse mappings, uncharged mremap reservations and pending allocation lanes.
  • Add hosted and Ring-3 regressions, update the exact hosted-count oracle and keep regenerated userspace ELFs in separate commits. Strip non-runtime musl symbols at link time so host-provided debug sections do not exceed the existing 256 KiB exec-image budget; print the actual exec errno on failure. Make the append-position oracle explicitly call pwrite64, and retain a separate non-append libc pwrite() check.

The rejected UID quota candidate matches the existing intended policy. The audit's other hardening observations, deferred coverage and full release qualification are outside this scoped repair.

Kernel safety and invariants

  • Trust boundaries: incoming flow state, signal credentials, physical input and process memory lifecycle.
  • Page tables / usercopy: retain the existing brk reservation, global PT lock and copyout helpers. Last-reference frames are freed only after invalidation; the test probe is restricted to syscall_test.
  • IRQ / locking / SMP: conntrack scanning remains bounded and allocation-free. Close tokens occupy one machine word; the empty ARP pending-queue poll uses a small wrapper before allocating bounded drain batches (112-byte local stack reservation in the verified release build). Console authorization runs outside PCB/keyboard locks during polling. Credential snapshots never hold two PCB locks simultaneously. OOM recovery retains its nonblocking lock scan.
  • Allocation / rollback: failed egress restores the selected UDP stream and namespace counters. No new allocation is introduced in authorization or OOM scoring.
  • ABI: syscall numbers and external layouts are unchanged. Console read permissions and pressure-driven UDP replacement are intentional behavior changes.

Validation evidence

Run locally on Fedora with pinned nightly-2025-12-08, QEMU 11.1.2, OVMF and musl 1.2.6. Each QEMU gate used a preserved copy of its matching ESP; the musl run used one CPU.

Gate Result
make fmt-check, make clippy, make lint (includes ABI oracle) PASS; pre-existing compiler/lint warnings retained
make build; release syscall_test and musl_test kernel builds PASS; isolated boot images preserved
bash scripts/tools/hosted_subcrate_tests.sh PASS: 608 unit tests (including 139 net and 25 robust/futex tests), CpuLocal doctests and 3 test-code compile checks; default parallelism
KERNEL_TEST_CPUS=4 KERNEL_TEST_TIMEOUT=240 bash scripts/gates/boot/ring3_mm_oracle.sh <syscall-test-esp> Latest final-source repeat: 51 passed, 0 failed, PID 1 exit 0. Previous final-source run: 50 passed, 1 failed (selective wait observed one extra wake). Futex parity passed in both.
python3 -m unittest discover -s scripts/tests -p 'gate*test.py' PASS: 26 tests
Network-parser fuzz campaign on 760fc1d: cargo fuzz run fuzz_network_packet -- -runs=10000 -max_len=2048 PASS with ASan/LSan; a sandbox-only LSan process-inspection error was resolved by rerunning the same bounded offline campaign outside that sandbox
BOOT_CHECK_TIMEOUT=120 bash scripts/gates/boot/boot_check.sh <default-esp> QUALIFIED (exit 3): 28 passed / 46 deferred / 0 failed, 1 warning marker
KERNEL_TEST_TIMEOUT=120 bash scripts/gates/boot/kernel_test.sh <default-esp> QUALIFIED (exit 3): 35 passed / 39 deferred / 0 failed, 1 warning marker
smp_test.sh with SMP_TEST_TIMEOUT=120; smp_test_4core.sh with SMP_4CORE_TEST_TIMEOUT=120 Both QUALIFIED (exit 3): 37 passed / 37 deferred / 0 failed; required topology/cross-CPU markers present
Journaled-disk gate on 760fc1d: KERNEL_TEST_DISK=<journaled-disk-copy> KERNEL_TEST_TIMEOUT=120 bash scripts/gates/boot/kernel_test.sh <default-esp> QUALIFIED (exit 3): 35 passed / 39 deferred / 0 failed, 2 warning markers
MUSL_CHECK_TIMEOUT=300 make musl-check (writable TMPDIR, retained serial logs) PASS (exit 0): all required libc/ABI markers, PID 1 exit 0, zero NX faults; complete 300-second observation
Net without default features (cargo check --no-default-features, hosted allocator) PASS
Patch whitespace and generated ELF comparison PASS; syscall fixture SHA-256 7c841717a6475e39d6ff7dd130cbcb0720b3b4cdc83f87f1a6ee98f8c7c10582; musl fixture SHA-256 e9e5b7c271ac66e80769c7c135e14c00cde77214b2ecaa31756bbe4c68ab0c71

The local musl rebuild exposed two existing fixture portability assumptions: debug-heavy host archives produced a 452,984-byte image above the 256 KiB exec budget, and musl 1.2.6 intentionally changed append-mode pwrite() semantics (upstream release announcement). The fixture now strips non-runtime sections and tests the intended Linux append ABI directly, retaining the data/offset assertions and a libc pwrite() check on a non-append descriptor. No exec limit was raised and no gate assertion was disabled. A separate QEMU launch failure from a read-only /var/tmp was corrected by providing a writable TMPDIR.

The TCP follow-up adds capacity recovery, exact-incarnation/namespace isolation, validated socket closure and final-ACK queue-retry regressions. The futex follow-up deterministically inserts a waiter after the preparation snapshot and verifies that it remains asleep on the target. The original four focused hosted regressions failed before their fixes, and a four-CPU guest detected both the console authorization failure and missing heap-shrink flush. These demonstrate the affected code paths, not a complete deployed exploit. The Ring-3 oracle accepts that fixture's intentional page faults; its generic boot harness status 1 is not its verdict. Qualified runtime outcomes retain their WARN/DEFERRED limitations. The selective-wait failure did not recur in the final repeat; its cause is not established or claimed fixed by this PR, so the repeat is not a claim of complete runtime stability. Pre-merge comparison confirmed that both wait_reap_core and the selective-wait fixture are byte-identical to base 7548e73. The existing code publishes an any-child filter before narrowing it to the selected PID, which permits a sibling wake during that interval; this is a possible explanation, not a proven trace of the observed failure. The failure did not report reaping the wrong child.

Kernel fixes: f843a30; syscall fixture: ab858fd; musl portability: dab3b67 and be48a18; musl fixture: 760fc1d; validated TCP close and bounded empty-queue polling: 8c70dc4; futex preparation revalidation: 2787d0c. CI for 2787d0c passed all 14 jobs, including hosted debug/release, kernel build, quality checks, boot/SMP, musl on one and four CPUs, IOMMU, mitigation and QEMU fuzzing. Final pre-merge verification of this exact head found no additional merge-blocking findings; there are no unresolved review threads.

Compatibility and limits

A replaced UDP stream must satisfy NEW-flow firewall policy again. Incoming FIN validation remains the socket layer's responsibility. Conntrack protects half-closed sessions and retires a socket-confirmed terminal flow only after any required final ACK reaches the device queue. Foreground TTY delegation is not implemented, so a separate userspace shell cannot inherit physical input authority from init.

The COW regression measures the actual shootdown path and peer-page preservation; it does not reproduce physical-hardware frame-reuse disclosure. Deployment input exposure, remote source spoofing, full constrained-memory OOM campaigns and cross-user-namespace init-death cascades are not established by these tests. Raw audit records and host-specific reproduction logs remain local under SECURITY.md. No full clean-audit or hardware qualification claim is made.

Checklist

  • Scoped fixes and regressions cover all six retained candidates.
  • Bounded work, lock ordering and transactional rollback are preserved.
  • Source comments document console ownership and conntrack eviction policy.
  • Generated fixtures are separate and reproducible.
  • Applicable local validation and qualified outcomes are recorded above.
  • Required CI and final pre-merge verification are complete.

@github-actions github-actions Bot added area: process/ABI Processes, syscalls, usercopy, signals, ELF, and Linux ABI area: storage/VFS VFS, filesystems, block I/O, and storage images area: network Network stack, sockets, firewall, conntrack, and network namespaces area: userspace Ring-3 programs, libc compatibility, and userspace support area: tests Unit, hosted, runtime, QEMU, SMP, stress, and conformance tests area: tooling/CI Build system, scripts, hooks, automation, and repository tooling size: L 500-999 review lines, excluding generated/binary artifacts bug Something isn't working security Security-sensitive hardening or privately coordinated remediation labels Oct 31, 2026
Bind socket-confirmed closure to the exact conntrack incarnation and make
completed flows replaceable only after any final FIN acknowledgement is
accepted by the transmit queue. Preserve half-close protection, queue retry,
concurrent egress rollback and namespace isolation.

Cover graceful-close capacity recovery, stale tuple tokens, validated socket
states and final ACK queue rejection with hosted regressions. Update the net
suite count from 135 to 139.
Retry preparation when waiters arrive after the source-length snapshot,
before waking or moving any waiter. Bound retries and return a resource error
on persistent churn; retain the existing allocation-pressure fallback.

Add a deterministic regression for publication between preparation and the
locked move, and update the futex hosted suite count from 24 to 25.
@github-actions github-actions Bot added area: IPC Pipes, futexes, message queues, and IPC namespaces size: XL At least 1000 review lines, excluding generated/binary artifacts and removed size: L 500-999 review lines, excluding generated/binary artifacts labels Oct 31, 2026
@YUZHEthefool
YUZHEthefool merged commit 0c7246b into main Nov 1, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: IPC Pipes, futexes, message queues, and IPC namespaces area: network Network stack, sockets, firewall, conntrack, and network namespaces area: process/ABI Processes, syscalls, usercopy, signals, ELF, and Linux ABI area: storage/VFS VFS, filesystems, block I/O, and storage images area: tests Unit, hosted, runtime, QEMU, SMP, stress, and conformance tests area: tooling/CI Build system, scripts, hooks, automation, and repository tooling area: userspace Ring-3 programs, libc compatibility, and userspace support bug Something isn't working security Security-sensitive hardening or privately coordinated remediation size: XL At least 1000 review lines, excluding generated/binary artifacts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Tracking]: harden conntrack admission, console ownership and memory lifecycle

1 participant