diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -923,14 +923,17 @@ } void -ktrcapfail(enum ktr_cap_fail_type type, const cap_rights_t *needed, - const cap_rights_t *held) +ktrcapfail(enum ktr_cap_violation type, const void *data) { struct thread *td = curthread; struct ktr_request *req; struct ktr_cap_fail *kcf; + union ktr_cap_data *kcd; - if (__predict_false(curthread->td_pflags & TDP_INKTRACE)) + if (__predict_false(td->td_pflags & TDP_INKTRACE)) + return; + if (type != CAPFAIL_SYSCALL && + (td->td_sa.callp->sy_flags & SYF_CAPENABLED) == 0) return; req = ktr_getrequest(KTR_CAPFAIL); @@ -938,14 +941,32 @@ return; kcf = &req->ktr_data.ktr_cap_fail; kcf->cap_type = type; - if (needed != NULL) - kcf->cap_needed = *needed; - else - cap_rights_init(&kcf->cap_needed); - if (held != NULL) - kcf->cap_held = *held; - else - cap_rights_init(&kcf->cap_held); + kcf->cap_code = td->td_sa.code; + kcf->cap_svflags = td->td_proc->p_sysent->sv_flags; + if (data != NULL) { + kcd = &kcf->cap_data; + switch (type) { + case CAPFAIL_NOTCAPABLE: + case CAPFAIL_INCREASE: + kcd->cap_needed = *(const cap_rights_t *)data; + kcd->cap_held = *((const cap_rights_t *)data + 1); + break; + case CAPFAIL_SYSCALL: + case CAPFAIL_SIGNAL: + case CAPFAIL_PROTO: + kcd->cap_int = *(const int *)data; + break; + case CAPFAIL_SOCKADDR: + kcd->cap_sockaddr = *(const struct sockaddr *)data; + break; + case CAPFAIL_NAMEI: + strlcpy(kcd->cap_path, data, MAXPATHLEN); + break; + case CAPFAIL_CPUSET: + default: + break; + } + } ktr_enqueuerequest(td, req); ktrace_exit(td); } diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -154,14 +154,13 @@ static inline int _cap_check(const cap_rights_t *havep, const cap_rights_t *needp, - enum ktr_cap_fail_type type) + enum ktr_cap_violation type) { + const cap_rights_t rights[] = { *needp, *havep }; if (!cap_rights_contains(havep, needp)) { -#ifdef KTRACE - if (KTRPOINT(curthread, KTR_CAPFAIL)) - ktrcapfail(type, needp, havep); -#endif + if (CAP_TRACING(curthread)) + ktrcapfail(type, rights); return (ENOTCAPABLE); } return (0); @@ -180,11 +179,10 @@ int cap_check_failed_notcapable(const cap_rights_t *havep, const cap_rights_t *needp) { + const cap_rights_t rights[] = { *needp, *havep }; -#ifdef KTRACE - if (KTRPOINT(curthread, KTR_CAPFAIL)) - ktrcapfail(CAPFAIL_NOTCAPABLE, needp, havep); -#endif + if (CAP_TRACING(curthread)) + ktrcapfail(CAPFAIL_NOTCAPABLE, rights); return (ENOTCAPABLE); } diff --git a/sys/sys/capsicum.h b/sys/sys/capsicum.h --- a/sys/sys/capsicum.h +++ b/sys/sys/capsicum.h @@ -44,6 +44,7 @@ #include #include #include +#include #ifndef _KERNEL #include @@ -419,6 +420,12 @@ #include +#ifdef KTRACE +#define CAP_TRACING(td) KTRPOINT((td), KTR_CAPFAIL) +#else +#define CAP_TRACING(td) 0 +#endif + #define IN_CAPABILITY_MODE(td) (((td)->td_ucred->cr_flags & CRED_FLAG_CAPMODE) != 0) struct filedesc; diff --git a/sys/sys/ktrace.h b/sys/sys/ktrace.h --- a/sys/sys/ktrace.h +++ b/sys/sys/ktrace.h @@ -32,8 +32,10 @@ #ifndef _SYS_KTRACE_H_ #define _SYS_KTRACE_H_ +#include #include #include +#include #include /* @@ -205,16 +207,31 @@ * KTR_CAPFAIL - trace capability check failures */ #define KTR_CAPFAIL 12 -enum ktr_cap_fail_type { +enum ktr_cap_violation { CAPFAIL_NOTCAPABLE, /* insufficient capabilities in cap_check() */ - CAPFAIL_INCREASE, /* attempt to increase capabilities */ + CAPFAIL_INCREASE, /* attempt to increase rights on a capability */ CAPFAIL_SYSCALL, /* disallowed system call */ - CAPFAIL_LOOKUP, /* disallowed VFS lookup */ + CAPFAIL_SIGNAL, /* sent signal to process other than self */ + CAPFAIL_PROTO, /* disallowed protocol */ + CAPFAIL_SOCKADDR, /* restricted address lookup */ + CAPFAIL_NAMEI, /* restricted namei lookup */ + CAPFAIL_CPUSET, /* restricted CPU set modification */ }; + +union ktr_cap_data { + cap_rights_t cap_rights[2]; +#define cap_needed cap_rights[0] +#define cap_held cap_rights[1] + int cap_int; + struct sockaddr cap_sockaddr; + char cap_path[MAXPATHLEN]; +}; + struct ktr_cap_fail { - enum ktr_cap_fail_type cap_type; - cap_rights_t cap_needed; - cap_rights_t cap_held; + enum ktr_cap_violation cap_type; + short cap_code; + u_int cap_svflags; + union ktr_cap_data cap_data; }; /* @@ -317,8 +334,7 @@ void ktrstruct(const char *, const void *, size_t); void ktrstruct_error(const char *, const void *, size_t, int); void ktrstructarray(const char *, enum uio_seg, const void *, int, size_t); -void ktrcapfail(enum ktr_cap_fail_type, const cap_rights_t *, - const cap_rights_t *); +void ktrcapfail(enum ktr_cap_violation, const void *); #define ktrcaprights(s) \ ktrstruct("caprights", (s), sizeof(cap_rights_t)) #define ktritimerval(s) \ diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c --- a/usr.bin/kdump/kdump.c +++ b/usr.bin/kdump/kdump.c @@ -2125,35 +2125,74 @@ void ktrcapfail(struct ktr_cap_fail *ktr) { + union ktr_cap_data *kcd = &ktr->cap_data; + switch (ktr->cap_type) { case CAPFAIL_NOTCAPABLE: /* operation on fd with insufficient capabilities */ printf("operation requires "); - sysdecode_cap_rights(stdout, &ktr->cap_needed); + sysdecode_cap_rights(stdout, &kcd->cap_needed); printf(", descriptor holds "); - sysdecode_cap_rights(stdout, &ktr->cap_held); + sysdecode_cap_rights(stdout, &kcd->cap_held); break; case CAPFAIL_INCREASE: /* requested more capabilities than fd already has */ printf("attempt to increase capabilities from "); - sysdecode_cap_rights(stdout, &ktr->cap_held); + sysdecode_cap_rights(stdout, &kcd->cap_held); printf(" to "); - sysdecode_cap_rights(stdout, &ktr->cap_needed); + sysdecode_cap_rights(stdout, &kcd->cap_needed); break; case CAPFAIL_SYSCALL: /* called restricted syscall */ - printf("disallowed system call"); + printf("system call not allowed: "); + syscallname(ktr->cap_code, ktr->cap_svflags); + if (syscallabi(ktr->cap_svflags) == SYSDECODE_ABI_FREEBSD) { + switch (ktr->cap_code) { + case SYS_sysarch: + printf(", op: "); + print_integer_arg(sysdecode_sysarch_number, + kcd->cap_int); + break; + case SYS_fcntl: + printf(", cmd: "); + print_integer_arg(sysdecode_fcntl_cmd, + kcd->cap_int); + break; + } + } break; - case CAPFAIL_LOOKUP: - /* absolute or AT_FDCWD path, ".." path, etc. */ - printf("restricted VFS lookup"); + case CAPFAIL_SIGNAL: + /* sent signal to proc other than self */ + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": signal delivery not allowed: "); + print_integer_arg(sysdecode_signal, kcd->cap_int); break; - default: - printf("unknown capability failure: "); - sysdecode_cap_rights(stdout, &ktr->cap_needed); - printf(" "); - sysdecode_cap_rights(stdout, &ktr->cap_held); + case CAPFAIL_PROTO: + /* created socket with restricted protocol */ + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": protocol not allowed: "); + print_integer_arg(sysdecode_ipproto, kcd->cap_int); break; + case CAPFAIL_SOCKADDR: + /* unable to look up address */ + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": restricted address lookup: "); + ktrsockaddr(&kcd->cap_sockaddr); + return; + case CAPFAIL_NAMEI: + /* absolute or AT_FDCWD path, ".." path, etc. */ + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": restricted VFS lookup: %s\n", kcd->cap_path); + return; + case CAPFAIL_CPUSET: + /* modification of an external cpuset */ + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": restricted cpuset operation\n"); + return; + default: + syscallname(ktr->cap_code, ktr->cap_svflags); + printf(": unknown capability failure\n"); + return; } printf("\n"); }