[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <9a59a67dad5b7455ff975a68ba5f5fb95a8d02a9.1750294482.git.thehajime@gmail.com>
Date: Thu, 19 Jun 2025 10:04:09 +0900
From: Hajime Tazaki <thehajime@...il.com>
To: linux-um@...ts.infradead.org
Cc: thehajime@...il.com,
ricarkol@...gle.com,
Liam.Howlett@...cle.com,
linux-kernel@...r.kernel.org,
Kenichi Yasukata <kenichi.yasukata@...il.com>
Subject: [PATCH v9 05/13] um: nommu: seccomp syscalls hook
This commit adds syscall hook with seccomp.
Using seccomp raises SIGSYS to UML process, which is captured in the
(UML) kernel, then jumps to the syscall entry point, __kernel_vsyscall,
to hook the original syscall instructions.
The SIGSYS signal is raised upon the execution from uml_reserved and
high_physmem, which locates userspace memory.
It also renames existing static function, sigsys_handler(), in
start_up.c to avoid name conflicts between them.
Signed-off-by: Hajime Tazaki <thehajime@...il.com>
Signed-off-by: Kenichi Yasukata <kenichi.yasukata@...il.com>
---
arch/um/include/shared/kern_util.h | 2 +
arch/um/include/shared/os.h | 10 +++
arch/um/kernel/um_arch.c | 3 +
arch/um/nommu/Makefile | 3 +
arch/um/nommu/os-Linux/Makefile | 7 +++
arch/um/nommu/os-Linux/signal.c | 16 +++++
arch/um/os-Linux/Makefile | 5 ++
arch/um/os-Linux/seccomp.c | 87 +++++++++++++++++++++++++++
arch/um/os-Linux/signal.c | 8 +++
arch/um/os-Linux/start_up.c | 4 +-
arch/x86/um/nommu/Makefile | 2 +-
arch/x86/um/nommu/os-Linux/Makefile | 6 ++
arch/x86/um/nommu/os-Linux/mcontext.c | 13 ++++
arch/x86/um/shared/sysdep/mcontext.h | 4 ++
14 files changed, 167 insertions(+), 3 deletions(-)
create mode 100644 arch/um/nommu/Makefile
create mode 100644 arch/um/nommu/os-Linux/Makefile
create mode 100644 arch/um/nommu/os-Linux/signal.c
create mode 100644 arch/um/os-Linux/seccomp.c
create mode 100644 arch/x86/um/nommu/os-Linux/Makefile
create mode 100644 arch/x86/um/nommu/os-Linux/mcontext.c
diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h
index 00ca3e12fd9a..ec8ba1f13c58 100644
--- a/arch/um/include/shared/kern_util.h
+++ b/arch/um/include/shared/kern_util.h
@@ -66,6 +66,8 @@ extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs
extern void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs,
void *mc);
extern void fatal_sigsegv(void) __attribute__ ((noreturn));
+extern void sigsys_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs,
+ void *mc);
void um_idle_sleep(void);
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index b35cc8ce333b..1251f08e26d0 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -338,4 +338,14 @@ extern void um_trace_signals_off(void);
/* time-travel */
extern void deliver_time_travel_irqs(void);
+/* seccomp.c */
+#ifdef CONFIG_MMU
+static inline int os_setup_seccomp(void)
+{
+ return 0;
+}
+#else
+extern int os_setup_seccomp(void);
+#endif
+
#endif
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 2f5ee045bc7a..14b9dcab9907 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -431,6 +431,9 @@ void __init setup_arch(char **cmdline_p)
add_bootloader_randomness(rng_seed, sizeof(rng_seed));
memzero_explicit(rng_seed, sizeof(rng_seed));
}
+
+ /* install seccomp filter */
+ os_setup_seccomp();
}
void __init arch_cpu_finalize_init(void)
diff --git a/arch/um/nommu/Makefile b/arch/um/nommu/Makefile
new file mode 100644
index 000000000000..baab7c2f57c2
--- /dev/null
+++ b/arch/um/nommu/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y := os-Linux/
diff --git a/arch/um/nommu/os-Linux/Makefile b/arch/um/nommu/os-Linux/Makefile
new file mode 100644
index 000000000000..68833c576437
--- /dev/null
+++ b/arch/um/nommu/os-Linux/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y := signal.o
+USER_OBJS := $(obj-y)
+
+include $(srctree)/arch/um/scripts/Makefile.rules
+USER_CFLAGS+=-I$(srctree)/arch/um/os-Linux
diff --git a/arch/um/nommu/os-Linux/signal.c b/arch/um/nommu/os-Linux/signal.c
new file mode 100644
index 000000000000..19043b9652e2
--- /dev/null
+++ b/arch/um/nommu/os-Linux/signal.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <signal.h>
+#include <kern_util.h>
+#include <os.h>
+#include <sysdep/mcontext.h>
+#include <sys/ucontext.h>
+
+void sigsys_handler(int sig, struct siginfo *si,
+ struct uml_pt_regs *regs, void *ptr)
+{
+ mcontext_t *mc = (mcontext_t *) ptr;
+
+ /* hook syscall via SIGSYS */
+ set_mc_sigsys_hook(mc);
+}
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index c048fc838068..432476a4239a 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -21,4 +21,9 @@ USER_OBJS := $(user-objs-y) elf_aux.o execvp.o file.o helper.o irq.o \
main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \
tty.o umid.o util.o
+ifneq ($(CONFIG_MMU),y)
+obj-y += seccomp.o
+USER_OBJS += seccomp.o
+endif
+
include $(srctree)/arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/seccomp.c b/arch/um/os-Linux/seccomp.c
new file mode 100644
index 000000000000..d1cfa6e3d632
--- /dev/null
+++ b/arch/um/os-Linux/seccomp.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h> /* For SYS_xxx definitions */
+#include <init.h>
+#include <as-layout.h>
+#include <os.h>
+#include <linux/filter.h>
+#include <linux/seccomp.h>
+
+int __init os_setup_seccomp(void)
+{
+ int err;
+ unsigned long __userspace_start = uml_reserved,
+ __userspace_end = high_physmem;
+
+ struct sock_filter filter[] = {
+ /* if (IP_high > __userspace_end) allow; */
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
+ offsetof(struct seccomp_data, instruction_pointer) + 4),
+ BPF_JUMP(BPF_JMP + BPF_JGT + BPF_K, __userspace_end >> 32,
+ /*true-skip=*/0, /*false-skip=*/1),
+ BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
+
+ /* if (IP_high == __userspace_end && IP_low >= __userspace_end) allow; */
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
+ offsetof(struct seccomp_data, instruction_pointer) + 4),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __userspace_end >> 32,
+ /*true-skip=*/0, /*false-skip=*/3),
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
+ offsetof(struct seccomp_data, instruction_pointer)),
+ BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, __userspace_end,
+ /*true-skip=*/0, /*false-skip=*/1),
+ BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
+
+ /* if (IP_high < __userspace_start) allow; */
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
+ offsetof(struct seccomp_data, instruction_pointer) + 4),
+ BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, __userspace_start >> 32,
+ /*true-skip=*/1, /*false-skip=*/0),
+ BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
+
+ /* if (IP_high == __userspace_start && IP_low < __userspace_start) allow; */
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
+ offsetof(struct seccomp_data, instruction_pointer) + 4),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __userspace_start >> 32,
+ /*true-skip=*/0, /*false-skip=*/3),
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
+ offsetof(struct seccomp_data, instruction_pointer)),
+ BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, __userspace_start,
+ /*true-skip=*/1, /*false-skip=*/0),
+ BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
+
+ /* other address; trap */
+ BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRAP),
+ };
+ struct sock_fprog prog = {
+ .len = ARRAY_SIZE(filter),
+ .filter = filter,
+ };
+
+ err = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+ if (err)
+ os_warn("PR_SET_NO_NEW_PRIVS (err=%d, ernro=%d)\n",
+ err, errno);
+
+ err = syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER,
+ SECCOMP_FILTER_FLAG_TSYNC, &prog);
+ if (err) {
+ os_warn("SECCOMP_SET_MODE_FILTER (err=%d, ernro=%d)\n",
+ err, errno);
+ exit(1);
+ }
+
+ set_handler(SIGSYS);
+
+ os_info("seccomp: setup filter syscalls in the range: 0x%lx-0x%lx\n",
+ __userspace_start, __userspace_end);
+
+ return 0;
+}
+
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 11f07f498270..53e276e81b37 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -20,6 +20,7 @@
#include <um_malloc.h>
#include <sys/ucontext.h>
#include <timetravel.h>
+#include <linux/compiler_attributes.h>
void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *, void *mc) = {
[SIGTRAP] = relay_signal,
@@ -30,6 +31,7 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *, void *mc) =
[SIGSEGV] = segv_handler,
[SIGIO] = sigio_handler,
[SIGCHLD] = sigchld_handler,
+ [SIGSYS] = sigsys_handler,
};
static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
@@ -176,6 +178,11 @@ static void sigusr1_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
uml_pm_wake();
}
+__weak void sigsys_handler(int sig, struct siginfo *unused_si,
+ struct uml_pt_regs *regs, void *mc)
+{
+}
+
void register_pm_wake_signal(void)
{
set_handler(SIGUSR1);
@@ -187,6 +194,7 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = {
[SIGILL] = sig_handler,
[SIGFPE] = sig_handler,
[SIGTRAP] = sig_handler,
+ [SIGSYS] = sig_handler,
[SIGIO] = sig_handler,
[SIGWINCH] = sig_handler,
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index a827c2e01aa5..4e1f05360c49 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -238,7 +238,7 @@ extern unsigned long *exec_fp_regs;
__initdata static struct stub_data *seccomp_test_stub_data;
-static void __init sigsys_handler(int sig, siginfo_t *info, void *p)
+static void __init _sigsys_handler(int sig, siginfo_t *info, void *p)
{
ucontext_t *uc = p;
@@ -273,7 +273,7 @@ static int __init seccomp_helper(void *data)
sizeof(seccomp_test_stub_data->sigstack));
sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO;
- sa.sa_sigaction = (void *) sigsys_handler;
+ sa.sa_sigaction = (void *) _sigsys_handler;
sa.sa_restorer = NULL;
if (sigaction(SIGSYS, &sa, NULL) < 0)
exit(2);
diff --git a/arch/x86/um/nommu/Makefile b/arch/x86/um/nommu/Makefile
index d72c63afffa5..ebe47d4836f4 100644
--- a/arch/x86/um/nommu/Makefile
+++ b/arch/x86/um/nommu/Makefile
@@ -5,4 +5,4 @@ else
BITS := 64
endif
-obj-y = do_syscall_$(BITS).o entry_$(BITS).o
+obj-y = do_syscall_$(BITS).o entry_$(BITS).o os-Linux/
diff --git a/arch/x86/um/nommu/os-Linux/Makefile b/arch/x86/um/nommu/os-Linux/Makefile
new file mode 100644
index 000000000000..4571e403a6ff
--- /dev/null
+++ b/arch/x86/um/nommu/os-Linux/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y = mcontext.o
+USER_OBJS := mcontext.o
+
+include $(srctree)/arch/um/scripts/Makefile.rules
diff --git a/arch/x86/um/nommu/os-Linux/mcontext.c b/arch/x86/um/nommu/os-Linux/mcontext.c
new file mode 100644
index 000000000000..c4ef877d5ea0
--- /dev/null
+++ b/arch/x86/um/nommu/os-Linux/mcontext.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <sys/ucontext.h>
+#define __FRAME_OFFSETS
+#include <asm/ptrace.h>
+#include <sysdep/ptrace.h>
+#include <sysdep/mcontext.h>
+#include <sysdep/syscalls.h>
+
+void set_mc_sigsys_hook(mcontext_t *mc)
+{
+ mc->gregs[REG_RCX] = mc->gregs[REG_RIP];
+ mc->gregs[REG_RIP] = (unsigned long) __kernel_vsyscall;
+}
diff --git a/arch/x86/um/shared/sysdep/mcontext.h b/arch/x86/um/shared/sysdep/mcontext.h
index 6fe490cc5b98..9a0d6087f357 100644
--- a/arch/x86/um/shared/sysdep/mcontext.h
+++ b/arch/x86/um/shared/sysdep/mcontext.h
@@ -17,6 +17,10 @@ extern int get_stub_state(struct uml_pt_regs *regs, struct stub_data *data,
extern int set_stub_state(struct uml_pt_regs *regs, struct stub_data *data,
int single_stepping);
+#ifndef CONFIG_MMU
+extern void set_mc_sigsys_hook(mcontext_t *mc);
+#endif
+
#ifdef __i386__
#define GET_FAULTINFO_FROM_MC(fi, mc) \
--
2.43.0
Powered by blists - more mailing lists