mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Cong Wang <xiyou.wangcong@gmail.com>
To: Richard Weinberger <richard@nod.at>,
	Anton Ivanov <anton.ivanov@cambridgegreys.com>,
	Johannes Berg <johannes@sipsolutions.net>
Cc: Benjamin Berg <benjamin@sipsolutions.net>,
	linux-um@lists.infradead.org, linux-kernel@vger.kernel.org,
	Cong Wang <cwang@multikernel.io>
Subject: [RFC PATCH 5/6] um: install guest mappings via pidfd_mmap() in both modes
Date: Fri, 10 Jul 2026 13:53:23 -0700	[thread overview]
Message-ID: <20260710205324.1343217-6-xiyou.wangcong@gmail.com> (raw)
In-Reply-To: <20260710205324.1343217-1-xiyou.wangcong@gmail.com>

From: Cong Wang <cwang@multikernel.io>

Route both seccomp and ptrace (SKAS0) map()/unmap() through
pidfd_mmap()/pidfd_munmap(): the monitor resolves the physmem fd in its
own fd table and installs the mapping into the stub's mm directly, so the
stub never executes mmap/munmap itself in either mode.

Neither mode drives the stub to execute syscalls anymore, so the whole
stub-syscall batcher and the seccomp-only SCM_RIGHTS fd-passing become
dead code and are removed. The seccomp model's inherent risks are not
addressed by pidfd_mmap() (a malicious guest can still block SIGALRM to
dodge scheduling), so that note is preserved in stub.c.

This is an RFC demonstration of pidfd_mmap()'s reach; it assumes a host
kernel that provides the syscall and does not add a fallback for older
hosts intentionally.

Assisted-by: Claude:claude-opus-4.8
Signed-off-by: Cong Wang <cwang@multikernel.io>
---
 arch/um/include/shared/os.h             |   4 -
 arch/um/include/shared/skas/mm_id.h     |   7 -
 arch/um/include/shared/skas/stub-data.h |  28 ---
 arch/um/kernel/skas/mmu.c               |   5 -
 arch/um/kernel/skas/stub.c              | 151 ++----------
 arch/um/kernel/skas/stub_exe.c          |  16 +-
 arch/um/os-Linux/skas/mem.c             | 295 ++----------------------
 arch/um/os-Linux/skas/process.c         |  86 +------
 arch/um/os-Linux/start_up.c             |   8 +-
 9 files changed, 67 insertions(+), 533 deletions(-)

diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index b26e94292fc1..c6917583ca64 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -280,10 +280,6 @@ extern long long os_persistent_clock_emulation(void);
 extern long long os_nsecs(void);
 
 /* skas/mem.c */
-int syscall_stub_flush(struct mm_id *mm_idp);
-struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp);
-void syscall_stub_dump_error(struct mm_id *mm_idp);
-
 int map(struct mm_id *mm_idp, unsigned long virt,
 	unsigned long len, int prot, int phys_fd,
 	unsigned long long offset);
diff --git a/arch/um/include/shared/skas/mm_id.h b/arch/um/include/shared/skas/mm_id.h
index cec97189f12b..0f74e1728a1e 100644
--- a/arch/um/include/shared/skas/mm_id.h
+++ b/arch/um/include/shared/skas/mm_id.h
@@ -8,18 +8,11 @@
 
 #include <linux/compiler_types.h>
 
-#define STUB_MAX_FDS 4
-
 struct mm_id {
 	int pid;
 	unsigned long stack;
-	int syscall_data_len;
 
-	/* Only used with SECCOMP mode */
 	int stub_pidfd;		/* pidfd to the stub, or -1 */
-	int sock;
-	int syscall_fd_num;
-	int syscall_fd_map[STUB_MAX_FDS];
 };
 
 struct mutex *__get_turnstile(struct mm_id *mm_id);
diff --git a/arch/um/include/shared/skas/stub-data.h b/arch/um/include/shared/skas/stub-data.h
index 27db38e95df9..eaa208bcdaff 100644
--- a/arch/um/include/shared/skas/stub-data.h
+++ b/arch/um/include/shared/skas/stub-data.h
@@ -31,36 +31,8 @@ struct stub_init_data {
 	unsigned long signal_restorer;
 };
 
