diff options
author | Mark Johnston <markj@FreeBSD.org> | 2022-04-13 14:47:08 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2022-04-13 14:51:30 +0000 |
commit | 869199d9922c7dee92c1c24f95b90f1d1319433e (patch) | |
tree | 7dc4d33d9dfbb25c5c52e7a7626aed12d06162d3 /lib/libsysdecode | |
parent | 4ad3423bc285f1fd66614e0a771d5dfed77234ee (diff) | |
download | src-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
Diffstat (limited to 'lib/libsysdecode')
-rw-r--r-- | lib/libsysdecode/flags.c | 53 | ||||
-rw-r--r-- | lib/libsysdecode/mktables | 2 | ||||
-rw-r--r-- | lib/libsysdecode/sysdecode_cap_rights.3 | 23 |
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 |