summaryrefslogtreecommitdiff
path: root/internal
AgeCommit message (Collapse)Author
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(generate): lock in mkdirat path capture at args[1]Paul Buetow
Audit of mkdirat(2) found the tracing implementation correct: the generated BPF handler reads the pathname from args[1] (after the dirfd at args[0]), while the sibling mkdir(2) reads from args[0] (no dirfd). Both are KindPathname / FamilyFS with an UNCLASSIFIED return, consistent with mknod/mknodat and docs/syscall-tracing-plan.md. The arg index is data-driven from the kernel format via FieldNumber, so no source change was needed. Add lock-in unit tests and real-format fixtures asserting: - mkdirat captures the path from args[1], NOT args[0] (negative guard) - mkdir captures the path from args[0] - mkdirat/mkdir/mknodat share FamilyFS and KindPathname - FieldNumber(pathname) = 1 for mkdirat, 0 for mkdir Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30creat: keep pathname on failed creat; lock in fd->path mappingPaul Buetow
creat(pathname, mode) is equivalent to open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode): on success it returns a new fd, on failure -1. handlePathExit already special-cased creat to register the returned fd->path mapping in fdState (matching handleOpenExit for open/openat/openat2), but on failure (ret<0) it left ep.File unset, silently dropping the path. handleOpenExit keeps the path via NewPathname for failed opens so error scenarios stay observable; align the creat branch with that behavior. Strengthen CreatEventTest to assert the returned fd is registered with the correct path and synthesized open flags, and add a negative FailedCreatEventTest covering the ret<0 path (no fd registered, path retained). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30fix(sleep): record sentinel for TIMER_ABSTIME clock_nanosleep (a20)Paul Buetow
clock_nanosleep with the TIMER_ABSTIME flag passes an ABSOLUTE wakeup time in the request timespec, not a relative duration. The generated BPF sleep handler computed requested_ns = tv_sec*1e9 + tv_nsec unconditionally, so absolute sleeps exported a bogus multi-decade "sleep duration" in CSV/parquet/stream. generateExtraSleep now carries an optional flags-argument expression per sleep syscall. For clock_nanosleep the generated handler checks args[1] & TIMER_ABSTIME (value 1) and only computes the relative duration when the flag is clear; absolute sleeps keep the existing -1 sentinel (same value used for null/unreadable timespec pointers). nanosleep is always relative and stays unconditional (no flags arg). - Regenerated internal/c/generated_tracepoints.c (mage generate idempotent). - Added codegen tests asserting the TIMER_ABSTIME guard for clock_nanosleep and its absence for nanosleep. - Extended the ioworkload sleep scenario to issue an absolute clock_nanosleep and the sleep parquet integration test to assert it is reported as -1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(clock_nanosleep): lock in exit handler UNCLASSIFIED ret + args[2] ↵Paul Buetow
request ptr Audit of clock_nanosleep tracing confirmed the classification is correct: KindSleep + FamilyTime (matching the nanosleep sibling), the enter handler captures the request timespec at ctx->args[2] (not args[0]/clockid), and the exit handler emits a plain ret_event with ret_type UNCLASSIFIED, which is correct since clock_nanosleep returns 0 or a positive errno, never an fd or byte count. Strengthen the existing enter-handler test with the requested_ns -1 sentinel and add TestClockNanosleepExitHandlerIsUnclassifiedRet to pin the exit-side behavior. No classification, docs, or generated-code changes were needed (mage generate produces no diff). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30Document Process-vs-Misc boundary; keep set_tid_address in Process (task 920)Paul Buetow
Resolve the family-split question for set_tid_address vs its per-thread registration siblings rseq/set_robust_list/get_robust_list (Misc). DECISION: keep set_tid_address in FamilyProcess. The 520 registration-vs- operation rule governs the IPC-vs-Misc boundary (does the syscall perform the futex/sync op?), not Process-vs-Misc. set_tid_address registers clear_child_tid, the kernel's primary thread-EXIT notification mechanism (zeroed + FUTEX_WAKEd at teardown), set by the C runtime for essentially every thread via clone(2) CLONE_CHILD_CLEARTID, and returns the caller's tid like gettid/getpid -- mandatory thread-lifecycle plumbing belonging with clone/fork/exit/gettid. rseq (scheduling optimization) and robust_list (opt-in futex cleanup) are OPTIONAL per-thread features and stay Misc. - family.go: add Process-vs-Misc boundary-rule block (mandatory-thread- lifecycle vs optional-opt-in-feature axis) next to set_tid_address. - family_test.go: lock in set_tid_address enter+exit as Process with a WHY comment contrasting it against the rseq/robust_list Misc cluster. No generated-artifact or docs drift: classification unchanged (Process list in docs/syscall-tracing-plan.md already correct); mage generate is idempotent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(generate): lock in set_tid_address ret as UNCLASSIFIEDPaul Buetow
set_tid_address(2) always returns the caller's thread ID and never fails (no -1, no byte count). Assert its exit stays UNCLASSIFIED in TestClassifyRetUnclassified alongside its pid/tid-returning Process siblings setsid/getsid/getpid/getppid, so a stray byte-count reclassification trips the test. Audit of yz confirmed the existing classification is correct: KindNull (single userspace tidptr, no fd/path) and FamilyProcess. The KindNull case is already covered by TestClassify97NameOnlyKinds; this adds the previously-missing return-value assertion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(generate): lock in tkill classification (Signals/null/UNCLASSIFIED)Paul Buetow
Audit of tkill(2) (task 310) confirmed correct tracing: tkill(tid, sig) is FamilySignals, kind=null, ret UNCLASSIFIED, matching its siblings kill/tgkill/rt_sig*. tkill/tgkill are intentionally absent from the name-only kind table; ClassifyFormat returns KindNone for them (the pid_t tid is not matched by the fd rule, so the thread id is never misread as a file descriptor) and classifyEnterForGeneration promotes that to KindNull at generation time. This was untested, so add lock-in coverage closing the gap: - TestGenerateTkillHandler: enter emits null_event, captures no arg (tid is not an fd), exit reports raw status as UNCLASSIFIED. - TestClassifyTkillFallsThroughToNull: pins ClassifyFormat=KindNone and the KindNull generation fallback, so a future fd-rule regression fails. - TestClassifyRetTkillUnclassified: 0/-1 status is not a byte count. - Extend TestClassifySyscallFamily with kill/tkill/tgkill (enter+exit) so a stray reclassification out of FamilySignals trips the test. No generated output or runtime behavior changed (mage generate clean). 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-30fix(z10): skip enter-state write for noreturn syscallsPaul Buetow
After p10 suppressed the sys_exit_exit/sys_exit_exit_group handlers, the enter handlers for exit/exit_group still called ior_on_syscall_enter, which writes a per-tid entry into syscall_enter_state_map. With the exit handler gone, nothing ever bpf_map_delete_elem'd that entry, so stale per-tid state accumulated in the bounded (32768) map on hosts churning many distinct tids and could starve legitimate inserts. Add ior_on_noreturn_syscall_enter in internal/c/filter.c: it only makes the sampling decision (ior_should_emit_trace) and deliberately does NOT record enter-state. The code generator now emits this hook for noreturn enter handlers (detected via isNoreturnSyscall(syscallName(name))) so the enter null_event is still emitted while the dead, unreclaimable map write is skipped. Regenerated generated_tracepoints.c accordingly. Extend TestGenerateExitNoreturnHandlers with a negative assertion (no ior_on_syscall_enter for noreturn) and add TestGenerateReturningSyscallEnterRecordsState as a positive contrast. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30fix(family): classify seteuid/setegid as Process for consistencyPaul Buetow
classify.go has KindNull entries for sys_enter_seteuid/sys_enter_setegid, but family.go's FamilyProcess credential cluster omitted them, so ClassifySyscallFamily returned Misc — inconsistent with their siblings setuid/setgid/setresuid/setreuid/setfsuid. Add seteuid/setegid to the FamilyProcess group with a comment noting they are latent: current kernels expose no dedicated seteuid/setegid tracepoints (glibc wraps them over setreuid/setresuid), so they never reach the generated tracepoint map or docs/syscall-tracing-plan.md. mage generate confirmed idempotent with no diff, so docs/drift test are untouched. Lock-in unit tests assert Process for seteuid/setegid (enter+exit) by name directly, since no tracepoint exists. Refs task 620. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30fix(family): reclassify get_mempolicy as Memory not SecurityPaul Buetow
get_mempolicy(2) retrieves the NUMA memory policy for a thread or address range and is logically a Memory-family syscall, sharing FamilyMemory with its NUMA siblings set_mempolicy, set_mempolicy_home_node, mbind, migrate_pages, and move_pages. It was misclassified FamilySecurity (a copy/paste/alphabetical-ordering slip alongside the security modules). Move it to the Memory group in internal/generate/family.go, update the Memory and Security lists in docs/syscall-tracing-plan.md (keeps the docs_drift_test green), and regenerate artifacts (traceId2Family 735/734 and syscallFamilies[get_mempolicy] flip Security->Memory; C unchanged, mage generate idempotent). Add enter+exit family lock-in assertions for get_mempolicy and set_mempolicy alongside the NUMA siblings so the whole cluster is pinned. Task 120. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30test(generate): lock in times(2) syscall classificationPaul Buetow
Audit of times(2) (clock_t times(struct tms *buf)) confirmed its classification is correct and consistent with its time/clock siblings: - sys_enter_times: KindNull (single userspace output struct tms *buf; no fd or pathname argument). - sys_exit_times: ret_event UNCLASSIFIED — times() returns a clock_t tick count (or (clock_t)-1 on error), which is a tick tally, not a transferred byte count. - family: FamilyTime, alongside gettimeofday/clock_gettime, and NOT FamilyProcess where getrusage lives. No misclassification was found; docs/syscall-tracing-plan.md already lists times under the Time family and the null kind. Add lock-in tests so any stray reclassification trips a unit test: - family_test.go: assert sys_enter/exit_times == FamilyTime. - retclassify_test.go: assert sys_exit_times stays UNCLASSIFIED. KindNull is already covered by TestClassifyM7NameOnlyKinds. 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(migrate_pages): lock in UNCLASSIFIED return classificationPaul Buetow
Audit of migrate_pages(2) confirmed its tracing classification matches the man page and its NUMA siblings: - KindNull (null_event): args are pid (a pid, NOT an fd), maxnode, and two userspace bitmask pointers; the BPF handler emits a null_event and never reads args[0] as an fd. - FamilyMemory: consistent with set_mempolicy/mbind/move_pages/ set_mempolicy_home_node (the lone get_mempolicy->Security inconsistency is tracked separately and out of scope here). - exit UNCLASSIFIED (ret_event): the return is the count of pages that could NOT be moved (>=0) or -1, a page tally rather than a transferred byte count. Add explicit lock-in assertions for migrate_pages and its sibling move_pages to TestClassifyRetUnclassified so a future stray read/write/transfer reclassification trips the test. 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(dup2): lock in fd_event handler captures oldfd (args[0])Paul Buetow
Audit of dup2(2) found the tracing implementation already correct and consistent with its dup/dup3 siblings: dup2 is KindFd (a plain fd_event), the enter handler captures ev->fd from args[0] (oldfd) per the KindFd convention, it is in the FS family, and its exit returns the new fd (newfd/-1) as a plain UNCLASSIFIED ret_event (never a byte-count transfer). Unlike dup3 it carries no flags and clears O_CLOEXEC on the duplicate, which the eventloop registerDup path already honors. No discrepancies were found, so add a lock-in test (matching prior audits) that asserts the generated BPF C for dup2 captures fd from args[0] (not args[1]/newfd), emits an fd_event (not a dup3_event), wires no flags, and classifies the exit UNCLASSIFIED. Adds FormatExitDup2 testdata to drive the exit handler assertions. 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 wait4 KindProc/Process auditPaul Buetow
Audit of wait4(2): pid_t wait4(pid_t pid, int *wstatus, int options, struct rusage *rusage) waits for a child process to change state and optionally retrieves its resource usage. None of the arguments is an fd or a filesystem path: args[0] (pid) is a process/group selector -- a pid, NOT a file descriptor; args[1] (wstatus) and args[3] (rusage) are userspace output pointers; args[2] (options) is an int flag set. The return value is a pid_t (child pid, 0 for WNOHANG, or -1) -- never a byte count. The existing classification (KindProc -> null_event, FamilyProcess, ret UNCLASSIFIED) and the generated null_event enter handler (captures no args) are correct, matching siblings waitid/clone/fork/vfork, and docs/syscall-tracing-plan.md plus the drift tests are in sync. Add a dedicated lock-in test, modeled on the clone3 audit, that asserts the wait* siblings classify as KindProc, the family is Process, the generated enter handler emits a null_event capturing none of the args (so the pid at args[0] is never misclassified as an fd), and the pid/0/-1 return stays UNCLASSIFIED rather than a byte-count transfer. 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-29test(remap_file_pages): harden mem handler lock-in testPaul Buetow
Audit of remap_file_pages(2): int remap_file_pages(void *addr, size_t size, int prot, size_t pgoff, int flags). The implementation was already correct (KindMem, FamilyMemory, addr=args[0], length=args[1], length2=pgoff=args[3], flags=args[4]), but the lock-in test was thinner than its madvise/mincore/munlock siblings. Strengthen TestGenerateMemHandlerRemapFilePages to: - negative-assert flags is never read from args[2] (prot, always 0) or args[0] (addr), guarding the prot/flags index hazard - verify the exit handler captures the int 0/-1 status generically as UNCLASSIFIED, like every other KindMem exit - document the wiring and the prot-vs-flags pitfall in the comment Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in munlock BPF handler wiringPaul Buetow
Audit of munlock(2): int munlock(const void addr[.size], size_t size). Verified the existing implementation is correct and consistent with its mlock/mlock2 siblings: - KindMem (classify.go) with addr=args[0], length=args[1] - length2=0 and flags=0 (munlock has no flags, unlike mlock2's MLOCK_ONFAULT at args[2]; distinct from munlockall which is KindNull) - FamilyMemory (family.go) - exit UNCLASSIFIED (returns int 0/-1, not a byte count) - docs/syscall-tracing-plan.md already lists munlock under Memory + mem No code or doc changes were needed; mage generate produces no diff. Added a dedicated TestGenerateMemHandlerMunlock lock-in test mirroring the madvise/mincore guards, asserting the correct arg mapping and the absence of any flags/length2 wiring so a future copy of the mlock2 handler cannot silently surface a nonexistent args[2] as flags. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(ppoll): lock in poll-family arg layout, reject fd capturePaul Buetow
Audit of the ppoll syscall confirmed the tracing implementation is correct: ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask) is classified as KindPoll (poll_event, sibling of poll/select/pselect6) in FamilyPolling, with an UNCLASSIFIED ret_event exit. The enter handler captures nfds from args[1] and the timeout from the args[2] timespec, and correctly never reads args[0] (a pointer to an ARRAY of pollfd structs) as a file descriptor. Add a dedicated codegen lock-in test mirroring the poll/pselect6 tests, including negative assertions that args[0] is not captured as an fd and that no byte-transfer field is emitted (the return value is a ready-count >=0 or -1, not a byte count). Introduce a requireNotContains helper for these negative checks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in rt_tgsigqueueinfo KindNull/Signals auditPaul Buetow
Audit of rt_tgsigqueueinfo(2): int rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *info) queues a signal plus data to a thread in a thread group. Args are pids (tgid/tid), a signal number, and a userspace siginfo_t pointer -- no fds or filesystem paths. The existing classification (KindNull, FamilySignals, ret UNCLASSIFIED) and the generated null_event enter handler (captures no args) are correct, and docs/syscall-tracing-plan.md plus the drift tests are in sync. Add dedicated lock-in tests, modeled on the rt_sigpending audit, that assert the generated handler emits a null_event capturing none of the args (so tgid/tid are never misclassified as fds) and that the int 0/-1 return stays UNCLASSIFIED rather than a byte-count transfer. 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(generate): lock in clone3 KindProc/Process/UNCLASSIFIED classificationPaul Buetow
Audit of clone3(2): long clone3(struct clone_args *cl_args, size_t size). Neither arg is an fd or filesystem path (cl_args is a userspace control block, size is its byte length), and the return value is a pid_t (child PID in the parent, 0 in the child, -1 on error) — not a byte count. clone3 was already correctly classified as KindProc in FamilyProcess with an UNCLASSIFIED exit, identical to its clone/fork/vfork siblings; the generated BPF handlers emit a null_event on enter (no arg capture) and a ret_event tagged UNCLASSIFIED on exit. No code, classification, or doc changes were needed. Add TestGenerateClone3Handler to pin this down against future drift: the name-only table maps all four siblings to KindProc even when fed the real (struct clone_args *, size_t) args, the family is Process, the ret is UNCLASSIFIED, the enter handler captures no ctx->args[], and the exit handler reports ret_type=UNCLASSIFIED. 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(sigaltstack): lock in KindNull/Signals classification and UNCLASSIFIED retPaul Buetow
Audit of sigaltstack(2) confirmed the existing tracing is correct: both args are userspace stack_t pointers (new + old alternate signal stack), neither an fd nor a path, and it returns 0/-1. It is already classified KindNull in FamilySignals across classify.go, family.go, docs/syscall-tracing-plan.md, and the generated C/Go artifacts, matching the rt_sig*/kill/pause sibling group. No discrepancies were found. Add lock-in tests mirroring the prior rt_sigpending audit: - TestGenerateSigaltstackHandler asserts the enter handler emits a null_event capturing no args and the exit handler reports ctx->ret as UNCLASSIFIED. - TestClassifyRetSigaltstackUnclassified asserts the 0/-1 status is never tagged as a byte count. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in setsid classification auditPaul Buetow
setsid(2) takes no arguments and returns the new session ID (a pid_t) on success or (pid_t)-1 on error. Audit confirms it is correctly classified as KindNull (null_event enter handler, captures nothing), FamilyProcess (alongside its session/process-group siblings getsid/setpgid/getpgid/getpgrp and the pid-returning getpid/getppid), and its exit ret_type stays UNCLASSIFIED so the session-id return is never mistaken for a transferred byte count. No codegen or doc changes were required (mage generate yields no diff). Add lock-in assertions so a stray reclassification trips a test: - family_test.go: setsid + session/pgrp/pid siblings -> FamilyProcess - retclassify_test.go: setsid + pid-returning siblings -> Unclassified 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-29test(sysinfo): lock in KindNull + FamilyMisc + UNCLASSIFIED retPaul Buetow
Audit of sysinfo(2): int sysinfo(struct sysinfo *info) returns overall system statistics into a single userspace output pointer (not an fd or path) and returns 0/-1. The existing classification was already correct (KindNull, FamilyMisc, UNCLASSIFIED return) and docs/generated artifacts are consistent; no behavior change was needed. Add dedicated lock-in regression tests mirroring the rt_sigpending audit: - TestGenerateSysinfoHandler: enter emits a null_event and captures no args; exit emits a ret_event with ctx->ret tagged UNCLASSIFIED. - TestClassifyRetSysinfoUnclassified: the 0/-1 status is never a byte count. - family_test.go: assert sysinfo/newuname/sysfs stay in FamilyMisc, with a note that ustat is FamilyFS (matched by the 'stat' name marker) and is intentionally not grouped here. 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(rt_sigpending): lock in KindNull + FamilySignals + UNCLASSIFIED retPaul Buetow
Audit of rt_sigpending(2) confirmed the existing classification is correct and added lock-in coverage: - KindNull: int rt_sigpending(sigset_t *set, size_t sigsetsize). args[0] is a userspace output pointer to a sigset_t (a signal mask, not a traced I/O resource) and args[1] is the byte size; neither is an fd or path. The enter handler emits a null_event and must not capture either arg. Added TestGenerateRtSigpendingHandler with a negative assertion guarding against any ctx->args[] capture in the enter handler. - Exit ret_type=UNCLASSIFIED: rt_sigpending returns 0/-1, a status code, not a byte count, so it must never be tagged READ/WRITE/TRANSFER. Added an exit handler assertion plus TestClassifyRetRtSigpendingUnclassified. - FamilySignals: shares the family with the whole rt_sig* group plus kill/pause/sigaltstack/tkill/tgkill. Added lock-in family cases asserting every rt_sig* sibling alongside rt_sigpending in TestClassifySyscallFamily. No classification/codegen/doc changes were required; mage generate produces no diff. Full ./internal/... passes (only the known pre-existing flake TestCleanupLeakedWorkloadTempDirCaughtByAssertion fails, unrelated). 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-29test(generate): lock in set_mempolicy_home_node classificationPaul Buetow
Audit of the set_mempolicy_home_node(2) NUMA syscall (task mz) confirmed it is correctly classified: KindNull (name-only, ior does not capture the addr/len range), FamilyMemory (matching its siblings set_mempolicy, mbind, migrate_pages, move_pages and docs/syscall-tracing-plan.md), and an Unclassified return (0/-1 with no byte count). Add lock-in tests so the classification cannot silently drift: - family_test.go asserts FamilyMemory for set_mempolicy_home_node and its NUMA siblings, with a note that get_mempolicy is the lone sibling still on FamilySecurity (tracked separately, out of scope here). - retclassify_test.go asserts the exit stays UNCLASSIFIED. 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(process_madvise): lock in KindFd + UNCLASSIFIED + FamilyMemoryPaul Buetow
Audit of process_madvise(2) confirmed the existing classification is correct and added lock-in coverage: - KindFd with fd=args[0]: the first arg is a pidfd (a PID file descriptor selecting the target process), not an address, so it must NOT be treated like madvise(2) (KindMem, addr=args[0]). Extended the enter-handler test with a negative assertion guarding against the KindMem addr wiring. - Exit ret_type=UNCLASSIFIED: process_madvise returns the number of bytes advised, but that is advisory accounting, not real I/O data movement, so it stays UNCLASSIFIED like madvise(2). Added an exit-handler assertion plus TestClassifyRetProcessMadviseUnclassified. - FamilyMemory: shares the family with madvise/process_mrelease/process_vm_* siblings rather than FamilyIPC (pidfd_* lifecycle). Added family lock-in cases in family_test.go. No classification/codegen changes were required; mage generate produces no diff. Full ./internal/... passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(eventloop): lock in sync_file_range EBADF failure pathPaul Buetow
Audit of sync_file_range(2) confirmed the existing tracing is correct: classified as KindFd (FS family) with fd from args[0] per the kernel tracepoint format, and an UNCLASSIFIED ret (int 0/-1, no userspace bytes transferred) - identical to siblings fsync/fdatasync/fadvise64/ readahead. The byte range/offset/flags are intentionally not captured for fd-kind syscalls. Add SyncFileRangeFailureTest to lock in the EBADF path: the enter fd_event still pairs with the exit ret_event carrying ret=-9, and the eventloop synthesizes a placeholder FdFile (unknown name, O_NONE flags) for the never-opened bogus fd rather than dropping file metadata. 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-29test(generate): lock in rseq family and return classificationPaul Buetow
Audit of the rseq(2) syscall confirmed the existing classification is correct and consistent with its siblings: - KindNull: the rseq argument is a userspace struct pointer (not an fd or filesystem path), and args[2] flags are intentionally not captured, in line with the KindNull convention shared with set_robust_list and membarrier. (Already covered by classify_test.go.) - FamilyMisc: rseq is not in the explicit family table and falls through to Misc, grouped with its closest per-thread sibling set_robust_list/get_robust_list (also Misc). - Return value is int 0/-1 with no byte count, so its exit stays UNCLASSIFIED. Add lock-in tests for the family and return-value classification (kind was already covered) so a future drift in either is caught. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in sched_get_priority_min classificationPaul Buetow
Audit of sched_get_priority_min(2): the syscall takes a single int policy scheduling-policy enum (not an fd or path) and returns the minimum static priority for that policy, or -1 on error. ior classifies it as KindNull in FamilySched, consistent with every sibling sched_* syscall and the man page. Add TestGenerateSchedGetPriorityMinHandler (covering the identical sibling sched_get_priority_max too) to lock in that the enter handler emits a null_event without capturing the int policy arg, that the family is FamilySched, and that a live exit handler emitting EXIT_RET_EVENT is generated since this syscall returns (unlike the noreturn exit syscalls). No classification change was required, so generated artifacts are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in mincore BPF handler wiring (zv)Paul Buetow
Audit of mincore(2) confirmed the existing tracing is correct: KindMem + FamilyMemory, with addr=args[0], length=args[1], and both flags and length2 held at zero. args[2] is the userspace 'vec' output pointer, not a flags value, so it is correctly NOT wired into ev->flags. Add TestGenerateMemHandlerMincore to lock in this wiring and explicitly guard against the historical mistake of mapping args[2] onto ev->flags the way flags-bearing siblings (madvise/mlock2/mseal) do. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29test(generate): lock in madvise BPF handler field wiringPaul Buetow
Audit of madvise(2) (int madvise(void *addr, size_t length, int advice)) confirmed the existing classification and BPF wiring are correct: KindMem / FamilyMemory, addr=args[0], length=args[1], advice (flags-like) at args[2], length2=0, and the int return captured generically as UNCLASSIFIED. This is correctly distinct from process_madvise(2) (KindFd, pidfd at args[0]). Unlike its KindMem siblings (mprotect, mlock2, brk, map_shadow_stack), madvise lacked a dedicated handler-field lock-in test. Add TestGenerateMemHandlerMadvise with positive field assertions plus negative guards: advice must come from args[2] (not args[0]/addr), length2 must stay zero (no second region), and the exit must return ctx->ret as UNCLASSIFIED. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>