-#define STUB_NEXT_SYSCALL(s) \
-	((struct stub_syscall *) (((unsigned long) s) + (s)->cmd_len))
-
-enum stub_syscall_type {
-	STUB_SYSCALL_UNSET = 0,
-	STUB_SYSCALL_MMAP,
-	STUB_SYSCALL_MUNMAP,
-};
-
-struct stub_syscall {
-	struct {
-		unsigned long addr;
-		unsigned long length;
-		unsigned long offset;
-		int fd;
-		int prot;
-	} mem;
-
-	enum stub_syscall_type syscall;
-};
-
 struct stub_data {
-	long err;
-
-	int syscall_data_len;
-	/* 128 leaves enough room for additional fields in the struct */
-	struct stub_syscall syscall_data[(UM_KERN_PAGE_SIZE - 128) / sizeof(struct stub_syscall)] __aligned(16);
-
 	/* data shared with signal handler (only used in seccomp mode) */
-	short restart_wait;
 	unsigned int futex;
 	int signal;
 	unsigned short si_offset;
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 441dcf94ec9c..b2c9cf023789 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -55,8 +55,6 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
 
 	new_id->stack = stack;
 	new_id->stub_pidfd = -1;
-	new_id->syscall_data_len = 0;
-	new_id->syscall_fd_num = 0;
 
 	scoped_guard(spinlock_irqsave, &mm_list_lock) {
 		/* Insert into list, used for lookups when the child dies */
@@ -109,9 +107,6 @@ void destroy_context(struct mm_struct *mm)
 		mmu->id.stub_pidfd = -1;
 	}
 
-	if (using_seccomp && mmu->id.sock)
-		os_close_file(mmu->id.sock);
-
 	free_pages(mmu->id.stack, ilog2(STUB_DATA_PAGES));
 }
 
diff --git a/arch/um/kernel/skas/stub.c b/arch/um/kernel/skas/stub.c
index e09216a20cb5..08443f2eb09d 100644
--- a/arch/um/kernel/skas/stub.c
+++ b/arch/um/kernel/skas/stub.c
@@ -6,119 +6,46 @@
 #include <sysdep/stub.h>
 
 #include <linux/futex.h>
-#include <sys/socket.h>
 #include <errno.h>
 
 /*
- * Known security issues
+ * Known security issues (SECCOMP userspace)
  *
- * Userspace can jump to this address to execute *any* syscall that is
- * permitted by the stub. As we will return afterwards, it can do
- * whatever it likes, including:
- * - Tricking the kernel into handing out the memory FD
- * - Using this memory FD to read/write all physical memory
- * - Running in parallel to the kernel processing a syscall
- *   (possibly creating data races?)
- * - Blocking e.g. SIGALRM to avoid time based scheduling
+ * The stub shares its address space with the untrusted guest application.
+ * Installing guest mappings via pidfd_mmap() closed some earlier holes --
+ * the stub no longer holds the physmem fd and no longer executes mmap/munmap
+ * on the guest's behalf (both are rejected by the SECCOMP filter) -- but the
+ * following are inherent to the model and remain unaddressed:
  *
- * To avoid this, the permitted location for each syscall needs to be
- * checked for in the SECCOMP filter (which is reasonably simple). Also,
- * more care will need to go into considerations how the code might be
- * tricked by using a prepared stack (or even modifying the stack from
- * another thread in case SMP support is added).
- *
- * As for the SIGALRM, the best counter measure will be to check in the
- * kernel that the process is reporting back the SIGALRM in a timely
- * fashion.
+ * - A malicious guest can influence the stub's signal state (e.g. via a
+ *   prepared stack restored on rt_sigreturn) and block SIGALRM to avoid
+ *   time-based scheduling. The intended counter measure is for the monitor
+ *   to check that the process reports SIGALRM back in a timely fashion; that
+ *   is not yet implemented.
+ * - The permitted location of each syscall the stub does issue must be
+ *   pinned down in the SECCOMP filter, and more care is needed around a
+ *   prepared stack (or the stack being modified from another thread should
+ *   SMP support be added).
  */
