Skip to content

issues: an optional severity field flags dangerous defects for one query - #1174

Merged
Japabu merged 3 commits into
mainfrom
issues-severity
Nov 4, 2026
Merged

Japabu merged 3 commits into
mainfrom
issues-severity

Conversation

@Japabu

@Japabu Japabu commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Problem and result

Dangerous defects could not be found without reading every record. Per the owner's ruling of 2026-11-04, issue frontmatter now takes an optional severity field. It holds a YAML flow list of fixed flags, for example severity: [security, hang]:

  • security: breaks an isolation boundary or an authority by itself. One client exhausting a resource other clients need counts. A missing hardening layer that needs another bug to exploit does not.
  • data-loss: loses or corrupts stored or in-flight data. Accepted data later reported lost counts. A refusal that loses nothing it had already accepted does not.
  • hang: a wait with no failure timeout, or lost progress.
  • kernel-from-userland: userland input can panic or degrade the kernel.

If the field is absent, no flag applies. Only a defect, or a finding that describes one, may carry it. There is no scale, and performance is not a flag. issues/README.md documents the field beside status and kind, with one rg query per flag.

Shape. The list is real YAML and stays on one line. No flag name is a substring of another, so rg -l '^severity:.*<flag>' issues/ matches exactly and works for records with several flags.

No validator is extended. None exists. build/userlandhost.rs's owed reads one named record's status and nothing else, and build/ and tests/ hold nothing else that parses the frontmatter. Following the brief, no new gate is added.

Backfill

72 records carry the field. Every one carries a single flag: no record's text supported a second one.

query records
rg -l '^severity:.*security' issues/ 25
rg -l '^severity:.*data-loss' issues/ 16
rg -l '^severity:.*hang' issues/ 24
rg -l '^severity:.*kernel-from-userland' issues/ 7
rg -l '^severity:' issues/ 72

The triage flagged 76 records. 69 of them still exist, and I read each one in full. The other seven were closed by fixes: a-counters-read-under-host-load-can-go-silent-for-15-s (28a9812), a-fresh-kernel-heap-chunk-holds-its-frames-last-owners-bytes (cc347f3), the-kernels-relro-stays-writable (4c03026), and four closed by 938c4a7 (a-new-x86-thread-enters-ring-3-holding-kernel-register-values, aarch64-el1-runs-without-pan, interrupt-entry-keeps-a-ring-3-ac-flag, user-pointer-checks-have-no-spectre-v1-fence-and-smap-is-optional).

I also scanned the 378 open defects the triage left unflagged, by slug and triage note, and read the candidates. I read the five defects filed since the triage base a0e8f1333 and the findings the triage never classified.

Disagreements with the triage

The triage letters are X=security, D=data-loss, T=hang and U=kernel-from-userland.

Flag removed (20).

record triage reason
a-corrupt-chain-met-by-a-queued-free-is-answered-by-the-next-call D The chain was already corrupt on the medium. The defect is that the error is attributed to the wrong call.
a-disk-plugged-in-after-settling-is-routed-as-soon-as-it-is-offered X The record shows no spoof: open sessions stay on the disk that offered first. The defect is a duplicate rule nobody stated.
a-file-server-waits-30-s-on-a-block-port-nobody-serves-and-says-nothing T The wait ends after about 30 s. The defect is its silence and its length, not a missing bound.
a-held-launcher-that-will-not-open-is-a-direct-spawn X The caller could already make the direct spawn, so it gains no authority. The defect is an unreported failure.
a-replayed-bcachefs-node-past-seven-nodes-is-refused D The mount stops read-only by name.
bcachefs-reclaim-reserves-are-sized-for-common-rewrites D The mount stops read-only by name. The record says the medium stays consistent and replays.
the-bcachefs-btree-room-bound-counts-no-reclaim-cascade D Same as the previous row.
a-stick-that-answers-late-is-broken-by-the-two-second-abandon D The stick goes offline, and that is reported. The record names no lost data, and the kernel driver it describes is gone.
a-t14-boot-said-rebooting-and-the-host-never-came-back T The record says a hang, the firmware and the host's network cannot be told apart.
a-threads-kernel-stack-has-no-guard-page X Missing hardening: no untrusted party is shown to reach the overflow.
an-executables-relro-stays-writable X Missing hardening: exploiting it needs a stray write first.
x86-64s-boot-map-is-writable-and-executable X Missing hardening: nothing untrusted runs on that map.
a-working-directory-path-reads-its-dot-dot-off-the-text X It resolves inside the process's own capabilities. This is a POSIX-conformance defect.
every-job-test-runner-starts-holds-its-whole-system-capability X It affects test images only, which do not ship.
test-runner-holds-logread-where-no-log-builtin-runs X It affects test images only, and the right is unused.
a-process-name-is-written-into-the-kernels-own-records-unsanitised U The record names only test judges as consumers of the forged record. Same standard as the test-only over-grants (review r1).
a-stops-file-sync-and-its-failure-are-never-recorded D The record shows the sync outcome cannot be observed, not that data is lost (review r1).
spawn-thread-disagrees-about-a-reaped-parent U The record leaves open whether the entry can be missing. Flag it once that is settled.
the-nvme-driver-resets-a-drive-that-is-slow-and-healthy D The record itself says "a loss reported for a drive that lost nothing".

