mirror of
https://github.com/freebsd/freebsd-src
synced 2024-07-22 10:48:02 +00:00
ktrace: Record namei violations with KTR_CAPFAIL
Report namei path lookups while Capsicum violation tracing with CAPFAIL_NAMEI. vfs caching is also ignored when tracing to mimic capability mode behavior. Reviewed by: markj Approved by: markj (mentor) MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D40680
This commit is contained in:
parent
6a4616a529
commit
0cd9cde767
|
@ -3054,7 +3054,7 @@ fgetvp_lookup_smr(struct nameidata *ndp, struct vnode **vpp, bool *fsearch)
|
|||
ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL ||
|
||||
ndp->ni_filecaps.fc_nioctls != -1) {
|
||||
#ifdef notyet
|
||||
ndp->ni_lcf |= NI_LCF_STRICTRELATIVE;
|
||||
ndp->ni_lcf |= NI_LCF_STRICTREL;
|
||||
#else
|
||||
return (EAGAIN);
|
||||
#endif
|
||||
|
@ -3146,7 +3146,7 @@ fgetvp_lookup(struct nameidata *ndp, struct vnode **vpp)
|
|||
if (!cap_rights_contains(&ndp->ni_filecaps.fc_rights, &rights) ||
|
||||
ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL ||
|
||||
ndp->ni_filecaps.fc_nioctls != -1) {
|
||||
ndp->ni_lcf |= NI_LCF_STRICTRELATIVE;
|
||||
ndp->ni_lcf |= NI_LCF_STRICTREL;
|
||||
ndp->ni_resflags |= NIRES_STRICTREL;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -454,6 +454,8 @@ do_execve(struct thread *td, struct image_args *args, struct mac *mac_p,
|
|||
interpret:
|
||||
if (args->fname != NULL) {
|
||||
#ifdef CAPABILITY_MODE
|
||||
if (CAP_TRACING(td))
|
||||
ktrcapfail(CAPFAIL_NAMEI, args->fname);
|
||||
/*
|
||||
* While capability mode can't reach this point via direct
|
||||
* path arguments to execve(), we also don't allow
|
||||
|
|
|
@ -1177,8 +1177,12 @@ kern_shm_open2(struct thread *td, const char *userpath, int flags, mode_t mode,
|
|||
/*
|
||||
* shm_open(2) is only allowed for anonymous objects.
|
||||
*/
|
||||
if (IN_CAPABILITY_MODE(td) && (userpath != SHM_ANON))
|
||||
return (ECAPMODE);
|
||||
if (userpath != SHM_ANON) {
|
||||
if (CAP_TRACING(td))
|
||||
ktrcapfail(CAPFAIL_NAMEI, userpath);
|
||||
if (IN_CAPABILITY_MODE(td))
|
||||
return (ECAPMODE);
|
||||
}
|
||||
#endif
|
||||
|
||||
AUDIT_ARG_FFLAGS(flags);
|
||||
|
|
|
@ -199,8 +199,12 @@ kern_bindat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
|
|||
int error;
|
||||
|
||||
#ifdef CAPABILITY_MODE
|
||||
if (IN_CAPABILITY_MODE(td) && (dirfd == AT_FDCWD))
|
||||
return (ECAPMODE);
|
||||
if (dirfd == AT_FDCWD) {
|
||||
if (CAP_TRACING(td))
|
||||
ktrcapfail(CAPFAIL_NAMEI, "AT_FDCWD");
|
||||
if (IN_CAPABILITY_MODE(td))
|
||||
return (ECAPMODE);
|
||||
}
|
||||
#endif
|
||||
|
||||
AUDIT_ARG_FD(fd);
|
||||
|
@ -468,8 +472,12 @@ kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
|
|||
int error;
|
||||
|
||||
#ifdef CAPABILITY_MODE
|
||||
if (IN_CAPABILITY_MODE(td) && (dirfd == AT_FDCWD))
|
||||
return (ECAPMODE);
|
||||
if (dirfd == AT_FDCWD) {
|
||||
if (CAP_TRACING(td))
|
||||
ktrcapfail(CAPFAIL_NAMEI, "AT_FDCWD");
|
||||
if (IN_CAPABILITY_MODE(td))
|
||||
return (ECAPMODE);
|
||||
}
|
||||
#endif
|
||||
|
||||
AUDIT_ARG_FD(fd);
|
||||
|
|
|
@ -4483,7 +4483,7 @@ cache_can_fplookup(struct cache_fpl *fpl)
|
|||
cache_fpl_aborted_early(fpl);
|
||||
return (false);
|
||||
}
|
||||
if (IN_CAPABILITY_MODE(td)) {
|
||||
if (IN_CAPABILITY_MODE(td) || CAP_TRACING(td)) {
|
||||
cache_fpl_aborted_early(fpl);
|
||||
return (false);
|
||||
}
|
||||
|
|
|
@ -236,14 +236,17 @@ nameicap_check_dotdot(struct nameidata *ndp, struct vnode *dp)
|
|||
struct mount *mp;
|
||||
|
||||
if (dp == NULL || dp->v_type != VDIR || (ndp->ni_lcf &
|
||||
NI_LCF_STRICTRELATIVE) == 0)
|
||||
NI_LCF_STRICTREL) == 0)
|
||||
return (0);
|
||||
if (__predict_false((ndp->ni_lcf & (NI_LCF_STRICTREL_KTR |
|
||||
NI_LCF_CAP_DOTDOT_KTR)) == NI_LCF_STRICTREL_KTR))
|
||||
NI_CAP_VIOLATION(ndp, ndp->ni_cnd.cn_pnbuf);
|
||||
if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0)
|
||||
return (ENOTCAPABLE);
|
||||
mp = dp->v_mount;
|
||||
if (lookup_cap_dotdot_nonlocal == 0 && mp != NULL &&
|
||||
(mp->mnt_flag & MNT_LOCAL) == 0)
|
||||
return (ENOTCAPABLE);
|
||||
goto capfail;
|
||||
TAILQ_FOREACH_REVERSE(nt, &ndp->ni_cap_tracker, nameicap_tracker_head,
|
||||
nm_link) {
|
||||
if (dp == nt->dp) {
|
||||
|
@ -253,6 +256,10 @@ nameicap_check_dotdot(struct nameidata *ndp, struct vnode *dp)
|
|||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
capfail:
|
||||
if (__predict_false((ndp->ni_lcf & NI_LCF_STRICTREL_KTR) != 0))
|
||||
NI_CAP_VIOLATION(ndp, ndp->ni_cnd.cn_pnbuf);
|
||||
return (ENOTCAPABLE);
|
||||
}
|
||||
|
||||
|
@ -271,12 +278,12 @@ namei_handle_root(struct nameidata *ndp, struct vnode **dpp)
|
|||
struct componentname *cnp;
|
||||
|
||||
cnp = &ndp->ni_cnd;
|
||||
if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0) {
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(curthread, KTR_CAPFAIL))
|
||||
ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
|
||||
#endif
|
||||
return (ENOTCAPABLE);
|
||||
if (__predict_false((ndp->ni_lcf & (NI_LCF_STRICTREL |
|
||||
NI_LCF_STRICTREL_KTR)) != 0)) {
|
||||
if ((ndp->ni_lcf & NI_LCF_STRICTREL_KTR) != 0)
|
||||
NI_CAP_VIOLATION(ndp, cnp->cn_pnbuf);
|
||||
if ((ndp->ni_lcf & NI_LCF_STRICTREL) != 0)
|
||||
return (ENOTCAPABLE);
|
||||
}
|
||||
while (*(cnp->cn_nameptr) == '/') {
|
||||
cnp->cn_nameptr++;
|
||||
|
@ -317,15 +324,17 @@ namei_setup(struct nameidata *ndp, struct vnode **dpp, struct pwd **pwdp)
|
|||
* previously walked by us, which prevents an escape from
|
||||
* the relative root.
|
||||
*/
|
||||
if (IN_CAPABILITY_MODE(td) && (cnp->cn_flags & NOCAPCHECK) == 0) {
|
||||
ndp->ni_lcf |= NI_LCF_STRICTRELATIVE;
|
||||
ndp->ni_resflags |= NIRES_STRICTREL;
|
||||
if (ndp->ni_dirfd == AT_FDCWD) {
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(td, KTR_CAPFAIL))
|
||||
ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
|
||||
#endif
|
||||
return (ECAPMODE);
|
||||
if ((cnp->cn_flags & NOCAPCHECK) == 0) {
|
||||
if (CAP_TRACING(td)) {
|
||||
ndp->ni_lcf |= NI_LCF_STRICTREL_KTR;
|
||||
if (ndp->ni_dirfd == AT_FDCWD)
|
||||
NI_CAP_VIOLATION(ndp, "AT_FDCWD");
|
||||
}
|
||||
if (IN_CAPABILITY_MODE(td)) {
|
||||
ndp->ni_lcf |= NI_LCF_STRICTREL;
|
||||
ndp->ni_resflags |= NIRES_STRICTREL;
|
||||
if (ndp->ni_dirfd == AT_FDCWD)
|
||||
return (ECAPMODE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -368,8 +377,8 @@ namei_setup(struct nameidata *ndp, struct vnode **dpp, struct pwd **pwdp)
|
|||
if (error == 0 && (cnp->cn_flags & RBENEATH) != 0) {
|
||||
if (cnp->cn_pnbuf[0] == '/') {
|
||||
error = ENOTCAPABLE;
|
||||
} else if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) == 0) {
|
||||
ndp->ni_lcf |= NI_LCF_STRICTRELATIVE |
|
||||
} else if ((ndp->ni_lcf & NI_LCF_STRICTREL) == 0) {
|
||||
ndp->ni_lcf |= NI_LCF_STRICTREL |
|
||||
NI_LCF_CAP_DOTDOT;
|
||||
}
|
||||
}
|
||||
|
@ -391,9 +400,12 @@ namei_setup(struct nameidata *ndp, struct vnode **dpp, struct pwd **pwdp)
|
|||
pwd_drop(pwd);
|
||||
return (error);
|
||||
}
|
||||
if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 &&
|
||||
lookup_cap_dotdot != 0)
|
||||
ndp->ni_lcf |= NI_LCF_CAP_DOTDOT;
|
||||
if (lookup_cap_dotdot != 0) {
|
||||
if ((ndp->ni_lcf & NI_LCF_STRICTREL_KTR) != 0)
|
||||
ndp->ni_lcf |= NI_LCF_CAP_DOTDOT_KTR;
|
||||
if ((ndp->ni_lcf & NI_LCF_STRICTREL) != 0)
|
||||
ndp->ni_lcf |= NI_LCF_CAP_DOTDOT;
|
||||
}
|
||||
SDT_PROBE4(vfs, namei, lookup, entry, *dpp, cnp->cn_pnbuf,
|
||||
cnp->cn_flags, false);
|
||||
*pwdp = pwd;
|
||||
|
@ -1168,12 +1180,11 @@ vfs_lookup(struct nameidata *ndp)
|
|||
* result of dotdot lookup.
|
||||
*/
|
||||
if (cnp->cn_flags & ISDOTDOT) {
|
||||
if ((ndp->ni_lcf & (NI_LCF_STRICTRELATIVE | NI_LCF_CAP_DOTDOT))
|
||||
== NI_LCF_STRICTRELATIVE) {
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(curthread, KTR_CAPFAIL))
|
||||
ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
|
||||
#endif
|
||||
if (__predict_false((ndp->ni_lcf & (NI_LCF_STRICTREL_KTR |
|
||||
NI_LCF_CAP_DOTDOT_KTR)) == NI_LCF_STRICTREL_KTR))
|
||||
NI_CAP_VIOLATION(ndp, cnp->cn_pnbuf);
|
||||
if (__predict_false((ndp->ni_lcf & (NI_LCF_STRICTREL |
|
||||
NI_LCF_CAP_DOTDOT)) == NI_LCF_STRICTREL)) {
|
||||
error = ENOTCAPABLE;
|
||||
goto bad;
|
||||
}
|
||||
|
@ -1190,10 +1201,14 @@ vfs_lookup(struct nameidata *ndp)
|
|||
bool isroot = dp == ndp->ni_rootdir ||
|
||||
dp == ndp->ni_topdir || dp == rootvnode ||
|
||||
pr != NULL;
|
||||
if (isroot && (ndp->ni_lcf &
|
||||
NI_LCF_STRICTRELATIVE) != 0) {
|
||||
error = ENOTCAPABLE;
|
||||
goto capdotdot;
|
||||
if (__predict_false(isroot && (ndp->ni_lcf &
|
||||
(NI_LCF_STRICTREL | NI_LCF_STRICTREL_KTR)) != 0)) {
|
||||
if ((ndp->ni_lcf & NI_LCF_STRICTREL_KTR) != 0)
|
||||
NI_CAP_VIOLATION(ndp, cnp->cn_pnbuf);
|
||||
if ((ndp->ni_lcf & NI_LCF_STRICTREL) != 0) {
|
||||
error = ENOTCAPABLE;
|
||||
goto capdotdot;
|
||||
}
|
||||
}
|
||||
if (isroot || ((dp->v_vflag & VV_ROOT) != 0 &&
|
||||
(cnp->cn_flags & NOCROSSMOUNT) != 0)) {
|
||||
|
@ -1218,10 +1233,6 @@ vfs_lookup(struct nameidata *ndp)
|
|||
error = nameicap_check_dotdot(ndp, dp);
|
||||
if (error != 0) {
|
||||
capdotdot:
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(curthread, KTR_CAPFAIL))
|
||||
ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
|
||||
#endif
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
@ -1374,13 +1385,8 @@ vfs_lookup(struct nameidata *ndp)
|
|||
}
|
||||
if (cnp->cn_flags & ISDOTDOT) {
|
||||
error = nameicap_check_dotdot(ndp, ndp->ni_vp);
|
||||
if (error != 0) {
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(curthread, KTR_CAPFAIL))
|
||||
ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
|
||||
#endif
|
||||
if (error != 0)
|
||||
goto bad2;
|
||||
}
|
||||
}
|
||||
if (*ndp->ni_next == '/') {
|
||||
cnp->cn_nameptr = ndp->ni_next;
|
||||
|
|
|
@ -196,8 +196,17 @@ int cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status,
|
|||
/*
|
||||
* Flags in ni_lcf, valid for the duration of the namei call.
|
||||
*/
|
||||
#define NI_LCF_STRICTRELATIVE 0x0001 /* relative lookup only */
|
||||
#define NI_LCF_STRICTREL 0x0001 /* relative lookup only */
|
||||
#define NI_LCF_CAP_DOTDOT 0x0002 /* ".." in strictrelative case */
|
||||
/* Track capability restrictions seperately for violation ktracing. */
|
||||
#define NI_LCF_STRICTREL_KTR 0x0004 /* trace relative lookups */
|
||||
#define NI_LCF_CAP_DOTDOT_KTR 0x0008 /* ".." in strictrelative case */
|
||||
#define NI_LCF_KTR_FLAGS (NI_LCF_STRICTREL_KTR | NI_LCF_CAP_DOTDOT_KTR)
|
||||
|
||||
#define NI_CAP_VIOLATION(ndp, path) do { \
|
||||
ktrcapfail(CAPFAIL_NAMEI, (path)); \
|
||||
(ndp)->ni_lcf &= ~NI_LCF_KTR_FLAGS; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Initialization of a nameidata structure.
|
||||
|
|
Loading…
Reference in a new issue