Page MenuHomeFreeBSD

D58586.id184258.diff
No OneTemporary

D58586.id184258.diff

diff --git a/lib/libsys/ptrace.2 b/lib/libsys/ptrace.2
--- a/lib/libsys/ptrace.2
+++ b/lib/libsys/ptrace.2
@@ -131,10 +131,19 @@
Similarly, for operations affecting only a thread, the thread ID
needs to be passed.
.Pp
+If the
+.Fa request
+argument is or-ed with the
+.Dv PT_PROCDESC
+flag, then the
+.Fa pid
+argument is interpreted as the process descriptor.
+The call operates on the process referenced by the descriptor.
+.Pp
Still, for global operations, the ID of any thread can be used as the
target, and system will perform the request on the process owning
that thread.
-If a thread operation got the process ID as
+If a thread operation got the process ID or the process descriptor as
.Fa pid ,
the system randomly selects a thread from among the threads owned
by the process.
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
@@ -484,6 +484,12 @@
.It Dv CAP_PDKILL
Permit
.Xr pdkill 2 .
+.It Dv CAP_PTRACE
+Permit debugging using
+.Xr ptrace 2
+requests with the
+.Dv PT_PROCDESC
+modifier.
.It Dv CAP_PDWAIT
Permit
.Xr pdwait 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
@@ -1047,6 +1047,7 @@
u_int pscr_args32[nitems(td->td_sa.args)];
void *addr;
int data, error, i;
+ bool pd_mode;
if (!allow_ptrace)
return (ENOSYS);
@@ -1057,6 +1058,9 @@
AUDIT_ARG_VALUE(uap->data);
addr = &r;
data = uap->data;
+ pd_mode = (uap->req & PT_PROCDESC) != 0;
+ uap->req &= ~PT_PROCDESC;
+
switch (uap->req) {
case PT_GET_EVENT_MASK:
case PT_GET_SC_ARGS:
@@ -1192,7 +1196,8 @@
if (error)
return (error);
- error = kern_ptrace(td, uap->req, uap->pid, addr, data);
+ error = (pd_mode ? kern_pdptrace : kern_ptrace)(td, uap->req,
+ uap->pid, addr, data);
if (error)
return (error);
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1906,7 +1906,7 @@
/*
* Fill the given filecaps structure with full rights.
*/
-static void
+void
filecaps_fill(struct filecaps *fcaps)
{
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -41,6 +41,7 @@
#include <sys/systm.h>
#include <sys/acct.h>
#include <sys/bitstring.h>
+#include <sys/capsicum.h>
#include <sys/eventhandler.h>
#include <sys/exterrvar.h>
#include <sys/fcntl.h>
@@ -119,6 +120,7 @@
sys_pdfork(struct thread *td, struct pdfork_args *uap)
{
struct fork_req fr;
+ struct filecaps fcaps;
int error, fd, pid;
bzero(&fr, sizeof(fr));
@@ -126,6 +128,10 @@
fr.fr_pidp = &pid;
fr.fr_pd_fd = &fd;
fr.fr_pd_flags = uap->flags;
+ filecaps_fill(&fcaps);
+ if ((uap->flags & PD_PTRACE_CAP) == 0)
+ cap_rights_clear(&fcaps.fc_rights, CAP_PTRACE);
+ fr.fr_pd_fcaps = &fcaps;
AUDIT_ARG_FFLAGS(uap->flags);
/*
* It is necessary to return fd by reference because 0 is a valid file
@@ -194,6 +200,7 @@
sys_pdrfork(struct thread *td, struct pdrfork_args *uap)
{
struct fork_req fr;
+ struct filecaps fcaps;
int error, fd, pid;
bzero(&fr, sizeof(fr));
@@ -226,6 +233,10 @@
fr.fr_pidp = &pid;
fr.fr_pd_fd = &fd;
fr.fr_pd_flags = uap->pdflags;
+ filecaps_fill(&fcaps);
+ if ((uap->pdflags & PD_PTRACE_CAP) == 0)
+ cap_rights_clear(&fcaps.fc_rights, CAP_PTRACE);
+ fr.fr_pd_fcaps = &fcaps;
error = fork1(td, &fr);
if (error == 0) {
td->td_retval[0] = pid;
@@ -1066,8 +1077,10 @@
if (flags & RFPROCDESC) {
error = procdesc_falloc(td, &fp_procdesc, fr->fr_pd_fd,
fr->fr_pd_flags, fr->fr_pd_fcaps);
- if (error != 0)
+ if (error != 0) {
+ filecaps_free(fr->fr_pd_fcaps);
goto fail2;
+ }
AUDIT_ARG_FD(*fr->fr_pd_fd);
}
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_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);
const cap_rights_t cap_recv_rights = CAP_RIGHTS_INITIALIZER(CAP_RECV);
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
@@ -692,6 +692,7 @@
{
struct file *fp;
struct procdesc *pdf;
+ struct filecaps fcaps;
int error, fd, fflags;
error = falloc_noinstall(td, &fp);
@@ -701,13 +702,16 @@
pdf = procdesc_alloc(flags);
if ((flags & PD_DAEMON) != 0)
fp->f_pdflags |= F_PD_NOKILL;
+ filecaps_fill(&fcaps);
+ if ((flags & PD_PTRACE_CAP) == 0)
+ cap_rights_clear(&fcaps.fc_rights, CAP_PTRACE);
sx_xlock(&proctree_lock);
error = pdopenpid1(td, pid, &pdf, fp);
sx_xunlock(&proctree_lock);
if (error == 0) {
- error = finstall(td, fp, &fd, fflags, NULL);
+ error = finstall(td, fp, &fd, fflags, &fcaps);
if (error == 0) {
td->td_retval[0] = fd;
} else {
@@ -716,6 +720,7 @@
* return file descriptor to userspace.
*/
fp->f_pdflags |= F_PD_NOKILL | F_PD_NOFINSTALL;
+ filecaps_free(&fcaps);
}
}
fdrop(fp, td);
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
@@ -32,7 +32,7 @@
*/
#include <sys/systm.h>
-#include <sys/caprights.h>
+#include <sys/capsicum.h>
#include <sys/filedesc.h>
#include <sys/imgact.h>
#include <sys/ktr.h>
@@ -43,6 +43,7 @@
#include <sys/mutex.h>
#include <sys/priv.h>
#include <sys/proc.h>
+#include <sys/procdesc.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/rwlock.h>
@@ -739,6 +740,7 @@
syscallarg_t pscr_args[nitems(td->td_sa.args)];
void *addr;
int error;
+ bool pd_mode;
if (!allow_ptrace)
return (ENOSYS);
@@ -748,6 +750,9 @@
AUDIT_ARG_CMD(uap->req);
AUDIT_ARG_VALUE(uap->data);
addr = &r;
+ pd_mode = (uap->req & PT_PROCDESC) != 0;
+ uap->req &= ~PT_PROCDESC;
+
switch (uap->req) {
case PT_GET_EVENT_MASK:
case PT_LWPINFO:
@@ -836,7 +841,8 @@
if (error != 0)
return (error);
- error = kern_ptrace(td, uap->req, uap->pid, addr, uap->data);
+ error = (pd_mode ? kern_pdptrace : kern_ptrace)(td, uap->req,
+ uap->pid, addr, uap->data);
if (error != 0)
return (error);
@@ -1055,8 +1061,9 @@
return (NULL);
}
-int
-kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
+static int
+ptraceimpl(struct thread *td, int req, bool pd_mode, int pid, void *addr,
+ int data)
{
struct iovec iov;
struct uio uio;
@@ -1070,6 +1077,7 @@
struct ptrace_coredump *pc;
struct thr_coredump_req *tcq;
struct thr_syscall_req *tsr;
+ struct file *pfp;
struct ptrace_child *children, *ptc;
int error, num, num1, tmp;
lwpid_t tid = 0, *buf;
@@ -1081,6 +1089,7 @@
curp = td->td_proc;
proctree_locked = false;
p2_req_set = false;
+ pfp = NULL;
/* Lock proctree before locking the process. */
switch (req) {
@@ -1108,24 +1117,30 @@
if (req == PT_TRACE_ME) {
p = td->td_proc;
PROC_LOCK(p);
- } else {
- if (pid <= PID_MAX) {
- if ((p = pfind(pid)) == NULL) {
- if (proctree_locked)
- sx_xunlock(&proctree_lock);
- return (ESRCH);
- }
- } else {
- td2 = tdfind(pid, -1);
- if (td2 == NULL) {
- if (proctree_locked)
- sx_xunlock(&proctree_lock);
- return (ESRCH);
- }
- p = td2->td_proc;
- tid = pid;
- pid = p->p_pid;
+ } else if (pd_mode) {
+ if (!proctree_locked)
+ sx_slock(&proctree_lock);
+ error = fget_procdesc(td, pid, &cap_ptrace_rights, EINVAL,
+ &pfp, NULL, &p);
+ if (!proctree_locked)
+ sx_sunlock(&proctree_lock);
+ if (error != 0)
+ goto fail_proctree;
+ pid = p->p_pid;
+ } else if (pid <= PID_MAX) {
+ if ((p = pfind(pid)) == NULL) {
+ error = ESRCH;
+ goto fail_proctree;
}
+ } else {
+ td2 = tdfind(pid, -1);
+ if (td2 == NULL) {
+ error = ESRCH;
+ goto fail_proctree;
+ }
+ p = td2->td_proc;
+ tid = pid;
+ pid = p->p_pid;
}
AUDIT_ARG_PROCESS(p);
@@ -2021,9 +2036,24 @@
p->p_flag2 &= ~P2_PTRACEREQ;
}
PROC_UNLOCK(p);
+fail_proctree:
if (proctree_locked)
sx_xunlock(&proctree_lock);
+ if (pfp != NULL)
+ fdrop(pfp, td);
return (error);
}
#undef PROC_READ
#undef PROC_WRITE
+
+int
+kern_pdptrace(struct thread *td, int req, int pfd, void *addr, int data)
+{
+ return (ptraceimpl(td, req, true, pfd, addr, data));
+}
+
+int
+kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
+{
+ return (ptraceimpl(td, req, false, pid, addr, data));
+}
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_ptrace_rights;
extern const cap_rights_t cap_pwrite_rights;
extern const cap_rights_t cap_read_rights;
extern const cap_rights_t cap_recv_rights;
diff --git a/sys/sys/capsicum.h b/sys/sys/capsicum.h
--- a/sys/sys/capsicum.h
+++ b/sys/sys/capsicum.h
@@ -299,7 +299,9 @@
/* Allows pddupfd(2). */
#define CAP_PDDUPFD CAPRIGHT(1, 0x0000000000800000ULL)
-#define CAP_UNUSED1_25 CAPRIGHT(1, 0x0000000001000000ULL)
+/* Allows ptrace(PT_PROCDESC) */
+#define CAP_PTRACE CAPRIGHT(1, 0x0000000001000000ULL)
+
#define CAP_UNUSED1_26 CAPRIGHT(1, 0x0000000002000000ULL)
#define CAP_UNUSED1_27 CAPRIGHT(1, 0x0000000004000000ULL)
#define CAP_UNUSED1_28 CAPRIGHT(1, 0x0000000008000000ULL)
@@ -333,8 +335,8 @@
#define CAP_UNUSED1_56 CAPRIGHT(1, 0x0080000000000000ULL)
#define CAP_UNUSED1_57 CAPRIGHT(1, 0x0100000000000000ULL)
-/* All used bits for index 1. */
-#define CAP_ALL1 CAPRIGHT(1, 0x0000000000FFFFFFULL)
+/* All default bits for index 1. */
+#define CAP_ALL1 CAPRIGHT(1, 0x0000000001FFFFFFULL)
/* Backward compatibility. */
#define CAP_POLL_EVENT CAP_EVENT
diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h
--- a/sys/sys/filedesc.h
+++ b/sys/sys/filedesc.h
@@ -243,6 +243,7 @@
bool filecaps_copy(const struct filecaps *src, struct filecaps *dst,
bool locked);
void filecaps_move(struct filecaps *src, struct filecaps *dst);
+void filecaps_fill(struct filecaps *fcaps);
void filecaps_free(struct filecaps *fcaps);
int closef(struct file *fp, struct thread *td);
diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h
--- a/sys/sys/procdesc.h
+++ b/sys/sys/procdesc.h
@@ -161,8 +161,10 @@
#define PD_DAEMON 0x00000001 /* Don't exit when procdesc closes. */
#define PD_CLOEXEC 0x00000002 /* Close file descriptor on exec. */
#define PD_NOWAITPID 0x00000004 /* Reap without waitpid(). */
+#define PD_PTRACE_CAP 0x00000008 /* Allow PT_PROCDESC in cap mode. */
-#define PD_ALLOWED_AT_FORK (PD_DAEMON | PD_CLOEXEC | PD_NOWAITPID)
-#define PD_ALLOWED_AT_OPENPID (PD_DAEMON | PD_CLOEXEC)
+#define PD_ALLOWED_AT_FORK \
+ (PD_DAEMON | PD_CLOEXEC | PD_NOWAITPID | PD_PTRACE_CAP)
+#define PD_ALLOWED_AT_OPENPID (PD_DAEMON | PD_CLOEXEC | PD_PTRACE_CAP)
#endif /* !_SYS_PROCDESC_H_ */
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -36,6 +36,8 @@
#include <sys/param.h>
#include <machine/reg.h>
+#define PT_PROCDESC 0x80000000 /* pid is procdesc */
+
#define PT_TRACE_ME 0 /* child declares it's being traced */
#define PT_READ_I 1 /* read word in child's I space */
#define PT_READ_D 2 /* read word in child's D space */
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -299,6 +299,8 @@
off_t len);
int kern_fspacectl(struct thread *td, int fd, int cmd,
const struct spacectl_range *, int flags, struct spacectl_range *);
+int kern_pdptrace(struct thread *td, int req, int pfd, void *addr,
+ int data);
int kern_pdwait(struct thread *td, int fd, int *status,
int options, struct __wrusage *wrusage, siginfo_t *sip);
int kern_procctl(struct thread *td, enum idtype idtype, id_t id, int com,

File Metadata

Mime Type
text/plain
Expires
Fri, Aug 28, 6:00 PM (9 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37473765
Default Alt Text
D58586.id184258.diff (12 KB)

Event Timeline