Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F168389260
D58694.id183539.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D58694.id183539.diff
View Options
diff --git a/lib/libsys/procctl.2 b/lib/libsys/procctl.2
--- a/lib/libsys/procctl.2
+++ b/lib/libsys/procctl.2
@@ -27,7 +27,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 21, 2025
+.Dd August 6, 2026
.Dt PROCCTL 2
.Os
.Sh NAME
@@ -65,8 +65,22 @@
.It Dv P_PGID
Control processes belonging to the process group with the ID
.Fa id .
+.It Dv P_PROCDESC
+Control the process referenced by the process descriptor
+.Fa id .
+The descriptor is required to have the
+.Dv CAP_PROCCTL
+right.
.El
.Pp
+Unlike the other identifier types, which name processes by numbers in a
+global namespace,
+.Dv P_PROCDESC
+names a process by a descriptor the caller already holds.
+It is therefore the only identifier type accepted in capability mode;
+see
+.Xr cap_enter 2 .
+.Pp
The control request to perform is specified by the
.Fa cmd
argument.
@@ -857,11 +871,39 @@
.It Bq Er EPERM
The calling process does not have permission to perform the requested
operation on any of the selected processes.
+.It Bq Er ECAPMODE
+The calling process is in capability mode and the
+.Fa idtype
+argument is not
+.Dv P_PROCDESC .
+.It Bq Er EBADF
+The
+.Fa idtype
+argument is
+.Dv P_PROCDESC
+and
+.Fa id
+is not a valid descriptor, or is a descriptor of a type other than a
+process descriptor.
+.It Bq Er ENOTCAPABLE
+The
+.Fa idtype
+argument is
+.Dv P_PROCDESC
+and
+.Fa id
+lacks the
+.Dv CAP_PROCCTL
+right.
.It Bq Er ESRCH
No processes matched the requested
.Fa idtype
and
.Fa id .
+A
+.Dv P_PROCDESC
+descriptor also stops matching once the process it referenced has exited and
+been reaped.
.It Bq Er ESRCH
No descendant processes can be found matching criteria specified in the
.Dv PROC_REAP_KILL
@@ -944,6 +986,7 @@
.Xr ktrace 2 ,
.Xr mmap 2 ,
.Xr mprotect 2 ,
+.Xr pdfork 2 ,
.Xr ptrace 2 ,
.Xr wait 2 ,
.Xr capsicum 4 ,
diff --git a/share/man/man4/rights.4 b/share/man/man4/rights.4
--- a/share/man/man4/rights.4
+++ b/share/man/man4/rights.4
@@ -30,7 +30,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 22, 2025
+.Dd August 6, 2026
.Dt RIGHTS 4
.Os
.Sh NAME
@@ -490,6 +490,13 @@
.It Dv CAP_PEELOFF
Permit
.Xr sctp_peeloff 2 .
+.It Dv CAP_PROCCTL
+Permit
+.Xr procctl 2
+with an
+.Fa idtype
+of
+.Dv P_PROCDESC .
.It Dv CAP_PREAD
An alias to
.Dv CAP_READ
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
--- a/sys/compat/freebsd32/freebsd32_sysent.c
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -611,7 +611,7 @@
{ .sy_narg = AS(accept4_args), .sy_call = (sy_call_t *)sys_accept4, .sy_auevent = AUE_ACCEPT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 541 = accept4 */
{ .sy_narg = AS(pipe2_args), .sy_call = (sy_call_t *)sys_pipe2, .sy_auevent = AUE_PIPE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 542 = pipe2 */
{ .sy_narg = AS(freebsd32_aio_mlock_args), .sy_call = (sy_call_t *)freebsd32_aio_mlock, .sy_auevent = AUE_AIO_MLOCK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 543 = freebsd32_aio_mlock */
- { .sy_narg = AS(freebsd32_procctl_args), .sy_call = (sy_call_t *)freebsd32_procctl, .sy_auevent = AUE_PROCCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 544 = freebsd32_procctl */
+ { .sy_narg = AS(freebsd32_procctl_args), .sy_call = (sy_call_t *)freebsd32_procctl, .sy_auevent = AUE_PROCCTL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 544 = freebsd32_procctl */
{ .sy_narg = AS(freebsd32_ppoll_args), .sy_call = (sy_call_t *)freebsd32_ppoll, .sy_auevent = AUE_POLL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 545 = freebsd32_ppoll */
{ .sy_narg = AS(freebsd32_futimens_args), .sy_call = (sy_call_t *)freebsd32_futimens, .sy_auevent = AUE_FUTIMES, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 546 = freebsd32_futimens */
{ .sy_narg = AS(freebsd32_utimensat_args), .sy_call = (sy_call_t *)freebsd32_utimensat, .sy_auevent = AUE_FUTIMESAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 547 = freebsd32_utimensat */
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -610,7 +610,7 @@
{ .sy_narg = AS(accept4_args), .sy_call = (sy_call_t *)sys_accept4, .sy_auevent = AUE_ACCEPT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 541 = accept4 */
{ .sy_narg = AS(pipe2_args), .sy_call = (sy_call_t *)sys_pipe2, .sy_auevent = AUE_PIPE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 542 = pipe2 */
{ .sy_narg = AS(aio_mlock_args), .sy_call = (sy_call_t *)sys_aio_mlock, .sy_auevent = AUE_AIO_MLOCK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 543 = aio_mlock */
- { .sy_narg = AS(procctl_args), .sy_call = (sy_call_t *)sys_procctl, .sy_auevent = AUE_PROCCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 544 = procctl */
+ { .sy_narg = AS(procctl_args), .sy_call = (sy_call_t *)sys_procctl, .sy_auevent = AUE_PROCCTL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 544 = procctl */
{ .sy_narg = AS(ppoll_args), .sy_call = (sy_call_t *)sys_ppoll, .sy_auevent = AUE_POLL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 545 = ppoll */
{ .sy_narg = AS(futimens_args), .sy_call = (sy_call_t *)sys_futimens, .sy_auevent = AUE_FUTIMES, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 546 = futimens */
{ .sy_narg = AS(utimensat_args), .sy_call = (sy_call_t *)sys_utimensat, .sy_auevent = AUE_FUTIMESAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 547 = utimensat */
diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c
--- a/sys/kern/kern_procctl.c
+++ b/sys/kern/kern_procctl.c
@@ -33,6 +33,9 @@
#include <sys/_unrhdr.h>
#include <sys/systm.h>
#include <sys/capsicum.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/procdesc.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mman.h>
@@ -1180,6 +1183,14 @@
const struct procctl_cmd_info *cmd_info;
int error, error1;
+ /*
+ * In capability mode only P_PROCDESC is available: the other identifier
+ * types name a process through a global namespace the sandbox is not
+ * supposed to be able to reach into.
+ */
+ if (IN_CAPABILITY_MODE(td) && uap->idtype != P_PROCDESC)
+ return (ECAPMODE);
+
if (uap->com >= PROC_PROCCTL_MD_MIN)
return (cpu_procctl(td, uap->idtype, uap->id,
uap->com, uap->data));
@@ -1221,6 +1232,29 @@
return (error);
}
+/*
+ * Common tail for the idtypes that name exactly one process: check that the
+ * caller may act on it, then run the command. Called with the process
+ * locked, and returns it unlocked.
+ *
+ * Callers acting on the calling process itself need no special case: both
+ * p_cansee() and p_candebug() return success immediately when the target is
+ * the caller's own process.
+ */
+static int
+kern_procctl_found(struct thread *td, struct proc *p,
+ const struct procctl_cmd_info *cmd_info, int com, void *data)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ error = cmd_info->need_candebug ? p_candebug(td, p) : p_cansee(td, p);
+ if (error == 0)
+ error = kern_procctl_single(td, p, com, data);
+ PROC_UNLOCK(p);
+ return (error);
+}
+
int
kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data)
{
@@ -1232,7 +1266,8 @@
MPASS(com > 0 && com < nitems(procctl_cmds_info));
cmd_info = &procctl_cmds_info[com];
- if (idtype != P_PID && cmd_info->one_proc)
+ /* P_PROCDESC, like P_PID, names exactly one process. */
+ if (idtype != P_PID && idtype != P_PROCDESC && cmd_info->one_proc)
return (EINVAL);
sapblk = false;
@@ -1257,7 +1292,6 @@
case P_PID:
if (id == 0) {
p = td->td_proc;
- error = 0;
PROC_LOCK(p);
} else {
p = pfind(id);
@@ -1266,13 +1300,41 @@
EINVAL : ESRCH;
break;
}
- error = cmd_info->need_candebug ? p_candebug(td, p) :
- p_cansee(td, p);
+ }
+ error = kern_procctl_found(td, p, cmd_info, com, data);
+ break;
+ case P_PROCDESC: {
+ /*
+ * Name the process by a descriptor rather than a pid, so that
+ * the operation stays available in capability mode.
+ *
+ * fget_procdesc() requires proctree_lock, which the command
+ * may already have taken, and returns the process locked. It
+ * hands back a reference on the file -- on some error paths as
+ * well as on success -- and that reference is what keeps the
+ * process from going away, so it is dropped only once the
+ * command has run. proctree_lock, in contrast, is needed only
+ * for the lookup itself.
+ */
+ struct file *fp;
+
+ {
+ bool slock;
+
+ slock = cmd_info->lock_tree == PCTL_UNLOCKED;
+ if (slock)
+ sx_slock(&proctree_lock);
+ error = fget_procdesc(td, (int)id,
+ &cap_procctl_rights, EBADF, &fp, NULL, &p);
+ if (slock)
+ sx_sunlock(&proctree_lock);
}
if (error == 0)
- error = kern_procctl_single(td, p, com, data);
- PROC_UNLOCK(p);
+ error = kern_procctl_found(td, p, cmd_info, com, data);
+ if (fp != NULL)
+ fdrop(fp, td);
break;
+ }
case P_PGID:
/*
* Attempt to apply the operation to all members of the
diff --git a/sys/kern/subr_capability.c b/sys/kern/subr_capability.c
--- a/sys/kern/subr_capability.c
+++ b/sys/kern/subr_capability.c
@@ -93,6 +93,7 @@
const cap_rights_t cap_pdkill_rights = CAP_RIGHTS_INITIALIZER(CAP_PDKILL);
const cap_rights_t cap_pdwait_rights = CAP_RIGHTS_INITIALIZER(CAP_PDWAIT);
const cap_rights_t cap_pread_rights = CAP_RIGHTS_INITIALIZER(CAP_PREAD);
+const cap_rights_t cap_procctl_rights = CAP_RIGHTS_INITIALIZER(CAP_PROCCTL);
const cap_rights_t cap_ptrace_rights = CAP_RIGHTS_INITIALIZER(CAP_PTRACE);
const cap_rights_t cap_pwrite_rights = CAP_RIGHTS_INITIALIZER(CAP_PWRITE);
const cap_rights_t cap_read_rights = CAP_RIGHTS_INITIALIZER(CAP_READ);
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3020,7 +3020,7 @@
_In_ _Contains_long_ptr_ struct aiocb *aiocbp
);
}
-544 AUE_PROCCTL STD {
+544 AUE_PROCCTL STD|CAPENABLED {
int procctl(
idtype_t idtype,
id_t id,
diff --git a/sys/sys/caprights.h b/sys/sys/caprights.h
--- a/sys/sys/caprights.h
+++ b/sys/sys/caprights.h
@@ -95,6 +95,7 @@
extern const cap_rights_t cap_pdkill_rights;
extern const cap_rights_t cap_pdwait_rights;
extern const cap_rights_t cap_pread_rights;
+extern const cap_rights_t cap_procctl_rights;
extern const cap_rights_t cap_ptrace_rights;
extern const cap_rights_t cap_pwrite_rights;
extern const cap_rights_t cap_read_rights;
diff --git a/sys/sys/capsicum.h b/sys/sys/capsicum.h
--- a/sys/sys/capsicum.h
+++ b/sys/sys/capsicum.h
@@ -301,8 +301,9 @@
/* Allows ptrace(PT_PROCDESC) */
#define CAP_PTRACE CAPRIGHT(1, 0x0000000001000000ULL)
+/* Allows procctl(P_PROCDESC) */
+#define CAP_PROCCTL CAPRIGHT(1, 0x0000000002000000ULL)
-#define CAP_UNUSED1_26 CAPRIGHT(1, 0x0000000002000000ULL)
#define CAP_UNUSED1_27 CAPRIGHT(1, 0x0000000004000000ULL)
#define CAP_UNUSED1_28 CAPRIGHT(1, 0x0000000008000000ULL)
#define CAP_UNUSED1_29 CAPRIGHT(1, 0x0000000010000000ULL)
@@ -336,7 +337,7 @@
#define CAP_UNUSED1_57 CAPRIGHT(1, 0x0100000000000000ULL)
/* All default bits for index 1. */
-#define CAP_ALL1 CAPRIGHT(1, 0x0000000001FFFFFFULL)
+#define CAP_ALL1 CAPRIGHT(1, 0x0000000003FFFFFFULL)
/* Backward compatibility. */
#define CAP_POLL_EVENT CAP_EVENT
diff --git a/sys/sys/wait.h b/sys/sys/wait.h
--- a/sys/sys/wait.h
+++ b/sys/sys/wait.h
@@ -118,7 +118,14 @@
P_JAILID, /* A zone identifier. */
P_CTID, /* A (process) contract identifier. */
P_CPUID, /* CPU identifier. */
- P_PSETID /* Processor set identifier. */
+ P_PSETID, /* Processor set identifier. */
+ /*
+ * A process descriptor. Unlike the identifiers above this names a
+ * process by a descriptor the caller holds rather than by a number
+ * in a global namespace, so it remains usable in capability mode.
+ * FreeBSD extension; beyond the range shared with Solaris.
+ */
+ P_PROCDESC
} idtype_t; /* The type of id_t we are using. */
#if __BSD_VISIBLE
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Aug 28, 11:03 PM (9 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37487059
Default Alt Text
D58694.id183539.diff (11 KB)
Attached To
Mode
D58694: procctl(2) addressed by process descriptor (P_PROCDESC)
Attached
Detach File
Event Timeline
Log In to Comment