Flag changed (4).

record triage now reason
a-claimed-function-can-storm-its-cpu X kernel-from-userland A holder's device degrades cpu0.
a-late-write-from-a-released-function-halts-the-machine X kernel-from-userland One process's bug halts the kernel.
a-cut-bulk-only-command-does-not-brick-the-benchs-stick D hang No data is reported lost. The record's exit is the hang that leaves the stick unenumerable.
the-shell-runs-a-command-whose-redirect-it-could-not-open X data-loss Output meant for the file is not stored, and the status says success. Nothing crosses a boundary.

Flag added where the triage had none (23). one-diskserver-session-can-hold-every-device-slot keeps the triage's security, under the denial-of-service ruling below.

  • security:
    • intels-store-forwarding-predictor-times-constant-time-code-by-its-data (filed after the triage)
    • the-avx2-poly1305-runs-under-intels-mxcsr-dependent-timing (filed after the triage)
    • user-pointer-checks-have-no-spectre-v1-fence, which succeeds the closed record the triage flagged
    • a-driver-that-reflashes-its-device-escapes-its-isolation
    • a-received-handle-has-no-knowable-type
    • a-driver-that-lends-its-device-a-handle-a-peer-sent-is-ended-when-it-is-no-region
    • a-class-claims-poll-in-flight-lands-after-the-claims-release
    • netstack-lookup-slots-have-no-per-client-share
    • netstacks-places-are-one-number-for-every-client. These two are the same class as one-program-that-fills-a-servers-table-holds-every-other-client-out.
    • Four speculative-execution gaps that leak across boundaries without another bug, each naming an affected supported machine: no-entry-or-switch-clears-the-bhb-fills-the-rsb-or-issues-an-ibpb, no-program-runs-with-speculative-store-bypass-disabled, indirect-branches-and-returns-run-without-thunks, spec-ctrl-and-gds-stay-as-firmware-left-them.
  • data-loss:
    • a-reallocated-extent-on-data-keeps-the-deleted-files-bytes (measured, never shown fixed)
    • a-forced-reboots-last-userland-lines-miss-the-console
  • kernel-from-userland:
    • a-claim-spends-device-addresses-its-slot-never-gets-back: a holder that claims, allocates and dies in a loop leaks remapping tables until Tables::alloc panics the kernel (review r1).
  • hang:
    • a-cpu-that-stops-passing-takes-the-console-with-it-when-its-driver-is-queued-there (a finding, renamed on main)
    • libc-childrens-tty-interrupt-can-stall-at-the-nested-shells-line (added after the rebase)
    • the-console-input-path-can-stop-after-a-ps2-overflow
    • spawned-process-never-starts
    • pulling-the-boot-stick-freezes-the-t14
    • t14-desktop-froze-at-64s
    • a-panic-reentry-inside-a-fatal-paths-console-hold-halts-with-it-held

Considered and left unflagged:

  • no-rule-decides-l1tf-mitigation-for-an-affected-intel-cpu and tsx-stays-as-firmware-left-it: neither names a supported machine that is affected.
  • Exploit-hardening gaps: stack protector, shadow stacks, IBT, ASLR/KASLR, the per-syscall stack offset, SLUB-style heap hardening, RNG reseeding, and secrets left in freed memory.
  • the-i8042s-holder-holds-the-machines-reset-line and the-acpi-servers-holder-drives-the-embedded-controller-unfiltered: these are privileges the signed image grants inside the trusted base.

