aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2022-04-13 14:47:08 +0000
committerMark Johnston <markj@FreeBSD.org>2022-04-13 14:51:30 +0000
commit869199d9922c7dee92c1c24f95b90f1d1319433e (patch)
tree7dc4d33d9dfbb25c5c52e7a7626aed12d06162d3
parent4ad3423bc285f1fd66614e0a771d5dfed77234ee (diff)
downloadsrc-869199d9922c7dee92c1c24f95b90f1d1319433e.tar.gz
src-869199d9922c7dee92c1c24f95b90f1d1319433e.zip
libsysdecode: Fix decoding of Capsicum rights
Capsicum rights are a bit tricky since some of them are subsets of others, and one can have rights R1 and R2 such that R1 is a subset of R2, but there is no collection of named rights whose union is R2. So, they don't behave like most other flag sets. sysdecode_cap_rights(3) does not handle this properly and so can emit misleading decodings. Try to fix all of these problems: - Include composite rights in the caprights table. - Use a constructor to sort the caprights table such that "larger" rights appear first and thus are matched first. - Don't print rights that are a subset of rights already printed, so as to minimize the length of the output. - Print a trailing message if some of the specific rights are not matched by the table. PR: 263165 Reviewed by: pauamma_gundo.com (doc), jhb, emaste MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D34874
-rw-r--r--lib/libsysdecode/flags.c53
-rw-r--r--lib/libsysdecode/mktables2
-rw-r--r--lib/libsysdecode/sysdecode_cap_rights.323
3 files changed, 73 insertions, 5 deletions
diff --git a/lib/libsysdecode/flags.c b/lib/libsysdecode/flags.c
index 35bce1ff77f9..f02c8dd8b339 100644
--- a/lib/libsysdecode/flags.c
+++ b/lib/libsysdecode/flags.c
@@ -1171,7 +1171,8 @@ sysdecode_umtx_rwlock_flags(FILE *fp, u_long flags, u_long *rem)
void
sysdecode_cap_rights(FILE *fp, cap_rights_t *rightsp)
{
- struct name_table *t;
+ cap_rights_t diff, sum, zero;
+ const struct name_table *t;
int i;
bool comma;
@@ -1181,13 +1182,59 @@ sysdecode_cap_rights(FILE *fp, cap_rights_t *rightsp)
return;
}
}
- comma = false;
- for (t = caprights; t->str != NULL; t++) {
+ cap_rights_init(&sum);
+ diff = *rightsp;
+ for (t = caprights, comma = false; t->str != NULL; t++) {
if (cap_rights_is_set(rightsp, t->val)) {
+ cap_rights_clear(&diff, t->val);
+ if (cap_rights_is_set(&sum, t->val)) {
+ /* Don't print redundant rights. */
+ continue;
+ }
+ cap_rights_set(&sum, t->val);
+
fprintf(fp, "%s%s", comma ? "," : "", t->str);
comma = true;
}
}
+ if (!comma)
+ fprintf(fp, "CAP_NONE");
+
+ /*
+ * Provide a breadcrumb if some of the provided rights are not included
+ * in the table, likely due to a bug in the mktables script.
+ */
+ CAP_NONE(&zero);
+ if (!cap_rights_contains(&zero, &diff))
+ fprintf(fp, ",unknown rights");
+}
+
+/*
+ * Pre-sort the set of rights, which has a partial ordering defined by the
+ * subset relation. This lets sysdecode_cap_rights() print a list of minimal
+ * length with a single pass over the "caprights" table.
+ */
+static void __attribute__((constructor))
+sysdecode_cap_rights_init(void)
+{
+ cap_rights_t tr, qr;
+ struct name_table *t, *q, tmp;
+ bool swapped;
+
+ do {
+ for (t = caprights, swapped = false; t->str != NULL; t++) {
+ cap_rights_init(&tr, t->val);
+ for (q = t + 1; q->str != NULL; q++) {
+ cap_rights_init(&qr, q->val);
+ if (cap_rights_contains(&qr, &tr)) {
+ tmp = *t;
+ *t = *q;
+ *q = tmp;
+ swapped = true;
+ }
+ }
+ }
+ } while (swapped);
}
static struct name_table cmsgtypeip[] = {
diff --git a/lib/libsysdecode/mktables b/lib/libsysdecode/mktables
index 66f243eab6e6..6b0b56c3b705 100644
--- a/lib/libsysdecode/mktables
+++ b/lib/libsysdecode/mktables
@@ -159,7 +159,7 @@ gen_table "msgflags" "MSG_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/
gen_table "sigcode" "SI_[A-Z]+[[:space:]]+0(x[0-9abcdef]+)?" "sys/signal.h"
gen_table "umtxcvwaitflags" "CVWAIT_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/umtx.h"
gen_table "umtxrwlockflags" "URWLOCK_PREFER_READER[[:space:]]+0x[0-9]+" "sys/umtx.h"
-gen_table "caprights" "CAP_[A-Z_]+[[:space:]]+CAPRIGHT\([0-9],[[:space:]]+0x[0-9]{16}ULL\)" "sys/capsicum.h"
+gen_table "caprights" "CAP_[A-Z_]+[[:space:]]+((CAPRIGHT\([0-9],[[:space:]]+0x[0-9]{16}ULL\))|(\(CAP_[A-Z_]+[[:space:]]*\|.*\)))" "sys/capsicum.h"
gen_table "sctpprpolicy" "SCTP_PR_SCTP_[A-Z_]+[[:space:]]+0x[0-9]+" "netinet/sctp_uio.h" "SCTP_PR_SCTP_ALL"
gen_table "cmsgtypesocket" "SCM_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/socket.h"
if [ -e "${include_dir}/x86/sysarch.h" ]; then
diff --git a/lib/libsysdecode/sysdecode_cap_rights.3 b/lib/libsysdecode/sysdecode_cap_rights.3
index 674e12ad3a01..e165e3d43938 100644
--- a/lib/libsysdecode/sysdecode_cap_rights.3
+++ b/lib/libsysdecode/sysdecode_cap_rights.3
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 24, 2017
+.Dd April 11, 2022
.Dt sysdecode_cap_rights 3
.Os
.Sh NAME
@@ -46,5 +46,26 @@ function outputs a comma-separated list of capability rights at
.Fa rightsp
to the stream
.Fa fp .
+.Pp
+Note that some capability rights are supersets of others; for example,
+.Dv CAP_PREAD
+is the union of
+.Dv CAP_READ
+and
+.Dv CAP_SEEK .
+.Fn sysdecode_cap_rights
+emits a minimal list of rights whose union is equal to
+.Fa *rightsp .
+For example, if both
+.Dv CAP_READ
+and
+.Dv CAP_SEEK
+are set in
+.Fa *rightsp ,
+then
+.Fn sysdecode_cap_rights
+will include only
+.Dv CAP_PREAD
+in the output list.
.Sh SEE ALSO
.Xr sysdecode 3