vfs: respect PRIV_VFS_LOOKUP in vaccess_smr

Reported by:	novel
This commit is contained in:
Mateusz Guzik 2020-08-25 14:18:50 +00:00
parent 411096d034
commit a459a6cfe7
4 changed files with 72 additions and 4 deletions

View File

@ -3049,6 +3049,7 @@ prison_priv_check(struct ucred *cred, int priv)
* called for them. See priv_check_cred().
*/
switch (priv) {
case PRIV_VFS_LOOKUP:
case PRIV_VFS_GENERATION:
KASSERT(0, ("prison_priv_check instead of a custom handler "
"called for %d\n", priv));
@ -3277,7 +3278,6 @@ prison_priv_check(struct ucred *cred, int priv)
case PRIV_VFS_WRITE:
case PRIV_VFS_ADMIN:
case PRIV_VFS_EXEC:
case PRIV_VFS_LOOKUP:
case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */
case PRIV_VFS_CHFLAGS_DEV:
case PRIV_VFS_CHOWN:

View File

@ -129,6 +129,8 @@ priv_check_cred(struct ucred *cred, int priv)
priv));
switch (priv) {
case PRIV_VFS_LOOKUP:
return (priv_check_cred_vfs_lookup(cred));
case PRIV_VFS_GENERATION:
return (priv_check_cred_vfs_generation(cred));
}
@ -247,6 +249,56 @@ priv_check(struct thread *td, int priv)
return (priv_check_cred(td->td_ucred, priv));
}
static int __noinline
priv_check_cred_vfs_lookup_slow(struct ucred *cred)
{
int error;
error = priv_check_cred_pre(cred, PRIV_VFS_LOOKUP);
if (error)
goto out;
if (cred->cr_uid == 0 && suser_enabled) {
error = 0;
goto out;
}
return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, false));
out:
return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, true));
}
int
priv_check_cred_vfs_lookup(struct ucred *cred)
{
int error;
if (__predict_false(mac_priv_check_fp_flag ||
mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
return (priv_check_cred_vfs_lookup_slow(cred));
error = EPERM;
if (cred->cr_uid == 0 && suser_enabled)
error = 0;
return (error);
}
int
priv_check_cred_vfs_lookup_nomac(struct ucred *cred)
{
int error;
if (__predict_false(mac_priv_check_fp_flag ||
mac_priv_grant_fp_flag || SDT_PROBES_ENABLED()))
return (EAGAIN);
error = EPERM;
if (cred->cr_uid == 0 && suser_enabled)
error = 0;
return (error);
}
static int __noinline
priv_check_cred_vfs_generation_slow(struct ucred *cred)
{

View File

@ -5045,6 +5045,7 @@ vn_isdisk(struct vnode *vp)
int
vaccess_vexec_smr(mode_t file_mode, uid_t file_uid, gid_t file_gid, struct ucred *cred)
{
int error;
VFS_SMR_ASSERT_ENTERED();
@ -5067,7 +5068,9 @@ vaccess_vexec_smr(mode_t file_mode, uid_t file_uid, gid_t file_gid, struct ucred
return (0);
out_error:
/*
* Permission check failed.
* Permission check failed, but it is possible denial will get overwritten
* (e.g., when root is traversing through a 700 directory owned by someone
* else).
*
* vaccess() calls priv_check_cred which in turn can descent into MAC
* modules overriding this result. It's quite unclear what semantics
@ -5075,9 +5078,20 @@ out_error:
* from within the SMR section. This also means if any such modules
* are present, we have to let the regular lookup decide.
*/
if (__predict_false(mac_priv_check_fp_flag || mac_priv_grant_fp_flag))
error = priv_check_cred_vfs_lookup_nomac(cred);
switch (error) {
case 0:
return (0);
case EAGAIN:
/*
* MAC modules present.
*/
return (EAGAIN);
return (EACCES);
case EPERM:
return (EACCES);
default:
return (error);
}
}
/*

View File

@ -536,6 +536,8 @@ struct thread;
struct ucred;
int priv_check(struct thread *td, int priv);
int priv_check_cred(struct ucred *cred, int priv);
int priv_check_cred_vfs_lookup(struct ucred *cred);
int priv_check_cred_vfs_lookup_nomac(struct ucred *cred);
int priv_check_cred_vfs_generation(struct ucred *cred);
#endif