svn commit: r357888 - in head/sys: kern sys
Mateusz Guzik
mjg at FreeBSD.org
Thu Feb 13 22:22:16 UTC 2020
Author: mjg
Date: Thu Feb 13 22:22:15 2020
New Revision: 357888
URL: https://svnweb.freebsd.org/changeset/base/357888
Log:
Partially decompose priv_check by adding priv_check_cred_vfs_generation
During buildkernel there are very frequent calls to priv_check and they
all are for PRIV_VFS_GENERATION (coming from stat/fstat).
This results in branching on several potential privileges checking if
perhaps that's the one which has to be evaluated.
Instead of the kitchen-sink approach provide a way to have commonly used
privs directly evaluated.
Modified:
head/sys/kern/kern_jail.c
head/sys/kern/kern_priv.c
head/sys/kern/vfs_syscalls.c
head/sys/kern/vfs_vnops.c
head/sys/sys/priv.h
Modified: head/sys/kern/kern_jail.c
==============================================================================
--- head/sys/kern/kern_jail.c Thu Feb 13 22:19:17 2020 (r357887)
+++ head/sys/kern/kern_jail.c Thu Feb 13 22:22:15 2020 (r357888)
@@ -2998,6 +2998,16 @@ int
prison_priv_check(struct ucred *cred, int priv)
{
+ /*
+ * Some policies have custom handlers. This routine should not be
+ * called for them. See priv_check_cred().
+ */
+ switch (priv) {
+ case PRIV_VFS_GENERATION:
+ KASSERT(0, ("prison_priv_check instead of a custom handler "
+ "called for %d\n", priv));
+ }
+
if (!jailed(cred))
return (0);
Modified: head/sys/kern/kern_priv.c
==============================================================================
--- head/sys/kern/kern_priv.c Thu Feb 13 22:19:17 2020 (r357887)
+++ head/sys/kern/kern_priv.c Thu Feb 13 22:22:15 2020 (r357888)
@@ -71,6 +71,51 @@ SDT_PROVIDER_DEFINE(priv);
SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__ok, "int");
SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__err, "int");
+static __always_inline int
+priv_check_cred_pre(struct ucred *cred, int priv)
+{
+ int error;
+
+#ifdef MAC
+ error = mac_priv_check(cred, priv);
+#else
+ error = 0;
+#endif
+ return (error);
+}
+
+static __always_inline int
+priv_check_cred_post(struct ucred *cred, int priv, int error, bool handled)
+{
+
+ if (__predict_true(handled))
+ goto out;
+ /*
+ * Now check with MAC, if enabled, to see if a policy module grants
+ * privilege.
+ */
+#ifdef MAC
+ if (mac_priv_grant(cred, priv) == 0) {
+ error = 0;
+ goto out;
+ }
+#endif
+
+ /*
+ * The default is deny, so if no policies have granted it, reject
+ * with a privilege error here.
+ */
+ error = EPERM;
+out:
+ if (SDT_PROBES_ENABLED()) {
+ if (error)
+ SDT_PROBE1(priv, kernel, priv_check, priv__err, priv);
+ else
+ SDT_PROBE1(priv, kernel, priv_check, priv__ok, priv);
+ }
+ return (error);
+}
+
/*
* Check a credential for privilege. Lots of good reasons to deny privilege;
* only a few to grant it.
@@ -83,15 +128,18 @@ priv_check_cred(struct ucred *cred, int priv)
KASSERT(PRIV_VALID(priv), ("priv_check_cred: invalid privilege %d",
priv));
+ switch (priv) {
+ case PRIV_VFS_GENERATION:
+ return (priv_check_cred_vfs_generation(cred));
+ }
+
/*
* We first evaluate policies that may deny the granting of
* privilege unilaterally.
*/
-#ifdef MAC
- error = mac_priv_check(cred, priv);
+ error = priv_check_cred_pre(cred, priv);
if (error)
goto out;
-#endif
/*
* Jail policy will restrict certain privileges that may otherwise be
@@ -177,30 +225,9 @@ priv_check_cred(struct ucred *cred, int priv)
}
}
- /*
- * Now check with MAC, if enabled, to see if a policy module grants
- * privilege.
- */
-#ifdef MAC
- if (mac_priv_grant(cred, priv) == 0) {
- error = 0;
- goto out;
- }
-#endif
-
- /*
- * The default is deny, so if no policies have granted it, reject
- * with a privilege error here.
- */
- error = EPERM;
+ return (priv_check_cred_post(cred, priv, error, false));
out:
- if (SDT_PROBES_ENABLED()) {
- if (error)
- SDT_PROBE1(priv, kernel, priv_check, priv__err, priv);
- else
- SDT_PROBE1(priv, kernel, priv_check, priv__ok, priv);
- }
- return (error);
+ return (priv_check_cred_post(cred, priv, error, true));
}
int
@@ -210,4 +237,29 @@ priv_check(struct thread *td, int priv)
KASSERT(td == curthread, ("priv_check: td != curthread"));
return (priv_check_cred(td->td_ucred, priv));
+}
+
+int
+priv_check_cred_vfs_generation(struct ucred *cred)
+{
+ int error;
+
+ error = priv_check_cred_pre(cred, PRIV_VFS_GENERATION);
+ if (error)
+ goto out;
+
+ if (jailed(cred)) {
+ error = EPERM;
+ goto out;
+ }
+
+ if (cred->cr_uid == 0 && suser_enabled) {
+ error = 0;
+ goto out;
+ }
+
+ return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, false));
+out:
+ return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, true));
+
}
Modified: head/sys/kern/vfs_syscalls.c
==============================================================================
--- head/sys/kern/vfs_syscalls.c Thu Feb 13 22:19:17 2020 (r357887)
+++ head/sys/kern/vfs_syscalls.c Thu Feb 13 22:22:15 2020 (r357888)
@@ -273,7 +273,7 @@ kern_do_statfs(struct thread *td, struct mount *mp, st
error = VFS_STATFS(mp, buf);
if (error != 0)
goto out;
- if (priv_check(td, PRIV_VFS_GENERATION)) {
+ if (priv_check_cred_vfs_generation(td->td_ucred)) {
buf->f_fsid.val[0] = buf->f_fsid.val[1] = 0;
prison_enforce_statfs(td->td_ucred, mp, buf);
}
@@ -488,7 +488,7 @@ restart:
continue;
}
}
- if (priv_check(td, PRIV_VFS_GENERATION)) {
+ if (priv_check_cred_vfs_generation(td->td_ucred)) {
sptmp = malloc(sizeof(struct statfs), M_STATFS,
M_WAITOK);
*sptmp = *sp;
Modified: head/sys/kern/vfs_vnops.c
==============================================================================
--- head/sys/kern/vfs_vnops.c Thu Feb 13 22:19:17 2020 (r357887)
+++ head/sys/kern/vfs_vnops.c Thu Feb 13 22:22:15 2020 (r357888)
@@ -1477,7 +1477,7 @@ vn_stat(struct vnode *vp, struct stat *sb, struct ucre
sb->st_blksize = max(PAGE_SIZE, vap->va_blocksize);
sb->st_flags = vap->va_flags;
- if (priv_check(td, PRIV_VFS_GENERATION))
+ if (priv_check_cred_vfs_generation(td->td_ucred))
sb->st_gen = 0;
else
sb->st_gen = vap->va_gen;
Modified: head/sys/sys/priv.h
==============================================================================
--- head/sys/sys/priv.h Thu Feb 13 22:19:17 2020 (r357887)
+++ head/sys/sys/priv.h Thu Feb 13 22:22:15 2020 (r357888)
@@ -533,6 +533,7 @@ 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_generation(struct ucred *cred);
#endif
#endif /* !_SYS_PRIV_H_ */
More information about the svn-src-all
mailing list