exectop: scoped process-launch monitor - #1
Merged
Merged
Conversation
Shows every program one application starts, folds repetition into one row per command kind, and ranks anything unusual above the rest. Three sched tracepoints maintain one idea: the set of tgids belonging to a traced application, and the stream of execs they perform. fork propagates membership (and depth) to children, exit reaps it, exec emits when the task is in scope. The fork/exit membership pattern follows agent-lock and omp-jail; cgroup-first scoping follows hotspot's argument that a per-task attach races churn and misses anything spawned after you look. argv is read from mm->arg_start..arg_end, which is already a NUL-separated blob, rather than walking the userspace argv pointer array. That avoids the bounded-loop-over-indexed-userspace-pointers the verifier fights, and the object loads clean on 6.12 arm64 with no verifier complaints. Three scope modes. Launch mode (bin/exectop -- <cmd>) parks the target with SIGSTOP until the probe attaches, so the process tree is genuinely complete; it lives in a wrapper script because a yeet isolate deliberately cannot spawn a process. Container mode resolves a name to its root pid and cgroup through the system graph. Pid mode carries an unavoidable attach race, and says so on screen rather than implying otherwise. The outlier pass was designed wrong and real data corrected it. Rarity-first scoring flagged a third of a real npm install, because 11 of 34 distinct commands in an ordinary build run exactly once. Rarity now gates (count <= 3) but never scores: a finding also needs an observed behavior such as fetching from the network, evaluating constructed input, widening permissions, or touching credential paths. Verified across nine real workloads, six benign and three adversarial: the benign ones stay silent, including a build that legitimately curls six times, and the adversarial ones fire. test/heuristics.test.mjs runs the folding and scoring against five recorded captures with no kernel involved. The fixtures are real probe output rather than synthesized: an earlier synthetic version of this suite passed while the heuristics were badly wrong.
Collaborator
Author
CI and
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
exectop: a scoped process-launch monitor. It shows every program one application starts, folds repetition into one row per command kind, and ranks anything unusual above the rest.The scaffold (build system, toolchain, kernel-matrix CI, Apache-2.0) is already on
main. This PR is the tool.Reviewer action items
About description
Topic tags
What it does
Three
schedtracepoints maintain one idea: the set of tgids belonging to a traced application, and the stream of execs they perform.sched_process_forkpropagates membership and depth to children,sched_process_exitreaps it, andsched_process_execemits when the task is in scope. That in-kernel propagation is what makes the scope a process tree rather than a pid.Three ways to name the application:
./bin/exectop -- npm ciSIGSTOPuntil the probe attaches.yeet run . -- --container apiyeet run . -- --pid 4242Findings worth a look
argv without fighting the verifier. The obvious approach walks the userspace
argvpointer array, which is the exact shape the verifier rejects. The kernel already stores the arguments contiguously atmm->arg_start..arg_endas a NUL-separated blob, so one boundedbpf_probe_read_usercopies the lot and JS splits it. Compiles and loads clean on 6.12 arm64, no verifier complaints.The outlier design was wrong and real data corrected it. Rarity-first scoring flagged a third of a real
npm install, because 11 of 34 distinct commands in an ordinary build run exactly once. Rarity now gates (count ≤ 3) but never scores: a finding also needs an observed behavior. Verified across nine real workloads, six benign and three adversarial. The benign set includes a build that legitimatelycurls six times and correctly stays silent.Two yeet envelope traps, both silent. A
char[]field arrives truncated at the first NUL, so a NUL-separated argv yields onlyargv[0]while the length field still reports the true size. And a map declared with scalar__type(key, __u32)silently drops writes from userspace, because the JS map API serializes through BTF and a scalar has no struct to name. Both cost real debugging time and are documented inline.bin/exectopis source, not a build artifact. It was covered by the/bin/*ignore rule and nearly shipped missing. Launch mode has to spawn a process and a yeet isolate deliberately cannot, so that wrapper owns theSIGSTOPhandoff.Positioning
Two of the README's eight questions lean on the supply-chain angle (an untrusted npm package, "is this a replacement for Snyk"). That is the strongest retrieval surface the tool has, and it invites being judged as a security detector, which it is not. Three mitigations are in the draft: the Snyk answer says no plainly, "What gets flagged" explains the rarity gate and the false-positive reasoning, and "What it can't see" leads with the limit that matters most: anything that doesn't exec is invisible, so a package doing damage inside Node with
fetch()rather thancurlproduces no rows at all. Worth a second opinion on whether that balance is right.Naming
Renamed from
execsnoopbefore publishing. That name is Brendan Gregg's bcc tool, a decade old and shipped inbpfcc-toolson every major distro.exectopkeepsexec(the vocabulary that shows up in category queries) and takes the honest category noun: it ranks and aggregates rather than streaming a feed. bcc'sexecsnoopis still named in three places in the README, deliberately, as a referral rather than a leftover.Testing
test/heuristics.test.mjsruns the folding and the outlier scoring against five recorded captures with no kernel involved (16 assertions). The fixtures are real probe output rather than synthesized, because an earlier synthetic version of this suite passed while the heuristics were badly wrong.The kernel matrix runs on this PR across 6.1, 6.6, 6.12 and bpf-next.
What changed
Added — the BPF probe, the three-tier TUI, the aggregation and outlier scoring, three scope modes, the launcher, five demo entry points, the regression suite and its fixtures, and the README.