From 7006cb7bd22d07d2ce30b0fb7ebfe58771b2a32f Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Wed, 8 Jul 2026 02:46:56 +0300 Subject: [PATCH] pdptrace(2): allow debugging in capability mode The pdopenpid(2) syscall is allowed in capability mode. Add the chicken switch security.bsd.ptrace_in_cap_mode, which disables it without reboot, if needed. The descriptor passed to pdptrace(2) must have the CAP_PTRACE capability enabled. This capability is not enabled by default by pdfork()/pdopenpid(), and the calls do not return a procdesc suitable for debugging. The opening code must prepare for debugging in advance by passing the PD_PTRACE_CAP flag to pdfork()/pdopenpid(). For ptrace(2), allow PT_CLEARSTEP and PT_GET_CHILDREN for the current thread and process in cap mode as well. Reviewed by: markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D58989 --- sys/compat/freebsd32/freebsd32_misc.c | 3 --- sys/kern/sys_process.c | 26 ++++++++++++++++++++++---- sys/kern/syscalls.master | 4 ++-- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 4da3b4ee97c1..bb4548660278 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -1050,9 +1050,6 @@ freebsd32_ptrace_useraction(struct thread *td, int req, bool pd_mode, pid_t pid, void *addr; int data, error, i; - if (!allow_ptrace) - return (ENOSYS); - error = 0; addr = &r; data = udata; diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 35aa376fb6f5..5c8f32773412 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -708,6 +709,24 @@ ptrace_vm_entry(struct thread *td, struct proc *p, struct ptrace_vm_entry *pve) return (error); } +static int +ptrace_check_allowed(struct thread *td, int req, bool pd_mode, pid_t pid) +{ + if (!allow_ptrace) + return (ENOSYS); + if (!IN_CAPABILITY_MODE(td)) + return (0); + if (!allow_ptrace_in_cap_mode) + return (ECAPMODE); + if (pd_mode) + return (0); + if (req == PT_GET_CHILDREN && pid == td->td_proc->p_pid) + return (0); + if (req == PT_CLEARSTEP && pid == td->td_tid) + return (0); + return (ECAPMODE); +} + /* * Process debugging system call. */ @@ -748,12 +767,11 @@ ptrace_useraction(struct thread *td, int req, bool pd_mode, pid_t pid, int pfd, void *addr; int error, data; - if (!allow_ptrace) - return (ENOSYS); + error = ptrace_check_allowed(td, req, pd_mode, pid); + if (error != 0) + return (error); - error = 0; addr = &r; - switch (req) { case PT_GET_EVENT_MASK: case PT_LWPINFO: diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 7050e564903e..656c73da348f 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -264,7 +264,7 @@ 25 AUE_GETEUID STD|CAPENABLED { uid_t geteuid(void); } -26 AUE_PTRACE STD { +26 AUE_PTRACE STD|CAPENABLED { int ptrace( int req, pid_t pid, @@ -3442,7 +3442,7 @@ int flags ); } -605 AUE_PDPTRACE STD { +605 AUE_PDPTRACE STD|CAPENABLED { int pdptrace( int req, int pfd,