Page MenuHomeFreeBSD

D58989.id185325.diff
No OneTemporary

D58989.id185325.diff

diff --git a/lib/libsys/pdfork.2 b/lib/libsys/pdfork.2
--- a/lib/libsys/pdfork.2
+++ b/lib/libsys/pdfork.2
@@ -176,6 +176,18 @@
.Er ESRCH
error.
.Pp
+The
+.Fn pdopenpid
+system call is allowed in the capability mode
+.Pq see Xr capsicum 4
+when the target process is the child of the calling process, or
+when the calling process is the debugger of the target process.
+The debugger is attached to its target by
+.Xr ptrace 2 ,
+.Xr pdptrace 2 ,
+or by other means, e.g., by debugging the target process' parent with
+the follow-on-fork mode enabled.
+.Pp
.Fn pdgetpid
queries the process ID (PID) in the process descriptor
.Fa fd .
@@ -454,6 +466,27 @@
refers to a file that cannot be duplicated across a process boundary,
such as a kqueue.
.El
+.Pp
+The
+.Fn pdptrace
+system call returns the same errors as
+.Xr ptrace 2 ,
+as well as the following specific errors:
+.Bl -tag -width Er
+.It Bq Er ECAPMODE
+The process issuing the
+.Fn pdptrace
+call is in capability mode,
+and the
+.Dv security.bsd.allow_ptrace_in_cap_mode
+tunable is set to
+.Dv false .
+.It Bq Er ENOTCAPABLE
+The process called
+.Fn pdptrace
+on the process descriptor that does not have the
+.Dv CAP_PTRACE
+capability enabled.
.Sh SEE ALSO
.Xr close 2 ,
.Xr fork 2 ,
diff --git a/lib/libsys/ptrace.2 b/lib/libsys/ptrace.2
--- a/lib/libsys/ptrace.2
+++ b/lib/libsys/ptrace.2
@@ -180,6 +180,12 @@
process'.
These requests will fail with error
.Er ESRCH .
+.It Dv security.bsd.allow_ptrace_in_cap_mode
+Setting this sysctl to true allows the
+.Fn ptrace
+requests issued by the processes in capability mode,
+see
+.Xr pdptrace 2 .
.It Dv securelevel and init
The
.Xr init 1
@@ -1522,6 +1528,10 @@
.Fa pve_pathlen
holds the minimum buffer size required on return.
.El
+.It Bq ECAPMODE
+The process issuing the
+.Fn ptrace
+call is in capability mode.
.El
.Sh SEE ALSO
.Xr execve 2 ,
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1050,9 +1050,6 @@
void *addr;
int data, error, i;
- if (!allow_ptrace)
- return (ENOSYS);
-
error = 0;
addr = &r;
data = udata;
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
@@ -93,7 +93,7 @@
{ .sy_narg = AS(setuid_args), .sy_call = (sy_call_t *)sys_setuid, .sy_auevent = AUE_SETUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 23 = setuid */
{ .sy_narg = 0, .sy_call = (sy_call_t *)sys_getuid, .sy_auevent = AUE_GETUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 24 = getuid */
{ .sy_narg = 0, .sy_call = (sy_call_t *)sys_geteuid, .sy_auevent = AUE_GETEUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 25 = geteuid */
- { .sy_narg = AS(freebsd32_ptrace_args), .sy_call = (sy_call_t *)freebsd32_ptrace, .sy_auevent = AUE_PTRACE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 26 = freebsd32_ptrace */
+ { .sy_narg = AS(freebsd32_ptrace_args), .sy_call = (sy_call_t *)freebsd32_ptrace, .sy_auevent = AUE_PTRACE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 26 = freebsd32_ptrace */
{ .sy_narg = AS(freebsd32_recvmsg_args), .sy_call = (sy_call_t *)freebsd32_recvmsg, .sy_auevent = AUE_RECVMSG, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 27 = freebsd32_recvmsg */
{ .sy_narg = AS(freebsd32_sendmsg_args), .sy_call = (sy_call_t *)freebsd32_sendmsg, .sy_auevent = AUE_SENDMSG, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 28 = freebsd32_sendmsg */
{ .sy_narg = AS(recvfrom_args), .sy_call = (sy_call_t *)sys_recvfrom, .sy_auevent = AUE_RECVFROM, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 29 = recvfrom */
@@ -670,7 +670,7 @@
{ .sy_narg = AS(pdrfork_args), .sy_call = (sy_call_t *)sys_pdrfork, .sy_auevent = AUE_PDRFORK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 600 = pdrfork */
{ .sy_narg = AS(freebsd32_pdwait_args), .sy_call = (sy_call_t *)freebsd32_pdwait, .sy_auevent = AUE_PDWAIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 601 = freebsd32_pdwait */
{ .sy_narg = AS(renameat2_args), .sy_call = (sy_call_t *)sys_renameat2, .sy_auevent = AUE_RENAMEAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 602 = renameat2 */
- { .sy_narg = AS(pdopenpid_args), .sy_call = (sy_call_t *)sys_pdopenpid, .sy_auevent = AUE_PDOPENPID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 603 = pdopenpid */
+ { .sy_narg = AS(pdopenpid_args), .sy_call = (sy_call_t *)sys_pdopenpid, .sy_auevent = AUE_PDOPENPID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 603 = pdopenpid */
{ .sy_narg = AS(pddupfd_args), .sy_call = (sy_call_t *)sys_pddupfd, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 604 = pddupfd */
- { .sy_narg = AS(freebsd32_pdptrace_args), .sy_call = (sy_call_t *)freebsd32_pdptrace, .sy_auevent = AUE_PDPTRACE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 605 = freebsd32_pdptrace */
+ { .sy_narg = AS(freebsd32_pdptrace_args), .sy_call = (sy_call_t *)freebsd32_pdptrace, .sy_auevent = AUE_PDPTRACE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 605 = freebsd32_pdptrace */
};
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
@@ -92,7 +92,7 @@
{ .sy_narg = AS(setuid_args), .sy_call = (sy_call_t *)sys_setuid, .sy_auevent = AUE_SETUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 23 = setuid */
{ .sy_narg = 0, .sy_call = (sy_call_t *)sys_getuid, .sy_auevent = AUE_GETUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 24 = getuid */
{ .sy_narg = 0, .sy_call = (sy_call_t *)sys_geteuid, .sy_auevent = AUE_GETEUID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 25 = geteuid */
- { .sy_narg = AS(ptrace_args), .sy_call = (sy_call_t *)sys_ptrace, .sy_auevent = AUE_PTRACE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 26 = ptrace */
+ { .sy_narg = AS(ptrace_args), .sy_call = (sy_call_t *)sys_ptrace, .sy_auevent = AUE_PTRACE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 26 = ptrace */
{ .sy_narg = AS(recvmsg_args), .sy_call = (sy_call_t *)sys_recvmsg, .sy_auevent = AUE_RECVMSG, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 27 = recvmsg */
{ .sy_narg = AS(sendmsg_args), .sy_call = (sy_call_t *)sys_sendmsg, .sy_auevent = AUE_SENDMSG, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 28 = sendmsg */
{ .sy_narg = AS(recvfrom_args), .sy_call = (sy_call_t *)sys_recvfrom, .sy_auevent = AUE_RECVFROM, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 29 = recvfrom */
@@ -669,7 +669,7 @@
{ .sy_narg = AS(pdrfork_args), .sy_call = (sy_call_t *)sys_pdrfork, .sy_auevent = AUE_PDRFORK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 600 = pdrfork */
{ .sy_narg = AS(pdwait_args), .sy_call = (sy_call_t *)sys_pdwait, .sy_auevent = AUE_PDWAIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 601 = pdwait */
{ .sy_narg = AS(renameat2_args), .sy_call = (sy_call_t *)sys_renameat2, .sy_auevent = AUE_RENAMEAT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 602 = renameat2 */
- { .sy_narg = AS(pdopenpid_args), .sy_call = (sy_call_t *)sys_pdopenpid, .sy_auevent = AUE_PDOPENPID, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 603 = pdopenpid */
+ { .sy_narg = AS(pdopenpid_args), .sy_call = (sy_call_t *)sys_pdopenpid, .sy_auevent = AUE_PDOPENPID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 603 = pdopenpid */
{ .sy_narg = AS(pddupfd_args), .sy_call = (sy_call_t *)sys_pddupfd, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 604 = pddupfd */
- { .sy_narg = AS(pdptrace_args), .sy_call = (sy_call_t *)sys_pdptrace, .sy_auevent = AUE_PDPTRACE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 605 = pdptrace */
+ { .sy_narg = AS(pdptrace_args), .sy_call = (sy_call_t *)sys_pdptrace, .sy_auevent = AUE_PDPTRACE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 605 = pdptrace */
};
diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -46,14 +46,13 @@
* System calls related to processes and protection
*/
-#include <sys/cdefs.h>
#include "opt_inet.h"
#include "opt_inet6.h"
-#include <sys/param.h>
#include <sys/systm.h>
#include <sys/abi_compat.h>
#include <sys/acct.h>
+#include <sys/capsicum.h>
#include <sys/imgact.h>
#include <sys/kdb.h>
#include <sys/kernel.h>
@@ -2313,6 +2312,31 @@
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 hierarhy, 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_procdesc.c b/sys/kern/sys_procdesc.c
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -665,6 +665,12 @@
PROC_UNLOCK(p);
return (EBUSY);
}
+ error = p_canopen(td, p);
+ if (error != 0) {
+ PROC_UNLOCK(p);
+ return (error);
+ }
+
pd = p->p_procdesc;
if (pd != NULL) {
MPASS((p->p_zombieref & PZOMBIEREF_PROCDESC) != 0);
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -51,6 +51,7 @@
#include <sys/sleepqueue.h>
#include <sys/sx.h>
#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/vnode.h>
@@ -70,6 +71,11 @@
#include <sys/procfs.h>
#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)
@@ -703,6 +709,24 @@
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.
*/
@@ -743,12 +767,11 @@
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
--- 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,
@@ -3429,7 +3429,7 @@
int flags
);
}
-603 AUE_PDOPENPID STD {
+603 AUE_PDOPENPID STD|CAPENABLED {
int pdopenpid(
pid_t pid,
int flags
@@ -3442,7 +3442,7 @@
int flags
);
}
-605 AUE_PDPTRACE STD {
+605 AUE_PDPTRACE STD|CAPENABLED {
int pdptrace(
int req,
int pfd,
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1195,6 +1195,7 @@
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
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -296,6 +296,7 @@
int pfd, lwpid_t lwpid, void *addr, int data);
extern bool allow_ptrace;
+extern bool allow_ptrace_in_cap_mode;
#else /* !_KERNEL */
diff --git a/tests/sys/kern/procdesc.c b/tests/sys/kern/procdesc.c
--- a/tests/sys/kern/procdesc.c
+++ b/tests/sys/kern/procdesc.c
@@ -343,10 +343,10 @@
}
/*
- * pdopenpid should fail in capability mode.
+ * pdopenpid works for children in capability mode.
*/
-ATF_TC_WITHOUT_HEAD(pdopenpid_capmode);
-ATF_TC_BODY(pdopenpid_capmode, tc)
+ATF_TC_WITHOUT_HEAD(pdopenpid_child);
+ATF_TC_BODY(pdopenpid_child, tc)
{
pid_t child, parent;
@@ -362,7 +362,36 @@
}
ATF_REQUIRE_MSG(cap_enter() == 0, "cap_enter: %s", strerror(errno));
- ATF_REQUIRE_ERRNO(ECAPMODE, pdopenpid(child, 0) < 0);
+ ATF_REQUIRE_MSG(pdopenpid(child, 0) >= 0, "pdopenpid: %s",
+ strerror(errno));
+}
+
+/*
+ * pdopenpid should fail in capability mode.
+ */
+ATF_TC_WITHOUT_HEAD(pdopenpid_capmode);
+ATF_TC_BODY(pdopenpid_capmode, tc)
+{
+ pid_t child, grandchild;
+
+ ATF_REQUIRE_FEATURE("security_capability_mode");
+
+ child = vfork();
+ ATF_REQUIRE_MSG(child >= 0, "fork: %s", strerror(errno));
+ if (child == 0) {
+ grandchild = fork();
+ ATF_REQUIRE_MSG(grandchild >= 0, "fork: %s", strerror(errno));
+ if (grandchild == 0) {
+ for (;;)
+ sleep(1);
+ } else {
+ _exit(0);
+ }
+ }
+
+ ATF_REQUIRE_MSG(cap_enter() == 0, "cap_enter: %s", strerror(errno));
+ ATF_REQUIRE_ERRNO(ECAPMODE, pdopenpid(grandchild, 0) < 0);
+ kill(grandchild, SIGKILL);
}
/*
@@ -759,6 +788,7 @@
ATF_TP_ADD_TC(tp, pdopenpid_einval);
ATF_TP_ADD_TC(tp, pdopenpid_emfile);
ATF_TP_ADD_TC(tp, pdopenpid_esrch);
+ ATF_TP_ADD_TC(tp, pdopenpid_child);
ATF_TP_ADD_TC(tp, pdopenpid_capmode);
ATF_TP_ADD_TC(tp, pdopenpid_pdfork_then_open);
ATF_TP_ADD_TC(tp, pdopenpid_fork_then_open);

File Metadata

Mime Type
text/plain
Expires
Sun, Sep 6, 10:31 PM (19 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38436467
Default Alt Text
D58989.id185325.diff (14 KB)

Event Timeline