Review round 1

  • Done: the data-loss clause narrowed to the reviewer's test; kernel-from-userland added to a-claim-spends-device-addresses-its-slot-never-gets-back; tsx-stays-as-firmware-left-it and the process-name record dropped; data-loss dropped from a-stops-file-sync-and-its-failure-are-never-recorded; the README query comments shortened.
  • Denial of service is now in the security definition and one-diskserver-session-can-hold-every-device-slot is flagged. This is the coordinator's ruling and still needs the owner's confirmation. If he rules the other way, six records lose security: that one, no-physical-memory-fairness, four-shares-take-a-file-server, both netstack records and one-program-that-fills-a-servers-table-holds-every-other-client-out.

Rebase onto main (ce3e5e4de)

  • Main deleted two flagged records, and they stay deleted: a-bounded-post-spends-its-wake-on-a-waiter-that-then-dies (hang, fixed by sched: a waiter a kill ends passes on the bounded post it may hold #1168) and the-console-loses-typed-keystrokes-under-host-load (data-loss, closed by issues: close the load-only records whose tests are deleted #1171).
  • Main renamed two flagged records, and the field followed both: a-woken-thread-can-wait-seconds-on-an-idle-cpu-under-hvf and a-cpu-that-stops-passing-takes-the-console-with-it-when-its-driver-is-queued-there. I re-read main's edits to the flagged records (the console carrier, the forced reboot's lines, the ps2 overflow). Each still supports its flag.
  • Main added three records, all kind: tooling, which may not carry the field. Of the unflagged records main modified, libc-childrens-tty-interrupt-can-stall-at-the-nested-shells-line now carries hang: its typed line never becomes held, and only the probe's 120 s ceiling ends the run.
  • Consolidate storage around native bcachefs and userland filesystems #1152's records are not on main yet. On its branch, a-sync-commits-the-entry-of-a-file-whose-pages-were-refused qualifies for data-loss: after a stop the file reads blocks that never got its pages. a-refused-carried-file-costs-every-other-files-fsync-or-leaks-its-blocks qualifies for data-loss because of its leak after a stop, by the same standard as the FAT leaks. Consolidate storage around native bcachefs and userland filesystems #1152 should add both when it lands.

Checks

  • cargo run -- --ci host: exit 0, Host(None): 109 step(s), all green. It ran on base 783569506 with this branch's Markdown edits uncommitted, a tree identical to round 0's head e5fd14458. Every later commit, the rebase onto ce3e5e4de included, changes only Markdown under issues/ relative to main. The only part of a record a host check reads is a status line, in build/userlandhost.rs, and no commit here changes one. Main's own code changes since that run were checked by their own merges, so I did not rerun. Log: https://github.com/ToyOSOrg/evidence/blob/cfa684c4a2200beb61d71c718f33d26be2af1373/r1/ci-host.log
  • The rg queries above, run on head 0fee9ecbb. Their counts are in the table.
  • I checked that every added severity: line sits inside its record's frontmatter. All 72 records are kind: defect or kind: finding.

Markdown only, so no image or guest test can change.

Risks

  • The flags are one agent's reading of each record's text. Several are judgment calls: the hardening rule, test-only over-grants, and read-only stops. Each one is listed above so it can be overturned.
  • I scanned the unflagged defects through their triage notes and read only the candidates in full. A record whose slug and note hide a qualifying defect may still be missing its flag.
  • Nothing enforces the field. Another kind can carry it, or a misspelled flag can appear, until review catches it.

🤖 Generated with Claude Code

@Japabu

Japabu commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator Author

Review of #1174 at e5fd144

Architecture and fit. This change touches Markdown only: 90 lines added and 4 removed, made of 14 README lines and one frontmatter line in each of 74 records. It adds no gate or tool, which matches the brief, and build/ holds no frontmatter parser that needs extending. The README implements the owner's design as approved: the field is optional, the four flags are fixed, there is no scale, performance is not a flag, it is limited to defects and defect-findings, and there is one rg query per flag. "Five fields, three required" is accurate (status, kind and opened are required; task and severity are optional). Nothing outside issues/ mentions the frontmatter fields, so no other instruction needs updating.

Queries. I ran them myself on the branch: 26, 18, 24 and 6 records, 74 in total. That is 74 ^severity: lines in 74 files, each inside its frontmatter after kind: and each in a defect or finding record. No flag name is a substring of another, and no body line begins with severity:, so every query matches exactly.

Findings

