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-head mailing list