diff options
author | kib <kib@FreeBSD.org> | 2016-09-28 09:28:26 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2016-09-28 09:28:26 +0000 |
commit | 99323399e34db51f6f54d27305ecdefe904a61cd (patch) | |
tree | bd9571099164439fc094a0b984670e3a87bca3f9 /sys/kern | |
parent | 71f3313e4975419065fd53a1c4cb6a135a94a686 (diff) | |
download | FreeBSD-src-99323399e34db51f6f54d27305ecdefe904a61cd.zip FreeBSD-src-99323399e34db51f6f54d27305ecdefe904a61cd.tar.gz |
MFC r306081:
Add PROC_TRAPCAP procctl(2) controls and global sysctl kern.trap_enocap.
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_fork.c | 2 | ||||
-rw-r--r-- | sys/kern/kern_procctl.c | 38 | ||||
-rw-r--r-- | sys/kern/subr_syscall.c | 15 | ||||
-rw-r--r-- | sys/kern/sys_capability.c | 4 |
4 files changed, 57 insertions, 2 deletions
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 818f44b..b288314 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -499,7 +499,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread * * Increase reference counts on shared objects. */ p2->p_flag = P_INMEM; - p2->p_flag2 = p1->p_flag2 & (P2_NOTRACE | P2_NOTRACE_EXEC); + p2->p_flag2 = p1->p_flag2 & (P2_NOTRACE | P2_NOTRACE_EXEC | P2_TRAPCAP); p2->p_swtick = ticks; if (p1->p_flag & P_PROFIL) startprofclock(p2); diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c index 8ef72901..d028e25 100644 --- a/sys/kern/kern_procctl.c +++ b/sys/kern/kern_procctl.c @@ -336,6 +336,34 @@ trace_status(struct thread *td, struct proc *p, int *data) return (0); } +static int +trapcap_ctl(struct thread *td, struct proc *p, int state) +{ + + PROC_LOCK_ASSERT(p, MA_OWNED); + + switch (state) { + case PROC_TRAPCAP_CTL_ENABLE: + p->p_flag2 |= P2_TRAPCAP; + break; + case PROC_TRAPCAP_CTL_DISABLE: + p->p_flag2 &= ~P2_TRAPCAP; + break; + default: + return (EINVAL); + } + return (0); +} + +static int +trapcap_status(struct thread *td, struct proc *p, int *data) +{ + + *data = (p->p_flag2 & P2_TRAPCAP) != 0 ? PROC_TRAPCAP_CTL_ENABLE : + PROC_TRAPCAP_CTL_DISABLE; + return (0); +} + #ifndef _SYS_SYSPROTO_H_ struct procctl_args { idtype_t idtype; @@ -359,6 +387,7 @@ sys_procctl(struct thread *td, struct procctl_args *uap) switch (uap->com) { case PROC_SPROTECT: case PROC_TRACE_CTL: + case PROC_TRAPCAP_CTL: error = copyin(uap->data, &flags, sizeof(flags)); if (error != 0) return (error); @@ -386,6 +415,7 @@ sys_procctl(struct thread *td, struct procctl_args *uap) data = &x.rk; break; case PROC_TRACE_STATUS: + case PROC_TRAPCAP_STATUS: data = &flags; break; default: @@ -403,6 +433,7 @@ sys_procctl(struct thread *td, struct procctl_args *uap) error = error1; break; case PROC_TRACE_STATUS: + case PROC_TRAPCAP_STATUS: if (error == 0) error = copyout(&flags, uap->data, sizeof(flags)); break; @@ -432,6 +463,10 @@ kern_procctl_single(struct thread *td, struct proc *p, int com, void *data) return (trace_ctl(td, p, *(int *)data)); case PROC_TRACE_STATUS: return (trace_status(td, p, data)); + case PROC_TRAPCAP_CTL: + return (trapcap_ctl(td, p, *(int *)data)); + case PROC_TRAPCAP_STATUS: + return (trapcap_status(td, p, data)); default: return (EINVAL); } @@ -452,6 +487,7 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data) case PROC_REAP_GETPIDS: case PROC_REAP_KILL: case PROC_TRACE_STATUS: + case PROC_TRAPCAP_STATUS: if (idtype != P_PID) return (EINVAL); } @@ -462,6 +498,7 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data) case PROC_REAP_GETPIDS: case PROC_REAP_KILL: case PROC_TRACE_CTL: + case PROC_TRAPCAP_CTL: sx_slock(&proctree_lock); tree_locked = true; break; @@ -471,6 +508,7 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data) tree_locked = true; break; case PROC_TRACE_STATUS: + case PROC_TRAPCAP_STATUS: tree_locked = false; break; default: diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c index 3e2a3b3..822976e 100644 --- a/sys/kern/subr_syscall.c +++ b/sys/kern/subr_syscall.c @@ -165,12 +165,25 @@ static inline void syscallret(struct thread *td, int error, struct syscall_args *sa) { struct proc *p, *p2; - int traced; + ksiginfo_t ksi; + int traced, error1; KASSERT((td->td_pflags & TDP_FORKING) == 0, ("fork() did not clear TDP_FORKING upon completion")); p = td->td_proc; + if ((trap_enotcap || (p->p_flag2 & P2_TRAPCAP) != 0) && + IN_CAPABILITY_MODE(td)) { + error1 = (td->td_pflags & TDP_NERRNO) == 0 ? error : + td->td_errno; + if (error1 == ENOTCAPABLE || error1 == ECAPMODE) { + ksiginfo_init_trap(&ksi); + ksi.ksi_signo = SIGTRAP; + ksi.ksi_errno = error1; + ksi.ksi_code = TRAP_CAP; + trapsignal(td, &ksi); + } + } /* * Handle reschedule and other end-of-syscall issues diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index e87f0b1..584d7ee 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -83,6 +83,10 @@ __FBSDID("$FreeBSD$"); #include <vm/uma.h> #include <vm/vm.h> +int trap_enotcap; +SYSCTL_INT(_kern, OID_AUTO, trap_enotcap, CTLFLAG_RW, &trap_enotcap, 0, + "Deliver SIGTRAP on ENOTCAPABLE"); + #ifdef CAPABILITY_MODE FEATURE(security_capability_mode, "Capsicum Capability Mode"); |