BLOCKER issues/README.md:38: the data-loss clause "a failure reported to the caller is not" does not describe the rule the backfill applied, and it is unsound as a definition.

  • The backfill contradicts it. logkeeper-ends-the-boots-log-on-one-refused-create… is flagged even though its create was refused to logkeeper, its caller. a-file-held-across-a-file-servers-restart-answers-gone is flagged even though logd is answered Gone.
  • Read literally, it excludes real loss. Write-back data can be dropped and the error reported only at the next fsync. The loss still happened.
  • What the drops actually used. The 18 drops (the bcachefs read-only stops, a-corrupt-chain…, the-nvme-driver-resets…) all rest on a narrower test: the operation was refused and nothing it had already accepted was lost.

State that test. For example: "loses or corrupts stored or in-flight data; a refusal that loses nothing already accepted is not".

BLOCKER issues/a-claim-spends-device-addresses-its-slot-never-gets-back.md: this record is missing severity: [kernel-from-userland]. Its own text says every table under a fresh grant address comes from Tables::alloc. That function's expect("no physical memory for a remapping table") panics the kernel when physical memory runs out, and no table a claim made is ever freed. So a holder that claims, allocates and dies in a loop leaks kernel memory toward a kernel panic. Any job can also exhaust memory, as no-physical-memory-fairness records, so the next claim panics. a-claimed-function-can-storm-its-cpu already treats a claim holder as userland, so by the PR's own standard this record qualifies. The fix is one line.

SUGGESTION issues/README.md:37: five security records rest on reading cross-client resource exhaustion as a broken isolation boundary:

  • no-physical-memory-fairness
  • four-shares-take-a-file-server
  • netstack-lookup-slots-have-no-per-client-share
  • netstacks-places-are-one-number-for-every-client
  • one-program-that-fills-a-servers-table-holds-every-other-client-out

Meanwhile one-diskserver-session-can-hold-every-device-slot was dropped as "fairness, not denial". The definition is silent on denial of service, so the next triager can read it either way. Whether one client shutting out others counts is the owner's call. Either record the ruling in the clause or ask him.

SUGGESTION The security judgment calls use inconsistent standards:

  • Affected hardware. tsx-stays-as-firmware-left-it is flagged, but its text names no supported machine affected by TAA. no-rule-decides-l1tf-mitigation… was left unflagged for exactly that reason.
  • Test-only consumers. a-process-name-is-written-into-the-kernels-own-records-unsanitised is flagged, but the only consumers its text names are the test judges (bootlog::EXIT, Boot::exit_code). The test-runner over-grants were dropped because they affect test images only.

Apply one standard to each pair.

SUGGESTION issues/a-stops-file-sync-and-its-failure-are-never-recorded.md: the defect it describes is that a stop's sync outcome is not observable. The record does not show that data is lost because of it. The flag is weakly supported; consider dropping it.

SUGGESTION issues/README.md:12-15: the query comments paraphrase the table again, and the security comment drops the table's "by itself". Shortening each comment to the flag's subject would keep one home per definition. This is optional; the existing status lines carry comments in the same style.

Clauses and sample

  • Hardening clause. The security exclusion for a missing hardening layer that needs another bug is sound. It follows from "by itself", and the backfill applied it consistently: the guard page, executable RELRO and the x86-64 boot map were dropped, while vendor speculation gaps exploitable without a software bug were kept.

  • Data-loss clause. It is sound only in the narrower form above.

  • The 18 drops. I read all of them. Each is supported by its record's own text. spawn-thread-disagrees-about-a-reaped-parent is fine as left: the record leaves open whether the entry can be missing.

  • The flagged sample. I read 31 flagged records:

    • security: the five above, a-received-handle-has-no-knowable-type, a-class-claims-poll…, the AVX2 Poly1305 record, tsx, spec-ctrl, ssbd, thunks, sshserver-authorized-keys and the process-name record.
    • data-loss: both console-loss records, a-64-mib-write…, fat-unlink…, a-file-held…, std-file-lock…, the-nvme-driver-reads…, a-write-back…, logkeeper…, a-stops-file-sync…, a-forced-reboot…, a-reallocated-extent… and nothing-reclaims….
    • hang: the boot-deadline-late record, klogd under HVF, the AMD hard-lockup record, TCO, t14-desktop-froze, spawned-process-never-starts, a-cut-bulk-only… and a-cpu-that-stops-passing.
    • kernel-from-userland: the heap-fragmentation, refused-syscall-log, claim-storm and late-write records.

    Apart from the points above, each flag is supported by its record's text.

  • Misses. I scanned the 408 unflagged defects and findings by keyword. Apart from the claim record, nothing I found clearly qualifies. copy-meets-a-remap… panics only under a test actuator that has been deleted.

