| Age | Commit message (Collapse) | Author |
|
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>
|
|
Audit of the rmdir(2) syscall found the tracing implementation already
correct and fully consistent with its siblings: rmdir is in the FS family,
classified KindPathname with the pathname captured from args[0] (its generated
BPF C handler is byte-identical to unlink's), and its exit is a ret_event with
UNCLASSIFIED ret_type (rmdir returns int 0/-1, not a byte count). The docs and
drift tests, integration tests (unlink-rmdir success and unlink-rmdir-notempty
ENOTEMPTY failure), and retclassify coverage all already match.
To guard against future drift, add a dedicated rmdir lock-in:
- FormatRmdir tracepoint fixture (single const char * pathname at args[0],
mirroring the real sys_enter_rmdir format and unlink's shape).
- TestGenerateRmdirHandlerCapturesPathFromArgs0: asserts the generated handler
reads the path from args[0] (with a negative guard against args[1], since
rmdir has no dirfd) and that the exit stays UNCLASSIFIED.
- TestRmdirFamilyAndKindMatchSiblings: asserts rmdir shares FamilyFS and
KindPathname/pathname with unlink/unlinkat/mkdir.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
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>
|
|
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>
|
|
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>
|
|
kexec_load(2) and kexec_file_load are documented together on the same
man page and both load a new kernel for later execution by reboot(2).
kexec_file_load was already FamilySecurity, but kexec_load fell through
to FamilyMisc. Move kexec_load to FamilySecurity so the siblings share
a family. Kind classification was already correct: kexec_load takes raw
user pointers (KindNull, no fd/path) while kexec_file_load takes fds
(KindFd); the return value (long 0/-1, no byte count) stays UNCLASSIFIED.
Update docs/syscall-tracing-plan.md to match, regenerate artifacts, and
add lock-in tests for the family and UNCLASSIFIED return of both kexec
syscalls plus reboot.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
Audit of bind(2): int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen). Verified the existing classification is correct and
consistent with its socket-setup siblings connect/listen/accept/
getsockname/getpeername:
- KindFd, capturing ev->fd = args[0] (the sockfd); the addr pointer and
addrlen are not captured.
- FamilyNetwork.
- Exit is UNCLASSIFIED (returns 0/-1, no transferred byte count).
No implementation or doc changes were needed (docs/syscall-tracing-plan.md
already lists bind under Network and fd; drift test green). Added
regression coverage:
- FormatBind/FormatExitBind fixtures mirroring the real kernel tracepoint.
- TestGenerateBindHandler with negative guards (no probe_read on the
sockaddr, no fd capture from args[1]/args[2], exit stays UNCLASSIFIED).
- bind + connect/listen/getsockname/getpeername added to the
family (FamilyNetwork) and ret-classification (UNCLASSIFIED) lock-in
lists.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
Audit of signalfd4(2) confirmed the tracing is correct: classified as
KindEventfd in FamilyIPC like its fd-creating siblings (eventfd2,
timerfd_create, inotify_init1, signalfd), flags captured from args[3]
per signalfd4(ufd, mask, sizemask, flags), and the return value left
Unclassified (it is an fd, not a byte count).
Add testdata fixtures FormatSignalfd4/FormatExitSignalfd4 (real Linux 7.0
tracepoint data) and a codegen lock-in test asserting the generated
handler reads flags from args[3], with negative guards against args[0]
(ufd), args[1] (mask pointer) and args[2] (sizemask).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
Audit of syscall select confirmed the tracing is already correct:
select is KindPoll/FamilyPolling like poll/ppoll/pselect6, the enter
handler captures nfds from args[0] as a count (not as an fd) and the
timeout from the args[4] timeval, and the exit is an UNCLASSIFIED
ret_event (ready-fd count, not a byte transfer).
Add TestGenerateSelectHandlerCapturesNfdsAndTimevalTimeout mirroring the
ppoll lock-in test, with negative assertions that no argument is ever
captured as an fd and that the exit carries no bytes/fd fields. This
guards against regressing nfds (a count) into a KindFd fd capture.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
TestCleanupLeakedWorkloadTempDirCaughtByAssertion was order/concurrency
dependent: passed in isolation but its detection scanned the shared system
temp root (os.TempDir) for ANY "ioworkload-" directory via a before/after
diff. Real ioworkload scenario workloads legitimately create
ioworkload-<scenario>-* dirs in that same root while they run (in parallel
under `mage integrationTest`), so this test both falsely attributed them as
leaks and, worse, RemoveAll'd them out from under the still-running tests.
Fix: scope both detection and cleanup to a prefix unique to this single test
invocation (PID + sanitized t.Name()) via listWorkloadTempDirsWithPrefix and
newLeakedDirs. Other tests' temp dirs can no longer be observed or deleted.
Also fixed a latent detection bug: the intentional-leak workload script
hard-coded /tmp instead of os.TempDir(), so detection silently failed whenever
$TMPDIR differed from /tmp. The mktemp template now uses os.TempDir().
Removed the dead assertNoNewWorkloadTempDirs helper (defined, never called).
Verified: mage build OK; mage test green across repeated runs; mage generate
produces no diff; gofmt clean. A stress run with decoy ioworkload-<scenario>-*
dirs confirms they survive untouched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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
genera |