Skip to content

Fix the kernel version table scripts, and fill in the kernel versions - #502

Open
kolyshkin wants to merge 7 commits into
seccomp:mainfrom
kolyshkin:kver-tables-fix
Open

kolyshkin wants to merge 7 commits into
seccomp:mainfrom
kolyshkin:kver-tables-fix

Conversation

@kolyshkin

@kolyshkin kolyshkin commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

This fixes the scripts used to generate the kernel version columns of src/syscalls.csv, and uses them to finally fill in these columns, for kernels v3.0 to v7.2.

Problems with the current scripts

When looking into #457 (whose syscalls.csv was generated using these scripts), I found that nearly all aarch64, riscv64 and loongarch64 syscalls were marked as available since v3.0 (e.g. clone3, openat2 and io_uring_setup). This is caused by a few issues with how arch-build-kver-tables.py uses syscalls-table's update-tables.sh, which silently produces wrong tables in a few cases:

  • Architectures not present in a kernel version. update-tables.sh only regenerates the tables for the architectures present in the kernel tree, and leaves the others intact (i.e. tables for a recent kernel, as committed to the syscalls-table repository). As the whole data/tables directory was copied, the "v3.0" arm64, riscv and loongarch tables were in fact the ones for a recent kernel (v6.17-rc1 at the time). This is how open_tree_attr ended up being reported as available since v3.0 for these architectures (as noted in RFE: Add support for maximum supported kernel version #457).
  • Kernel headers that can not be built. If make headers_install fails, update-tables.sh compiles its helper against the host's system headers instead, producing a table for the host's kernel headers version. With a modern toolchain this happens for old kernels (e.g. with GCC 16, v3.0 and v3.15 fail to build their host tools), resulting in e.g. clone3 on x86_64 being reported as available in v3.0.
  • Failure to compile the helper (e.g. for x32 without the x32 glibc headers). The old table is kept, and only a message is printed.
  • x32 before v3.4. The x32 ABI was added in v3.4, but for older kernels the generated x32 table is the same as the x86_64 one.

In all these cases update-tables.sh exits with 0. The update-tables.sh issues are now fixed by hrw/syscalls-table#153 (merged).

In addition, arch-create-syscalls-csv.py regenerates the whole CSV file, including the syscall numbers, which are maintained using arch-syscall-validate. It can not reproduce them: syscalls-table has no s390 (31-bit) tables at all, the script keeps the numbers of the syscalls no longer present in newer kernels (e.g. _llseek on parisc64), syscalls-table uses the sync_file_range2 alias instead of arm_sync_file_range on arm, and the script's own syscall list is already out of sync with syscalls.csv (it lacks file_getattr, file_setattr, listns, rseq_slice_yield and uprobe), so running it would lose data.

Changes

  • Remove arch-create-syscalls-csv.py, and make arch-update-syscalls-csv.py only fill in the missing kernel versions, leaving the syscall numbers (which arch-syscall-validate maintains, while preserving the kernel versions) intact.
  • Fix arch-build-kver-tables.py to only use the tables actually generated for each kernel version, and to fail on table generation errors (relying on the update-tables.sh fixes from update-tables: do not silently generate bogus tables hrw/syscalls-table#153 to report them).
  • Add kernel versions v6.18 to v7.2.
  • Fill in the kernel versions in syscalls.csv.
  • Document the whole process in doc/admin/SYSCALL_KVER_TABLES.md, including a container with a toolchain able to build all the kernel versions (Ubuntu 20.04, GCC 9.4, with the x32 glibc headers). Adding a new kernel version later only requires building the tables for that version, which a recent toolchain can do.

Verification of the kernel versions

  • The x86, x86_64 and x32 kernel versions were cross-checked against the kernel's syscall_32.tbl and syscall_64.tbl (available since v3.3), with no differences other than the expected ones listed in the commit message.
  • No syscall has a kernel version older than its architecture (aarch64 v3.7, riscv64 v4.15, loongarch64 v5.19, x32 v3.4).
  • A spot check of 23 syscalls with well-known kernel versions on 7 architectures.

The s390 (31-bit) kernel versions, as well as the ones of the syscalls that syscalls-table ignores as removed or never implemented (all of which predate v3.0), are left as SCMP_KV_UNDEF; see the commit message for details.

@kolyshkin

Copy link
Copy Markdown
Contributor Author

@drakenclimber I was reviewing the already-merged part of #457, and the syscalls.csv generated, and found some issues. This PR tries to fix many of those, mostly aiming for correct kver entries in syscalls.csv. Coincidentally I also made the generator smaller by removing one of the scripts.

I also found a few issues with @hrw's syscall-table which I'm working around here. I will try to fix this in syscall-table tomorrow.

arch-create-syscalls-csv.py generates the whole syscalls.csv file from
the syscalls-table data, including the syscall numbers. However, the
syscall numbers in syscalls.csv are maintained using
arch-syscall-validate, which gets them from the kernel sources, and
arch-create-syscalls-csv.py can not reproduce them:

 * syscalls-table does not have the s390 (31-bit) tables, so all the
   s390 syscall numbers would be lost;

 * the number of a syscall is kept even if it is no longer present in
   the newer kernels (e.g. _llseek on parisc64, last present in v7.0,
   or vm86 on sh, last present in v3.3);

 * syscalls-table uses the sync_file_range2 alias instead of
   arm_sync_file_range on arm.

The script also has its own copy of the kernel version list, and of the
syscall list, which is already out of sync with syscalls.csv (it lacks
file_getattr, file_setattr, listns, rseq_slice_yield and uprobe), so
running it would drop these syscalls.

As arch-syscall-validate preserves the kernel version columns, only
these need to be filled in from the syscalls-table data. Remove the
script; arch-update-syscalls-csv.py is changed to do just that in a
following commit.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The syscalls-table update-tables.sh script only regenerates the tables
for the architectures present in the given kernel tree, leaving all the
other tables in data/tables intact, i.e. whatever is committed in the
syscalls-table repository (tables for a recent kernel).

arch-build-kver-tables.py copied the whole data/tables directory, so
for the kernel versions predating an architecture (arm64 before v3.7,
riscv before v4.15, loongarch before v5.19), the copied table was in
fact one for a recent kernel. As the first kernel version a syscall is
found in is used as its kernel version, nearly all aarch64, riscv64 and
loongarch64 syscalls ended up being marked as available since v3.0.

Only copy the tables for the architectures update-tables.sh lists in
data/architectures-present-in-kernel.text, and teach
arch-update-syscalls-csv.py that a missing table means the architecture
is not present in that kernel version.

While at it, replace "cp -r" which, if the destination directory
already exists, copies the tables into a nested subdirectory.

Fixes: 7e6cc86 ("arch: Add a script to build the arch and kernel version syscall tables")
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
When update-tables.sh fails to generate the table for an architecture,
it prints a message, and keeps the old table (if any), so
arch-build-kver-tables.py would use a bogus table, or no table at all
(as if the architecture was not present in this kernel version).

The table generation fails if list-syscalls can not be compiled (e.g.
for x32 without the x32 glibc headers installed), or if the kernel
headers can not be installed, which is common when building old kernels
with a modern toolchain (e.g. with GCC 16, Linux v3.0 and v3.15 fail to
build their host tools).

Treat such failures as errors, except for the kernel headers failures
of the architectures not used by libseccomp (e.g. the cris headers can
not be installed in Linux v3.x), and ignore the exit code of
update-tables.sh in that case.

This relies on syscalls-table commits c58bc160537f ("update-tables:
exit with non-zero status on failures"), e5b5b182d2c9 ("update-tables:
do not generate tables if installing headers fails"), and b019db68a150
("update-tables: do not generate x32 table for kernels without x32").

Fixes: 7e6cc86 ("arch: Add a script to build the arch and kernel version syscall tables")
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Add the kernel versions v6.18 to v7.2 to the scmp_kver enumeration,
the Python bindings, and the kernel version list in
arch-build-kver-tables.py.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The syscall numbers in syscalls.csv are maintained using
arch-syscall-validate, which gets them from the kernel sources, and
preserves the kernel version columns.

arch-update-syscalls-csv.py, in addition to the kernel versions, also
added the missing syscall numbers, and optionally new syscalls, using
the syscalls-table data. This duplicates what arch-syscall-validate
does, except that syscalls-table uses aliases for some syscalls (e.g.
sync_file_range2 instead of arm_sync_file_range on arm), which would
end up being added as separate syscalls.

Make arch-update-syscalls-csv.py only fill in the missing kernel
versions of the syscalls which have a number in the csv file, using the
first kernel version a syscall is found in, and leave everything else
(including the header) intact. Remove the -a/--add option, as well as
the -k/--kernelpath option, as the kernel sources are no longer needed.

Also, fail if there are no tables for a given kernel version, rather
than treating all the architectures as not present in that version,
which results in wrong kernel versions.

While at it, sort the kernel versions, read and write the csv file only
once, and print the number of syscalls left without a kernel version
for each architecture.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Fill in the kernel version columns of syscalls.csv, using the tables
for Linux v3.0 to v7.2 built from the kernel tags by
arch-build-kver-tables.py with syscalls-table commit b019db68a150, in
an Ubuntu 20.04 container (GCC 9.4, with the x32 glibc headers):

	$ arch-build-kver-tables.py -d <syscalls-table> -k <linux>
	$ arch-update-syscalls-csv.py -d <tables> -c src/syscalls.csv \
		-V $(ls <tables> | sed 's/^tables-//' | paste -sd,)

The syscall numbers, as well as the rest of the file, are unchanged.

Since v3.0 is the oldest kernel version processed, the syscalls added
before it are marked as SCMP_KV_3_0. The following are left as
SCMP_KV_UNDEF:

 * all the s390 (31-bit) syscalls, as syscalls-table does not generate
   the s390 tables;

 * the syscalls that syscalls-table ignores as removed (e.g. _sysctl,
   bdflush, uselib) or never implemented (e.g. afs_syscall, tuxcall,
   vserver), all of which predate v3.0.

The x86, x86_64 and x32 kernel versions were cross-checked against the
kernel's syscall_32.tbl and syscall_64.tbl files (available since v3.3),
with no differences other than the above, and mq_getsetattr on x86,
which is misspelled as mq_getsetaddr in v3.3 syscall_32.tbl.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Document how to build the per-kernel-version syscall tables and use
them to generate the kernel version columns in syscalls.csv, including
a toolchain container definition, as old kernels can not be built with
a modern toolchain, and some distributions lack the x32 glibc headers.

Replace the x32 warning in arch-build-kver-tables.py with a reference
to the new document.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
@kolyshkin

Copy link
Copy Markdown
Contributor Author

I also found a few issues with @hrw's syscall-table which I'm working around here. I will try to fix this in syscall-table tomorrow.

Update: the syscalls-table issues are now fixed upstream (hrw/syscalls-table#153), so instead of working around them, this PR now relies on these fixes. I've also re-generated the tables with the fixed syscalls-table to verify the resulting syscalls.csv is the same.

Also, while comparing syscalls.csv with the syscalls-table data, I found that memfd_secret is missing for loongarch64; this is being fixed by #503.

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.

1 participant