Page MenuHomeFreeBSD

D58586.id185223.diff
No OneTemporary

D58586.id185223.diff

diff --git a/lib/libsys/Symbol.sys.map b/lib/libsys/Symbol.sys.map
--- a/lib/libsys/Symbol.sys.map
+++ b/lib/libsys/Symbol.sys.map
@@ -393,6 +393,7 @@
FBSD_1.9 {
pddupfd;
pdopenpid;
+ pdptrace;
pdrfork;
pdrfork_thread;
renameat2;
diff --git a/lib/libsys/_libsys.h b/lib/libsys/_libsys.h
--- a/lib/libsys/_libsys.h
+++ b/lib/libsys/_libsys.h
@@ -477,6 +477,7 @@
typedef int (__sys_renameat2_t)(int, const char *, int, const char *, int);
typedef int (__sys_pdopenpid_t)(pid_t, int);
typedef int (__sys_pddupfd_t)(int, int, int);
+typedef int (__sys_pdptrace_t)(int, int, int, void *, int);
_Noreturn void __sys__exit(int rval);
int __sys_fork(void);
@@ -889,6 +890,7 @@
int __sys_renameat2(int oldfd, const char * old, int newfd, const char * new, int flags);
int __sys_pdopenpid(pid_t pid, int flags);
int __sys_pddupfd(int pd, int fd, int flags);
+int __sys_pdptrace(int req, int pfd, int lwpid, void * addr, int data);
__END_DECLS
#endif /* __LIBSYS_H_ */
diff --git a/lib/libsys/pdfork.2 b/lib/libsys/pdfork.2
--- a/lib/libsys/pdfork.2
+++ b/lib/libsys/pdfork.2
@@ -66,6 +66,14 @@
.Fc
.Ft int
.Fn pddupfd "int fd" "int remotefd" "int flags"
+.Ft int
+.Fo pdptrace
+.Fa "int req"
+.Fa "int fd"
+.Fa "int lwpid"
+.Fa "void *addr"
+.Fa "int data"
+.Fc
.Sh DESCRIPTION
Process descriptors are special file descriptors that represent processes,
and are created using
@@ -83,7 +91,7 @@
.Fn pdfork
can accept the
.Fa pdflags:
-.Bl -tag -width PD_CLOEXEC
+.Bl -tag -width PD_PTRACE_CAP
.It Dv PD_DAEMON
Instead of the default terminate-on-close behaviour, allow the process to
live until it is explicitly killed with
@@ -106,6 +114,16 @@
.It Dv PD_NOWAITPID
The parent cannot obtain the child's status with
.Xr waitpid 2 .
+.It Dv PD_PTRACE_CAP
+Enable
+.Xr pdptrace 2
+requests on the resulting file descriptor.
+Otherwise the descriptor cannot be used to debug the child process.
+See
+.Xr rights 4
+for the description of the
+.Dv CAP_PTRACE
+capability.
.El
.Pp
The
@@ -197,6 +215,24 @@
argument is reserved and must be zero.
Certain file descriptor types cannot be copied this way, namely
kqueues.
+.Pp
+The
+.Fn pdptrace
+function enables execution of
+.Xr ptrace 2
+requests on the process specified by the process descriptor
+.Fa fd .
+.Pp
+In addition to the arguments taken by the
+.Xr ptrace 2 ,
+system call, the
+.Fa lwpid
+thread identifier can designate the thread on which the request
+must operate.
+The
+.Fa lwpid
+argument can be specified as \-1 if the call is not thread-specific,
+or kernel is allowed to select some thread on its own.
.Sh INTERACTION OF PROCESS DESCRIPTORS AND Xr WAITPID 2
.Pp
The
@@ -461,8 +497,9 @@
with input from
.An Alan Somers Aq Mt asomers@FreeBSD.org .
The
-.Fn pdopenpid
+.Fn pdopenpid ,
+.Fn pddupfd ,
and
-.Fn pddupfd
+.Fn pdptrace
functions were developed by
.An Konstantin Belousov Aq Mt kib@FreeBSD.org .
diff --git a/lib/libsys/syscalls.map b/lib/libsys/syscalls.map
--- a/lib/libsys/syscalls.map
+++ b/lib/libsys/syscalls.map
@@ -829,4 +829,6 @@
__sys_pdopenpid;
_pddupfd;
__sys_pddupfd;
+ _pdptrace;
+ __sys_pdptrace;
};
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,9 @@
.It Dv CAP_PDKILL
Permit
.Xr pdkill 2 .
+.It Dv CAP_PTRACE
+Permit debugging using
+.Xr pdptrace 2 .
.It Dv CAP_PDWAIT
Permit
.Xr pdwait 2 .
diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h
--- a/sys/bsm/audit_kevents.h
+++ b/sys/bsm/audit_kevents.h
@@ -666,6 +666,7 @@
#define AUE_INOTIFY 43272 /* FreeBSD/Linux. */
#define AUE_PDRFORK 43273 /* FreeBSD-specific. */
#define AUE_PDOPENPID 43274 /* FreeBSD-specific. */
+#define AUE_PDPTRACE 43275 /* FreeBSD-specific. */
/*
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
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
@@ -1015,8 +1015,9 @@
psr->sr_error = psr32->sr_error;
}
-int
-freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
+static int
+freebsd32_ptrace_useraction(struct thread *td, int req, bool pd_mode, pid_t pid,
+ int pfd, lwpid_t lwpid, void *uaddr, int udata)
{
union {
struct ptrace_io_desc piod;
@@ -1050,39 +1051,32 @@
if (!allow_ptrace)
return (ENOSYS);
- error = 0;
- AUDIT_ARG_PID(uap->pid);
- AUDIT_ARG_CMD(uap->req);
- AUDIT_ARG_VALUE(uap->data);
+ error = 0;
addr = &r;
- data = uap->data;
- switch (uap->req) {
+ data = udata;
+
+ switch (req) {
case PT_GET_EVENT_MASK:
case PT_GET_SC_ARGS:
case PT_GET_SC_RET:
break;
case PT_SET_SC_RET:
- if (uap->data != sizeof(r32.psr)) {
- error = EINVAL;
- } else {
- error = copyin(uap->addr, &r32.psr, sizeof(r32.psr));
- if (error == 0)
- ptrace_sc_ret32_to_ret(&r32.psr, &r.psr);
- }
+ error = udata != sizeof(r32.psr) ? EINVAL :
+ copyin(uaddr, &r32.psr, sizeof(r32.psr));
+ if (error == 0)
+ ptrace_sc_ret32_to_ret(&r32.psr, &r.psr);
break;
case PT_LWPINFO:
- if (uap->data > sizeof(r32.pl))
+ if (udata > sizeof(r32.pl))
return (EINVAL);
-
/*
* Pass size of native structure in 'data'. Truncate
* if necessary to avoid siginfo.
*/
- data = sizeof(r.pl);
- if (uap->data < offsetof(struct ptrace_lwpinfo32, pl_siginfo) +
- sizeof(struct __siginfo32))
- data = offsetof(struct ptrace_lwpinfo, pl_siginfo);
+ data = udata < offsetof(struct ptrace_lwpinfo32,
+ pl_siginfo) + sizeof(struct __siginfo32) ?
+ offsetof(struct ptrace_lwpinfo, pl_siginfo) : sizeof(r.pl);
break;
case PT_GETREGS:
bzero(&r.reg, sizeof(r.reg));
@@ -1094,17 +1088,17 @@
bzero(&r.dbreg, sizeof(r.dbreg));
break;
case PT_SETREGS:
- error = copyin(uap->addr, &r.reg, sizeof(r.reg));
+ error = copyin(uaddr, &r.reg, sizeof(r.reg));
break;
case PT_SETFPREGS:
- error = copyin(uap->addr, &r.fpreg, sizeof(r.fpreg));
+ error = copyin(uaddr, &r.fpreg, sizeof(r.fpreg));
break;
case PT_SETDBREGS:
- error = copyin(uap->addr, &r.dbreg, sizeof(r.dbreg));
+ error = copyin(uaddr, &r.dbreg, sizeof(r.dbreg));
break;
case PT_GETREGSET:
case PT_SETREGSET:
- error = copyin(uap->addr, &r32.vec, sizeof(r32.vec));
+ error = copyin(uaddr, &r32.vec, sizeof(r32.vec));
if (error != 0)
break;
@@ -1112,14 +1106,12 @@
r.vec.iov_base = PTRIN(r32.vec.iov_base);
break;
case PT_SET_EVENT_MASK:
- if (uap->data != sizeof(r.ptevents))
- error = EINVAL;
- else
- error = copyin(uap->addr, &r.ptevents, uap->data);
+ error = udata != sizeof(r.ptevents) ? EINVAL :
+ copyin(uaddr, &r.ptevents, udata);
break;
case PT_IO:
- error = copyin(uap->addr, &r32.piod, sizeof(r32.piod));
- if (error)
+ error = copyin(uaddr, &r32.piod, sizeof(r32.piod));
+ if (error != 0)
break;
CP(r32.piod, r.piod, piod_op);
PTRIN_CP(r32.piod, r.piod, piod_offs);
@@ -1127,8 +1119,8 @@
CP(r32.piod, r.piod, piod_len);
break;
case PT_VM_ENTRY:
- error = copyin(uap->addr, &r32.pve, sizeof(r32.pve));
- if (error)
+ error = copyin(uaddr, &r32.pve, sizeof(r32.pve));
+ if (error != 0)
break;
CP(r32.pve, r.pve, pve_entry);
@@ -1143,21 +1135,18 @@
PTRIN_CP(r32.pve, r.pve, pve_path);
break;
case PT_COREDUMP:
- if (uap->data != sizeof(r32.pc))
- error = EINVAL;
- else
- error = copyin(uap->addr, &r32.pc, uap->data);
+ error = udata != sizeof(r32.pc) ? EINVAL :
+ copyin(uaddr, &r32.pc, udata);
+ if (error != 0)
+ break;
CP(r32.pc, r.pc, pc_fd);
CP(r32.pc, r.pc, pc_flags);
r.pc.pc_limit = PAIR32TO64(off_t, r32.pc.pc_limit);
data = sizeof(r.pc);
break;
case PT_SC_REMOTE:
- if (uap->data != sizeof(r32.sr)) {
- error = EINVAL;
- break;
- }
- error = copyin(uap->addr, &r32.sr, uap->data);
+ error = udata != sizeof(r32.sr) ? EINVAL :
+ copyin(uaddr, &r32.sr, udata);
if (error != 0)
break;
CP(r32.sr, r.sr, pscr_syscall);
@@ -1175,9 +1164,9 @@
r.sr.pscr_args = pscr_args;
break;
case PT_GET_CHILDREN:
- if (uap->addr == NULL)
+ if (uaddr == NULL)
addr = NULL;
- else if (uap->data < 0)
+ else if (udata < 0)
error = EINVAL;
else
addr = &r.children;
@@ -1186,17 +1175,17 @@
error = EINVAL;
break;
default:
- addr = uap->addr;
+ addr = uaddr;
break;
}
- if (error)
+ if (error != 0)
return (error);
- error = kern_ptrace(td, uap->req, uap->pid, addr, data);
- if (error)
+ error = ptrace_action(td, req, pd_mode, pid, pfd, lwpid, addr, data);
+ if (error != 0)
return (error);
- switch (uap->req) {
+ switch (req) {
case PT_VM_ENTRY:
CP(r.pve, r32.pve, pve_entry);
CP(r.pve, r32.pve, pve_timestamp);
@@ -1207,53 +1196,51 @@
CP(r.pve, r32.pve, pve_pathlen);
CP(r.pve, r32.pve, pve_fileid);
CP(r.pve, r32.pve, pve_fsid);
- error = copyout(&r32.pve, uap->addr, sizeof(r32.pve));
+ error = copyout(&r32.pve, uaddr, sizeof(r32.pve));
break;
case PT_IO:
CP(r.piod, r32.piod, piod_len);
- error = copyout(&r32.piod, uap->addr, sizeof(r32.piod));
+ error = copyout(&r32.piod, uaddr, sizeof(r32.piod));
break;
case PT_GETREGS:
- error = copyout(&r.reg, uap->addr, sizeof(r.reg));
+ error = copyout(&r.reg, uaddr, sizeof(r.reg));
break;
case PT_GETFPREGS:
- error = copyout(&r.fpreg, uap->addr, sizeof(r.fpreg));
+ error = copyout(&r.fpreg, uaddr, sizeof(r.fpreg));
break;
case PT_GETDBREGS:
- error = copyout(&r.dbreg, uap->addr, sizeof(r.dbreg));
+ error = copyout(&r.dbreg, uaddr, sizeof(r.dbreg));
break;
case PT_GETREGSET:
r32.vec.iov_len = r.vec.iov_len;
- error = copyout(&r32.vec, uap->addr, sizeof(r32.vec));
+ error = copyout(&r32.vec, uaddr, sizeof(r32.vec));
break;
case PT_GET_EVENT_MASK:
/* NB: The size in uap->data is validated in kern_ptrace(). */
- error = copyout(&r.ptevents, uap->addr, uap->data);
+ error = copyout(&r.ptevents, uaddr, udata);
break;
case PT_LWPINFO:
ptrace_lwpinfo_to32(&r.pl, &r32.pl);
- error = copyout(&r32.pl, uap->addr, uap->data);
+ error = copyout(&r32.pl, uaddr, udata);
break;
case PT_GET_SC_ARGS:
for (i = 0; i < nitems(r.args); i++)
r32.args[i] = (uint32_t)r.args[i];
- error = copyout(r32.args, uap->addr, MIN(uap->data,
- sizeof(r32.args)));
+ error = copyout(r32.args, uaddr, MIN(udata, sizeof(r32.args)));
break;
case PT_GET_SC_RET:
ptrace_sc_ret_to32(&r.psr, &r32.psr);
- error = copyout(&r32.psr, uap->addr, MIN(uap->data,
- sizeof(r32.psr)));
+ error = copyout(&r32.psr, uaddr, MIN(udata, sizeof(r32.psr)));
break;
case PT_SC_REMOTE:
ptrace_sc_ret_to32(&r.sr.pscr_ret, &r32.sr.pscr_ret);
- error = copyout(&r32.sr.pscr_ret, uap->addr +
+ error = copyout(&r32.sr.pscr_ret, (char *)uaddr +
offsetof(struct ptrace_sc_remote32, pscr_ret),
sizeof(r32.psr));
break;
case PT_GET_CHILDREN:
- if (uap->addr != 0) {
- error = copyout(r.children, uap->addr,
+ if (uaddr != NULL) {
+ error = copyout(r.children, uaddr,
td->td_retval[0] * sizeof(struct ptrace_child));
free(r.children, M_TEMP);
}
@@ -1263,6 +1250,34 @@
return (error);
}
+int
+freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
+{
+ int error;
+
+ AUDIT_ARG_PID(uap->pid);
+ AUDIT_ARG_CMD(uap->req);
+ AUDIT_ARG_VALUE(uap->data);
+
+ error = freebsd32_ptrace_useraction(td, uap->req, false, uap->pid,
+ -1, -1, uap->addr, uap->data);
+ return (error);
+}
+
+int
+freebsd32_pdptrace(struct thread *td, struct freebsd32_pdptrace_args *uap)
+{
+ int error;
+
+ AUDIT_ARG_FD(uap->pfd);
+ AUDIT_ARG_CMD(uap->req);
+ AUDIT_ARG_VALUE(uap->data);
+
+ error = freebsd32_ptrace_useraction(td, uap->req, true, -1,
+ uap->pfd, uap->lwpid, uap->addr, uap->data);
+ return (error);
+}
+
int
freebsd32_copyinuio(const struct iovec32 *iovp, u_int iovcnt, struct uio **uiop)
{
diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h
--- a/sys/compat/freebsd32/freebsd32_proto.h
+++ b/sys/compat/freebsd32/freebsd32_proto.h
@@ -706,6 +706,13 @@
char wrusage_l_[PADL_(struct __wrusage32 *)]; struct __wrusage32 * wrusage; char wrusage_r_[PADR_(struct __wrusage32 *)];
char info_l_[PADL_(struct __siginfo32 *)]; struct __siginfo32 * info; char info_r_[PADR_(struct __siginfo32 *)];
};
+struct freebsd32_pdptrace_args {
+ char req_l_[PADL_(int)]; int req; char req_r_[PADR_(int)];
+ char pfd_l_[PADL_(int)]; int pfd; char pfd_r_[PADR_(int)];
+ char lwpid_l_[PADL_(int)]; int lwpid; char lwpid_r_[PADR_(int)];
+ char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)];
+ char data_l_[PADL_(int)]; int data; char data_r_[PADR_(int)];
+};
int freebsd32_wait4(struct thread *, struct freebsd32_wait4_args *);
int freebsd32_ptrace(struct thread *, struct freebsd32_ptrace_args *);
int freebsd32_recvmsg(struct thread *, struct freebsd32_recvmsg_args *);
@@ -825,6 +832,7 @@
int freebsd32_timerfd_settime(struct thread *, struct freebsd32_timerfd_settime_args *);
int freebsd32_setcred(struct thread *, struct freebsd32_setcred_args *);
int freebsd32_pdwait(struct thread *, struct freebsd32_pdwait_args *);
+int freebsd32_pdptrace(struct thread *, struct freebsd32_pdptrace_args *);
#ifdef COMPAT_43
@@ -1328,6 +1336,7 @@
#define FREEBSD32_SYS_AUE_freebsd32_timerfd_settime AUE_TIMERFD
#define FREEBSD32_SYS_AUE_freebsd32_setcred AUE_SETCRED
#define FREEBSD32_SYS_AUE_freebsd32_pdwait AUE_PDWAIT
+#define FREEBSD32_SYS_AUE_freebsd32_pdptrace AUE_PDPTRACE
#undef PAD_
#undef PADL_
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
--- a/sys/compat/freebsd32/freebsd32_syscall.h
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -522,4 +522,5 @@
#define FREEBSD32_SYS_renameat2 602
#define FREEBSD32_SYS_pdopenpid 603
#define FREEBSD32_SYS_pddupfd 604
-#define FREEBSD32_SYS_MAXSYSCALL 605
+#define FREEBSD32_SYS_freebsd32_pdptrace 605
+#define FREEBSD32_SYS_MAXSYSCALL 606
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
--- a/sys/compat/freebsd32/freebsd32_syscalls.c
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -610,4 +610,5 @@
"renameat2", /* 602 = renameat2 */
"pdopenpid", /* 603 = pdopenpid */
"pddupfd", /* 604 = pddupfd */
+ "freebsd32_pdptrace", /* 605 = freebsd32_pdptrace */
};
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
@@ -672,4 +672,5 @@
{ .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(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 */
};
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
--- a/sys/compat/freebsd32/freebsd32_systrace_args.c
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -3475,6 +3475,17 @@
*n_args = 3;
break;
}
+ /* freebsd32_pdptrace */
+ case 605: {
+ struct freebsd32_pdptrace_args *p = params;
+ iarg[a++] = p->req; /* int */
+ iarg[a++] = p->pfd; /* int */
+ iarg[a++] = p->lwpid; /* int */
+ uarg[a++] = (intptr_t)p->addr; /* void * */
+ iarg[a++] = p->data; /* int */
+ *n_args = 5;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9393,6 +9404,28 @@
break;
};
break;
+ /* freebsd32_pdptrace */
+ case 605:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ case 4:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11336,6 +11369,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* freebsd32_pdptrace */
+ case 605:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
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
@@ -671,4 +671,5 @@
{ .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(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 */
};
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;
@@ -1068,6 +1079,7 @@
fr->fr_pd_flags, fr->fr_pd_fcaps);
if (error != 0)
goto fail2;
+ fr->fr_pd_fcaps = NULL;
AUDIT_ARG_FD(*fr->fr_pd_fd);
}
@@ -1163,6 +1175,8 @@
fdclose(td, fp_procdesc, *fr->fr_pd_fd);
fdrop(fp_procdesc, td);
}
+ if (fr->fr_pd_fcaps != NULL)
+ filecaps_free(fr->fr_pd_fcaps);
atomic_add_int(&nprocs, -1);
cleanup:
if (killsx_locked)
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>
@@ -714,8 +715,9 @@
};
#endif
-int
-sys_ptrace(struct thread *td, struct ptrace_args *uap)
+static int
+ptrace_useraction(struct thread *td, int req, bool pd_mode, pid_t pid, int pfd,
+ lwpid_t lwpid, void *uaddr, int udata)
{
/*
* XXX this obfuscation is to reduce stack usage, but the register
@@ -742,23 +744,19 @@
if (!allow_ptrace)
return (ENOSYS);
- error = 0;
- AUDIT_ARG_PID(uap->pid);
- AUDIT_ARG_CMD(uap->req);
- AUDIT_ARG_VALUE(uap->data);
+ error = 0;
addr = &r;
- switch (uap->req) {
+
+ switch (req) {
case PT_GET_EVENT_MASK:
case PT_LWPINFO:
case PT_GET_SC_ARGS:
case PT_GET_SC_RET:
break;
case PT_SET_SC_RET:
- if (uap->data != sizeof(r.psr))
- error = EINVAL;
- else
- error = copyin(uap->addr, &r.psr, sizeof(r.psr));
+ error = udata != sizeof(r.psr) ? EINVAL :
+ copyin(uaddr, &r.psr, sizeof(r.psr));
break;
case PT_GETREGS:
bzero(&r.reg, sizeof(r.reg));
@@ -771,41 +769,34 @@
break;
case PT_GETREGSET:
case PT_SETREGSET:
- error = copyin(uap->addr, &r.vec, sizeof(r.vec));
+ error = copyin(uaddr, &r.vec, sizeof(r.vec));
break;
case PT_SETREGS:
- error = copyin(uap->addr, &r.reg, sizeof(r.reg));
+ error = copyin(uaddr, &r.reg, sizeof(r.reg));
break;
case PT_SETFPREGS:
- error = copyin(uap->addr, &r.fpreg, sizeof(r.fpreg));
+ error = copyin(uaddr, &r.fpreg, sizeof(r.fpreg));
break;
case PT_SETDBREGS:
- error = copyin(uap->addr, &r.dbreg, sizeof(r.dbreg));
+ error = copyin(uaddr, &r.dbreg, sizeof(r.dbreg));
break;
case PT_SET_EVENT_MASK:
- if (uap->data != sizeof(r.ptevents))
- error = EINVAL;
- else
- error = copyin(uap->addr, &r.ptevents, uap->data);
+ error = udata != sizeof(r.ptevents) ? EINVAL :
+ copyin(uaddr, &r.ptevents, udata);
break;
case PT_IO:
- error = copyin(uap->addr, &r.piod, sizeof(r.piod));
+ error = copyin(uaddr, &r.piod, sizeof(r.piod));
break;
case PT_VM_ENTRY:
- error = copyin(uap->addr, &r.pve, sizeof(r.pve));
+ error = copyin(uaddr, &r.pve, sizeof(r.pve));
break;
case PT_COREDUMP:
- if (uap->data != sizeof(r.pc))
- error = EINVAL;
- else
- error = copyin(uap->addr, &r.pc, uap->data);
+ error = udata != sizeof(r.pc) ? EINVAL :
+ copyin(uaddr, &r.pc, udata);
break;
case PT_SC_REMOTE:
- if (uap->data != sizeof(r.sr)) {
- error = EINVAL;
- break;
- }
- error = copyin(uap->addr, &r.sr, uap->data);
+ error = udata != sizeof(r.sr) ? EINVAL :
+ copyin(uaddr, &r.sr, udata);
if (error != 0)
break;
if (r.sr.pscr_nargs > nitems(td->td_sa.args)) {
@@ -819,9 +810,9 @@
r.sr.pscr_args = pscr_args;
break;
case PT_GET_CHILDREN:
- if (uap->addr == NULL)
+ if (uaddr == NULL)
addr = NULL;
- else if (uap->data < 0)
+ else if (udata < 0)
error = EINVAL;
else
addr = &r.children;
@@ -830,59 +821,57 @@
error = EINVAL;
break;
default:
- addr = uap->addr;
+ addr = uaddr;
break;
}
if (error != 0)
return (error);
- error = kern_ptrace(td, uap->req, uap->pid, addr, uap->data);
+ error = ptrace_action(td, req, pd_mode, pid, pfd, lwpid, addr, udata);
if (error != 0)
return (error);
- switch (uap->req) {
+ switch (req) {
case PT_VM_ENTRY:
- error = copyout(&r.pve, uap->addr, sizeof(r.pve));
+ error = copyout(&r.pve, uaddr, sizeof(r.pve));
break;
case PT_IO:
- error = copyout(&r.piod, uap->addr, sizeof(r.piod));
+ error = copyout(&r.piod, uaddr, sizeof(r.piod));
break;
case PT_GETREGS:
- error = copyout(&r.reg, uap->addr, sizeof(r.reg));
+ error = copyout(&r.reg, uaddr, sizeof(r.reg));
break;
case PT_GETFPREGS:
- error = copyout(&r.fpreg, uap->addr, sizeof(r.fpreg));
+ error = copyout(&r.fpreg, uaddr, sizeof(r.fpreg));
break;
case PT_GETDBREGS:
- error = copyout(&r.dbreg, uap->addr, sizeof(r.dbreg));
+ error = copyout(&r.dbreg, uaddr, sizeof(r.dbreg));
break;
case PT_GETREGSET:
- error = copyout(&r.vec, uap->addr, sizeof(r.vec));
+ error = copyout(&r.vec, uaddr, sizeof(r.vec));
break;
case PT_GET_EVENT_MASK:
- /* NB: The size in uap->data is validated in kern_ptrace(). */
- error = copyout(&r.ptevents, uap->addr, uap->data);
+ /* NB: The size in uap->data is validated in ptraceimpl(). */
+ error = copyout(&r.ptevents, uaddr, udata);
break;
case PT_LWPINFO:
- /* NB: The size in uap->data is validated in kern_ptrace(). */
- error = copyout(&r.pl, uap->addr, uap->data);
+ /* NB: The size in uap->data is validated in ptraceimpl(). */
+ error = copyout(&r.pl, uaddr, udata);
break;
case PT_GET_SC_ARGS:
- error = copyout(r.args, uap->addr, MIN(uap->data,
- sizeof(r.args)));
+ error = copyout(r.args, uaddr, MIN(udata, sizeof(r.args)));
break;
case PT_GET_SC_RET:
- error = copyout(&r.psr, uap->addr, MIN(uap->data,
- sizeof(r.psr)));
+ error = copyout(&r.psr, uaddr, MIN(udata, sizeof(r.psr)));
break;
case PT_SC_REMOTE:
- error = copyout(&r.sr.pscr_ret, uap->addr +
+ error = copyout(&r.sr.pscr_ret, (char *)uaddr +
offsetof(struct ptrace_sc_remote, pscr_ret),
sizeof(r.sr.pscr_ret));
break;
case PT_GET_CHILDREN:
- if (uap->addr != NULL) {
- error = copyout(r.children, uap->addr,
+ if (uaddr != NULL) {
+ error = copyout(r.children, uaddr,
td->td_retval[0] * sizeof(struct ptrace_child));
free(r.children, M_TEMP);
}
@@ -1056,7 +1045,8 @@
}
int
-kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
+ptrace_action(struct thread *td, int req, bool pd_mode, pid_t pid, int pfd,
+ lwpid_t lwpid, void *addr, int data)
{
struct iovec iov;
struct uio uio;
@@ -1070,6 +1060,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 +1072,7 @@
curp = td->td_proc;
proctree_locked = false;
p2_req_set = false;
+ pfp = NULL;
/* Lock proctree before locking the process. */
switch (req) {
@@ -1108,24 +1100,42 @@
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 if (pd_mode) {
+ if (!proctree_locked)
+ sx_slock(&proctree_lock);
+ error = fget_procdesc(td, pfd, &cap_ptrace_rights, EINVAL,
+ &pfp, NULL, &p);
+ if (!proctree_locked)
+ sx_sunlock(&proctree_lock);
+ if (error != 0)
+ goto fail_proctree;
+ pid = p->p_pid;
+ if (lwpid != -1) {
+ FOREACH_THREAD_IN_PROC(p, td2) {
+ if (td2->td_tid == lwpid)
+ break;
}
- } else {
- td2 = tdfind(pid, -1);
if (td2 == NULL) {
- if (proctree_locked)
- sx_xunlock(&proctree_lock);
- return (ESRCH);
+ PROC_UNLOCK(p);
+ error = ESRCH;
+ goto fail_proctree;
}
- p = td2->td_proc;
- tid = pid;
- pid = p->p_pid;
+ tid = td2->td_tid;
}
+ } 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 +2031,46 @@
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_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
+{
+ return (ptrace_action(td, req, false, pid, -1, -1, addr, data));
+}
+
+int
+sys_ptrace(struct thread *td, struct ptrace_args *uap)
+{
+ int error;
+
+ AUDIT_ARG_PID(uap->pid);
+ AUDIT_ARG_CMD(uap->req);
+ AUDIT_ARG_VALUE(uap->data);
+
+ error = ptrace_useraction(td, uap->req, false, uap->pid, -1, -1,
+ uap->addr, uap->data);
+ return (error);
+}
+
+int
+sys_pdptrace(struct thread *td, struct pdptrace_args *uap)
+{
+ int error;
+
+ AUDIT_ARG_FD(uap->pfd);
+ AUDIT_ARG_CMD(uap->req);
+ AUDIT_ARG_VALUE(uap->data);
+
+ error = ptrace_useraction(td, uap->req, true, -1, uap->pfd, uap->lwpid,
+ uap->addr, uap->data);
+ return (error);
+}
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -610,4 +610,5 @@
"renameat2", /* 602 = renameat2 */
"pdopenpid", /* 603 = pdopenpid */
"pddupfd", /* 604 = pddupfd */
+ "pdptrace", /* 605 = pdptrace */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3442,5 +3442,14 @@
int flags
);
}
+605 AUE_PDPTRACE STD {
+ int pdptrace(
+ int req,
+ int pfd,
+ int lwpid,
+ _Inout_opt_ _Contains_long_ptr_ void *addr,
+ int data
+ );
+ }
; vim: syntax=off
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -3572,6 +3572,17 @@
*n_args = 3;
break;
}
+ /* pdptrace */
+ case 605: {
+ struct pdptrace_args *p = params;
+ iarg[a++] = p->req; /* int */
+ iarg[a++] = p->pfd; /* int */
+ iarg[a++] = p->lwpid; /* int */
+ uarg[a++] = (intptr_t)p->addr; /* void * */
+ iarg[a++] = p->data; /* int */
+ *n_args = 5;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9567,6 +9578,28 @@
break;
};
break;
+ /* pdptrace */
+ case 605:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "userland void *";
+ break;
+ case 4:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11605,6 +11638,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* pdptrace */
+ case 605:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
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
@@ -151,6 +151,7 @@
int pdwait(int, int *, int, struct __wrusage *, struct __siginfo *);
int pddupfd(int, int, int);
pid_t pdrfork_thread(int *, int, int, void *, int (*)(void *), void *);
+int pdptrace(int, int, int, void *, int);
__END_DECLS
#endif /* _KERNEL */
@@ -161,8 +162,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
@@ -291,6 +291,8 @@
#endif
void ptrace_unsuspend(struct proc *p);
+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;
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -543,4 +543,5 @@
#define SYS_renameat2 602
#define SYS_pdopenpid 603
#define SYS_pddupfd 604
-#define SYS_MAXSYSCALL 605
+#define SYS_pdptrace 605
+#define SYS_MAXSYSCALL 606
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -446,4 +446,5 @@
pdwait.o \
renameat2.o \
pdopenpid.o \
- pddupfd.o
+ pddupfd.o \
+ pdptrace.o
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -1941,6 +1941,13 @@
char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
};
+struct pdptrace_args {
+ char req_l_[PADL_(int)]; int req; char req_r_[PADR_(int)];
+ char pfd_l_[PADL_(int)]; int pfd; char pfd_r_[PADR_(int)];
+ char lwpid_l_[PADL_(int)]; int lwpid; char lwpid_r_[PADR_(int)];
+ char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)];
+ char data_l_[PADL_(int)]; int data; char data_r_[PADR_(int)];
+};
int sys__exit(struct thread *, struct _exit_args *);
int sys_fork(struct thread *, struct fork_args *);
int sys_read(struct thread *, struct read_args *);
@@ -2353,6 +2360,7 @@
int sys_renameat2(struct thread *, struct renameat2_args *);
int sys_pdopenpid(struct thread *, struct pdopenpid_args *);
int sys_pddupfd(struct thread *, struct pddupfd_args *);
+int sys_pdptrace(struct thread *, struct pdptrace_args *);
#ifdef COMPAT_43
@@ -3357,6 +3365,7 @@
#define SYS_AUE_renameat2 AUE_RENAMEAT
#define SYS_AUE_pdopenpid AUE_PDOPENPID
#define SYS_AUE_pddupfd AUE_NULL
+#define SYS_AUE_pdptrace AUE_PDPTRACE
#undef PAD_
#undef PADL_

File Metadata

Mime Type
text/plain
Expires
Sat, Aug 29, 1:49 AM (16 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37486137
Default Alt Text
D58586.id185223.diff (35 KB)

Event Timeline