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
This commit is contained in:
Mark Johnston 2022-04-13 10:47:08 -04:00
parent 4ad3423bc2
commit 869199d992
3 changed files with 73 additions and 5 deletions

View File

@ -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[] = {

View File

@ -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

View File

@ -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