Skip to content

Complete syscall coverage through nr 471 on both architectures#135

Merged
kov merged 4 commits into
mainfrom
syscall-coverage
Jun 10, 2026
Merged

Complete syscall coverage through nr 471 on both architectures#135
kov merged 4 commits into
mainfrom
syscall-coverage

Conversation

@kov

@kov kov commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Fourth PR from the review pass (after #132, #133, #134): syscall coverage, bringing both architectures up to complete coverage through syscall 471.

aarch64 free winssendfile (71), fadvise64 (223), and kexec_file_load (294) had complete handlers sitting behind x86_64 gates; they exist on arm64 kernels but were missing from the project's aarch64 table. Table entries added, gates widened, tests de-gated.

Modern batch (both arches)cachestat (451), fchmodat2 (452, x86_64 table already had it), the futex2 family futex_wake/futex_wait/futex_requeue (454-456), and statmount/listmount (457-458). New kernel types (CachestatRange, Cachestat, MntIdReq) with size-versioning notes where the kernel struct is still growing.

Tail batchmap_shadow_stack (453), lsm_get_self_attr/lsm_set_self_attr/lsm_list_modules (459-461), the *xattrat family setxattrat/getxattrat/listxattrat/removexattrat (463-466), open_tree_attr (467), file_getattr/file_setattr (468-469), listns (470), and rseq_slice_yield (471). open_tree_attr shares the mount_setattr payload and parsing (identical argument layout); setxattrat/getxattrat and file_getattr/file_setattr likewise share payload structs. ns_id_req and file_attr are too new to rely on from libc and are printed as raw pointers for now.

All numbers were verified against the kernel's syscall_64.tbl and include/uapi/asm-generic/unistd.h rather than memory; 451-471 are identical on both supported architectures. The syscall table edits (normally hands-off per project policy) were explicitly approved.

Each syscall follows the project checklist: eBPF handler (trivial or consolidated category), tailcall registration, payload struct + compact_payload_size registration, events.rs parsing, format_return_value coverage, and parse tests.

🤖 Generated with Claude Code

The arm64 kernel has had sendfile (71), fadvise64 (223) and
kexec_file_load (294) all along, but they were missing from our aarch64
syscall table, so the existing handlers were cfg-gated to x86_64. Add
the table entries and drop the gates: eBPF capture, payload structs,
tailcall registration, parsing, formatting and tests are now shared.

Also remove a dead duplicate sendfile parsing arm in events.rs (the
second match arm was unreachable), move the sendfile workload out of
the x86_64-only block in test-helper so aarch64 exercises it, and add
the missing kexec_file_load parse test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends Pinchy’s syscall coverage to be complete through syscall nr 471 on both x86_64 and aarch64, wiring new syscalls end-to-end (eBPF capture → tailcall registration → compact payload sizing → userspace parsing/formatting → tests).

Changes:

  • Widened cross-arch coverage for previously x86_64-gated syscalls (sendfile, fadvise64, kexec_file_load) and updated tests accordingly.
  • Added support for modern syscalls 451–471 (e.g., cachestat, fchmodat2, futex2 family, statmount/listmount, LSM self-attr APIs, *xattrat, open_tree_attr, file_{get,set}attr, listns, rseq_slice_yield).
  • Updated tailcall registration plus userspace parsing and return-value formatting for the new syscalls, with new parse tests.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pinchy/src/tests/system.rs Adds/updates syscall parse tests (incl. de-gating) for newly supported system syscalls.
pinchy/src/tests/sync.rs Adds parse tests for futex2 syscalls (futex_wake, futex_wait, futex_requeue).
pinchy/src/tests/security.rs Adds parse tests for LSM syscalls (lsm_get_self_attr, lsm_set_self_attr, lsm_list_modules).
pinchy/src/tests/memory.rs Adds parse test for map_shadow_stack.
pinchy/src/tests/filesystem.rs Adds parse tests for filesystem-related new syscalls (fchmodat2, cachestat, statmount, listmount, *xattrat, open_tree_attr, file_{get,set}attr).
pinchy/src/tests/basic_io.rs De-gates sendfile tests and updates imports to include sendfile on aarch64.
pinchy/src/server.rs Registers additional syscalls in the appropriate tailcall arrays (trivial/system/security/sync/filesystem).
pinchy/src/format_helpers.rs Extends format_return_value for new syscalls and de-gates helpers for cross-arch use.
pinchy/src/events.rs Adds userspace payload parsing/formatting for new syscalls and de-gates sendfile/fadvise64/kexec_file_load parsing.
pinchy/src/bin/test-helper.rs Updates benchmark helper to use Pinchy syscall constants for sendfile (cross-arch).
pinchy-ebpf/src/system.rs Adds eBPF capture for listns under the system handler.
pinchy-ebpf/src/sync.rs Adds eBPF capture for futex_wait and futex_requeue under the sync handler.
pinchy-ebpf/src/security.rs Adds eBPF capture for lsm_get_self_attr and lsm_list_modules.
pinchy-ebpf/src/main.rs Expands trivial handler to include additional syscalls now treated as trivial across arches.
pinchy-ebpf/src/filesystem.rs Adds eBPF capture for new filesystem syscalls (*xattrat, file_{get,set}attr, fchmodat2, cachestat, statmount, listmount, open_tree_attr).
pinchy-ebpf/src/basic_io.rs De-gates sendfile capture so it’s available on aarch64 as well.
pinchy-common/src/syscalls/x86_64.rs Adds syscall number constants for 451–471.
pinchy-common/src/syscalls/aarch64.rs Adds missing syscall number constants (sendfile, fadvise64, kexec_file_load) and 451–471.
pinchy-common/src/lib.rs Registers compact payload sizes for new syscalls and adds new compact payload structs.
pinchy-common/src/kernel_types.rs Adds kernel struct definitions used by new syscalls (CachestatRange, Cachestat, MntIdReq, XattrArgs).

Comment thread pinchy-ebpf/src/filesystem.rs Outdated
Comment on lines +231 to +246
// For setxattrat the value is an input; for
// getxattrat it is only there on success.
let want_value =
syscall_nr == syscalls::SYS_setxattrat || return_value >= 0;
let value_ptr = payload.args.value as *const u8;
if payload.has_args && want_value && !value_ptr.is_null() {
let read_size =
core::cmp::min(payload.args.size as usize, payload.value.len());

unsafe {
let _ = bpf_probe_read_user_buf(
value_ptr,
&mut payload.value[..read_size],
);
}
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed and squashed into the commit that introduced it: getxattrat/listxattrat reads are now bounded by the return value (and skipped on error), and statmount/listmount copy only the caller-declared mnt_id_req size via a shared size-versioned read helper.

Comment thread pinchy-ebpf/src/filesystem.rs Outdated
Comment on lines +269 to +280
if !list_ptr.is_null() && payload.size > 0 {
let read_size = core::cmp::min(payload.size, DATA_READ_SIZE);

unsafe {
let _ = bpf_probe_read_user_buf(
list_ptr,
&mut payload.xattr_list.data[..read_size],
);
}

payload.xattr_list.size = read_size;
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed and squashed into the commit that introduced it: getxattrat/listxattrat reads are now bounded by the return value (and skipped on error), and statmount/listmount copy only the caller-declared mnt_id_req size via a shared size-versioned read helper.

Comment thread pinchy-ebpf/src/filesystem.rs Outdated
Comment on lines +746 to +752
let req_ptr = args[0] as *const MntIdReq;
if !req_ptr.is_null() {
if let Ok(req) = unsafe { bpf_probe_read_user(req_ptr) } {
payload.req = req;
payload.has_req = true;
}
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed and squashed into the commit that introduced it: getxattrat/listxattrat reads are now bounded by the return value (and skipped on error), and statmount/listmount copy only the caller-declared mnt_id_req size via a shared size-versioned read helper.

Comment thread pinchy-ebpf/src/filesystem.rs Outdated
Comment on lines +765 to +771
let req_ptr = args[0] as *const MntIdReq;
if !req_ptr.is_null() {
if let Ok(req) = unsafe { bpf_probe_read_user(req_ptr) } {
payload.req = req;
payload.has_req = true;
}
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed and squashed into the commit that introduced it: getxattrat/listxattrat reads are now bounded by the return value (and skipped on error), and statmount/listmount copy only the caller-declared mnt_id_req size via a shared size-versioned read helper.

kov and others added 3 commits June 10, 2026 13:24
…listmount

Add the modern syscalls that current glibc and util-linux already use
(numbers 451-458, identical on x86_64 and aarch64; verified against the
kernel's syscall_64.tbl and asm-generic unistd.h):

- fchmodat2: reuses FchmodatData and the fchmodat parsing arm
- cachestat: reads the cachestat_range argument and, on success, the
  resulting cachestat struct
- futex_wake: trivial handler (uaddr printed raw)
- futex_wait: complex (timespec timeout), mirrors futex/futex_waitv
- futex_requeue: reads the two-element futex_waitv waiter array
- statmount/listmount: read the mnt_id_req (mnt_ns_id only shown when
  the request size includes it); listmount also captures the returned
  mount IDs

Also fix a latent panic in the futex_waitv parsing arm, which indexed
the waiters array with the unclamped kernel-supplied nr_waiters.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds tracing support for map_shadow_stack, the LSM attribute
syscalls (lsm_get_self_attr, lsm_set_self_attr, lsm_list_modules),
the *xattrat family (setxattrat, getxattrat, listxattrat,
removexattrat), open_tree_attr, file_getattr/file_setattr, listns,
and rseq_slice_yield.

open_tree_attr shares the mount_setattr payload and parsing since
the argument layouts match; setxattrat/getxattrat and
file_getattr/file_setattr likewise share payload structs. The
ns_id_req and file_attr structs are too new to rely on from libc,
so they are printed as raw pointers for now.

Syscall numbers verified against the kernel's syscall_64.tbl and
include/uapi/asm-generic/unistd.h; 451-471 are identical on both
supported architectures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
At 64M the guest occasionally OOM-kills pinchyd during startup --
silently, since SIGKILL leaves no output -- producing the sporadic
"pinchyd exited prematurely" CI failures. The eBPF programs have
grown with the expanded syscall coverage, making the squeeze more
frequent (three failures in one run). Host cost stays trivial:
the test harness runs a handful of instances in parallel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kov kov force-pushed the syscall-coverage branch from 2a61fdf to 3d95e74 Compare June 10, 2026 16:25
@kov kov merged commit 4319597 into main Jun 10, 2026
1 check passed
@kov kov deleted the syscall-coverage branch June 10, 2026 16:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants