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
next prev 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