Skip to content

R0040: pod-spec exec fallback matches full argv vector#53

Open
entlein wants to merge 17 commits into
upstream-pr/sbob-execsfrom
test-mirror/upstream-pr/sbob-execs-podspec
Open

R0040: pod-spec exec fallback matches full argv vector#53
entlein wants to merge 17 commits into
upstream-pr/sbob-execsfrom
test-mirror/upstream-pr/sbob-execs-podspec

Conversation

@entlein

@entlein entlein commented Jun 4, 2026

Copy link
Copy Markdown

Fork CI test branch for the pod-spec fallback fix.

was_executed_with_args fell back to a path-only pod-spec check, so an exec of a pod-spec-declared binary with unexpected arguments was treated as allowed and R0040 stayed silent. This compares the full runtime argv against the declared command vector (Command++Args, or a lifecycle hook Exec.Command) across main / init / ephemeral containers.

Coverage:

  • unit (exec_podspec_test.go): full-vector match, command+args split, image-entrypoint no-match, PreStop/PostStart hooks, init + ephemeral containers.
  • component (Test_32): podspec_declared_command_matches_silent (exact declared command stays silent), podspec_command_arg_mismatch_fires_R0040 (same binary, undeclared args fires R0040).

entlein and others added 17 commits May 29, 2026 11:45
Signed-off-by: entlein <einentlein@gmail.com>
resolveExecPath and getExecPathWithExePath both gained an
"if argv[0] is absolute, trust argv[0] over exepath" tier in fd9e262.
The justification (busybox-image symlink fidelity — record /bin/sh
instead of /bin/busybox) does not survive the argv[0] spoofing case:
`exec -a /bin/sh sleep 2` yields cmdline=/bin/sh while /proc/<pid>/exe
stays /usr/bin/sleep, so the recorded identity is whatever an
attacker chose, not what actually ran. ap.was_executed lookups for
allowed paths then pass for arbitrary binaries.

Reverts both functions to the v0.3.113 precedence:
  1. exepath (kernel-authoritative)
  2. argv[0] non-empty when exepath empty (fexecve / AT_EMPTY_PATH)
  3. comm

Busybox-image profiles record /bin/busybox (kernel-resolved) — the
v0.3.113 behaviour. The symlink-faithful tier never shipped in a
tagged release; only profiles built against fd9e262 depended on it,
all internal.

Adds explicit absolute-argv[0]-spoof regression tests on both sides
(resolveExecPath and getExecPathWithExePath) pinning that
`args=["/bin/sh", …], exepath="/usr/bin/sleep"` resolves to
`/usr/bin/sleep`. Updated the busybox tests on both sides to reflect
the kernel-authoritative semantics.

Addresses matthyx review on event_reporting.go:63 (2026-05-27).

Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
Prevents Go MVS from picking up a higher storage version pulled in
transitively by other deps. PR kubescape#805 (parse.get_exec_path 3-arg overload,
event_reporting spoof revert, CEL auto-rewrite shim) does not reference
any post-v0.0.258 storage symbol, so v0.0.258 is the floor — and now
also the ceiling.

Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
…just maybe

Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
…rage , lets do a benchmark and get this green before pivoting abck to storage

Signed-off-by: entlein <einentlein@gmail.com>
…x, good thing this ll be squashed

Signed-off-by: entlein <einentlein@gmail.com>
…se the cel rule will be slow

Signed-off-by: entlein <einentlein@gmail.com>
…ow various wildcards

Signed-off-by: entlein <einentlein@gmail.com>
was_executed_with_args fell back to a path-only pod-spec check, so an exec
of a pod-spec-declared binary with unexpected arguments was treated as
allowed and R0040 stayed silent. Compare the full runtime argv against a
declared command vector (Command++Args, or a lifecycle hook Exec.Command)
across main / init / ephemeral containers instead.

Tests:
- unit (exec_podspec_test.go): full-vector match, command+args split,
  image-entrypoint no-match, PreStop/PostStart hooks, init + ephemeral.
- component (Test_32): podspec_declared_command_matches_silent and
  podspec_command_arg_mismatch_fires_R0040.
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8868a2a1-484e-4343-ae4e-5abbf558e816

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test-mirror/upstream-pr/sbob-execs-podspec

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@entlein

entlein commented Jun 4, 2026

Copy link
Copy Markdown
Author

Regression-tested this branch through the fork's real CI (CT run 26974475205): 21/21 GREEN.

Heads-up on the branch itself: test-mirror/upstream-pr/sbob-execs-podspec was named like a mirror but didn't carry the fork's CI — it had no build.yaml and an unpatched component-tests.yaml (upstream's workflow set, which can't build/push a fork image). That's the recurring upstream-pr-vs-fork-workflow gap. I overlaid the fork's build.yaml + patched component-tests.yaml onto a throwaway buildable mirror (this branch / PR #53 head left untouched), built the NA image, and ran CT against it.

Coherence (all anchored on the same content):

  • candidate NA = tip 2a4418b0 = the prior 21/21 33616e03 + the one new commit "R0040: pod-spec exec fallback must match the full argv vector"
  • go.mod already replaces storage => k8sstormcenter/storage@v0.0.240-0.20260601171344-787cc4376971, so it compiled against — and CT deployed — storage image ghcr.io/k8sstormcenter/storage:sbob-execs-787cc437 (the 787cc437 matcher fix, unit-tested green)

Verified from per-job API conclusions (21× success, 0 failure) and the Test_32 log. Test_32 grew from 6 → 8 subtests — the two new pod-spec cases this PR adds both pass:

--- PASS: Test_32_UnexpectedProcessArguments (471.85s)
    --- PASS: sh_dash_c_matches_wildcard_trailing
    --- PASS: sh_dash_x_mismatches_R0040
    --- PASS: echo_hello_matches_wildcard_trailing
    --- PASS: echo_goodbye_mismatches_R0040
    --- PASS: curl_dash_s_one_url_matches_ellipsis
    --- PASS: curl_dash_s_two_urls_mismatches_R0040
    --- PASS: podspec_declared_command_matches_silent          (new)
    --- PASS: podspec_command_arg_mismatch_fires_R0040         (new)

Test_02 (AllAlertsFromMaliciousApp) green; all 21 component tests green. The pod-spec exec fallback change is exercised end-to-end (declared-command match stays silent; arg mismatch fires R0040) with no regressions in the rest of the suite.

@entlein entlein force-pushed the upstream-pr/sbob-execs branch from 7c4f269 to 40647b0 Compare June 17, 2026 10:15
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