diff --git a/lib/libsysdecode/flags.c b/lib/libsysdecode/flags.c --- a/lib/libsysdecode/flags.c +++ b/lib/libsysdecode/flags.c @@ -1171,7 +1171,8 @@ 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 @@ 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 --- a/lib/libsysdecode/mktables +++ b/lib/libsysdecode/mktables @@ -159,7 +159,7 @@ 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 --- 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 @@ .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