summaryrefslogtreecommitdiff
path: root/internal/generate/classify_test.go
AgeCommit message (Collapse)Author
12 daysfix(classify): capture timerfd_gettime/settime + splice/tee fd, not KindNullPaul Buetow
Root cause: the generic field matcher classifyByField only maps an arg literally named "fd" to KindFd. Several syscalls operate on an EXISTING fd whose tracepoint arg0 is named something else, so they fell through to KindNull -> null_event, capturing NO descriptor and dropping the fd they act on: - timerfd_gettime / timerfd_settime: arg0 is "int ufd" (the timerfd) - splice: arg0 is "int fd_in" (source fd of an in-kernel transfer) - tee: arg0 is "int fdin" (source fd of an in-kernel transfer) Fix: add explicit KindFd overrides for these four sys_enter_* keys to nameOnlyKindsTable so the enter handler captures arg0, mirroring the established epoll_wait(epfd) / mq_*(mqdes) / sendfile64(out_fd) / copy_file_range(fd_in) precedent. splice/tee were surfaced by a systemic sweep of tracepoint formats for fd-typed arg0 named other than "fd" that currently classify to null; they are TransferClassified siblings of sendfile64/copy_file_range and clearly fd-operating. The *at() family (dfd arg0) is intentionally untouched: it is path-classified, and timerfd_create remains the KindEventfd fd CREATOR. Regenerated artifacts (mage generate): the four enter handlers now emit fd_event capturing ctx->args[0] instead of null_event; exit handlers stay UNCLASSIFIED. Updated the generated kind maps, the golden result.txt, the classify_test expectations, and docs/syscall-tracing-plan.md (moved the four from kind "null" to kind "fd"; families IPC/Network unchanged). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01fix(classify): mq_timedsend returns status, not bytes — make ret UNCLASSIFIEDPaul Buetow
mq_timedsend(2)/mq_send(3) return 0 on success or -1 on error; the payload size msg_len is an INPUT argument, never the return value. It was wrongly listed in retClassifications as WriteClassified, which made bytesFromRet attribute its 0 return as "bytes written" (the stats engine WriteClassified path). Remove it so its return stays UNCLASSIFIED, consistent with its POSIX mq sibling mq_timedreceive (which legitimately stays ReadClassified because it returns the received byte count). This is the exact same defect just fixed for SysV msgsnd (5057bd9) and mirrors the msgrcv/msgsnd asymmetry. Regenerated tracepoints/docs accordingly and updated the pre-existing classify unit test and the TestPosixMqBasic integration assertion: the mq_timedsend send no longer asserts a write byte count (now expects 0), while mq_timedreceive keeps its received-byte-count assertion. Verified: mage generate idempotent, mage build OK, internal/generate tests pass. TestPosixMqBasic skips in this sandbox (mq_open: permission denied) but compiles with the corrected assertions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01test(generate): remove redundant pure-classification unit testsPaul Buetow
Classification correctness (which family/kind/return-class a syscall maps to) is verified by inspection against the man pages and the classifier rules, not by dedicated unit tests. The tracing-relevant outcome — which fd/path/byte-count the generated BPF C actually captures — is covered by the GenerateTracepointsC codegen tests and the end-to-end integration tests, all of which are retained. Removed: - internal/generate/family_test.go (ClassifySyscallFamily / .Family table) - internal/generate/retclassify_test.go (ClassifyRet read/write/transfer/ unclassified tables) - ~70 pure-classification tests trimmed from classify_test.go, keeping only the GenerateTracepointsC codegen/tracing tests plus the shared helpers (mustParseAll, mqFormats, phaseAFormats, syntheticEnter/Exit, itoa) used by codegen_test.go. - pure-classification funcs interleaved in codegen_test.go (TestClassifyRet*Unclassified, TestClassifyTkillFallsThroughToNull, Test{Mkdirat,Rmdir}FamilyAndKindMatchSiblings). Kept all TestGenerate* handler tests (they assert the generated BPF C captures the correct fd/path/arg-index/return classification), the isNoreturnSyscall tests, docs-drift guards, eventloop dispatch tests, and the integration suite — so every affected syscall still has tracing coverage. No tracing gaps discovered. generate package: go test (incl. -race) green; mage build green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(generate): lock in pwritev WRITE byte-count classificationPaul Buetow
Audit of pwritev(2) confirmed the existing classification is correct: pwritev returns the number of bytes written, so its exit is WRITE_CLASSIFIED (matching write/pwrite64/writev/pwritev2), fd is at args[0] (KindFd), and it lives in the FS family. The read-side sibling preadv stays READ_CLASSIFIED. No implementation changes were needed. Add TestClassifyPwritevWriteByteCount as a lock-in test mirroring the prior pwritev2/pwrite64 audits, with a preadv off-by-one contrast guard and transfer/unclassified negative checks across the whole p/readv/writev family so any stray reclassification trips the test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(pipe): lock in pipe/pipe2 IPC classification and fd-pair exit readsPaul Buetow
Audit of pipe(2)/pipe2(2) (task dx) confirmed the tracing implementation is correct: KindPipe (not KindFd, since args[0] is an output ptr to int[2], not an fd), FamilyIPC, and an UNCLASSIFIED int return. Enter stashes the output ptr (flags=0 for pipe, args[1] for pipe2); exit reads the fd pair via bpf_probe_read_user guarded by ret==0, mirroring the socketpair pipe-like pattern. The only gaps were missing lock-in tests, now added: - codegen: assert the exit handler reads the fd pair from the stashed output buffer (ret==0 guard, bpf_probe_read_user, fd0/fd1) and that the flag-less pipe variant hardcodes flags=0 and never reads args[1]. - classify: pipe/pipe2 are never KindFd and stay UNCLASSIFIED on ret. - runtime: a failed pipe (ret==-1) tracks no descriptors and attaches no file. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(arch_prctl): lock in KindNull/UNCLASSIFIED + FamilyProcessPaul Buetow
Audit of the arch_prctl(2) syscall found the tracing implementation already correct and consistent with the man page: - enter classifies as KindNull (op/addr never captured as fd/path) - exit is a ret_event with UNCLASSIFIED ret_type (int 0/-1 status) - family is Process (deliberately, unlike its x86 siblings ioperm/iopl/modify_ldt which are Misc), in sync with the docs and the tracepoints drift tests Add dedicated lock-in tests mirroring the prior iopl audit, using the real kernel tracepoint fields (option/arg2 on enter, ret on exit) so the heuristics are proven safe even without the name-only mapping. Also add explicit FamilyProcess assertions for arch_prctl and personality to guard against drift toward Misc. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(socketpair): lock in domain-is-not-an-fd invariant (c00)Paul Buetow
Audit of socketpair(2) found the tracing implementation already correct: KindSocketpair captures the two output fds from the sv[2] buffer (args[3]) at exit and never treats args[0] (the address-family/domain constant) as a file descriptor. Family=Network and UNCLASSIFIED ret are consistent with the socket/accept siblings and the docs. Add regression lock-in tests so a future field-shape or classification change cannot silently regress to recording the domain integer as a bogus fd: - TestClassifySocketpairNotFd: pins the name-based override so socketpair is KindSocketpair, never the generic KindFd path that reads args[0]. - TestHandleSocketpairExitDoesNotTrackDomainAsFd: uses AF_INET6 (10), distinct from the returned fds, and asserts fd 10 is never tracked while sv0/sv1 are. - TestHandleSocketpairExitDropsFdsOnError: on ret!=0 no descriptors are tracked. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(setsockopt): lock in KindFd enter, UNCLASSIFIED exit, Network familyPaul Buetow
Audit of setsockopt(2) found the tracing implementation already correct: sockfd captured at ctx->args[0] (KindFd), exit ret_event UNCLASSIFIED, and FamilyNetwork — matching the man page and the bind/connect/getsockname/ getpeername/getsockopt siblings, with generated C/Go and docs all consistent. Add lock-in tests mirroring prior per-syscall audits: - TestClassifySetsockoptEnterFd: enter is KindFd with no pathname capture, asserted against the real sockfd/level/optname/optval/optlen fields. - TestClassifyExitSetsockoptUnclassifiedRet: exit is KindRet + UNCLASSIFIED (0/-1 status, not a byte count). - TestClassifyExitGetsockoptUnclassifiedRet: same for the read-side sibling. - TestClassifySyscallFamily: pin setsockopt (enter+exit) and getsockopt to FamilyNetwork. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(request_key): lock in keyctl kind, security family, and unclassified returnPaul Buetow
Audit of request_key(2) found the tracing implementation already correct and consistent with the man page and the prior keyctl audit (task 7v): request_key classifies as KindKeyctl/FamilySecurity, the BPF handler captures option=-2 sentinel and key_serial=dest_keyring (args[3]) with no path/string capture of the const char * type/description/callout_info key-metadata args, and the exit returns a key serial / -1 that stays UNCLASSIFIED. Strengthen the dedicated TestClassifyRequestKey beyond a bare kind check to also assert PathnameField stays empty (string args are key metadata, not paths), family is Security on enter and exit, and the return is UNCLASSIFIED — bringing it to parity with the add_key contrast assertion. No code/generated changes; mage generate produces no diff. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(generate): lock in pwrite64 WRITE_CLASSIFIED auditPaul Buetow
Add TestClassifyPwrite64WriteByteCount pinning the pwrite64(2) audit: fd at args[0] (KindFd), FS family, and WRITE_CLASSIFIED return (the syscall returns the number of bytes written). Asserts pread64 stays READ_CLASSIFIED as the read-side positional contrast, guards against transfer/unclassified misclassification, and checks the write/pread sibling group so a stray reclassification trips the test. No implementation changes: classify.go, family.go, generated C/Go, and docs/syscall-tracing-plan.md were already consistent and correct. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(generate): lock in lseek classification (offset, not byte count)Paul Buetow
Audit of lseek(2) confirmed the tracing implementation is already correct: enter is a KindFd fd_event capturing the fd from args[0], the syscall is FamilyFS alongside its read/write/fsync siblings, and the exit is a plain ret_event that stays UNCLASSIFIED. lseek returns the RESULTING file offset (off_t, bytes from the start of the file), which is a file position, NOT a count of bytes transferred — so it must never be READ/WRITE/TRANSFER classified, which would wrongly inflate I/O byte totals. Add lock-in tests pinning that behaviour so a future reclassification trips: - FormatLseek/FormatExitLseek tracepoint fixtures. - TestClassifyFdLseek: enter resolves to KindFd (fd at args[0]). - TestClassifyRetExitLseek: exit is KindRet and ClassifyRet stays UNCLASSIFIED. - lseek entry in TestClassifySyscallPairAccepted (end-to-end pair). - FS-family asserts for sys_enter/exit_lseek in family_test. - Enriched UNCLASSIFIED comment in retclassify_test explaining offset != bytes. No generated-artifact changes (mage generate produces no diff); no in-scope bugs and no out-of-scope follow-ups found. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(generate): lock in io_uring_register classification auditPaul Buetow
Audit of io_uring_register(2) confirmed the existing tracing is correct: KindFd with the io_uring fd captured at args[0], FamilyAIO (matching io_uring_setup/io_uring_enter), and an UNCLASSIFIED ret_event exit. The sys_enter_io_ KindNull prefix rule does NOT mis-catch it because classifyNameOnly consults the exact nameOnlyKindsTable (KindFd) before the prefix list. Add two lock-in tests to guard these invariants: - TestIoUringRegisterTablePrecedenceOverIoPrefix: the explicit KindFd table entry wins over the sys_enter_io_ KindNull prefix rule (with an io_submit sanity check that the prefix rule still yields KindNull for fd-less AIO siblings). - TestIoUringRegisterReturnUnclassified: the exit returns 0/small-positive, never a byte count, so the io_uring group stays out of retClassifications. No code, docs, or generated artifacts changed; mage generate produces no diff. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(getsockname): lock in KindFd/FamilyNetwork/UNCLASSIFIED classificationPaul Buetow
Audit of getsockname(2) confirmed correct tracing: enter is KindFd with the sockfd captured from args[0], family is FamilyNetwork, and the exit ret_event is UNCLASSIFIED (0/-1, no byte count) — matching the man page and its bind/connect/listen/accept/getpeername siblings. Integration coverage already exists (ioworkload calls Getsockname; TestSocketIntro- spection asserts enter_getsockname). Add lock-in tests symmetric with the existing getpeername coverage: - TestClassifyExitGetsockname: exit tracepoint maps to KindRet. - TestGenerateGetsocknameHandler: enter captures fd=args[0]; the addr output pointer (args[1]) and addrlen in/out pointer (args[2]) are not captured, and the exit stays UNCLASSIFIED. - FormatGetsockname/FormatExitGetsockname fixtures copied verbatim from the real kernel tracepoint format (third arg is a pointer, unlike bind's by-value addrlen). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(getcwd): lock in KindNull enter + exit-time cwd resolutionPaul Buetow
Audit of the getcwd(2) tracing path. getcwd's args[0] is a char *buf OUTPUT buffer: the kernel writes the absolute cwd path into it and the contents are only valid AFTER the syscall returns. Reading it at enter would capture an empty/garbage string, so getcwd is correctly KindNull at enter and the cwd is resolved at EXIT from /proc/<tid>/cwd when the return value is positive (handleNullExit). Family FS, docs and drift tests already aligned; no behavior change required. Add lock-in tests pinning the correct behavior: - generate: strengthen TestClassifyNullGetcwd to assert the enter kind is never KindPathname/KindName and no pathname field is captured; add TestClassifyByFieldGetcwdBufNotPath proving the generic field classifier never treats char *buf as a path (defense-in-depth). - eventloop: add GetcwdFailureEventTest asserting that a failed getcwd (negative errno, e.g. -ERANGE) attaches no cwd path, and document the output-buffer nuance in the success-case test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(kill): lock in KindNull enter and UNCLASSIFIED retPaul Buetow
Audit of kill(2) (pid_t pid, int sig): the pid at args[0] is a process/ process-group identifier and sig a signal number, neither an fd nor a path, so the enter tracepoint is KindNull and the int 0/-1 return is a status code (UNCLASSIFIED), not a transferred byte count. Classification and docs (Signals/null) already matched and need no change. Add TestClassifyExitKillUnclassifiedRet (the return-value lock-in its signal siblings tkill/tgkill/rt_sigqueueinfo already have) and harden TestClassifyKillExplicitNull to assert no PathnameField is captured, documenting the deliberate contrast with pidfd_send_signal (KindFd/IPC, args[0] is a real pidfd). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(iopl): lock in KindNull enter and UNCLASSIFIED ret classificationPaul Buetow
Audit of iopl(2) (task wu). iopl(int level) changes the x86 I/O privilege level of the calling thread and returns int 0/-1. The existing coverage only asserted KindNull via a synthetic arg0 field (TestClassifyE7NullNameOnlyKinds) and the FamilyMisc family tag (from the prior ioperm audit, task uu). Add dedicated lock-in tests that use the real 'int level' tracepoint field to prove it is never captured as an fd or path, and that the sys_exit_iopl ret stays KindRet/UNCLASSIFIED (a status code, not a transferred byte count). No implementation, generated-artifact, or docs changes were needed - everything already matched the man page. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(gettid): lock in KindNull/FamilyProcess/UNCLASSIFIED classificationPaul Buetow
Audit of gettid(2) ('pid_t gettid(void)', no args, always succeeds) found the classification correct and consistent with its no-arg id-returning siblings getpid/getppid/getuid/getgid (FamilyProcess, KindNull enter, ret_event UNCLASSIFIED exit), and mage generate produces no diff. However gettid lacked dedicated lock-in coverage and was missing entirely from the family_test.go Process table despite its siblings being asserted there. Add TestClassifyGettidNullEnter and TestClassifyExitGettidUnclassifiedRet (mirroring the getgid pattern: enter null_event capturing nothing, exit ret classified UNCLASSIFIED so the returned tid is never mistaken for a byte count) plus gettid enter+exit FamilyProcess assertions in family_test.go. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(generate): lock in getgid null enter and UNCLASSIFIED retPaul Buetow
Audit of getgid(2) found its classification already correct: family Process, enter KindNull (gid_t getgid(void) takes no arguments), exit KindRet with UNCLASSIFIED ret_type (returns a gid, never a byte count, and always succeeds). Family, kind, generated C handler, and docs all matched its no-arg id-returning siblings getuid/geteuid/getegid/getpid/ gettid/getppid, so no implementation or doc changes were needed. Add two dedicated lock-in tests using the real tracepoint fields, mirroring the setuid/setpgid audit pattern, so a stray reclassification of getgid trips a test: - TestClassifyGetgidNullEnter: enter is KindNull, no path/fd capture. - TestClassifyExitGetgidUnclassifiedRet: exit is KindRet, UNCLASSIFIED. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(finit_module): lock in family and ret classificationPaul Buetow
The finit_module audit (task 8t) confirmed the tracing implementation matches man 2 finit_module: KindFd with fd at args[0], param_values string never captured as a path, exit UNCLASSIFIED, and FamilySecurity alongside init_module/delete_module. No implementation discrepancies were found. Extend TestClassifyInitModuleVsFinitModule to also assert the previously-untested dimensions so the classification stays pinned: - finit_module captures no path (empty PathnameField), like init_module - both module-loading syscalls are FamilySecurity - both exits are UNCLASSIFIED (0/-1 return, no byte count) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30sendfile64: capture out_fd instead of dropping both fdsPaul Buetow
sendfile64(out_fd, in_fd, offset, count) transfers bytes between two file descriptors in the kernel and returns the number of bytes written to out_fd. Its tracepoint fields carry no field literally named "fd", so it fell through to KindNull and captured no descriptor at all - inconsistent with its sibling copy_file_range (KindFd) and the read/write/sendto/recvfrom families. Add an explicit sys_enter_sendfile64 -> KindFd override that captures out_fd (args[0], the destination the bytes are written to), matching the single-fd KindFd convention. The return value stays TransferClassified, consistent with copy_file_range/splice/tee/vmsplice. Family stays Network (sendfile is historically socket-oriented; copy_file_range=FS is pure file-to-file). Update docs/syscall-tracing-plan.md (move sendfile64 from null to fd kind), regenerate C/Go artifacts, fix the phase-A classify assertion, and add TestClassifySendfile64CapturesOutFd as a lock-in + negative test. The existing TestRetbytesPhaseA integration test still passes with the runtime change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(generate): lock in sched_setparam pid-not-fd classificationPaul Buetow
Add TestClassifySchedSetparamPidNotFd as a dedicated regression test for the sched_setparam(2) audit. The syscall takes a pid_t (args[0], NOT an fd; 0 = calling thread) and a userspace const struct sched_param *, so the enter must classify as KindNull and the exit as KindRet/UNCLASSIFIED (returns 0/-1, no byte transfer), matching family Sched. Implementation, docs, and generated C/Go artifacts already matched the man page; sched_setparam was previously only asserted as a sibling check inside the sched_getparam test. This pins its full behavior directly, consistent with prior sched_getparam/sched_getattr audits. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(sched_getparam): lock in KindNull/FamilySched/UNCLASSIFIED classificationPaul Buetow
Audit of sched_getparam(2): int sched_getparam(pid_t pid, struct sched_param *param). args[0] is a PID (not an fd) and param is a userspace output pointer, so the enter tracepoint classifies as KindNull and the family is Sched; the exit returns int 0/-1 (a status code, not a byte count) and stays KindRet/UNCLASSIFIED. Classification in classify.go, family.go, and docs/syscall-tracing-plan.md already match the man page and the sched_* siblings; mage generate produces no diff. This adds a dedicated lock-in regression test mirroring the prior sched_getattr audit, pinning the pid-not-fd invariant, the family, the exit classification, and sibling consistency with sched_setparam. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(setpgid): lock in KindNull/Process/UNCLASSIFIED audit findingsPaul Buetow
Audit of setpgid(pid_t pid, pid_t pgid): both args are process/process- group identifiers (kernel tracepoint type pid_t), never an fd or path; the call returns int 0/-1. Verified it is correctly classified KindNull (null_event), FamilyProcess, and UNCLASSIFIED ret, and that the Process and null lists in docs/syscall-tracing-plan.md stay in sync. No classification change was needed. Add lock-in tests so a future stray reclassification trips immediately: - TestClassifySetpgidNullEnter feeds the REAL tracepoint fields (pid_t pid, pid_t pgid) and asserts KindNull, proving args[0] (pid) is never mistaken for an fd: isFdType matches only int/unsigned int/unsigned long (not pid_t) and the fd heuristic also requires field name fd. - TestClassifyExitSetpgidUnclassifiedRet asserts the exit is KindRet and ClassifyRet stays UNCLASSIFIED (status code, not a byte count). - Add setpgid to the retclassify UNCLASSIFIED cluster beside setsid/getsid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30family: document Misc-vs-IPC boundary rule; keep robust_list in Misc (task 520)Paul Buetow
Resolve the get_robust_list/set_robust_list classification decision: keep both as FamilyMisc rather than promoting them to FamilyIPC alongside the recently-moved futex_* syscalls. Rule (now documented in family.go next to the futex IPC block): a syscall is IPC only if it PERFORMS the actual IPC/sync operation (futex wait/wake/requeue on the futex word, or an op on an IPC object). Per-thread registration/bookkeeping that merely hands the kernel a pointer it consults later -- rseq and get_robust_list/set_robust_list -- stays Misc. man 2 get_robust_list confirms the robust futex list is 'managed in user space: the kernel knows only about the location of the head'; these syscalls register/query that per-thread head pointer and never wait/wake or touch shared memory, structurally identical to rseq. The split axis is operation-vs-registration, not name similarity. No classification change, so mage generate is a no-op (generated artifacts and docs/syscall-tracing-plan.md unchanged). Strengthened the rseq/ robust_list comments in family_test.go and the TestClassifyGetRobustListPidNotFd lock-in comment in classify_test.go to cite the rule and mark the decision resolved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in setuid classification auditPaul Buetow
Audit of setuid(2) confirmed correct tracing classification: - KindNull (single uid_t arg, never an fd or path) - FamilyProcess (credential-setting, consistent with siblings) - Unclassified exit ret (int 0/-1 status, not a byte count) Add lock-in tests asserting the setuid enter (KindNull, no pathname capture) and exit (KindRet, UNCLASSIFIED) classification, plus a family assertion covering the credential-setting cluster (setuid/setresuid/setreuid/setfsuid, the gid analogues, and the getuid/geteuid/... readers). Discovered out of scope: family.go omits seteuid/setegid from the FamilyProcess list (they fall through to Misc), unlike their siblings. These have no dedicated kernel tracepoints today, so it is latent; tracked as follow-up task 620. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(mknod): lock in mknod/mknodat path-arg classificationPaul Buetow
Audit of mknod(2) found the tracing implementation already correct: sys_enter_mknod captures the real pathname from args[0] (no dirfd), while the sibling sys_enter_mknodat captures it from args[1] (after dirfd). Both are FamilyFS path_events; both exits are ret_event UNCLASSIFIED (int 0/-1). No code or doc changes were needed. Add lock-in tests guarding this behavior against regressions: - TestGenerateMknodMknodatHandlers asserts the generated BPF C reads the path from args[0] for mknod and args[1] for mknodat. - FormatMknodat/FormatExitMknodat testdata mirroring the real tracepoint layout (dfd pushes filename to args[1]). - mknodat rows added to the classify kind (KindPathname) and family (FamilyFS) test tables, matching the existing mknod coverage. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(classify): lock in keyctl-family audit (kind/family/ret)Paul Buetow
Audit of keyctl(2), add_key(2), request_key(2) confirmed the existing tracing is correct: all three are KindKeyctl (operation + generic numeric args captured via keyctl_event, no fd/path probe), live in FamilySecurity alongside their *_key/landlock_*/lsm_*/seccomp siblings, and return an operation-dependent value or -1 that is not a byte transfer (UNCLASSIFIED). Add TestClassifyKeyctlAudit as a lock-in regression test, mirroring prior audits: it asserts the Security family on both enter and exit names, the UNCLASSIFIED return classification, and that add_key's const char * type/description arguments are key metadata that must not trip the generic pathname/open heuristics (PathnameField stays empty, kind stays KindKeyctl). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in get_robust_list/set_robust_list classificationPaul Buetow
Audit of get_robust_list(2)/set_robust_list(2) found the existing classification already correct and consistent across classify.go, family.go, the generated C handlers, and docs/syscall-tracing-plan.md: - enter is KindNull: args[0] of get_robust_list is a PID, not an fd, and head_ptr/len_ptr are userspace output pointers (no fd/path), so the pid must not be picked up as a file descriptor. - exit is ret_event UNCLASSIFIED: both return 0/-1 with no byte count. - family is Misc, grouped with the per-thread sibling rseq rather than promoted to IPC like the futex_* shared-memory primitives. Add TestClassifyGetRobustListPidNotFd pinning these invariants (Kind, Family, Ret) plus a futex_* IPC contrast case, mirroring the prior sched_getattr/recvmsg audit lock-in tests. No behavior change. The IPC-vs-Misc family question for the robust-list pair is tracked as a separate follow-up task, not changed here (no clear correctness case). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in access/faccessat path classificationPaul Buetow
Audit of access(2) found the tracing implementation already correct: FS family, KindPathname capturing the real path, and an UNCLASSIFIED int 0/-1 ret_event on exit. access(2) captures its path from args[0] (no dirfd), while siblings faccessat(2)/faccessat2(2) capture from args[1] (dfd precedes the path). mage generate produces no diff and the docs/integration coverage already match. Add unit lock-in tests mirroring prior syscall audits: - FormatAccess/FormatFaccessat tracepoint fixtures (real kernel formats). - classify tests asserting both classify as KindPathname/"filename". - family_test cluster asserting access/faccessat/faccessat2 stay FamilyFS. - codegen test proving access reads ctx->args[0] while faccessat reads ctx->args[1], guarding against a wrong-arg or dropped-path regression. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in sync(2) void-but-returns classificationPaul Buetow
Audit of bare sync(2) per man 2 sync: void sync(void) takes no args and returns no value. Confirmed it is correctly classified KindNull in FamilyFS, its ret is UNCLASSIFIED, and — unlike noreturn exit/exit_group — its exit handler IS emitted because sync does return (void != noreturn). Docs and generated maps already match; no code or doc changes needed. Add lock-in tests: - TestGenerateSyncHandler: enter null_event with no arg capture (sync has no args at all), live exit handler emitted, ret recorded UNCLASSIFIED. - TestClassifyRetSyncUnclassified: meaningless void ret stays UNCLASSIFIED. - TestSyncIsNotNoreturn: guards sync from the noreturn suppression list. - Add sync (FamilyFS) to the family/exit-handler table test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in recvmsg READ_CLASSIFIED auditPaul Buetow
recvmsg(2) returns the number of bytes received, so its exit must be READ_CLASSIFIED (bytes counted as read), matching recvfrom/recv/read/readv. Audit confirmed the implementation is already correct: enter=KindFd off the first 'fd' field (sockfd at args[0]), family=Network, exit= READ_CLASSIFIED. Add a dedicated lock-in test mirroring the prior sendmsg audit, with contrast cases guarding the easy mistakes: sendmsg is the write-side sibling (WRITE_CLASSIFIED) and recvmmsg is the batch variant whose scalar return is a message count, deferred to UNCLASSIFIED. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29ioprio_set/ioprio_get: classify as Process familyPaul Buetow
Audit of ioprio_set found a family inconsistency. ioprio_set(which, who, ioprio) and ioprio_get(which, who) query/set the I/O scheduling class and priority of a process, process group, or user. They are the direct I/O-priority analogues of getpriority/setpriority (the CPU nice value) and share the identical which/who selector signature, yet were falling through to FamilyMisc while getpriority/setpriority are FamilyProcess. Reclassify both ioprio syscalls to FamilyProcess for consistency with their priority siblings, update docs/syscall-tracing-plan.md, and regenerate the tracepoint/type artifacts (mage generate is idempotent). Argument capture is unchanged and confirmed correct: the args are all ints (which/who/ioprio), none named fd/path, so ClassifyFormat returns KindNone and the generator promotes the enter format to KindNull (null_event). In particular the 'who' argument (a pid/pgid/uid, never an fd) is not misclassified as KindFd. The exit is a ret_event (UNCLASSIFIED, int 0/-1). Add lock-in tests: - TestClassifyIoprioNullKind asserts KindNone/KindNull using the real kernel tracepoint fields, proving 'who' is not captured as an fd. - Family assertions for the ioprio pair alongside getpriority/setpriority so a stray reclassification of any of them trips the test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(fallocate): lock in FS family, KindFd enter, UNCLASSIFIED retPaul Buetow
Audit of fallocate(2) found the tracing correct and consistent with its fd-based siblings, so add lock-in tests rather than fixing anything: - fallocate(int fd, int mode, off_t offset, off_t len) returns int 0/-1 (a status code, NOT a transferred byte count). Its exit must stay a plain ret_event with ret_type UNCLASSIFIED so it is never mistaken for a READ/WRITE/TRANSFER byte count. - The enter tracepoint carries a leading fd field (args[0]); only fd is captured into a fd_event (KindFd), matching fadvise64/ftruncate/ sync_file_range which likewise drop their trailing offset/len/advice args. - fallocate belongs to FamilyFS alongside fadvise64/ftruncate/ sync_file_range. TestClassifyFallocateEnterFd and TestClassifyExitFallocateUnclassifiedRet assert the per-syscall behavior; TestClassifySyscallFamily now also covers fallocate/fadvise64/ftruncate so a stray reclassification trips a test. No classification logic or generated artifacts changed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(classify): lock in pwritev2 WRITE byte-count classificationPaul Buetow
Audit of pwritev2(2) confirmed its tracing is already correct: enter is KindFd (fd at args[0]), return is WRITE_CLASSIFIED so the byte count is counted as written like its pwritev/writev/write/pwrite64 siblings, and family is FS. Add a dedicated lock-in test pinning kind, family, and the WRITE return classification, with the read-side preadv2 as a contrast and the whole p/readv/writev family asserted together to guard against a stray off-by-one reclassification. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in init_module vs finit_module classificationPaul Buetow
Audit of init_module (man 2 init_module) confirmed the implementation is correct: init_module(void *module_image, unsigned long len, const char *param_values) is classified KindModule (null_event), capturing neither an fd nor a path — param_values is a module-parameter string, not a filesystem path. finit_module(int fd, ...) is classified KindFd via field-based matching and captures fd = args[0]. Both syscalls live in the Security family and match docs/syscall-tracing-plan.md. No explicit finit_module test or init_module-vs-finit_module distinction test existed, so add lock-in coverage: - testdata.go: real-layout Format constants for (f)init_module enter/exit. - classify_test.go: assert init_module=KindModule with no PathnameField and finit_module=KindFd. - codegen_test.go: assert generated BPF C for init_module captures no fd and no filename/path, while finit_module captures fd = args[0]. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(syncfs): lock in FS family + fd kind classificationPaul Buetow
Audit of syncfs(2) confirmed the existing tracing is correct: single fd arg (fd=args[0], KindFd), FamilyFS like its fsync/fdatasync/ sync_file_range siblings, and an int 0/-1 return that stays Unclassified (plain ret_event). No code or generated artifacts changed. Add lock-in tests so a stray reclassification trips CI: - TestClassifySyncFamilyFdSyscallsByName: enter -> KindFd for the fsync/fdatasync/syncfs/sync_file_range group. - TestClassifyExitSyncfs: exit -> KindRet. - sync-family FamilyFS assertions in TestClassifySyncallFamily. - syncfs added to the ret-UNCLASSIFIED list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29utime/utimes: classify as FS family (fix Misc misclassification)Paul Buetow
utime(2) and utimes(2) change a file's access/modification times by a real filesystem path (filename at args[0]). The path was already captured (KindPathname), but both syscalls fell through to FamilyMisc instead of joining their siblings utimensat/futimesat in FamilyFS. Add them to fsSyscalls and regenerate; the only generated change is trace IDs 1034-1037 flipping FamilyMisc -> FamilyFS. Lock-in coverage: - family_test.go asserts utime/utimes/utimensat/futimesat are all FamilyFS. - classify_test.go + FormatUtime fixture assert utime is KindPathname with PathnameField "filename" (path captured even though it is a char* string, unlike domain/host name args). - New ioworkload scenarios utime-basic/utimes/enoent and integration tests TestUtimeBasic/Utimes/Enoent verify the path is captured at runtime, including on the ENOENT error path. Docs updated: moved utime/utimes from Misc to FS in docs/syscall-tracing-plan.md to keep the drift tests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in sendmsg write byte-count classificationPaul Buetow
Audit of sendmsg(2) found the tracing implementation already correct: enter is an fd_event with fd=args[0] (the kernel tracepoint first field is 'int fd'), family is Network, and the exit is WRITE_CLASSIFIED so the bytes-sent return value is counted as written, consistent with the send/sendto/write siblings and distinct from recvmsg (read side) and the deferred sendmmsg batch variant. Add TestClassifySendmsgWriteByteCount as a lock-in regression test pinning KindFd + FamilyNetwork + WRITE_CLASSIFIED, with recvmsg and sendmmsg contrast cases to guard against read/write and batch misclassification. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(classify): lock in sched_getattr pid-not-fd classificationPaul Buetow
Audit of sched_getattr confirmed it is correctly classified as FamilySched + KindNull, consistent with its siblings (sched_setattr, sched_getparam, sched_getscheduler). The syscall's first argument is a pid_t (a process/thread id), not a file descriptor, and the kernel tracepoint field is named "pid" rather than "fd", so the fd heuristic never applies; the name-only classification table also short-circuits before any field inspection. Add TestClassifySchedGetattrPidNotFd as a regression guard that pins KindNull and FamilySched using the real kernel field layout, explicitly asserting the pid arg is never treated as an fd, plus sibling consistency. No behavior or generated-artifact changes (mage generate produces no diff). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29classify: move lsm_* syscalls from Misc to Security familyPaul Buetow
The Linux Security Module introspection syscalls lsm_list_modules, lsm_get_self_attr and lsm_set_self_attr (Linux 6.8+) were classified as FamilyMisc while every sibling LSM/security syscall (landlock_*, keyctl, add_key, request_key, seccomp) is FamilySecurity. This audited inconsistency is fixed by adding the three lsm_* entries to the syscallFamilies map; their kind stays KindNull (args are userspace pointers + flags, no fd/path) and the exit remains a ret_event. Docs (syscall-tracing-plan.md) updated accordingly, generated artifacts regenerated via mage generate, and lock-in family assertions added to TestClassifySyscallPairEmitsAllFamilies. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in setdomainname KindNull classificationPaul Buetow
Audit of setdomainname(2): its first arg is a const char *name, but that name is the NIS/YP domain-name string, not a filesystem path. The name-only classification table pins it to KindNull, which short-circuits before the field-based path heuristic that would otherwise treat a const char *name arg as KindPathname. Classification, family (Misc), docs, and existing tests all already matched; this adds a dedicated lock-in test asserting KindNull, an empty PathnameField, and kind+family parity with the sibling sethostname. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29codegen: suppress unreachable sys_exit handlers for noreturn syscallsPaul Buetow
exit and exit_group never return to userspace, so their sys_exit tracepoints can never fire. The generator previously emitted matching EXIT_RET_EVENT handlers anyway, producing dead code in the generated BPF program. classifySyscall now skips exit-handler emission for noreturn syscalls via isNoreturnSyscall, and the regenerated artifacts drop the sys_exit_exit / sys_exit_exit_group handlers (enter handlers are kept). Tests updated to match the new reality: - TestGenerateExitNoreturnHandlers asserts no exit handler is emitted. - TestClassifySyscallPairEmitsAllFamilies exempts noreturn syscalls from the exit-handler-required assertion while staying strict for all others. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in getpeername exit classification as KindRetPaul Buetow
Audit of the getpeername(2) syscall confirmed the tracing pipeline already matches the man page: FamilyNetwork + KindFd (sockfd at args[0]) on enter, and a plain ret_event (int 0/-1) on exit. The enter classification was already covered by TestClassifySocketFdSyscallsByName, but the exit path (resolved via the generic 'ret' field matcher) had no dedicated assertion. Add TestClassifyExitGetpeername to pin sys_exit_getpeername -> KindRet so future classifier changes cannot silently regress it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-28close_range: honor last bound and CLOSE_RANGE_CLOEXEC flagPaul Buetow
close_range was captured as a single-fd fd_event carrying only first, so the runtime evicted every tracked fd >= first, ignoring the last upper bound and the flags. Bounded calls wrongly dropped still-open higher fds, and CLOSE_RANGE_CLOEXEC (which keeps fds open) was treated as a full close. Reclassify close_range to the two_fd_event kind, mapping fd_a/fd_b/extra to first/last/flags. The runtime now closes only the inclusive [first, last] range (a negative last from ~0U means unbounded) and skips eviction when CLOSE_RANGE_CLOEXEC is set or the syscall fails. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-223c table-drive name-only syscall classificationPaul Buetow
2026-05-21o7 classify landlock add-rule and restrict-self as fdPaul Buetow
2026-05-21m7 classify time and posix timer syscallsPaul Buetow
2026-05-21k7 classify process control and prctl syscallsPaul Buetow
2026-05-21j7 add futex kind and aggregate-only defaultsPaul Buetow
2026-05-21l7 classify numa and process memory syscallsPaul Buetow