diff options
-rw-r--r-- | sys/kern/kern_ktrace.c | 4 | ||||
-rw-r--r-- | sys/kern/sys_capability.c | 10 | ||||
-rw-r--r-- | sys/kern/vfs_lookup.c | 18 | ||||
-rw-r--r-- | sys/sys/ktrace.h | 9 | ||||
-rw-r--r-- | usr.bin/kdump/kdump.c | 34 |
5 files changed, 65 insertions, 10 deletions
diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index bf99971..3bb529f 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -772,7 +772,8 @@ ktrstruct(name, data, datalen) } void -ktrcapfail(needed, held) +ktrcapfail(type, needed, held) + enum ktr_cap_fail_type type; cap_rights_t needed; cap_rights_t held; { @@ -784,6 +785,7 @@ ktrcapfail(needed, held) if (req == NULL) return; kcf = &req->ktr_data.ktr_cap_fail; + kcf->cap_type = type; kcf->cap_needed = needed; kcf->cap_held = held; ktr_enqueuerequest(td, req); diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index b22cfb2..f1fb1b1 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -218,7 +218,7 @@ cap_check(struct capability *c, cap_rights_t rights) if ((c->cap_rights | rights) != c->cap_rights) { #ifdef KTRACE if (KTRPOINT(curthread, KTR_CAPFAIL)) - ktrcapfail(rights, c->cap_rights); + ktrcapfail(CAPFAIL_NOTCAPABLE, rights, c->cap_rights); #endif return (ENOTCAPABLE); } @@ -314,8 +314,14 @@ kern_capwrap(struct thread *td, struct file *fp, cap_rights_t rights, */ if (fp->f_type == DTYPE_CAPABILITY) { cp_old = fp->f_data; - if ((cp_old->cap_rights | rights) != cp_old->cap_rights) + if ((cp_old->cap_rights | rights) != cp_old->cap_rights) { +#ifdef KTRACE + if (KTRPOINT(curthread, KTR_CAPFAIL)) + ktrcapfail(CAPFAIL_INCREASE, + rights, cp_old->cap_rights); +#endif return (ENOTCAPABLE); + } } /* diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index a145017..e2aad7c 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -188,8 +188,13 @@ namei(struct nameidata *ndp) */ if (IN_CAPABILITY_MODE(td)) { ndp->ni_strictrelative = 1; - if (ndp->ni_dirfd == AT_FDCWD) + if (ndp->ni_dirfd == AT_FDCWD) { +#ifdef KTRACE + if (KTRPOINT(td, KTR_CAPFAIL)) + ktrcapfail(CAPFAIL_LOOKUP, 0, 0); +#endif error = ECAPMODE; + } } #endif if (error) { @@ -281,8 +286,13 @@ namei(struct nameidata *ndp) if (*(cnp->cn_nameptr) == '/') { vrele(dp); VFS_UNLOCK_GIANT(vfslocked); - if (ndp->ni_strictrelative != 0) + if (ndp->ni_strictrelative != 0) { +#ifdef KTRACE + if (KTRPOINT(curthread, KTR_CAPFAIL)) + ktrcapfail(CAPFAIL_LOOKUP, 0, 0); +#endif return (ENOTCAPABLE); + } while (*(cnp->cn_nameptr) == '/') { cnp->cn_nameptr++; ndp->ni_pathlen--; @@ -644,6 +654,10 @@ dirloop: */ if (cnp->cn_flags & ISDOTDOT) { if (ndp->ni_strictrelative != 0) { +#ifdef KTRACE + if (KTRPOINT(curthread, KTR_CAPFAIL)) + ktrcapfail(CAPFAIL_LOOKUP, 0, 0); +#endif error = ENOTCAPABLE; goto bad; } diff --git a/sys/sys/ktrace.h b/sys/sys/ktrace.h index 592db6f..d537c1b 100644 --- a/sys/sys/ktrace.h +++ b/sys/sys/ktrace.h @@ -181,7 +181,14 @@ struct ktr_proc_ctor { * KTR_CAPFAIL - trace capability check failures */ #define KTR_CAPFAIL 12 +enum ktr_cap_fail_type { + CAPFAIL_NOTCAPABLE, /* insufficient capabilities in cap_check() */ + CAPFAIL_INCREASE, /* attempt to increase capabilities */ + CAPFAIL_SYSCALL, /* disallowed system call */ + CAPFAIL_LOOKUP, /* disallowed VFS lookup */ +}; struct ktr_cap_fail { + enum ktr_cap_fail_type cap_type; cap_rights_t cap_needed; cap_rights_t cap_held; }; @@ -230,7 +237,7 @@ void ktrprocexit(struct thread *); void ktrprocfork(struct proc *, struct proc *); void ktruserret(struct thread *); void ktrstruct(const char *, void *, size_t); -void ktrcapfail(cap_rights_t, cap_rights_t); +void ktrcapfail(enum ktr_cap_fail_type, cap_rights_t, cap_rights_t); #define ktrsockaddr(s) \ ktrstruct("sockaddr", (s), ((struct sockaddr *)(s))->sa_len) #define ktrstat(s) \ diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c index 45893df..2c5d03b 100644 --- a/usr.bin/kdump/kdump.c +++ b/usr.bin/kdump/kdump.c @@ -1592,10 +1592,36 @@ invalid: void ktrcapfail(struct ktr_cap_fail *ktr) { - printf("needed "); - capname((intmax_t)ktr->cap_needed); - printf(" held "); - capname((intmax_t)ktr->cap_held); + switch (ktr->cap_type) { + case CAPFAIL_NOTCAPABLE: + /* operation on fd with insufficient capabilities */ + printf("operation requires "); + capname((intmax_t)ktr->cap_needed); + printf(", process holds "); + capname((intmax_t)ktr->cap_held); + break; + case CAPFAIL_INCREASE: + /* requested more capabilities than fd already has */ + printf("attempt to increase capabilities from "); + capname((intmax_t)ktr->cap_needed); + printf(" to "); + capname((intmax_t)ktr->cap_held); + break; + case CAPFAIL_SYSCALL: + /* called restricted syscall */ + printf("disallowed system call"); + break; + case CAPFAIL_LOOKUP: + /* used ".." in strict-relative mode */ + printf("restricted VFS lookup"); + break; + default: + printf("unknown capability failure: "); + capname((intmax_t)ktr->cap_needed); + printf(" "); + capname((intmax_t)ktr->cap_held); + break; + } } #if defined(__amd64__) || defined(__i386__) |