-static __always_inline int syscall_handler(int fd_map[STUB_MAX_FDS])
-{
-	struct stub_data *d = get_stub_data();
-	int i;
-	unsigned long res;
-	int fd;
-
-	for (i = 0; i < d->syscall_data_len; i++) {
-		struct stub_syscall *sc = &d->syscall_data[i];
-
-		switch (sc->syscall) {
-		case STUB_SYSCALL_MMAP:
-			if (fd_map)
-				fd = fd_map[sc->mem.fd];
-			else
-				fd = sc->mem.fd;
-
-			res = stub_syscall6(STUB_MMAP_NR,
-					    sc->mem.addr, sc->mem.length,
-					    sc->mem.prot,
-					    MAP_SHARED | MAP_FIXED,
-					    fd, sc->mem.offset);
-			if (res != sc->mem.addr) {
-				d->err = res;
-				d->syscall_data_len = i;
-				return -1;
-			}
-			break;
-		case STUB_SYSCALL_MUNMAP:
-			res = stub_syscall2(__NR_munmap,
-					    sc->mem.addr, sc->mem.length);
-			if (res) {
-				d->err = res;
-				d->syscall_data_len = i;
-				return -1;
-			}
-			break;
-		default:
-			d->err = -95; /* EOPNOTSUPP */
-			d->syscall_data_len = i;
-			return -1;
-		}
-	}
-
-	d->err = 0;
-	d->syscall_data_len = 0;
-
-	return 0;
-}
-
-void __section(".__syscall_stub")
-stub_syscall_handler(void)
-{
-	syscall_handler(NULL);
-
-	trap_myself();
-}
 
 void __section(".__syscall_stub")
 stub_signal_interrupt(int sig, siginfo_t *info, void *p)
 {
 	struct stub_data *d = get_stub_data();
-	char rcv_data;
-	union {
-		char data[CMSG_SPACE(sizeof(int) * STUB_MAX_FDS)];
-		struct cmsghdr align;
-	} ctrl = {};
-	struct iovec iov = {
-		.iov_base = &rcv_data,
-		.iov_len = 1,
-	};
-	struct msghdr msghdr = {
-		.msg_iov = &iov,
-		.msg_iovlen = 1,
-		.msg_control = &ctrl,
-		.msg_controllen = sizeof(ctrl),
-	};
 	ucontext_t *uc = p;
-	struct cmsghdr *fd_msg;
-	int *fd_map;
-	int num_fds;
 	long res;
 
 	d->signal = sig;
 	d->si_offset = (unsigned long)info - (unsigned long)&d->sigstack[0];
 	d->mctx_offset = (unsigned long)&uc->uc_mcontext - (unsigned long)&d->sigstack[0];
 
-restart_wait:
+	/*
+	 * Hand the guest trap to the monitor and block until it resumes us:
+	 * wake the monitor (FUTEX_WAKE) and FUTEX_WAIT until it is done. In
+	 * seccomp mode the monitor installs any address-space changes itself
+	 * via pidfd_mmap(), so the stub no longer executes syscalls on its
+	 * behalf and never receives an fd.
+	 */
 	d->futex = FUTEX_IN_KERN;
 	do {
 		res = stub_syscall3(__NR_futex, (unsigned long)&d->futex,
@@ -133,40 +60,6 @@ stub_signal_interrupt(int sig, siginfo_t *info, void *p)
 	if (res < 0 && res != -EAGAIN)
 		stub_syscall1(__NR_exit_group, 1);
 
-	if (d->syscall_data_len) {
-		/* Read passed FDs (if any) */
-		do {
-			res = stub_syscall3(__NR_recvmsg, 0, (unsigned long)&msghdr, 0);
-		} while (res == -EINTR);
-
-		/* We should never have a receive error (other than -EAGAIN) */
-		if (res < 0 && res != -EAGAIN)
-			stub_syscall1(__NR_exit_group, 1);
-
-		/* Receive the FDs */
-		num_fds = 0;
-		fd_msg = msghdr.msg_control;
-		fd_map = (void *)CMSG_DATA(fd_msg);
-		if (res == iov.iov_len && msghdr.msg_controllen > sizeof(struct cmsghdr))
-			num_fds = (fd_msg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-
-		/* Try running queued syscalls. */
-		res = syscall_handler(fd_map);
-
-		while (num_fds)
-			stub_syscall2(__NR_close, fd_map[--num_fds], 0);
-	} else {
-		res = 0;
-	}
-
-	if (res < 0 || d->restart_wait) {
-		/* Report SIGSYS if we restart. */
-		d->signal = SIGSYS;
-		d->restart_wait = 0;
-
-		goto restart_wait;
-	}
-
 	/* Restore arch dependent state that is not part of the mcontext */
 	stub_seccomp_restore_state(&d->arch_data);
 
diff --git a/arch/um/kernel/skas/stub_exe.c b/arch/um/kernel/skas/stub_exe.c
index a88274449168..af1d011be0a4 100644
--- a/arch/um/kernel/skas/stub_exe.c
+++ b/arch/um/kernel/skas/stub_exe.c
@@ -166,15 +166,13 @@ noinline static void real_init(void)
 				 offsetof(struct seccomp_data, nr)),
 
 			/*
-			 * [10-14] Check against permitted syscalls. mmap and
-			 * munmap are deliberately absent: in seccomp mode the
-			 * monitor installs all guest mappings via pidfd_mmap(),
-			 * so a stub that attempts mmap/munmap hits the KILL at
-			 * [15].
+			 * [10-13] Check against permitted syscalls. mmap, munmap
+			 * and recvmsg are deliberately absent: in seccomp mode
+			 * the monitor installs all guest mappings via
+			 * pidfd_mmap() and no longer passes fds to the stub, so a
+			 * stub that attempts mmap/munmap hits the KILL at [14].
 			 */
 			BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_futex,
-				 5, 0),
-			BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_recvmsg,
 				 4, 0),
 			BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_close,
 				 3, 0),
