Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 3 Feb 2020 17:08:12 +0000 (UTC)
From:      Mateusz Guzik <mjg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r357452 - in head/sys: kern sys
Message-ID:  <202002031708.013H8CV7076993@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mjg
Date: Mon Feb  3 17:08:11 2020
New Revision: 357452
URL: https://svnweb.freebsd.org/changeset/base/357452

Log:
  capsicum: faster cap_rights_contains
  
  Instead of doing a 2 iteration loop (determined at runeimt), take advantage
  of the fact that the size is already known.
  
  While here provdie cap_check_inline so that fget_unlocked does not have to
  do a function call.
  
  Verified with the capsicum suite /usr/tests.

Modified:
  head/sys/kern/kern_descrip.c
  head/sys/kern/subr_capability.c
  head/sys/kern/sys_capability.c
  head/sys/sys/capsicum.h

Modified: head/sys/kern/kern_descrip.c
==============================================================================
--- head/sys/kern/kern_descrip.c	Mon Feb  3 17:06:21 2020	(r357451)
+++ head/sys/kern/kern_descrip.c	Mon Feb  3 17:08:11 2020	(r357452)
@@ -2724,7 +2724,7 @@ fget_unlocked(struct filedesc *fdp, int fd, cap_rights
 		if (fp == NULL)
 			return (EBADF);
 #ifdef CAPABILITIES
-		error = cap_check(&haverights, needrightsp);
+		error = cap_check_inline(&haverights, needrightsp);
 		if (error != 0)
 			return (error);
 #endif

Modified: head/sys/kern/subr_capability.c
==============================================================================
--- head/sys/kern/subr_capability.c	Mon Feb  3 17:06:21 2020	(r357451)
+++ head/sys/kern/subr_capability.c	Mon Feb  3 17:08:11 2020	(r357452)
@@ -394,25 +394,3 @@ cap_rights_remove(cap_rights_t *dst, const cap_rights_
 
 	return (dst);
 }
-
-bool
-cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little)
-{
-	unsigned int i, n;
-
-	assert(CAPVER(big) == CAP_RIGHTS_VERSION_00);
-	assert(CAPVER(little) == CAP_RIGHTS_VERSION_00);
-	assert(CAPVER(big) == CAPVER(little));
-
-	n = CAPARSIZE(big);
-	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
-
-	for (i = 0; i < n; i++) {
-		if ((big->cr_rights[i] & little->cr_rights[i]) !=
-		    little->cr_rights[i]) {
-			return (false);
-		}
-	}
-
-	return (true);
-}

Modified: head/sys/kern/sys_capability.c
==============================================================================
--- head/sys/kern/sys_capability.c	Mon Feb  3 17:06:21 2020	(r357451)
+++ head/sys/kern/sys_capability.c	Mon Feb  3 17:08:11 2020	(r357452)
@@ -179,6 +179,17 @@ cap_check(const cap_rights_t *havep, const cap_rights_
 	return (_cap_check(havep, needp, CAPFAIL_NOTCAPABLE));
 }
 
+int
+cap_check_failed_notcapable(const cap_rights_t *havep, const cap_rights_t *needp)
+{
+
+#ifdef KTRACE
+	if (KTRPOINT(curthread, KTR_CAPFAIL))
+		ktrcapfail(CAPFAIL_NOTCAPABLE, needp, havep);
+#endif
+	return (ENOTCAPABLE);
+}
+
 /*
  * Convert capability rights into VM access flags.
  */

Modified: head/sys/sys/capsicum.h
==============================================================================
--- head/sys/sys/capsicum.h	Mon Feb  3 17:06:21 2020	(r357451)
+++ head/sys/sys/capsicum.h	Mon Feb  3 17:08:11 2020	(r357452)
@@ -342,8 +342,37 @@ bool __cap_rights_is_set(const cap_rights_t *rights, .
 bool cap_rights_is_valid(const cap_rights_t *rights);
 cap_rights_t *cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
 cap_rights_t *cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
-bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
 void __cap_rights_sysinit(void *arg);
+
+
+/*
+ * We only support one size to reduce branching.
+ */
+_Static_assert(CAP_RIGHTS_VERSION == CAP_RIGHTS_VERSION_00,
+    "unsupported version of capsicum rights");
+
+static inline bool
+cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little)
+{
+
+        if (__predict_true(
+            (big->cr_rights[0] & little->cr_rights[0]) == little->cr_rights[0] &&
+            (big->cr_rights[1] & little->cr_rights[1]) == little->cr_rights[1]))
+                return (true);
+        return (false);
+}
+
+int cap_check_failed_notcapable(const cap_rights_t *havep,
+    const cap_rights_t *needp);
+
+static inline int
+cap_check_inline(const cap_rights_t *havep, const cap_rights_t *needp)
+{
+
+        if (__predict_false(!cap_rights_contains(havep, needp)))
+		return (cap_check_failed_notcapable(havep, needp));
+        return (0);
+}
 
 __END_DECLS
 struct cap_rights_init_args {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202002031708.013H8CV7076993>