Skip to content

fix: report absent sysctl knobs as N/A instead of Unknown - #356

Open
slimm609 wants to merge 1 commit into
mainfrom
fix/sysctl-missing-knob-na
Open

slimm609 wants to merge 1 commit into
mainfrom
fix/sysctl-missing-knob-na

Conversation

@slimm609

Copy link
Copy Markdown
Owner

Fixes #355

Problem

SysctlCheck discarded the error from sysctl.Get and keyed only off an empty value, so on Linux it could not distinguish two very different situations:

  • the knob does not exist on this kernel
  • the knob exists but could not be read, or its value wasn't in the check's value map

Both collapsed to Unknown. kernel.exec-shield is the clearest case — it was a RHEL-only patch that no longer exists in any modern kernel, so it always rendered as Unknown, implying the check was inconclusive rather than inapplicable.

Fix

Drive the result off the read error instead. fs.ErrNotExist maps to N/A; an unreadable, empty, or unrecognized value keeps Unknown.

The issue suggested gating on kernel version. I went with presence detection instead: exec-shield's absence isn't tied to a version boundary (it never existed in vanilla kernels at all), and presence detection generalizes to every sysctl in the registry rather than special-casing one. On the reporter's system that also cleans up anything else their kernel doesn't build in — e.g. dev.tty.legacy_tiocsti, vm.unprivileged_userfaultfd, or kernel.yama.ptrace_scope without YAMA.

This also removes the runtime.GOOS special case: platforms without /proc/sys hit the same ErrNotExist path and still report N/A, so behavior there is unchanged.

Kernel config checks already handled this correctly — absent options are skipped entirely in KernelConfig — so no change was needed there.

Testing

  • 5 new table-driven cases in pkg/checksec/sysctl_test.go covering each branch: absent knob, permission-denied knob, empty value, unmapped value, mapped value
  • gofmt / go vet clean, go build ./... OK, full go test ./... passes

One caveat worth stating plainly: I could not exercise this end-to-end against a real Linux kernel locally (macOS has no /proc, no Docker available), so the Linux path is covered by unit tests on the extracted resolveSysctlResult rather than a live run. CI should cover the real thing.

Docs

Updated the two Unknown entries in the README's sample kernel output (kernel.yama.ptrace_scope, kernel.exec-shield) to match. checksec.bash already prints Unsupported for a missing exec-shield and was left alone.

https://claude.ai/code/session_01QKUqcgQ5TDA2GYJh2MKX9s

SysctlCheck discarded the error from sysctl.Get and keyed only off an
empty value, so on Linux it could not distinguish "this knob does not
exist on this kernel" from "this knob exists but could not be read or
its value was not recognized". Both collapsed to Unknown.

kernel.exec-shield is the clearest case: it was a RHEL-only patch that
no longer exists in any modern kernel, so it always rendered as Unknown,
implying the check was inconclusive rather than inapplicable.

Drive the result off the read error instead: fs.ErrNotExist now maps to
N/A, while an unreadable, empty, or unrecognized value keeps Unknown.
This applies to every sysctl in the registry, not just exec-shield. The
runtime.GOOS special case is no longer needed -- platforms without
/proc/sys hit the same ErrNotExist path and still report N/A.

Fixes #355

Claude-Session: https://claude.ai/code/session_01QKUqcgQ5TDA2GYJh2MKX9s
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.

Suppress kernel.exec-shield on Kernel 7.x and beyond

1 participant