Evidence. The change is Markdown only, so no build or guest test can change. The host-CI log was recorded on a tree said to be identical to the head; I did not need it to verify anything.

SEND BACK

Japabu added a commit that referenced this pull request Nov 4, 2026
…f service is security

- data-loss: a refusal that loses nothing it had already accepted does not
  qualify; accepted data later reported lost does.
- security: one client exhausting a resource other clients need counts (the
  coordinator's ruling, pending the owner), so
  one-diskserver-session-can-hold-every-device-slot is flagged.
- a-claim-spends-device-addresses-its-slot-never-gets-back is
  kernel-from-userland: a holder looping claim, allocate and die leaks
  remapping tables until Tables::alloc panics the kernel.
- One standard for each pair. tsx-stays-as-firmware-left-it names no affected
  machine, like L1TF. The process-name record's forged records reach only test
  judges, like the test over-grants. Both lose security.
- a-stops-file-sync-and-its-failure-are-never-recorded shows an outcome that
  cannot be observed, not lost data, so it loses data-loss.
- The README's query comments are shortened.

Now 73 records: security 25, data-loss 17, hang 24, kernel-from-userland 7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu

Japabu commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator Author

Orchestrator verification: round 1 (e5fd14458..2422f0e44) touches only records under issues/, with no code. It makes the six requested changes. The two definitions (hardening gaps are not security; starving other clients of a shared resource is security) are the orchestrator's ruling.

@Japabu
Japabu marked this pull request as ready for review November 4, 2026 21:30
@Japabu
Japabu enabled auto-merge November 4, 2026 21:30
@Japabu
Japabu disabled auto-merge November 4, 2026 21:30
Japabu and others added 3 commits November 4, 2026 22:31
The owner's ruling of 2026-11-04 adds `severity` to the issue frontmatter: a
list drawn from four flags (security, data-loss, hang,
kernel-from-userland), carried only by a defect or a finding that describes
one, with no scale. issues/README.md defines each flag beside status and
kind and gives one rg query per flag.

No tool validates issue frontmatter, so none is extended.

The backfill reads each record the 2026-11-03 triage flagged that still
exists (69 of 76; the other seven were closed by fixes), keeps a flag only
where the record's own text supports it, and adds records the triage did not
flag: the records opened since, the findings it did not classify, and
unflagged defects that clearly qualify. 74 records carry the field: 26
security, 18 data-loss, 24 hang, 6 kernel-from-userland. The pull request
lists each disagreement with the triage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…f service is security

- data-loss: a refusal that loses nothing it had already accepted does not
  qualify; accepted data later reported lost does.
- security: one client exhausting a resource other clients need counts (the
  coordinator's ruling, pending the owner), so
  one-diskserver-session-can-hold-every-device-slot is flagged.
- a-claim-spends-device-addresses-its-slot-never-gets-back is
  kernel-from-userland: a holder looping claim, allocate and die leaks
  remapping tables until Tables::alloc panics the kernel.
- One standard for each pair. tsx-stays-as-firmware-left-it names no affected
  machine, like L1TF. The process-name record's forged records reach only test
  judges, like the test over-grants. Both lose security.
- a-stops-file-sync-and-its-failure-are-never-recorded shows an outcome that
  cannot be observed, not lost data, so it loses data-loss.
- The README's query comments are shortened.

Now 73 records: security 25, data-loss 17, hang 24, kernel-from-userland 7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Its typed line never becomes a held line, and only the probe's 120 s
ceiling ends the run: lost progress, like the ps2 overflow's.

After the rebase onto main, 72 records carry severity: security 25,
data-loss 16, hang 24, kernel-from-userland 7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu
Japabu added this pull request to the merge queue Nov 4, 2026
Merged via the queue into main with commit 1049225 Nov 4, 2026
5 checks passed
@Japabu
Japabu deleted the issues-severity branch November 4, 2026 21:37
Japabu added a commit that referenced this pull request Nov 4, 2026
Brings #1176 (the declared QEMU moves to 11.1.3) and #1174 (the optional
issue severity field). One conflict: main added `severity: [security]` to
issues/a-swapped-binary-lives-where-any-process-can-rewrite-it.md, which
this branch closes (swap lends the bytes in a memory region the
supervisor verifies); the deletion stands. The issues this branch files
carry no severity flag: none of the four applies to them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant