Add PROC_TRAPCAP procctl(2) controls and global sysctl kern.trap_enocap.
Both can be used to cause processes in capability mode to receive SIGTRAP when ENOTCAPABLE or ECAPMODE errors are returned from syscalls. Idea by: emaste Reviewed by: oshogbo (previous version), emaste Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D7965
This commit is contained in:
parent
5271129cd6
commit
643f6f47fd
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=306081
@ -3048,6 +3048,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
|
||||
switch (uap->com) {
|
||||
case PROC_SPROTECT:
|
||||
case PROC_TRACE_CTL:
|
||||
case PROC_TRAPCAP_CTL:
|
||||
error = copyin(PTRIN(uap->data), &flags, sizeof(flags));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
@ -3077,6 +3078,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
|
||||
data = &x.rk;
|
||||
break;
|
||||
case PROC_TRACE_STATUS:
|
||||
case PROC_TRAPCAP_STATUS:
|
||||
data = &flags;
|
||||
break;
|
||||
default:
|
||||
@ -3095,6 +3097,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_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;
|
||||
|
@ -497,7 +497,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);
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -368,6 +368,8 @@ int cap_ioctl_check(struct filedesc *fdp, int fd, u_long cmd);
|
||||
int cap_fcntl_check_fde(struct filedescent *fde, int cmd);
|
||||
int cap_fcntl_check(struct filedesc *fdp, int fd, int cmd);
|
||||
|
||||
extern int trap_enotcap;
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
@ -716,6 +716,7 @@ struct proc {
|
||||
#define P2_NOTRACE_EXEC 0x00000004 /* Keep P2_NOPTRACE on exec(2). */
|
||||
#define P2_AST_SU 0x00000008 /* Handles SU ast for kthreads. */
|
||||
#define P2_PTRACE_FSTP 0x00000010 /* SIGSTOP from PT_ATTACH not yet handled. */
|
||||
#define P2_TRAPCAP 0x00000020 /* SIGTRAP on ENOTCAPABLE */
|
||||
|
||||
/* Flags protected by proctree_lock, kept in p_treeflags. */
|
||||
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
|
||||
|
@ -43,6 +43,8 @@
|
||||
#define PROC_REAP_KILL 6 /* kill descendants */
|
||||
#define PROC_TRACE_CTL 7 /* en/dis ptrace and coredumps */
|
||||
#define PROC_TRACE_STATUS 8 /* query tracing status */
|
||||
#define PROC_TRAPCAP_CTL 9 /* trap capability errors */
|
||||
#define PROC_TRAPCAP_STATUS 10 /* query trap capability status */
|
||||
|
||||
/* Operations for PROC_SPROTECT (passed in integer arg). */
|
||||
#define PPROT_OP(x) ((x) & 0xf)
|
||||
@ -102,6 +104,9 @@ struct procctl_reaper_kill {
|
||||
#define PROC_TRACE_CTL_DISABLE 2
|
||||
#define PROC_TRACE_CTL_DISABLE_EXEC 3
|
||||
|
||||
#define PROC_TRAPCAP_CTL_ENABLE 1
|
||||
#define PROC_TRAPCAP_CTL_DISABLE 2
|
||||
|
||||
#ifndef _KERNEL
|
||||
__BEGIN_DECLS
|
||||
int procctl(idtype_t, id_t, int, void *);
|
||||
|
@ -291,6 +291,7 @@ typedef struct __siginfo {
|
||||
#define TRAP_BRKPT 1 /* Process breakpoint. */
|
||||
#define TRAP_TRACE 2 /* Process trace trap. */
|
||||
#define TRAP_DTRACE 3 /* DTrace induced trap. */
|
||||
#define TRAP_CAP 4 /* Capabilities protective trap. */
|
||||
|
||||
/* codes for SIGCHLD */
|
||||
#define CLD_EXITED 1 /* Child has exited */
|
||||
|
Loading…
Reference in New Issue
Block a user