| Age | Commit message (Collapse) | Author |
|
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>
|
|
Audit of semctl(2) confirmed the implementation is correct: it is
classified KindSysVOp in FamilyIPC, consistent with its SysV
control-syscall siblings msgctl/shmctl (and semget/semop/semtimedop).
The enter handler emits a null_event and captures no argument, so the
semid at args[0] -- a System V IPC identifier, NOT a file descriptor --
is correctly not recorded as an fd. The exit handler reports the raw
op-dependent int status (value or -1) as UNCLASSIFIED, never a byte
count.
The classification table already covered semctl, but only msgctl's
generated handler body was directly asserted. Add dedicated lock-in
tests mirroring TestGenerateMsgctlHandler:
- TestGenerateSemctlHandler: enter emits null_event, no ctx->args[]
capture, no ev->fd; exit ret_type UNCLASSIFIED.
- TestClassifyRetSemctlUnclassified: ret is UNCLASSIFIED.
No classification, generated C, docs, or runtime behavior changed
(mage generate produces no diff), so this is a test-only addition.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
rt_sigreturn(2) restores the pre-signal execution context off the signal
stack frame and resumes the interrupted instruction; it never returns to
the instruction after the syscall. man sigreturn(2) states plainly that
"sigreturn() never returns", and tracing against /sys/kernel/tracing
confirms it: sys_enter_rt_sigreturn fires once per signal-handler return
while sys_exit_rt_sigreturn never fires.
The generator previously emitted a dead handle_sys_exit_rt_sigreturn (it
can never run) and recorded a per-tid syscall_enter_state_map entry on the
enter path that nothing would ever delete (no exit fires), leaking entries
in the bounded map on every signal-handler return.
Add rt_sigreturn to noreturnSyscalls so codegen suppresses the dead exit
handler and routes the enter handler through ior_on_noreturn_syscall_enter
(sampling decision only, no map write), exactly like exit/exit_group. The
enter null_event is still emitted, and the FamilySignals/KindNull
classification is unchanged. Regenerated the C/Go artifacts and the result
baseline accordingly, and generalized the related comments.
Lock-in tests: TestRtSigreturnIsNoreturn asserts rt_sigreturn is noreturn;
TestRtSigSiblingsAreNotNoreturn guards that the returning rt_sig* siblings
are not; TestGenerateExitNoreturnHandlers now also covers rt_sigreturn.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
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>
|
|
Audited perf_event_open(2) against the man page: it returns a new fd (or
-1), args[0] is a struct perf_event_attr* userspace pointer (NOT an fd),
args[1] is a monitored pid, and only args[3] group_fd is a real fd.
The existing implementation is correct (KindPerfOpen by name, not KindFd;
FamilySecurity; exit as UNCLASSIFIED RetEvent). Add lock-in tests:
- codegen: assert args[0] is read via bpf_probe_read_user as the attr
struct and never captured as an fd (negative assertions on args[0]/args[1]).
- eventloop: a failed return (-1) registers no fd in fdState.
- perfDescriptorName format pin (perf: prefix).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
msgctl(2) operates on a System V message queue identified by msqid
(args[0]). msqid is a SysV IPC id returned by msgget, NOT a file
descriptor; capturing it as an fd would corrupt the fd-resource view.
ior already classifies msgctl as KindSysVOp in FamilyIPC (consistent
with siblings semctl/shmctl/msgget/msgsnd/msgrcv), emits a null_event
with no arg capture, and reports the int status as UNCLASSIFIED.
Add lock-in tests pinning this behavior:
- TestGenerateMsgctlHandler: KindSysVOp for msgctl/semctl/shmctl, all
FamilyIPC; generated enter handler emits null_event and captures no
args (asserts no ctx->args[ and no ev->fd); exit ret is UNCLASSIFIED.
- TestClassifyRetMsgctlUnclassified: msgctl ret is never a byte count.
No implementation change needed; mage generate produces no diff.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
Audit of mlockall(2) (task 6w). mlockall(int flags) locks ALL process
memory and takes a single flags bitmask (MCL_CURRENT/MCL_FUTURE/
MCL_ONFAULT) with NO address range, unlike its KindMem siblings
mlock/mlock2/munlock (which take addr+len). It is therefore correctly
classified KindNull in FamilyMemory, matching its sibling munlockall(2).
All existing classification (classify.go, family.go, generated artifacts,
docs plan) already match; no fixes needed. Add two lock-in tests
documenting the reasoning: TestGenerateNullHandlerMlockall asserts the
enter handler emits a null_event and never captures the flags int as an
addr/fd/path, and TestClassifyRetMlockallUnclassified asserts the 0/-1
return is UNCLASSIFIED (not a byte count).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
Audit of dup(2) found the tracing implementation already correct and
consistent with its dup2/dup3 siblings: dup(int oldfd) takes a single fd
argument (the sys_enter_dup tracepoint exposes it as field "fildes",
unsigned int, at args[0]). It is classified KindFd (a plain fd_event),
the enter handler captures ev->fd from args[0] per the KindFd
convention, it is in the FS family (fd grouping), and its exit returns
the new (lowest-numbered unused) descriptor or -1 as a plain UNCLASSIFIED
ret_event (never a byte-count transfer). Like dup2, dup carries no flags
and clears FD_CLOEXEC on the duplicate; the eventloop registerDup path
registers the returned newfd onto the same underlying file with flags=0,
which it already honors (applyFdTransferOp handles SYS_ENTER_DUP).
Docs (FS, fd) and the drift tests are in sync; existing coverage already
includes TestClassifyDup, the makeFdDupTestData full-lifecycle eventloop
test, and integration TestDupBasic/TestDupInvalidFd.
No discrepancies were found, so add a lock-in test (matching the dup2
audit) asserting the generated BPF C for dup captures fd from args[0]
(not args[1]), emits an fd_event (not a dup3_event), wires no flags, and
classifies the exit UNCLASSIFIED. Adds FormatExitDup testdata to drive
the exit handler assertions.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
Audit of syscall listen(2): int listen(int sockfd, int backlog). Confirmed
the tracing implementation already matches the man page and its socket
siblings (bind/connect/accept/getsockname/getpeername):
- KindFd, capturing ev->fd = args[0] (sockfd)
- FamilyNetwork
- exit ret_event UNCLASSIFIED (returns 0/-1, no byte count)
listen was already covered by the name-based classify/family/retclassify
tests but lacked a dedicated generated-handler lock-in test like its
bind/getsockname siblings. Add FormatListen/FormatExitListen tracepoint
fixtures and TestGenerateListenHandler asserting the enter captures
fd=args[0] (and never backlog at args[1]) and the exit stays UNCLASSIFIED.
No classification or generated-code changes; mage generate produces no diff.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
Audit of kexec_file_load(2) against the man page confirmed the existing
classification is already correct and consistent: KindFd capturing
kernel_fd at args[0], FamilySecurity (matching its sibling kexec_load
after task 6v), and an UNCLASSIFIED ret_event exit (returns 0/-1).
The cmdline argument (args[3]) is a kernel command-line STRING, not a
filesystem path, and is correctly never read as a path; the second fd
initrd_fd (args[1]) is not captured, per the single-fd KindFd convention.
Add a dedicated lock-in test plus real-kernel-format fixtures so future
refactors cannot silently regress the fd wiring: assert ev->fd=args[0],
no args[1] fd capture, no bpf_probe_read_user_str on the cmdline, and an
UNCLASSIFIED (never READ/WRITE/TRANSFER) exit.
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 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 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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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 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 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>
|
|
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 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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
Audit of the x86 CET map_shadow_stack syscall (Linux 6.6+,
void *map_shadow_stack(unsigned long addr, unsigned long size,
unsigned int flags)) confirmed the existing tracing is correct:
KindMem / FamilyMemory classification, memFieldSpec wires
addr=args[0], length=args[1] (size), flags=args[2], length2=0, and
the return (mapped address or -errno) is captured generically as
ev->ret like every other KindMem exit. Docs and classify tests
already match.
The only gap was the lack of a codegen lock-in test for the BPF
handler field wiring, which mlock2/remap_file_pages/mprotect/brk all
have. Add TestGenerateMemHandlerMapShadowStack to guard against
future drift.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
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>
|
|
exit(2) and exit_group(2) take a single int status arg and never return.
ior classifies both as KindNull (FamilyProcess): the enter handler emits a
null_event without capturing the status arg, and the kernel-exposed
sys_exit_{exit,exit_group} EXIT_RET_EVENT handlers are emitted but never
fire at runtime. Audit confirmed the implementation already matches the
man page; this adds a lock-in test documenting the noreturn behavior.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
Audited epoll_create/epoll_create1 against man 2 epoll_create.
Implementation already correct: both classify as KindEventfd (fd-creating),
epoll_create(size) hardcodes flags=0 (no flags arg), epoll_create1(flags)
reads ctx->args[0], and exit captures the returned fd via ev->ret.
Add FormatEpollCreate1/FormatExitEpollCreate1 fixtures and
TestGenerateEpollCreate1HandlerUsesArg0Flags as the positive counterpart to
the existing TestGenerateEpollCreateHandlerUsesZeroFlags negative test,
asserting the enter handler captures args[0] as flags rather than 0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
epoll_create(size) was recording size (args[0]) as flags — hardcode to
0 since the syscall has no flags argument. pidfd_open(pid, flags) was
recording pid (args[0]) as flags — use args[1] instead.
Add test fixtures and codegen tests that verify the correct argument
indexes and reject the old wrong ones. Regenerate generated_tracepoints.c.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
Generated exit handlers now pass the explicit enter trace ID
(SYS_ENTER_X) to ior_on_syscall_exit instead of relying on the
implicit enter_id == exit_id + 1 arithmetic invariant. filter.c
compares directly against the passed enter ID.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
|
|
|
|
|
|
|
|
|
|
|