Skip to content

The syscall inventory

Antinomie records the native x86-64 system calls of the guest’s Linux 6.12.94 kernel. Its inventory is generated from the kernel’s own syscall_64.tbl and syscall declarations, so names, numbers and argument names are not typed by hand.

Count Meaning
375 Named slots in the native table (328 of ABI common, 47 of ABI 64)
358 Implemented: the kernel has an entry point, and the recorder has a decoder for it
17 No entry point; each returns ENOSYS in every configuration

The Syscall list shows every one of them with its coverage mark and links to a dictionary page per syscall.

Not counted: the 36 x32 rows, i386 (32-bit) calls, and numbers with no table entry. See Known gaps.

uselib, _sysctl, create_module, get_kernel_syms, query_module, nfsservctl, getpmsg, putpmsg, afs_syscall, tuxcall, security, set_thread_area, get_thread_area, lookup_dcookie, epoll_ctl_old, epoll_wait_old, vserver.

A program may still call them; the recording shows the call with its raw arguments, and the host labels the row Not implemented. The kernel records the raw arguments and a “no decoder” status because no prototype exists.

For each implemented syscall the recorder knows the arguments by name and type, and copies what the call reads or writes through its pointers:

  • Integer and flag arguments are decoded into names, with unknown bits kept.
  • Strings, buffers, vectors and many structures are copied and stored with a capture status.
  • Structure members use layouts checked against the pinned Linux 6.12.94 x86-64 headers. You can filter on them; see Syscall Trace filter.
  • Families that take a selector (such as prctl, ptrace, keyctl, bpf, setsockopt and getsockopt) decode what each recognized selector points to. An unrecognized selector or option is recorded as raw bytes with a “no decoder” gap.
  • Outputs are captured only when the call succeeds, apart from a few documented interruption cases.
  • Calls that never return, exit and exit_group, show how the task ended.

The syscall groups in Syscall Trace’s chips cover all 375 slots: Process & threads, File & filesystem, Network, Memory, IPC & sync, Signals, Polling & async I/O, Credentials & security, System & kernel, Time & scheduling and Info queries.

Some facts are not the arguments of one call. The kernel writes them as lifecycle records attached to the call they belong to. A task’s end is one, which is how exit and exit_group show how the task ended. A base built for Antinomie 0.7.0 or later (guest contract revision 17) adds:

Record What it holds When
lifecycle.creds The task’s uid, euid, suid and fsuid, the gid equivalents, the audit login uid and session, all five capability sets and the securebits At the task’s first traced call, then whenever any of them changes (setuid, setgid, setres*, setfs*, capset, a prctl that changes the ambient or bounding set or the securebits, a setuid, setgid or file-capability exec, a login uid change). No change, no record.
lifecycle.file_hash The SHA-256 of a file, or the reason there is none The image an exec committed; a file an unlink removed; each regular file the run wrote, when its last writer closes it; the launched program’s own image
lifecycle.file_id The device, inode, generation, link count and mode of a file An open, openat, openat2 or creat that returned a descriptor, a rename*, a link* and an unlink* that succeeded. An io_uring request carries the same identity as an operand.
lifecycle.exec_image The image an exec loaded, and for a script the interpreter as its #! line names it Once per exec

A hash is read by a kernel worker after the call returned, so the digest is the file’s bytes at hashing time. If the file changed between the call and the read, the record is flagged as changed; an unlink by the sample itself does not count as a change. A file is not hashed when it is larger than 16 MiB, is not on ext4, tmpfs or ramfs, or the queue (16 jobs, 64 MiB) is full; the record then gives the reason. Only SHA-256 is recorded. A hash or credential record the guest could not send is counted, and the count is shown as Guest hash / credential drops in Summary; see Loss counters.

A base built for Antinomie 0.8.0 (contract revision 18, in development) adds three more, as fields of a call’s Exit or as one lifecycle record before it:

Record What it holds When
file.position Where a read or write began in the file, how much it moved, and for a write the order in which the file system applied it Read and write family calls on a regular file or block device
file.copy (and file.copy.data) Both files and offsets, the length, the destination’s size after the call and the fallocate mode; for a splice from a pipe, the bytes the destination got, up to 1 MiB per call sendfile, splice, copy_file_range, FICLONE/FICLONERANGE, fallocate
lifecycle.file_mapped (and .data) The file, the range, the size, the time, a write order and why bytes are missing, with the page contents, up to 4 MiB and 64 ranges per call A call that writes back dirty pages of a MAP_SHARED file mapping (msync, fsync, sync) or removes a mapping that held them (munmap, mremap, a MAP_FIXED mapping over it, madvise, exec, exit)

Revision 18 also types the arrays of getgroups and setgroups (gid_t[]), getdents and getdents64 (linux_dirent[], linux_dirent64[]) and the descriptors modify_ldt reads (desc_struct[]), so the trace decodes them; the bytes are unchanged. An app that does not know a layout shows the bytes.

Older bases and recordings made before these records simply lack them; nothing is guessed in their place. Triage and the Sigma event journal read them.

The project’s safe test program traces a large part of the table in a disposable guest, but a pass means that exercise was traced. It does not prove every pointer layout, every asynchronous operation or all 375 calls were fully tested, and it does not certify payload completeness. Treat any single recorded value with the same care as the rest of a recording: read its status.