Revisit the capability failure trace points. The initial implementation
only logged instances where an operation on a file descriptor required capabilities which the file descriptor did not have. By adding a type enum to struct ktr_cap_fail, we can catch other types of capability failures as well, such as disallowed system calls or attempts to wrap a file descriptor with more capabilities than it had to begin with.
This commit is contained in:
parent
2c0dd4bbe4
commit
e141be6f79
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=226495
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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 @@ lookup(struct nameidata *ndp)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
@ -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) \
|
||||
|
@ -1592,10 +1592,36 @@ ktrstruct(char *buf, size_t buflen)
|
||||
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__)
|
||||
|
Loading…
Reference in New Issue
Block a user