From 85eca321838b6d66a44ffd5760fc45c91602aa4b Mon Sep 17 00:00:00 2001 From: Tom Hromatka Date: Mon, 18 Aug 2025 13:21:57 -0600 Subject: [PATCH] api: doc: tests: Add SCMP_ACT_TRAPX() Add a new action macro, SCMP_ACT_TRAPX(), which accepts user-specified data in the lower 16-bits. When a userspace signal handler has been specified, the Linux kernel populates the si_errno field in the siginfo structure with these lower 16-bits from the trap action. To maintain backward compatibility, redefine SCMP_ACT_TRAP to map to SCMP_ACT_TRAPX(0). This will guarantee that filters that utilize SCMP_ACT_TRAP will behave identically. Signed-off-by: Tom Hromatka --- doc/man/man3/seccomp_init.3 | 12 ++++ doc/man/man3/seccomp_rule_add.3 | 7 ++ include/seccomp.h.in | 6 +- src/gen_pfc.c | 4 +- src/system.c | 2 +- tests/.gitignore | 1 + tests/38-basic-pfc_coverage.pfc | 108 +++++++++++++++---------------- tests/63-live-trapx.c | 109 ++++++++++++++++++++++++++++++++ tests/63-live-trapx.py | 33 ++++++++++ tests/63-live-trapx.tests | 11 ++++ tests/Makefile.am | 9 ++- 11 files changed, 241 insertions(+), 61 deletions(-) create mode 100644 tests/63-live-trapx.c create mode 100755 tests/63-live-trapx.py create mode 100644 tests/63-live-trapx.tests diff --git a/doc/man/man3/seccomp_init.3 b/doc/man/man3/seccomp_init.3 index ca6224ce..680bb692 100644 --- a/doc/man/man3/seccomp_init.3 +++ b/doc/man/man3/seccomp_init.3 @@ -67,12 +67,24 @@ The entire process will be terminated by the kernel with SIGSYS when it calls a syscall that does not match any of the configured seccomp filter rules. .TP .B SCMP_ACT_TRAP +See +.B SCMP_ACT_TRAPX +.TP +.B SCMP_ACT_TRAPX(unit16_t reason) The thread will be sent a SIGSYS signal when it calls a syscall that does not match any of the configured seccomp filter rules. It may catch this and change its behavior accordingly. When using SA_SIGINFO with .BR sigaction (2), si_code will be set to SYS_SECCOMP, si_syscall will be set to the syscall that failed the rules, and si_arch will be set to the AUDIT_ARCH for the active ABI. +If +.B SCMP_ACT_TRAPX +is utilized, +the si_errno field in +.BR sigaction (2), +will be set to +.I reason +. .TP .B SCMP_ACT_ERRNO(uint16_t errno) The thread will receive a return value of diff --git a/doc/man/man3/seccomp_rule_add.3 b/doc/man/man3/seccomp_rule_add.3 index dce4f755..280b9c5e 100644 --- a/doc/man/man3/seccomp_rule_add.3 +++ b/doc/man/man3/seccomp_rule_add.3 @@ -184,6 +184,13 @@ the filter rule. The thread will throw a SIGSYS signal when it calls a syscall that matches the filter rule. .TP +.B SCMP_ACT_TRAPX(uint16_t reason) +The thread will throw a SIGSYS signal when it calls a syscall that matches the +filter rule. When using SA_SIGINFO with +.BR sigaction (2), +.I reason +will be populated in the si_errno field. +.TP .B SCMP_ACT_ERRNO(uint16_t errno) The thread will receive a return value of .I errno diff --git a/include/seccomp.h.in b/include/seccomp.h.in index 38c50d29..466d7269 100644 --- a/include/seccomp.h.in +++ b/include/seccomp.h.in @@ -365,8 +365,12 @@ struct scmp_arg_cmp { #define SCMP_ACT_KILL SCMP_ACT_KILL_THREAD /** * Throw a SIGSYS signal + * + * The Linux kernel supports a 16-bit parameter for the TRAP action, but + * libseccomp v2.6.x and older did not support or utilize this parameter. */ -#define SCMP_ACT_TRAP 0x00030000U +#define SCMP_ACT_TRAP SCMP_ACT_TRAPX(0) +#define SCMP_ACT_TRAPX(x) (0x00030000U | ((x) & 0x0000ffffU)) /** * Notifies userspace */ diff --git a/src/gen_pfc.c b/src/gen_pfc.c index 62dd9842..91017166 100644 --- a/src/gen_pfc.c +++ b/src/gen_pfc.c @@ -135,8 +135,8 @@ static void _pfc_action(FILE *fds, uint32_t action) case SCMP_ACT_KILL_THREAD: fprintf(fds, "action KILL;\n"); break; - case SCMP_ACT_TRAP: - fprintf(fds, "action TRAP;\n"); + case SCMP_ACT_TRAPX(0): + fprintf(fds, "action TRAP(%u);\n", (action & 0x0000ffff)); break; case SCMP_ACT_ERRNO(0): fprintf(fds, "action ERRNO(%u);\n", (action & 0x0000ffff)); diff --git a/src/system.c b/src/system.c index f2709521..f2f76368 100644 --- a/src/system.c +++ b/src/system.c @@ -196,7 +196,7 @@ int sys_chk_seccomp_action(uint32_t action) return state.sup_kill_process; } else if (action == SCMP_ACT_KILL_THREAD) { return 1; - } else if (action == SCMP_ACT_TRAP) { + } else if (action == SCMP_ACT_TRAPX(action & 0x0000ffff)) { return 1; } else if ((action == SCMP_ACT_ERRNO(action & 0x0000ffff)) && ((action & 0x0000ffff) < MAX_ERRNO)) { diff --git a/tests/.gitignore b/tests/.gitignore index c66e85f2..f0e2bac6 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -70,3 +70,4 @@ util.pyc 60-sim-precompute 61-sim-transactions 62-sim-arch_transactions +63-live-trapx diff --git a/tests/38-basic-pfc_coverage.pfc b/tests/38-basic-pfc_coverage.pfc index 02cbf726..56aa45d5 100644 --- a/tests/38-basic-pfc_coverage.pfc +++ b/tests/38-basic-pfc_coverage.pfc @@ -33,18 +33,18 @@ if ($arch == 3221225534) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a1.hi32 > 0) else @@ -56,18 +56,18 @@ if ($arch == 3221225534) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); # filter for syscall "read" (0) [priority: 65525] if ($syscall == 0) if ($a0.hi32 == 0) @@ -123,7 +123,7 @@ if ($arch == 1073741827) else if ($a2 >= 2) else - action TRAP; + action TRAP(0); # filter for syscall "read" (3) [priority: 65531] if ($syscall == 3) if ($a0 == 0) @@ -158,7 +158,7 @@ if ($arch == 3221225534) else if ($a2 >= 2) else - action TRAP; + action TRAP(0); # filter for syscall "read" (1073741824) [priority: 65531] if ($syscall == 1073741824) if ($a0 == 0) @@ -193,7 +193,7 @@ if ($arch == 1073741864) else if ($a2 >= 2) else - action TRAP; + action TRAP(0); # filter for syscall "read" (3) [priority: 65531] if ($syscall == 3) if ($a0 == 0) @@ -235,18 +235,18 @@ if ($arch == 3221225655) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a1.hi32 > 0) else @@ -258,18 +258,18 @@ if ($arch == 3221225655) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); # filter for syscall "read" (63) [priority: 65525] if ($syscall == 63) if ($a0.hi32 == 0) @@ -332,18 +332,18 @@ if ($arch == 3221225730) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a1.hi32 > 0) else @@ -355,18 +355,18 @@ if ($arch == 3221225730) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); # filter for syscall "read" (63) [priority: 65525] if ($syscall == 63) if ($a0.hi32 == 0) @@ -422,7 +422,7 @@ if ($arch == 1073741832) else if ($a2 >= 2) else - action TRAP; + action TRAP(0); # filter for syscall "read" (4003) [priority: 65531] if ($syscall == 4003) if ($a0 == 0) @@ -464,18 +464,18 @@ if ($arch == 3221225480) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a1.hi32 > 0) else @@ -487,18 +487,18 @@ if ($arch == 3221225480) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); # filter for syscall "read" (5000) [priority: 65525] if ($syscall == 5000) if ($a0.hi32 == 0) @@ -554,7 +554,7 @@ if ($arch == 3758096392) else if ($a2 >= 2) else - action TRAP; + action TRAP(0); # filter for syscall "read" (6000) [priority: 65531] if ($syscall == 6000) if ($a0 == 0) @@ -596,18 +596,18 @@ if ($arch == 3221225493) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a1.hi32 > 0) else @@ -619,18 +619,18 @@ if ($arch == 3221225493) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); # filter for syscall "read" (3) [priority: 65525] if ($syscall == 3) if ($a0.hi32 == 0) @@ -686,7 +686,7 @@ if ($arch == 1073741866) else if ($a2 >= 2) else - action TRAP; + action TRAP(0); # filter for syscall "read" (3) [priority: 65531] if ($syscall == 3) if ($a0 == 0) @@ -728,18 +728,18 @@ if ($arch == 3221225715) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a1.hi32 > 0) else @@ -751,18 +751,18 @@ if ($arch == 3221225715) if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); else if ($a2.hi32 > 0) else if ($a2.hi32 == 0) if ($a2.lo32 >= 2) else - action TRAP; + action TRAP(0); else - action TRAP; + action TRAP(0); # filter for syscall "read" (63) [priority: 65525] if ($syscall == 63) if ($a0.hi32 == 0) diff --git a/tests/63-live-trapx.c b/tests/63-live-trapx.c new file mode 100644 index 00000000..9a3aa176 --- /dev/null +++ b/tests/63-live-trapx.c @@ -0,0 +1,109 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2025 Oracle and/or its affiliates. + * Author: Tom Hromatka + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include +#include +#include + +#include + +#include "util.h" + + +#include + + +#define EXPECTED_REASON 1234 + +static int trap_rc; + +static void _trap_handler(int signal, siginfo_t *info, void *ctx) +{ + if (info->si_errno == EXPECTED_REASON) + trap_rc = 0; + else + trap_rc = -EINVAL; +} + +int trap_install(void) +{ + struct sigaction signal_handler; + sigset_t signal_mask; + + trap_rc = -EBUSY; + + memset(&signal_handler, 0, sizeof(signal_handler)); + sigemptyset(&signal_mask); + sigaddset(&signal_mask, SIGSYS); + + signal_handler.sa_sigaction = &_trap_handler; + signal_handler.sa_flags = SA_SIGINFO; + if (sigaction(SIGSYS, &signal_handler, NULL) < 0) + return -errno; + if (sigprocmask(SIG_UNBLOCK, &signal_mask, NULL)) + return -errno; + + return 0; +} + +int main(int argc, char *argv[]) +{ + scmp_filter_ctx ctx = NULL; + pid_t ppid; + int cnt, rc; + + rc = trap_install(); + if (rc != 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + return ENOMEM; + + rc = seccomp_rule_add(ctx, SCMP_ACT_TRAPX(EXPECTED_REASON), + SCMP_SYS(getppid), 0); + if (rc != 0) + goto out; + + rc = seccomp_load(ctx); + if (rc != 0) + goto out; + + ppid = getppid(); + (void)ppid; + + cnt = 0; + while (trap_rc == -EBUSY) { + sleep(1); + cnt++; + + if (cnt > 5) + break; + } + + if (trap_rc == 0) + rc = 161; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/63-live-trapx.py b/tests/63-live-trapx.py new file mode 100755 index 00000000..67fc61e0 --- /dev/null +++ b/tests/63-live-trapx.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2025 Oracle and/or its affiliates. +# Author: Tom Hromatka +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see . +# + +def test(): + # The python signal handler doesn't support the si_errno field in the + # siginfo structure. Therefore SCMP_ACT_TRAPX() cannot be tested in + # python + quit(160) + +test() + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/63-live-trapx.tests b/tests/63-live-trapx.tests new file mode 100644 index 00000000..67c0200a --- /dev/null +++ b/tests/63-live-trapx.tests @@ -0,0 +1,11 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2025 Oracle and/or its affiliates. +# Author: Tom Hromatka +# + +test type: live + +# Testname API Result +63-live-trapx 1 TRAP diff --git a/tests/Makefile.am b/tests/Makefile.am index bbe71324..84b724e8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -97,7 +97,8 @@ check_PROGRAMS = \ 59-basic-empty_binary_tree \ 60-sim-precompute \ 61-sim-transactions \ - 62-sim-arch_transactions + 62-sim-arch_transactions \ + 63-live-trapx EXTRA_DIST_TESTPYTHON = \ util.py \ @@ -160,7 +161,8 @@ EXTRA_DIST_TESTPYTHON = \ 59-basic-empty_binary_tree.py \ 60-sim-precompute.py \ 61-sim-transactions.py \ - 62-sim-arch_transactions.py + 62-sim-arch_transactions.py \ + 63-live-trapx.py EXTRA_DIST_TESTCFGS = \ 01-sim-allow.tests \ @@ -224,7 +226,8 @@ EXTRA_DIST_TESTCFGS = \ 59-basic-empty_binary_tree.tests \ 60-sim-precompute.tests \ 61-sim-transactions.tests \ - 62-sim-arch_transactions.tests + 62-sim-arch_transactions.tests \ + 63-live-trapx.tests EXTRA_DIST_TESTSCRIPTS = \ 38-basic-pfc_coverage.sh 38-basic-pfc_coverage.pfc \