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_ */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to