@@ -188,10 +186,10 @@ noinline static void real_init(void)
 			BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_rt_sigreturn,
 				 1, 0),
 
-			/* [15] Not one of the permitted syscalls */
+			/* [14] Not one of the permitted syscalls */
 			BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
 
-			/* [16] Permitted call for the stub */
+			/* [15] Permitted call for the stub */
 			BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
 		};
 		struct sock_fprog prog = {
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index f751a1ea1c4c..9330f97f8beb 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -22,287 +22,34 @@
 #include <sysdep/stub.h>
 #include "../internal.h"
 
-extern char __syscall_stub_start[];
-
-void syscall_stub_dump_error(struct mm_id *mm_idp)
-{
-	struct stub_data *proc_data = (void *)mm_idp->stack;
-	struct stub_syscall *sc;
-
-	if (proc_data->syscall_data_len < 0 ||
-	    proc_data->syscall_data_len >= ARRAY_SIZE(proc_data->syscall_data))
-		panic("Syscall data was corrupted by stub (len is: %d, expected maximum: %d)!",
-			proc_data->syscall_data_len,
-			mm_idp->syscall_data_len);
-
-	sc = &proc_data->syscall_data[proc_data->syscall_data_len];
-
-	printk(UM_KERN_ERR "%s : length = %d, last offset = %d",
-		__func__, mm_idp->syscall_data_len,
-		proc_data->syscall_data_len);
-	printk(UM_KERN_ERR "%s : stub syscall type %d failed, return value = 0x%lx\n",
-		__func__, sc->syscall, proc_data->err);
-
-	print_hex_dump(UM_KERN_ERR, "    syscall data: ", 0,
-		       16, 4, sc, sizeof(*sc), 0);
-
-	if (using_seccomp) {
-		printk(UM_KERN_ERR "%s: FD map num: %d", __func__,
-		       mm_idp->syscall_fd_num);
-		print_hex_dump(UM_KERN_ERR,
-				"    FD map: ", 0, 16,
-				sizeof(mm_idp->syscall_fd_map[0]),
-				mm_idp->syscall_fd_map,
-				sizeof(mm_idp->syscall_fd_map), 0);
-	}
-}
-
-static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
-					      unsigned long *stack)
-{
-	if (stack == NULL) {
-		stack = (unsigned long *) mm_idp->stack + 2;
-		*stack = 0;
-	}
-	return stack;
-}
-
-static unsigned long syscall_regs[MAX_REG_NR];
-
-static int __init init_syscall_regs(void)
-{
-	get_safe_registers(syscall_regs, NULL);
-
-	syscall_regs[REGS_IP_INDEX] = STUB_CODE +
-		((unsigned long) stub_syscall_handler -
-		 (unsigned long) __syscall_stub_start);
-	syscall_regs[REGS_SP_INDEX] = STUB_DATA +
-		offsetof(struct stub_data, sigstack) +
-		sizeof(((struct stub_data *) 0)->sigstack) -
-		sizeof(void *);
-
-	return 0;
-}
-
-__initcall(init_syscall_regs);
-
-static inline long do_syscall_stub(struct mm_id *mm_idp)
-{
-	struct stub_data *proc_data = (void *)mm_idp->stack;
-	int n, i;
-	int err, pid = mm_idp->pid;
-
-	/* Inform process how much we have filled in. */
-	proc_data->syscall_data_len = mm_idp->syscall_data_len;
-
-	if (using_seccomp) {
-		proc_data->restart_wait = 1;
-		wait_stub_done_seccomp(mm_idp, 0, 1);
-	} else {
-		n = ptrace_setregs(pid, syscall_regs);
-		if (n < 0) {
-			printk(UM_KERN_ERR "Registers -\n");
-			for (i = 0; i < MAX_REG_NR; i++)
-				printk(UM_KERN_ERR "\t%d\t0x%lx\n", i, syscall_regs[i]);
-			panic("%s : PTRACE_SETREGS failed, errno = %d\n",
-			      __func__, -n);
-		}
-
-		err = ptrace(PTRACE_CONT, pid, 0, 0);
-		if (err)
-			panic("Failed to continue stub, pid = %d, errno = %d\n",
-			      pid, errno);
-
-		wait_stub_done(pid);
-	}
-
-	/*
-	 * proc_data->err will be negative if there was an (unexpected) error.
-	 * In that case, syscall_data_len points to the last executed syscall,
-	 * otherwise it will be zero (but we do not need to rely on that).
-	 */
-	if (proc_data->err < 0) {
-		syscall_stub_dump_error(mm_idp);
-
-		/* Store error code in case someone tries to add more syscalls */
-		mm_idp->syscall_data_len = proc_data->err;
-	} else {
-		mm_idp->syscall_data_len = 0;
-	}
-
-	if (using_seccomp)
-		mm_idp->syscall_fd_num = 0;
-
-	return mm_idp->syscall_data_len;
-}
-
-int syscall_stub_flush(struct mm_id *mm_idp)
-{
-	int res;
-
-	if (mm_idp->syscall_data_len == 0)
-		return 0;
-
-	/* If an error happened already, report it and reset the state. */
-	if (mm_idp->syscall_data_len < 0) {
-		res = mm_idp->syscall_data_len;
-		mm_idp->syscall_data_len = 0;
-		return res;
-	}
-
-	res = do_syscall_stub(mm_idp);
-	mm_idp->syscall_data_len = 0;
-
-	return res;
-}
-
-struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp)
-{
-	struct stub_syscall *sc;
-	struct stub_data *proc_data = (struct stub_data *) mm_idp->stack;
-
-	if (mm_idp->syscall_data_len > 0 &&
-	    mm_idp->syscall_data_len == ARRAY_SIZE(proc_data->syscall_data))
-		do_syscall_stub(mm_idp);
-
-	if (mm_idp->syscall_data_len < 0) {
-		/* Return dummy to retain error state. */
-		sc = &proc_data->syscall_data[0];
-	} else {
-		sc = &proc_data->syscall_data[mm_idp->syscall_data_len];
-		mm_idp->syscall_data_len += 1;
-	}
-	memset(sc, 0, sizeof(*sc));
-
-	return sc;
-}
-
-static struct stub_syscall *syscall_stub_get_previous(struct mm_id *mm_idp,
-						      int syscall_type,
-						      unsigned long virt)
-{
-	if (mm_idp->syscall_data_len > 0) {
-		struct stub_data *proc_data = (void *) mm_idp->stack;
-		struct stub_syscall *sc;
-
-		sc = &proc_data->syscall_data[mm_idp->syscall_data_len - 1];
-
-		if (sc->syscall == syscall_type &&
-		    sc->mem.addr + sc->mem.length == virt)
-			return sc;
-	}
-
-	return NULL;
-}
-
-static int get_stub_fd(struct mm_id *mm_idp, int fd)
-{
-	int i;
-
-	/* Find an FD slot (or flush and use first) */
-	if (!using_seccomp)
-		return fd;
-
-	/* Already crashed, value does not matter */
-	if (mm_idp->syscall_data_len < 0)
-		return 0;
-
-	/* Find existing FD in map if we can allocate another syscall */
-	if (mm_idp->syscall_data_len <
-	    ARRAY_SIZE(((struct stub_data *)NULL)->syscall_data)) {
-		for (i = 0; i < mm_idp->syscall_fd_num; i++) {
-			if (mm_idp->syscall_fd_map[i] == fd)
-				return i;
-		}
-
-		if (mm_idp->syscall_fd_num < STUB_MAX_FDS) {
-			i = mm_idp->syscall_fd_num;
-			mm_idp->syscall_fd_map[i] = fd;
-
-			mm_idp->syscall_fd_num++;
-
-			return i;
-		}
-	}
-
-	/* FD map full or no syscall space available, continue after flush */
-	do_syscall_stub(mm_idp);
-	mm_idp->syscall_fd_map[0] = fd;
-	mm_idp->syscall_fd_num = 1;
-
-	return 0;
-}
-
+/*
+ * Install (map) or remove (unmap) a guest mapping in the stub's address space.
+ * Both seccomp and ptrace modes now go through pidfd_mmap()/pidfd_munmap():
+ * the monitor resolves the physmem fd in its own fd table and installs the
+ * mapping into the stub's mm directly, so the stub never has to execute
+ * mmap/munmap itself. This makes the ptrace stub-syscall batcher unnecessary
+ * for memory management and shows the primitive works uniformly across modes.
+ */
 int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, int prot,
 	int phys_fd, unsigned long long offset)
 {
-	struct stub_syscall *sc;
-
-	if (using_seccomp) {
-		struct pidfd_mmap_args args = {
-			.size	= sizeof(args),
-			.addr	= virt,
-			.len	= len,
-			.prot	= prot,
-			.flags	= MAP_SHARED | MAP_FIXED,
-			.pgoff	= offset >> UM_KERN_PAGE_SHIFT,
-			.fd	= phys_fd,
-		};
-		long res = syscall(__NR_pidfd_mmap, mm_idp->stub_pidfd, &args, 0);
-
-		return res < 0 ? -errno : 0;
-	}
+	struct pidfd_mmap_args args = {
+		.size	= sizeof(args),
+		.addr	= virt,
+		.len	= len,
+		.prot	= prot,
+		.flags	= MAP_SHARED | MAP_FIXED,
+		.pgoff	= offset >> UM_KERN_PAGE_SHIFT,
+		.fd	= phys_fd,
+	};
+	long res = syscall(__NR_pidfd_mmap, mm_idp->stub_pidfd, &args, 0);
 
-	/* Compress with previous syscall if that is possible */
-	sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MMAP, virt);
-	if (sc && sc->mem.prot == prot &&
-	    sc->mem.offset == MMAP_OFFSET(offset - sc->mem.length)) {
-		int prev_fd = sc->mem.fd;
-
-		if (using_seccomp)
-			prev_fd = mm_idp->syscall_fd_map[sc->mem.fd];
-
-		if (phys_fd == prev_fd) {
-			sc->mem.length += len;
-			return 0;
-		}
-	}
-
-	phys_fd = get_stub_fd(mm_idp, phys_fd);
-
-	sc = syscall_stub_alloc(mm_idp);
-	sc->syscall = STUB_SYSCALL_MMAP;
-	sc->mem.addr = virt;
-	sc->mem.length = len;
-	sc->mem.prot = prot;
-	sc->mem.fd = phys_fd;
-	sc->mem.offset = MMAP_OFFSET(offset);
-
-	return 0;
+	return res < 0 ? -errno : 0;
 }
 
 int unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len)
 {
-	struct stub_syscall *sc;
-
-	if (using_seccomp) {
-		long res = syscall(__NR_pidfd_munmap, mm_idp->stub_pidfd,
-				   addr, len);
-
-		return res < 0 ? -errno : 0;
-	}
-
-	/* Compress with previous syscall if that is possible */
-	sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MUNMAP, addr);
-	if (sc) {
-		sc->mem.length += len;
-		return 0;
-	}
-
-	sc = syscall_stub_alloc(mm_idp);
-	sc->syscall = STUB_SYSCALL_MUNMAP;
-	sc->mem.addr = addr;
-	sc->mem.length = len;
+	long res = syscall(__NR_pidfd_munmap, mm_idp->stub_pidfd, addr, len);
 
