libsepol: avoid fixed sized format buffer for xperms

An extended access vector rule can consist of many individual ranges of
permissions.  Use a dynamically growing sized buffer for formatting such
rules instead of a static buffer to avoid write failures due to
truncations.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
This commit is contained in:
Christian Göttsche 2023-11-20 16:47:35 +01:00 committed by James Carter
parent 285d7cc81b
commit fdb536f38d
5 changed files with 67 additions and 27 deletions

View File

@ -347,6 +347,7 @@ static int display_avrule(avrule_t * avrule, policydb_t * policy,
display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, ""); display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, "");
} else if (avrule->specified & AVRULE_XPERMS) { } else if (avrule->specified & AVRULE_XPERMS) {
avtab_extended_perms_t xperms; avtab_extended_perms_t xperms;
char *perms;
int i; int i;
if (avrule->xperms->specified == AVRULE_XPERMS_IOCTLFUNCTION) if (avrule->xperms->specified == AVRULE_XPERMS_IOCTLFUNCTION)
@ -362,7 +363,13 @@ static int display_avrule(avrule_t * avrule, policydb_t * policy,
for (i = 0; i < EXTENDED_PERMS_LEN; i++) for (i = 0; i < EXTENDED_PERMS_LEN; i++)
xperms.perms[i] = avrule->xperms->perms[i]; xperms.perms[i] = avrule->xperms->perms[i];
fprintf(fp, "%s", sepol_extended_perms_to_string(&xperms)); perms = sepol_extended_perms_to_string(&xperms);
if (!perms) {
fprintf(fp, " ERROR: failed to format xperms\n");
return -1;
}
fprintf(fp, "%s", perms);
free(perms);
} }
fprintf(fp, ";\n"); fprintf(fp, ";\n");

View File

@ -196,6 +196,8 @@ static int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t wha
fprintf(fp, ";\n"); fprintf(fp, ";\n");
} }
} else if (key->specified & AVTAB_XPERMS) { } else if (key->specified & AVTAB_XPERMS) {
char *perms;
if (key->specified & AVTAB_XPERMS_ALLOWED) if (key->specified & AVTAB_XPERMS_ALLOWED)
fprintf(fp, "allowxperm "); fprintf(fp, "allowxperm ");
else if (key->specified & AVTAB_XPERMS_AUDITALLOW) else if (key->specified & AVTAB_XPERMS_AUDITALLOW)
@ -203,7 +205,13 @@ static int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t wha
else if (key->specified & AVTAB_XPERMS_DONTAUDIT) else if (key->specified & AVTAB_XPERMS_DONTAUDIT)
fprintf(fp, "dontauditxperm "); fprintf(fp, "dontauditxperm ");
render_key(key, p, fp); render_key(key, p, fp);
fprintf(fp, "%s;\n", sepol_extended_perms_to_string(datum->xperms)); perms = sepol_extended_perms_to_string(datum->xperms);
if (!perms) {
fprintf(fp, " ERROR: failed to format xperms\n");
return -1;
}
fprintf(fp, "%s;\n", perms);
free(perms);
} else { } else {
fprintf(fp, " ERROR: no valid rule type specified\n"); fprintf(fp, " ERROR: no valid rule type specified\n");
return -1; return -1;

View File

@ -178,15 +178,20 @@ static int report_assertion_extended_permissions(sepol_handle_t *handle,
rc = check_extended_permissions(avrule->xperms, xperms); rc = check_extended_permissions(avrule->xperms, xperms);
/* failure on the extended permission check_extended_permissions */ /* failure on the extended permission check_extended_permissions */
if (rc) { if (rc) {
char *permstring;
extended_permissions_violated(&error, avrule->xperms, xperms); extended_permissions_violated(&error, avrule->xperms, xperms);
permstring = sepol_extended_perms_to_string(&error);
ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n" ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n"
"allowxperm %s %s:%s %s;", "allowxperm %s %s:%s %s;",
avrule->source_line, avrule->source_filename, avrule->line, policy_name(p), avrule->source_line, avrule->source_filename, avrule->line, policy_name(p),
p->p_type_val_to_name[i], p->p_type_val_to_name[i],
p->p_type_val_to_name[j], p->p_type_val_to_name[j],
p->p_class_val_to_name[curperm->tclass - 1], p->p_class_val_to_name[curperm->tclass - 1],
sepol_extended_perms_to_string(&error)); permstring ?: "<format-failure>");
free(permstring);
errors++; errors++;
} }
} }

