From ee935e8dc757614006ac29a7d98a15882cdcaeb2 Mon Sep 17 00:00:00 2001 From: Gregory Price Date: Mon, 6 Jul 2026 10:00:18 -0400 Subject: [PATCH] syscall_user_dispatch: Make it configurable in Kconfig Syscall User Dispatch is presently built under CONFIG_GENERIC_SYSCALL and cannot be disabled independently. Add CONFIG_SYSCALL_USER_DISPATCH to make it an optional feature. Signed-off-by: Gregory Price Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260706140020.873735-2-gourry@gourry.net --- arch/Kconfig | 10 +++++++ include/linux/entry-common.h | 6 ++-- include/linux/syscall_user_dispatch.h | 28 +++++++++++++++++-- include/linux/syscall_user_dispatch_types.h | 2 +- kernel/entry/Makefile | 3 +- .../selftests/syscall_user_dispatch/config | 2 +- 6 files changed, 42 insertions(+), 9 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index fa7507ac8e13..0c01521c2f3f 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -114,6 +114,16 @@ config GENERIC_ENTRY select GENERIC_IRQ_ENTRY select GENERIC_SYSCALL +config SYSCALL_USER_DISPATCH + bool "Syscall User Dispatch" + depends on GENERIC_ENTRY + default y + help + Syscall User Dispatch lets a thread have its own system calls + intercepted and redirected to a userspace signal handler based + on a prctl() configured instruction pointer range. + If unsure, say Y. + config KPROBES bool "Kprobes" depends on HAVE_KPROBES diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h index 416a3352261f..9336516430a1 100644 --- a/include/linux/entry-common.h +++ b/include/linux/entry-common.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -55,7 +56,6 @@ static __always_inline int arch_ptrace_report_syscall_entry(struct pt_regs *regs } #endif -bool syscall_user_dispatch(struct pt_regs *regs); long trace_syscall_enter(struct pt_regs *regs, long syscall); void trace_syscall_exit(struct pt_regs *regs, long ret); @@ -232,10 +232,8 @@ static __always_inline void syscall_exit_work(struct pt_regs *regs, unsigned lon * of these syscalls is unknown. */ if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) { - if (unlikely(current->syscall_dispatch.on_dispatch)) { - current->syscall_dispatch.on_dispatch = false; + if (syscall_user_dispatch_clear_on_dispatch()) return; - } } audit_syscall_exit(regs); diff --git a/include/linux/syscall_user_dispatch.h b/include/linux/syscall_user_dispatch.h index 3858a6ffdd5c..3dd30f4b2799 100644 --- a/include/linux/syscall_user_dispatch.h +++ b/include/linux/syscall_user_dispatch.h @@ -6,9 +6,23 @@ #define _SYSCALL_USER_DISPATCH_H #include +#include #include -#ifdef CONFIG_GENERIC_ENTRY +struct pt_regs; + +#ifdef CONFIG_SYSCALL_USER_DISPATCH + +bool syscall_user_dispatch(struct pt_regs *regs); + +static __always_inline bool syscall_user_dispatch_clear_on_dispatch(void) +{ + if (likely(!current->syscall_dispatch.on_dispatch)) + return false; + + current->syscall_dispatch.on_dispatch = false; + return true; +} int set_syscall_user_dispatch(unsigned long mode, unsigned long offset, unsigned long len, char __user *selector); @@ -24,6 +38,16 @@ int syscall_user_dispatch_set_config(struct task_struct *task, unsigned long siz #else +static __always_inline bool syscall_user_dispatch(struct pt_regs *regs) +{ + return false; +} + +static __always_inline bool syscall_user_dispatch_clear_on_dispatch(void) +{ + return false; +} + static inline int set_syscall_user_dispatch(unsigned long mode, unsigned long offset, unsigned long len, char __user *selector) { @@ -46,6 +70,6 @@ static inline int syscall_user_dispatch_set_config(struct task_struct *task, return -EINVAL; } -#endif /* CONFIG_GENERIC_ENTRY */ +#endif /* CONFIG_SYSCALL_USER_DISPATCH */ #endif /* _SYSCALL_USER_DISPATCH_H */ diff --git a/include/linux/syscall_user_dispatch_types.h b/include/linux/syscall_user_dispatch_types.h index 3be36b06c7d7..c0bdd4f760d3 100644 --- a/include/linux/syscall_user_dispatch_types.h +++ b/include/linux/syscall_user_dispatch_types.h @@ -4,7 +4,7 @@ #include -#ifdef CONFIG_GENERIC_ENTRY +#ifdef CONFIG_SYSCALL_USER_DISPATCH struct syscall_user_dispatch { char __user *selector; diff --git a/kernel/entry/Makefile b/kernel/entry/Makefile index 2333d70802e4..f220bae86b12 100644 --- a/kernel/entry/Makefile +++ b/kernel/entry/Makefile @@ -13,5 +13,6 @@ CFLAGS_REMOVE_common.o = -fstack-protector -fstack-protector-strong CFLAGS_common.o += -fno-stack-protector obj-$(CONFIG_GENERIC_IRQ_ENTRY) += common.o -obj-$(CONFIG_GENERIC_SYSCALL) += syscall-common.o syscall_user_dispatch.o +obj-$(CONFIG_GENERIC_SYSCALL) += syscall-common.o +obj-$(CONFIG_SYSCALL_USER_DISPATCH) += syscall_user_dispatch.o obj-$(CONFIG_VIRT_XFER_TO_GUEST_WORK) += virt.o diff --git a/tools/testing/selftests/syscall_user_dispatch/config b/tools/testing/selftests/syscall_user_dispatch/config index 039e303e59d7..22c4dfe167ca 100644 --- a/tools/testing/selftests/syscall_user_dispatch/config +++ b/tools/testing/selftests/syscall_user_dispatch/config @@ -1 +1 @@ -CONFIG_GENERIC_ENTRY=y +CONFIG_SYSCALL_USER_DISPATCH=y