-	return 0;
+	return res < 0 ? -errno : 0;
 }
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 3dd97ca7999a..cd6e40451576 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -157,39 +157,7 @@ void wait_stub_done_seccomp(struct mm_id *mm_idp, int running, int wait_sigsys)
 	int ret;
 
 	do {
-		const char byte = 0;
-		struct iovec iov = {
-			.iov_base = (void *)&byte,
-			.iov_len = sizeof(byte),
-		};
-		union {
-			char data[CMSG_SPACE(sizeof(mm_idp->syscall_fd_map))];
-			struct cmsghdr align;
-		} ctrl;
-		struct msghdr msgh = {
-			.msg_iov = &iov,
-			.msg_iovlen = 1,
-		};
-
 		if (!running) {
-			if (mm_idp->syscall_fd_num) {
-				unsigned int fds_size =
-					sizeof(int) * mm_idp->syscall_fd_num;
-				struct cmsghdr *cmsg;
-
-				msgh.msg_control = ctrl.data;
-				msgh.msg_controllen = CMSG_SPACE(fds_size);
-				cmsg = CMSG_FIRSTHDR(&msgh);
-				cmsg->cmsg_level = SOL_SOCKET;
-				cmsg->cmsg_type = SCM_RIGHTS;
-				cmsg->cmsg_len = CMSG_LEN(fds_size);
-				memcpy(CMSG_DATA(cmsg), mm_idp->syscall_fd_map,
-				       fds_size);
-
-				CATCH_EINTR(syscall(__NR_sendmsg, mm_idp->sock,
-						&msgh, 0));
-			}
-
 			data->signal = 0;
 			data->futex = FUTEX_IN_CHILD;
 			CATCH_EINTR(syscall(__NR_futex, &data->futex,
@@ -482,15 +450,13 @@ int start_userspace(struct mm_id *mm_id)
 		proc_data->futex = FUTEX_IN_CHILD;
 
 	/*
-	 * In SECCOMP mode, acquire a pidfd to the stub via CLONE_PIDFD (it is
-	 * returned through the legacy-clone parent_tid argument). The monitor
-	 * installs guest mappings into the stub's mm directly via pidfd_mmap(),
-	 * so the stub itself never needs the mmap capability. The ptrace mode
-	 * does not use it and drives the stub directly.
+	 * Acquire a pidfd to the stub via CLONE_PIDFD (it is returned through
+	 * the legacy-clone parent_tid argument). The monitor installs guest
+	 * mappings into the stub's mm directly via pidfd_mmap() in both seccomp
+	 * and ptrace modes, so it needs the pidfd regardless of mode.
 	 */
 	mm_id->pid = clone(userspace_tramp, (void *) sp,
-		    CLONE_VFORK | CLONE_VM | (using_seccomp ? CLONE_PIDFD : 0) |
-		    SIGCHLD,
+		    CLONE_VFORK | CLONE_VM | CLONE_PIDFD | SIGCHLD,
 		    (void *)&tramp_data, &stub_pidfd);
 	if (mm_id->pid < 0) {
 		err = -errno;
@@ -498,8 +464,7 @@ int start_userspace(struct mm_id *mm_id)
 		       __func__, errno);
 		goto out_close;
 	}
-	if (using_seccomp)
-		mm_id->stub_pidfd = stub_pidfd;
+	mm_id->stub_pidfd = stub_pidfd;
 
 	if (using_seccomp) {
 		wait_stub_done_seccomp(mm_id, 1, 1);
@@ -539,10 +504,7 @@ int start_userspace(struct mm_id *mm_id)
 	}
 
 	close(tramp_data.sockpair[0]);
-	if (using_seccomp)
-		mm_id->sock = tramp_data.sockpair[1];
-	else
-		close(tramp_data.sockpair[1]);
+	close(tramp_data.sockpair[1]);
 
 	return 0;
 
@@ -620,28 +582,15 @@ void userspace(struct uml_pt_regs *regs)
 				fatal_sigsegv();
 			}
 
-			/* Must have been reset by the syscall caller */
-			if (proc_data->restart_wait != 0)
-				panic("Programming error: Flag to only run syscalls in child was not cleared!");
-
-			/* Mark pending syscalls for flushing */
-			proc_data->syscall_data_len = mm_id->syscall_data_len;
-
+			/*
+			 * SECCOMP mode no longer batches stub syscalls (mmap is
+			 * installed by the monitor via pidfd_mmap()); this only
+			 * relays the guest trap to the monitor.
+			 */
 			wait_stub_done_seccomp(mm_id, 0, 0);
 
 			sig = proc_data->signal;
 
-			if (sig == SIGTRAP && proc_data->err != 0) {
-				printk(UM_KERN_ERR "%s - Error flushing stub syscalls",
-				       __func__);
-				syscall_stub_dump_error(mm_id);
-				mm_id->syscall_data_len = proc_data->err;
-				fatal_sigsegv();
-			}
-
-			mm_id->syscall_data_len = 0;
-			mm_id->syscall_fd_num = 0;
-
 			err = get_stub_state(regs, proc_data, NULL);
 			if (err) {
 				printk(UM_KERN_ERR "%s - failed to get regs: %d",
@@ -667,17 +616,6 @@ void userspace(struct uml_pt_regs *regs)
 		} else {
 			int pid = mm_id->pid;
 
-			/* Flush out any pending syscalls */
-			err = syscall_stub_flush(mm_id);
-			if (err) {
-				if (err == -ENOMEM)
-					report_enomem();
-
-				printk(UM_KERN_ERR "%s - Error flushing stub syscalls: %d",
-					__func__, -err);
-				fatal_sigsegv();
-			}
-
 			/*
 			 * This can legitimately fail if the process loads a
 			 * bogus value into a segment register.  It will
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index 054ac03bbf5e..518107622a2d 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -311,9 +311,11 @@ static bool __init init_seccomp(void)
 				      PROT_READ | PROT_WRITE,
 				      MAP_SHARED | MAP_ANON, 0, 0);
 
-	/* Use the syscall data area as stack, we just need something */
-	sp = (unsigned long)&seccomp_test_stub_data->syscall_data +
-	     sizeof(seccomp_test_stub_data->syscall_data) -
+	/*
+	 * We just need some valid stack; use the first page of the shared
+	 * stub_data region (sigstack occupies the following page).
+	 */
+	sp = (unsigned long)&seccomp_test_stub_data->sigstack[0] -
 	     sizeof(void *);
 	pid = clone(seccomp_helper, (void *)sp, CLONE_VFORK | CLONE_VM, NULL);
 
-- 
2.43.0


  parent reply	other threads:[~2026-07-10 20:54 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-10 20:53 [RFC PATCH 0/6] um: introduce pidfd_mmap()/pidfd_munmap() syscalls Cong Wang
2026-07-10 20:53 ` [RFC PATCH 1/6] pidfd: add " Cong Wang
2026-07-10 20:53 ` [RFC PATCH 2/6] um: acquire a stub pidfd via CLONE_PIDFD in seccomp mode Cong Wang
2026-07-10 20:53 ` [RFC PATCH 3/6] um: install guest mappings via pidfd_mmap() " Cong Wang
2026-07-10 20:53 ` [RFC PATCH 4/6] um: forbid mmap/munmap in the stub seccomp filter Cong Wang
2026-07-10 20:53 ` Cong Wang [this message]
2026-07-10 20:53 ` [RFC PATCH 6/6] selftests/pidfd: add pidfd_mmap()/pidfd_munmap() tests Cong Wang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260710205324.1343217-6-xiyou.wangcong@gmail.com \
    --to=xiyou.wangcong@gmail.com \
    --cc=anton.ivanov@cambridgegreys.com \
    --cc=benjamin@sipsolutions.net \
    --cc=cwang@multikernel.io \
    --cc=johannes@sipsolutions.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-um@lists.infradead.org \
    --cc=richard@nod.at \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox