From nobody Thu Oct 2 11:50:38 2025 Received: from mail-pj1-f49.google.com (mail-pj1-f49.google.com [209.85.216.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DAC30288C39 for ; Thu, 18 Sep 2025 05:16:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758172595; cv=none; b=LtkbimyVxS+G18KLY+fpjY6npsshpfQdWLdK9cOuMb49IlZpp4zdQel1tAkHBtiXfcsxLEvu5TTCNQdu5sd2VSIQeqZd3ancK0TB/W9Sie8nMX1h6yiJ3sHKHpqunDMxH08b7wyawCcATPlAWfjUiEIPM/XUNgazme2KitXmzB4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758172595; c=relaxed/simple; bh=7/bypW60GL8eL/uqYkt5R7qvzBuLOGenTkwRBAP7t9k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VUJdDNuQfECPB4Y25zZGTY9JIrg2em7AAqZdYojJZxr+fZrNOFf5B1wXtuKVe8EEaz/Y4PxKatDnnanyKOIhgfirI9yEKihSrRyzna+UVPIeg+Hywe0i0Teg0BL5IL+zwep0nKQGArfMJBGy07Ib7JxvZntiuneJJSBgGBkga/g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Xwh+HCy9; arc=none smtp.client-ip=209.85.216.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Xwh+HCy9" Received: by mail-pj1-f49.google.com with SMTP id 98e67ed59e1d1-32ee4817c43so430056a91.0 for ; Wed, 17 Sep 2025 22:16:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1758172593; x=1758777393; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=q19q5PL21Wai78SSc2mwVr4TVT2qO2bW74gFJJ8pT9o=; b=Xwh+HCy9RhW5Uyvt/EAa3N6IJH7OP3t8KW2n7wHGH0Tr7rh9oAkc3UaYEx1HYB1XVA fj6sNBi1dfhghlzAwxYs2gHWWJxYVHmYj56TvD6bbfjLz6scAKL0zFTcn7Npdx5jREi7 Yr2zH6EnLggdg4aP/rwFCCtFiXw2tP99YKAGOYAXKXzH/o0AI5wK1FwU36efLOKCEp+A 2zBFBBtCG4UIzteH/bfBeGpi5AivcHvW9CRyskYregXdR09ZDwVZNBOuLrcNkMqy/Yhk lWnv9NfvlGoYkLmtfWTQc3YkoXzHUjAdVl8ctIUohMJoQSLY+4BypGfnfBlsDIc3l1ng aRAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1758172593; x=1758777393; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=q19q5PL21Wai78SSc2mwVr4TVT2qO2bW74gFJJ8pT9o=; b=Q7GQavSAn+ywv3QcRY/3Ww0EYRcv375yn8xTYj/+VUcuMhLAnqQTOhiLf9zSBFIBOF T9qFkv4lw/IUjS/0o1T4ADyXVlDGUMy5OyHLKImDnx91USRNJm4Vd6h3fv/9eOsaHhdb +oWUuG2ll9+UXd5n0Hr70TqwWUhSf+s3Fu4aV+j4LZ81XlA/4wC0qDZ+rHSmJyFnuNos hgMwBGSrsE3TJh5kQEGvOFs1rS8gmu7ixuMpi5lXQfarO7GtUmV2vVpxbX7MHQzv9YCF JjMxgk5Wsz1XfrFrWgJri5L7bYf8ECa0xFOBQYUHGJ/uxFT4A3Zr6TEwON5zDQB1KQ0k M0dQ== X-Forwarded-Encrypted: i=1; AJvYcCX0KKbogh3L9ZLQi4AHPpKgTf8O2PBAi81EXi0iTi9rG+o4nJ8MJv1gl6tUtgdEgEX17yvKNGjPZPqCz9E=@vger.kernel.org X-Gm-Message-State: AOJu0Yy/nA20o0Wss5YNMFgSTQa+4jNO8/ZGdSJNEndUG966MMKBePVJ 9Lj1NLNxL64FInOQqQ8Xa48sztSmIRqA+D8g7rvALVRA9N/k8uTq0FUP X-Gm-Gg: ASbGnctVE45FfE3YhP7ZSvaNcV1gtHdssVXaJNo43Uw7e3i++egogLnoa87/nDzZaC1 Qhq79ah1CRnzdjLG1ILdHjHcu34NETA8JjNNZqGpD4hE/5WMpLYdlRITd2OyuVKS6fbmPu9JRjo YE2D7NVj30GsCR5DwCi9ek6liDf4OGt57SbHIqF5n7CZ54+fH1vdDxDHA7PmFJr7c9adR+bduU3 tIb5waPl0Xs/dEJoo4bx2Dy691nE0N/YIwLYK1CpJXw74XnnUF5L8N+lpXkrveFUJjplC8jespl c9dUTcnuGWezZ/VPsCWbRCNd0Za86V8BhtIjzdURG0g1KumwESNs5hgMjGY4G2uA4Matl1FOBQP TV8rizH4sHxZuqbRBWYeFP+pntn/0C9/KRfY/rU8EM3wh+ywADZCFfPtPUFlDe4Q1uIZsEm67uI mWJ6mcMQbdVYs= X-Google-Smtp-Source: AGHT+IGPq6NoJecMSRuhP/l9ouJtlFCnSkKR9+iBv1QGL1Q1oGRUhlnsX+GsoH3jhGeW+/vjvX25Wg== X-Received: by 2002:a17:90b:3f0f:b0:32d:e309:8d76 with SMTP id 98e67ed59e1d1-3305c64978fmr2409491a91.10.1758172592958; Wed, 17 Sep 2025 22:16:32 -0700 (PDT) Received: from ikb-h07-29-noble.in.iijlab.net ([202.214.97.5]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-33046a4d0basm2726998a91.27.2025.09.17.22.16.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 Sep 2025 22:16:32 -0700 (PDT) Received: by ikb-h07-29-noble.in.iijlab.net (Postfix, from userid 1010) id 003E61061EEA; Thu, 18 Sep 2025 14:16:31 +0900 (JST) From: Hajime Tazaki To: linux-um@lists.infradead.org Cc: thehajime@gmail.com, ricarkol@google.com, Liam.Howlett@oracle.com, linux-kernel@vger.kernel.org, Kenichi Yasukata Subject: [PATCH v11 05/14] um: nommu: seccomp syscalls hook Date: Thu, 18 Sep 2025 14:15:58 +0900 Message-ID: <952f2620bf435d90358bf5868a17ec27f213bf3f.1758171893.git.thehajime@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Signed-off-by: Kenichi Yasukata --- 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 | 15 +++++ arch/x86/um/shared/sysdep/mcontext.h | 4 ++ 14 files changed, 169 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/ke= rn_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); =20 void um_idle_sleep(void); =20 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); =20 +/* 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 cfbbbf8500c3..e90b8744144a 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -426,6 +426,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(); } =20 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 :=3D os-Linux/ diff --git a/arch/um/nommu/os-Linux/Makefile b/arch/um/nommu/os-Linux/Makef= ile 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 :=3D signal.o +USER_OBJS :=3D $(obj-y) + +include $(srctree)/arch/um/scripts/Makefile.rules +USER_CFLAGS+=3D-I$(srctree)/arch/um/os-Linux diff --git a/arch/um/nommu/os-Linux/signal.c b/arch/um/nommu/os-Linux/signa= l.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 +#include +#include +#include +#include + +void sigsys_handler(int sig, struct siginfo *si, + struct uml_pt_regs *regs, void *ptr) +{ + mcontext_t *mc =3D (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 :=3D $(user-objs-y) elf_aux.o execvp.o file.o h= elper.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 =20 +ifneq ($(CONFIG_MMU),y) +obj-y +=3D seccomp.o +USER_OBJS +=3D 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 +#include +#include +#include +#include +#include +#include /* For SYS_xxx definitions */ +#include +#include +#include +#include +#include + +int __init os_setup_seccomp(void) +{ + int err; + unsigned long __userspace_start =3D uml_reserved, + __userspace_end =3D high_physmem; + + struct sock_filter filter[] =3D { + /* 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=3D*/0, /*false-skip=3D*/1), + BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW), + + /* if (IP_high =3D=3D __userspace_end && IP_low >=3D __userspace_end) al= low; */ + 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=3D*/0, /*false-skip=3D*/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=3D*/0, /*false-skip=3D*/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=3D*/1, /*false-skip=3D*/0), + BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW), + + /* if (IP_high =3D=3D __userspace_start && IP_low < __userspace_start) a= llow; */ + 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=3D*/0, /*false-skip=3D*/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=3D*/1, /*false-skip=3D*/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 =3D { + .len =3D ARRAY_SIZE(filter), + .filter =3D filter, + }; + + err =3D prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); + if (err) + os_warn("PR_SET_NO_NEW_PRIVS (err=3D%d, ernro=3D%d)\n", + err, errno); + + err =3D syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, + SECCOMP_FILTER_FLAG_TSYNC, &prog); + if (err) { + os_warn("SECCOMP_SET_MODE_FILTER (err=3D%d, ernro=3D%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 #include #include +#include =20 void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *, void *= mc) =3D { [SIGTRAP] =3D relay_signal, @@ -30,6 +31,7 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_= pt_regs *, void *mc) =3D [SIGSEGV] =3D segv_handler, [SIGIO] =3D sigio_handler, [SIGCHLD] =3D sigchld_handler, + [SIGSYS] =3D sigsys_handler, }; =20 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 *u= nused_si, mcontext_t *mc) uml_pm_wake(); } =20 +__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) =3D { [SIGILL] =3D sig_handler, [SIGFPE] =3D sig_handler, [SIGTRAP] =3D sig_handler, + [SIGSYS] =3D sig_handler, =20 [SIGIO] =3D sig_handler, [SIGWINCH] =3D 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; =20 __initdata static struct stub_data *seccomp_test_stub_data; =20 -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 =3D p; =20 @@ -273,7 +273,7 @@ static int __init seccomp_helper(void *data) sizeof(seccomp_test_stub_data->sigstack)); =20 sa.sa_flags =3D SA_ONSTACK | SA_NODEFER | SA_SIGINFO; - sa.sa_sigaction =3D (void *) sigsys_handler; + sa.sa_sigaction =3D (void *) _sigsys_handler; sa.sa_restorer =3D 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 :=3D 64 endif =20 -obj-y =3D do_syscall_$(BITS).o entry_$(BITS).o +obj-y =3D 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-Lin= ux/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 =3D mcontext.o +USER_OBJS :=3D 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-L= inux/mcontext.c new file mode 100644 index 000000000000..b62a6195096f --- /dev/null +++ b/arch/x86/um/nommu/os-Linux/mcontext.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#define __FRAME_OFFSETS +#include +#include +#include + +extern long __kernel_vsyscall(int64_t a0, int64_t a1, int64_t a2, int64_t = a3, + int64_t a4, int64_t a5, int64_t a6); + +void set_mc_sigsys_hook(mcontext_t *mc) +{ + mc->gregs[REG_RCX] =3D mc->gregs[REG_RIP]; + mc->gregs[REG_RIP] =3D (unsigned long) __kernel_vsyscall; +} diff --git a/arch/x86/um/shared/sysdep/mcontext.h b/arch/x86/um/shared/sysd= ep/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, stru= ct stub_data *data, extern int set_stub_state(struct uml_pt_regs *regs, struct stub_data *data, int single_stepping); =20 +#ifndef CONFIG_MMU +extern void set_mc_sigsys_hook(mcontext_t *mc); +#endif + #ifdef __i386__ =20 #define GET_FAULTINFO_FROM_MC(fi, mc) \ --=20 2.43.0