View File

@ -1683,7 +1683,7 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat
uint32_t data = datum->data; uint32_t data = datum->data;
type_datum_t *type; type_datum_t *type;
const char *flavor, *src, *tgt, *class, *perms, *new; const char *flavor, *src, *tgt, *class, *perms, *new;
char *rule = NULL; char *rule = NULL, *permstring;
switch (0xFFF & key->specified) { switch (0xFFF & key->specified) {
case AVTAB_ALLOWED: case AVTAB_ALLOWED:
@ -1738,13 +1738,14 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat
rule = create_str("%s %s %s:%s { %s };", 5, rule = create_str("%s %s %s:%s { %s };", 5,
flavor, src, tgt, class, perms+1); flavor, src, tgt, class, perms+1);
} else if (key->specified & AVTAB_XPERMS) { } else if (key->specified & AVTAB_XPERMS) {
perms = sepol_extended_perms_to_string(datum->xperms); permstring = sepol_extended_perms_to_string(datum->xperms);
if (perms == NULL) { if (permstring == NULL) {
ERR(NULL, "Failed to generate extended permission string"); ERR(NULL, "Failed to generate extended permission string");
goto exit; goto exit;
} }
rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, perms); rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, permstring);
free(permstring);
} else { } else {
new = pdb->p_type_val_to_name[data - 1]; new = pdb->p_type_val_to_name[data - 1];

View File

@ -132,21 +132,32 @@ char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms)
uint16_t low_bit; uint16_t low_bit;
uint16_t low_value; uint16_t low_value;
unsigned int bit; unsigned int bit;
unsigned int in_range = 0; unsigned int in_range;
static char xpermsbuf[2048]; char *buffer = NULL, *p;
char *p; int len;
int len, xpermslen = 0; size_t remaining, size = 128;
xpermsbuf[0] = '\0';
p = xpermsbuf;
if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
return NULL; return NULL;
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "ioctl { "); retry:
p += len; size *= 2;
xpermslen += len; if (size == 0)
goto err;
p = realloc(buffer, size);
if (!p)
goto err;
buffer = p;
remaining = size;
len = snprintf(p, remaining, "ioctl { ");
if (len < 0 || (size_t)len >= remaining)
goto err;
p += len;
remaining -= len;
in_range = 0;
for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) { for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
if (!xperm_test(bit, xperms->perms)) if (!xperm_test(bit, xperms->perms))
continue; continue;
@ -165,35 +176,43 @@ char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms)
value = xperms->driver<<8 | bit; value = xperms->driver<<8 | bit;
if (in_range) { if (in_range) {
low_value = xperms->driver<<8 | low_bit; low_value = xperms->driver<<8 | low_bit;
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, value); len = snprintf(p, remaining, "0x%hx-0x%hx ", low_value, value);
} else { } else {
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx ", value); len = snprintf(p, remaining, "0x%hx ", value);
} }
} else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { } else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
value = bit << 8; value = bit << 8;
if (in_range) { if (in_range) {
low_value = low_bit << 8; low_value = low_bit << 8;
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff)); len = snprintf(p, remaining, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
} else { } else {
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff)); len = snprintf(p, remaining, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
} }
} }
if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen)) if (len < 0)
return NULL; goto err;
if ((size_t) len >= remaining)
goto retry;
p += len; p += len;
xpermslen += len; remaining -= len;
if (in_range) if (in_range)
in_range = 0; in_range = 0;
} }
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "}"); len = snprintf(p, remaining, "}");
if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen)) if (len < 0)
return NULL; goto err;
if ((size_t) len >= remaining)
goto retry;
return xpermsbuf; return buffer;
err:
free(buffer);
return NULL;
} }
/* /*