analyze: add io-uring-filter verb

IOUringFilter= takes the names of io_uring operations, and
SystemCallFilter= denies an operation if it denies one of the system calls
that the operation can do the work of. Users can only find the operation
names and the system calls of each operation in the source code.

Let's add "systemd-analyze io-uring-filter", which lists the operations
that systemd knows, together with the system calls of each operation,
like "systemd-analyze syscall-filter" does for the system call groups.
This commit is contained in:
Daan De Meyer committed 2026-11-04 10:54:29 +01:00
1 parent 9dcd9ffd89
commit 846cafe9ae
9 files changed
+147 -4

No files matched your search

+31
View File
@@ -116,6 +116,12 @@
<arg choice="plain">syscall-filter</arg>
<arg choice="opt"><replaceable>SET</replaceable>…</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="plain">io-uring-filter</arg>
<arg choice="opt"><replaceable>NAME</replaceable>…</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
@@ -600,6 +606,31 @@ Conditions succeeded.</programlisting>
<replaceable>SET</replaceable> must include the <literal>@</literal> prefix.</para>
</refsect2>
<refsect2>
<title><command>systemd-analyze io-uring-filter <optional><replaceable>NAME</replaceable>...</optional></command></title>
<para>Lists the
<citerefentry project='man-pages'><refentrytitle>io_uring</refentrytitle><manvolnum>7</manvolnum></citerefentry>
operations that systemd knows, or only the operations with the specified names. The names are the ones
that <varname>IOUringFilter=</varname> takes, see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>. For
each operation, the <literal>SYSCALLS</literal> column lists the system calls whose work the operation
can do. <varname>SystemCallFilter=</varname> denies an operation if it denies any of the listed system
calls.</para>
<example>
<title>Table output</title>
<programlisting>$ systemd-analyze io-uring-filter nop read socket uring_cmd
NAME SYSCALLS
nop -
read read pread64
socket socket
uring_cmd ioctl setsockopt getsockopt getsockname</programlisting>
</example>
<xi:include href="version-info.xml" xpointer="v263"/>
</refsect2>
<refsect2>
<title><command>systemd-analyze filesystems <optional><replaceable>SET</replaceable>...</optional></command></title>
+4 -2
View File
@@ -2539,7 +2539,8 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
listed operations are denied (deny-listing). Otherwise, only the listed operations are allowed
(allow-listing). An allow list also denies the operations of newer kernels that systemd doesn't
know, even though the kernel reports them as supported. Operation names that systemd doesn't know
are ignored.</para>
are ignored. Use <command>systemd-analyze io-uring-filter</command> to list the operations that
systemd knows.</para>
<para>This option may be specified more than once, in which case the lists are merged. If the first
assignment starts with <literal>~</literal>, the list is a deny list, otherwise it is an allow list.
@@ -3043,7 +3044,8 @@ RestrictNamespaces=~cgroup net</programlisting>
if the filter allows <function>io_uring_setup()</function>. An operation that can do the work of
one or more system calls, such as <constant>IORING_OP_OPENAT</constant> or
<constant>IORING_OP_SOCKET</constant>, is denied if the filter denies any of its equivalent system
calls. Operations of newer kernels that systemd doesn't know are not affected. Denied requests
calls. <command>systemd-analyze io-uring-filter</command> lists the equivalent system calls of each
operation. Operations of newer kernels that systemd doesn't know are not affected. Denied requests
always fail with <constant>EACCES</constant>, regardless of
<varname>SystemCallErrorNumber=</varname> and of the action of the system call. System calls that
are denied with an error number of 0 do not affect io_uring operations, since a denied request
+12
View File
@@ -52,6 +52,10 @@ __get_syscall_sets() {
done
}
__get_io_uring_ops() {
systemd-analyze --no-legend --no-pager io-uring-filter 2>/dev/null | { while read -r a b; do echo " $a"; done; }
}
__get_architectures() {
systemd-analyze --no-legend --no-pager architectures 2>/dev/null | { while read -r a b; do echo " $a"; done; }
}
@@ -88,6 +92,7 @@ _systemd_analyze() {
[DUMP]='dump'
[VERIFY]='verify'
[SECCOMP_FILTER]='syscall-filter'
[IO_URING_FILTER]='io-uring-filter'
[CAT_CONFIG]='cat-config'
[SECURITY]='security'
[CONDITION]='condition'
@@ -249,6 +254,13 @@ _systemd_analyze() {
comps='--help --version --system --user --global --no-pager --json=off --json=pretty --json=short --table --no-legend --scale-svg --detailed'
fi
elif __contains_word "$verb" ${VERBS[IO_URING_FILTER]}; then
if [[ $cur = -* ]]; then
comps='--help --version --no-pager --json=off --json=pretty --json=short --no-legend'
else
comps=$( __get_io_uring_ops )
fi
elif __contains_word "$verb" ${VERBS[ARCHITECTURES]}; then
if [[ $cur = -* ]]; then
comps='--help --version --no-pager --json=off --json=pretty --json=short --no-legend'
+8
View File
@@ -43,6 +43,13 @@
_describe -t groups 'syscall groups' _groups || compadd "$@"
}
(( $+functions[_systemd-analyze_io-uring-filter] )) ||
_systemd-analyze_io-uring-filter() {
local -a _ops
_ops=( $(systemd-analyze --quiet --no-pager --no-legend io-uring-filter 2>/dev/null | { while read -r a b; do echo " $a"; done; }) )
_describe -t operations 'io_uring operations' _ops || compadd "$@"
}
(( $+functions[_systemd-analyze_filesystems] )) ||
_systemd-analyze_filesystems() {
local -a _groups
@@ -95,6 +102,7 @@
'exit-status:List known exit statuses'
'capability:List capability definitions'
'syscall-filter:List syscalls in seccomp filters'
'io-uring-filter:List io_uring operations'
'filesystems:List known filesystems'
'condition:Evaluate Condition*= and Assert*= assignments'
'verify:Check unit files for correctness'
+76
View File
@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/io_uring.h>
#include <stdlib.h>
#include "analyze.h"
#include "analyze-io-uring-filter.h"
#include "format-table.h"
#include "io-uring-filter.h"
#include "log.h"
#include "nulstr-util.h"
#include "strv.h"
static int add_op(Table *t, int op) {
_cleanup_strv_free_ char **syscalls = NULL;
const char *s;
int r;
assert(t);
s = io_uring_op_syscalls_to_string(op);
if (s) {
syscalls = strv_split_nulstr(s);
if (!syscalls)
return log_oom();
}
r = table_add_many(t,
TABLE_INT, op,
TABLE_STRING, io_uring_op_to_string(op),
TABLE_STRV_WRAPPED, syscalls);
if (r < 0)
return table_log_add_error(r);
return 0;
}
int verb_io_uring_filter(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(table_unrefp) Table *table = NULL;
int r;
table = table_new("opcode", "name", "syscalls");
if (!table)
return log_oom();
(void) table_hide_column_from_display(table, (size_t) 0);
table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
char **args = strv_skip(argv, 1);
if (args) {
STRV_FOREACH(arg, args) {
int op;
op = io_uring_op_from_string(*arg);
if (op < 0)
return log_error_errno(op, "io_uring operation \"%s\" not known.", *arg);
r = add_op(table, op);
if (r < 0)
return r;
}
(void) table_set_sort(table, (size_t) 0);
} else
for (int op = 0; op < IORING_OP_LAST; op++) {
r = add_op(table, op);
if (r < 0)
return r;
}
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
if (r < 0)
return r;
return EXIT_SUCCESS;
}
+6
View File
@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "forward.h"
int verb_io_uring_filter(int argc, char *argv[], uintptr_t _data, void *userdata);
+5 -2
View File
@@ -31,6 +31,7 @@
#include "analyze-has-tpm2.h"
#include "analyze-image-policy.h"
#include "analyze-inspect-elf.h"
#include "analyze-io-uring-filter.h"
#include "analyze-log-control.h"
#include "analyze-malloc.h"
#include "analyze-nvpcrs.h"
@@ -241,6 +242,8 @@ VERB_SCOPE(, verb_capabilities, "capability", "[CAP...]\0", VERB_ANY, VERB_ANY,
"List capability definitions");
VERB_SCOPE(, verb_syscall_filters, "syscall-filter", "[NAME...]\0", VERB_ANY, VERB_ANY, 0,
"List syscalls in seccomp filters");
VERB_SCOPE(, verb_io_uring_filter, "io-uring-filter", "[NAME...]\0", VERB_ANY, VERB_ANY, 0,
"List io_uring operations");
VERB_SCOPE(, verb_filesystems, "filesystems", "[NAME...]\0", VERB_ANY, VERB_ANY, 0,
"List known filesystems");
VERB_SCOPE(, verb_architectures, "architectures", "[NAME...]\0", VERB_ANY, VERB_ANY, 0,
@@ -587,9 +590,9 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
!STRPTR_IN_SET(verb,
"security", "inspect-elf", "dlopen-metadata", "plot", "fdstore", "pcrs", "nvpcrs",
"architectures", "cpu-features", "capability", "exit-status", "chid", "blame",
"identify-tpm2", "restart-delays"))
"identify-tpm2", "restart-delays", "io-uring-filter"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --json= is only supported for security, inspect-elf, dlopen-metadata, plot, fdstore, pcrs, nvpcrs, architectures, cpu-features, capability, exit-status, chid, blame, identify-tpm2, restart-delays right now.");
"Option --json= is only supported for security, inspect-elf, dlopen-metadata, plot, fdstore, pcrs, nvpcrs, architectures, cpu-features, capability, exit-status, chid, blame, identify-tpm2, restart-delays, io-uring-filter right now.");
if (arg_threshold != 100 && !streq_ptr(verb, "security"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+1
View File
@@ -20,6 +20,7 @@ systemd_analyze_sources = files(
'analyze-has-tpm2.c',
'analyze-image-policy.c',
'analyze-inspect-elf.c',
'analyze-io-uring-filter.c',
'analyze-log-control.c',
'analyze-malloc.c',
'analyze-nvpcrs.c',
+4
View File
@@ -150,6 +150,10 @@ systemd-analyze syscall-filter @chown @sync
systemd-analyze syscall-filter @sync @sync @sync
(! systemd-analyze syscall-filter @chown @sync @foobar)
(! systemd-analyze syscall-filter --global)
systemd-analyze io-uring-filter >/dev/null
systemd-analyze io-uring-filter nop read uring_cmd
systemd-analyze io-uring-filter --json=short socket | jq -e '.[0] == {"name": "socket", "syscalls": ["socket"]}'
(! systemd-analyze io-uring-filter read foobar)
# filesystems (requires libbpf support)
if systemctl --version | grep "+BPF_FRAMEWORK"; then
systemd-analyze filesystems >/dev/null