From 68d4b311270ecca80bbb887a5e502e2caacebc98 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Tue, 14 Jul 2026 19:59:17 +0300 Subject: [PATCH] kern: add p_canopen() The function defines the policy for allowing to open a pid. Reviewed by: markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D58989 --- sys/kern/kern_prot.c | 28 ++++++++++++++++++++++++++-- sys/kern/sys_process.c | 5 +++++ sys/sys/proc.h | 1 + sys/sys/ptrace.h | 1 + 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 5aa7fcf7c653..5370028f4490 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -46,14 +46,13 @@ * System calls related to processes and protection */ -#include #include "opt_inet.h" #include "opt_inet6.h" -#include #include #include #include +#include #include #include #include @@ -2313,6 +2312,31 @@ cr_xids_subset(struct ucred *active_cred, struct ucred *obj_cred) return (uidsubset && grpsubset); } +/* + * Determine whether the td thread allowed to do pdopenpid(2) on the + * process p. The permissions are scoped to the PIDs namespace and + * processes hierarchy, and do not imply permissions to perform + * operations on the resulting process descriptor, e.g. pdkill(2) and + * other. + */ +int +p_canopen(struct thread *td, struct proc *p) +{ +#ifdef INVARIANTS + if (IN_CAPABILITY_MODE(td)) + sx_assert(&proctree_lock, SX_LOCKED); +#endif + + /* + * Allow implicit parent in cap mode: either real parent or + * debugger can open pid. + */ + if (!IN_CAPABILITY_MODE(td) || (allow_ptrace_in_cap_mode && + (td->td_proc == p->p_pptr || p->p_oppid == td->td_proc->p_pid))) + return (0); + return (ECAPMODE); +} + /*- * Determine whether td may debug p. * Returns: 0 for permitted, an errno value otherwise diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 2cf9ffaa68dd..35aa376fb6f5 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -70,6 +70,11 @@ #include #endif +bool allow_ptrace_in_cap_mode = true; +SYSCTL_BOOL(_security_bsd, OID_AUTO, allow_ptrace_in_cap_mode, CTLFLAG_RWTUN, + &allow_ptrace_in_cap_mode, 0, + "Allow ptrace(2) in capability mode"); + /* Assert it's safe to unlock a process, e.g. to allocate working memory */ #define PROC_ASSERT_TRACEREQ(p) MPASS(((p)->p_flag2 & P2_PTRACEREQ) != 0) diff --git a/sys/sys/proc.h b/sys/sys/proc.h index c052540cece5..a10bcfb9d910 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1195,6 +1195,7 @@ int leavepgrp(struct proc *p); void maybe_yield(void); void mi_switch(int flags); int p_candebug(struct thread *td, struct proc *p); +int p_canopen(struct thread *td, struct proc *p); int p_cansee(struct thread *td, struct proc *p); int p_cansched(struct thread *td, struct proc *p); int p_cansignal(struct thread *td, struct proc *p, int signum); diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index 1e219b606dbd..d6e071285eac 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -296,6 +296,7 @@ int ptrace_action(struct thread *td, int req, bool pd_mode, pid_t pid, int pfd, lwpid_t lwpid, void *addr, int data); extern bool allow_ptrace; +extern bool allow_ptrace_in_cap_mode; #else /* !_KERNEL */