diff options
| author | Gregory Price <gourry@gourry.net> | 2026-07-06 10:00:19 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@kernel.org> | 2026-07-08 10:22:00 +0200 |
| commit | 5b6e32ba7b5967a2787fafaa9f4740c590e1e00b (patch) | |
| tree | 24570f6c14d6369e9355911d3db0d3d9b43c2f81 /kernel/entry | |
| parent | ee935e8dc757614006ac29a7d98a15882cdcaeb2 (diff) | |
syscall_user_dispatch: Add kernel.syscall_user_dispatch sysctl
Add a matching sysctl to go with CONFIG_SYSCALL_USER_DISPATCH.
kernel.syscall_user_dispatch (default 1 - allow) controls whether
userspace may arm syscall user dispatch (both via prctl and ptrace).
Disarming is always permitted - same semantics as comparable knobs.
Disabling while a task has armed syscall user dispatch does not
cause it to become inactive - instead it remains active until the
user attempts to disable/re-enable via prctl or ptrace. On the
next attempt to re-enable, the prctl/ptrace call fails gracefully.
The alternative would cause programs translating non-linux syscalls
to interpret those syscalls as linux syscalls, resulting in undefined
userland behavior.
Signed-off-by: Gregory Price <gourry@gourry.net>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260706140020.873735-3-gourry@gourry.net
Diffstat (limited to 'kernel/entry')
| -rw-r--r-- | kernel/entry/syscall_user_dispatch.c | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/kernel/entry/syscall_user_dispatch.c b/kernel/entry/syscall_user_dispatch.c index d89dffcc2d64..2002c7aae435 100644 --- a/kernel/entry/syscall_user_dispatch.c +++ b/kernel/entry/syscall_user_dispatch.c @@ -2,21 +2,22 @@ /* * Copyright (C) 2020 Collabora Ltd. */ - +#include <linux/elf.h> #include <linux/entry-common.h> -#include <linux/sched.h> #include <linux/prctl.h> #include <linux/ptrace.h> -#include <linux/syscall_user_dispatch.h> -#include <linux/uaccess.h> -#include <linux/signal.h> -#include <linux/elf.h> - +#include <linux/sched.h> #include <linux/sched/signal.h> #include <linux/sched/task_stack.h> +#include <linux/signal.h> +#include <linux/syscall_user_dispatch.h> +#include <linux/sysctl.h> +#include <linux/uaccess.h> #include <asm/syscall.h> +static bool syscall_user_dispatch_allowed __read_mostly = true; + static void trigger_sigsys(struct pt_regs *regs) { struct kernel_siginfo info; @@ -102,6 +103,10 @@ static int task_set_syscall_user_dispatch(struct task_struct *task, unsigned lon return -EINVAL; } + /* Arming can be denied at runtime via sysctl, disarming is allowed */ + if (mode != PR_SYS_DISPATCH_OFF && !syscall_user_dispatch_allowed) + return -EPERM; + /* * access_ok() will clear memory tags for tagged addresses * if current has memory tagging enabled. @@ -172,3 +177,22 @@ int syscall_user_dispatch_set_config(struct task_struct *task, unsigned long siz return task_set_syscall_user_dispatch(task, cfg.mode, cfg.offset, cfg.len, (char __user *)(uintptr_t)cfg.selector); } + +#ifdef CONFIG_PROC_SYSCTL +static const struct ctl_table syscall_user_dispatch_sysctls[] = { + { + .procname = "syscall_user_dispatch", + .data = &syscall_user_dispatch_allowed, + .maxlen = sizeof(syscall_user_dispatch_allowed), + .mode = 0644, + .proc_handler = proc_dobool, + }, +}; + +static int __init syscall_user_dispatch_sysctl_init(void) +{ + register_sysctl_init("kernel", syscall_user_dispatch_sysctls); + return 0; +} +late_initcall(syscall_user_dispatch_sysctl_init); +#endif /* CONFIG_PROC_SYSCTL */ |
