git: a7100ae23aca - main - capsicum: introduce cap_rights_is_empty Function

From: Mariusz Zaborski <oshogbo_at_FreeBSD.org>
Date: Mon, 11 Dec 2023 11:17:45 UTC
The branch main has been updated by oshogbo:

URL: https://cgit.FreeBSD.org/src/commit/?id=a7100ae23aca07976926bd8d50223c45149f65d6

commit a7100ae23aca07976926bd8d50223c45149f65d6
Author:     Mariusz Zaborski <oshogbo@FreeBSD.org>
AuthorDate: 2023-12-11 11:09:31 +0000
Commit:     Mariusz Zaborski <oshogbo@FreeBSD.org>
CommitDate: 2023-12-11 11:15:46 +0000

    capsicum: introduce cap_rights_is_empty Function
    
    Before this commit, we only had the capability to check if a specific
    capability was set (using cap_rights_is_set function). However, there
    was no efficient method to determine if a cap_rights_t structure doesn't
    contain any capability. The cap_rights_is_empty function addresses
    this gap.
    
    PR:             275330
    Reported by:    vini.ipsmaker@gmail.com
    Reviewed by:    emaste, markj
    Differential Revision:  https://reviews.freebsd.org/D42780
---
 contrib/capsicum-test/capability-fd.cc | 15 +++++++++++++++
 lib/libc/capability/Symbol.map         |  4 ++++
 lib/libc/capability/cap_rights_init.3  | 19 ++++++++++++++++++-
 sys/kern/subr_capability.c             | 19 +++++++++++++++++++
 sys/sys/capsicum.h                     |  2 ++
 5 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/contrib/capsicum-test/capability-fd.cc b/contrib/capsicum-test/capability-fd.cc
index f255c6425cdd..0551d9bd81ef 100644
--- a/contrib/capsicum-test/capability-fd.cc
+++ b/contrib/capsicum-test/capability-fd.cc
@@ -1342,3 +1342,18 @@ TEST(Capability, NoBypassDACIfRoot) {
   close(fd);
   unlink(TmpFile("cap_root_owned"));
 }
+
+TEST(Capability, CheckIsEmpty) {
+  cap_rights_t rights;
+
+  cap_rights_init(&rights);
+  EXPECT_TRUE(cap_rights_is_empty(&rights));
+
+  size_t num_known = (sizeof(known_rights)/sizeof(known_rights[0]));
+  for (size_t ii = 0; ii < num_known; ii++) {
+    cap_rights_init(&rights, known_rights[ii].right);
+    EXPECT_FALSE(cap_rights_is_empty(&rights));
+    cap_rights_clear(&rights, known_rights[ii].right);
+    EXPECT_TRUE(cap_rights_is_empty(&rights));
+  }
+}
diff --git a/lib/libc/capability/Symbol.map b/lib/libc/capability/Symbol.map
index 0deff024a046..8bf11670a5a8 100644
--- a/lib/libc/capability/Symbol.map
+++ b/lib/libc/capability/Symbol.map
@@ -8,3 +8,7 @@ FBSD_1.3 {
 	cap_rights_remove;
 	__cap_rights_set;
 };
+
+FBSD_1.8 {
+	cap_rights_is_empty;
+};
diff --git a/lib/libc/capability/cap_rights_init.3 b/lib/libc/capability/cap_rights_init.3
index 80b522820097..98b50f653f2c 100644
--- a/lib/libc/capability/cap_rights_init.3
+++ b/lib/libc/capability/cap_rights_init.3
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd May 5, 2020
+.Dd November 25, 2023
 .Dt CAP_RIGHTS_INIT 3
 .Os
 .Sh NAME
@@ -33,6 +33,7 @@
 .Nm cap_rights_set ,
 .Nm cap_rights_clear ,
 .Nm cap_rights_is_set ,
+.Nm cap_rights_is_empty ,
 .Nm cap_rights_is_valid ,
 .Nm cap_rights_merge ,
 .Nm cap_rights_remove ,
@@ -51,6 +52,8 @@
 .Ft bool
 .Fn cap_rights_is_set "const cap_rights_t *rights" "..."
 .Ft bool
+.Fn cap_rights_is_empty "const cap_rights_t *rights"
+.Ft bool
 .Fn cap_rights_is_valid "const cap_rights_t *rights"
 .Ft cap_rights_t *
 .Fn cap_rights_merge "cap_rights_t *dst" "const cap_rights_t *src"
@@ -118,6 +121,12 @@ function checks if all the given capability rights are set for the given
 structure.
 .Pp
 The
+.Fn cap_rights_is_empty
+function checks if the
+.Fa rights
+structure is empty.
+.Pp
+The
 .Fn cap_rights_is_valid
 function verifies if the given
 .Vt cap_rights_t
@@ -182,6 +191,14 @@ if all the given capability rights are set in the
 argument.
 .Pp
 The
+.Fn cap_rights_is_empty
+function returns
+.Va true
+if none of the capability rights are set in the
+.Fa rights
+structure.
+.Pp
+The
 .Fn cap_rights_is_valid
 function performs various checks to see if the given
 .Vt cap_rights_t
diff --git a/sys/kern/subr_capability.c b/sys/kern/subr_capability.c
index e40c57c5307d..1f3a181a91cb 100644
--- a/sys/kern/subr_capability.c
+++ b/sys/kern/subr_capability.c
@@ -306,6 +306,25 @@ __cap_rights_is_set(const cap_rights_t *rights, ...)
 	return (ret);
 }
 
+bool
+cap_rights_is_empty(const cap_rights_t *rights)
+{
+#ifndef _KERNEL
+	cap_rights_t cap_no_rights;
+	cap_rights_init(&cap_no_rights);
+#endif
+
+	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
+	assert(CAPVER(&cap_no_rights) == CAP_RIGHTS_VERSION_00);
+
+	for (int i = 0; i < CAPARSIZE(rights); i++) {
+		if (rights->cr_rights[i] != cap_no_rights.cr_rights[i])
+			return (false);
+	}
+
+	return (true);
+}
+
 bool
 cap_rights_is_valid(const cap_rights_t *rights)
 {
diff --git a/sys/sys/capsicum.h b/sys/sys/capsicum.h
index b9eb61409613..3979fd718909 100644
--- a/sys/sys/capsicum.h
+++ b/sys/sys/capsicum.h
@@ -336,6 +336,8 @@ cap_rights_t *__cap_rights_clear(cap_rights_t *rights, ...);
 	__cap_rights_is_set(__VA_ARGS__, 0ULL)
 bool __cap_rights_is_set(const cap_rights_t *rights, ...);
 
+bool cap_rights_is_empty(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);