mirror of
https://github.com/SELinuxProject/selinux
synced 2025-01-20 12:30:45 +00:00
libsepol: Use a dynamic buffer in sepol_av_to_string()
In the internal function sepol_av_to_string(), use a dynamically allocated buffer for the permission names of an access vector instead of a fixed static buffer to support very long permission names. Update the internal users of sepol_av_to_string() to free the buffer. The exported function sepol_perm_to_string() is just a wrapper to the internal function. To avoid changing the behavior of this function, use a static buffer and copy the resulting string from the internal function. If the string is too long for the buffer or there was an error in creating the string, return a string indicating the error. All of the changes to the internal function and users was the work of Christian Göttsche <cgzones@googlemail.com>. Reported-by: oss-fuzz (issue 64832, 64933) Suggested-by: Christian Göttsche <cgzones@googlemail.com> Signed-off-by: James Carter <jwcart2@gmail.com>
This commit is contained in:
parent
82195e77e3
commit
90db06c524
@ -118,12 +118,11 @@ static __attribute__((__noreturn__)) void usage(const char *progname)
|
||||
static void render_access_mask(uint32_t mask, uint32_t class, policydb_t * p,
|
||||
FILE * fp)
|
||||
{
|
||||
char *perm;
|
||||
char *perm = sepol_av_to_string(p, class, mask);
|
||||
fprintf(fp, "{");
|
||||
perm = sepol_av_to_string(p, class, mask);
|
||||
if (perm)
|
||||
fprintf(fp, "%s ", perm);
|
||||
fprintf(fp, "%s ", perm ?: "<format-failure>");
|
||||
fprintf(fp, "}");
|
||||
free(perm);
|
||||
}
|
||||
|
||||
static void render_access_bitmap(ebitmap_t * map, uint32_t class,
|
||||
@ -135,8 +134,8 @@ static void render_access_bitmap(ebitmap_t * map, uint32_t class,
|
||||
for (i = ebitmap_startbit(map); i < ebitmap_length(map); i++) {
|
||||
if (ebitmap_get_bit(map, i)) {
|
||||
perm = sepol_av_to_string(p, class, UINT32_C(1) << i);
|
||||
if (perm)
|
||||
fprintf(fp, "%s", perm);
|
||||
fprintf(fp, "%s", perm ?: "<format-failure>");
|
||||
free(perm);
|
||||
}
|
||||
}
|
||||
fprintf(fp, " }");
|
||||
|
@ -91,12 +91,11 @@ static __attribute__((__noreturn__)) void usage(const char *progname)
|
||||
static int render_access_mask(uint32_t mask, avtab_key_t * key, policydb_t * p,
|
||||
FILE * fp)
|
||||
{
|
||||
char *perm;
|
||||
char *perm = sepol_av_to_string(p, key->target_class, mask);
|
||||
fprintf(fp, "{");
|
||||
perm = sepol_av_to_string(p, key->target_class, mask);
|
||||
if (perm)
|
||||
fprintf(fp, "%s ", perm);
|
||||
fprintf(fp, "%s ", perm ?: "<format-failure>");
|
||||
fprintf(fp, "}");
|
||||
free(perm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ extern "C" {
|
||||
|
||||
extern int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a);
|
||||
|
||||
extern char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
|
||||
extern char *sepol_av_to_string(const policydb_t *policydbp, sepol_security_class_t tclass,
|
||||
sepol_access_vector_t av);
|
||||
|
||||
char *sepol_extended_perms_to_string(const avtab_extended_perms_t *xperms);
|
||||
|
@ -48,26 +48,30 @@ static void report_failure(sepol_handle_t *handle, policydb_t *p, const avrule_t
|
||||
unsigned int stype, unsigned int ttype,
|
||||
const class_perm_node_t *curperm, uint32_t perms)
|
||||
{
|
||||
char *permstr = sepol_av_to_string(p, curperm->tclass, perms);
|
||||
|
||||
if (avrule->source_filename) {
|
||||
ERR(handle, "neverallow on line %lu of %s (or line %lu of %s) violated by allow %s %s:%s {%s };",
|
||||
avrule->source_line, avrule->source_filename, avrule->line, policy_name(p),
|
||||
p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_av_to_string(p, curperm->tclass, perms));
|
||||
permstr ?: "<format-failure>");
|
||||
} else if (avrule->line) {
|
||||
ERR(handle, "neverallow on line %lu violated by allow %s %s:%s {%s };",
|
||||
avrule->line, p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_av_to_string(p, curperm->tclass, perms));
|
||||
permstr ?: "<format-failure>");
|
||||
} else {
|
||||
ERR(handle, "neverallow violated by allow %s %s:%s {%s };",
|
||||
p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_av_to_string(p, curperm->tclass, perms));
|
||||
permstr ?: "<format-failure>");
|
||||
}
|
||||
|
||||
free(permstr);
|
||||
}
|
||||
|
||||
static int match_any_class_permissions(class_perm_node_t *cp, uint32_t class, uint32_t data)
|
||||
@ -200,13 +204,17 @@ static int report_assertion_extended_permissions(sepol_handle_t *handle,
|
||||
|
||||
/* failure on the regular permissions */
|
||||
if (!found_xperm) {
|
||||
char *permstr = sepol_av_to_string(p, curperm->tclass, perms);
|
||||
|
||||
ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n"
|
||||
"allow %s %s:%s {%s };",
|
||||
avrule->source_line, avrule->source_filename, avrule->line, policy_name(p),
|
||||
p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_av_to_string(p, curperm->tclass, perms));
|
||||
permstr ?: "<format-failure>");
|
||||
|
||||
free(permstr);
|
||||
errors++;
|
||||
|
||||
}
|
||||
|
@ -443,12 +443,15 @@ static void bounds_report(sepol_handle_t *handle, policydb_t *p, uint32_t child,
|
||||
p->p_type_val_to_name[child - 1],
|
||||
p->p_type_val_to_name[parent - 1]);
|
||||
for (; cur; cur = cur->next) {
|
||||
char *permstr = sepol_av_to_string(p, cur->key.target_class, cur->datum.data);
|
||||
|
||||
ERR(handle, " %s %s : %s { %s }",
|
||||
p->p_type_val_to_name[cur->key.source_type - 1],
|
||||
p->p_type_val_to_name[cur->key.target_type - 1],
|
||||
p->p_class_val_to_name[cur->key.target_class - 1],
|
||||
sepol_av_to_string(p, cur->key.target_class,
|
||||
cur->datum.data));
|
||||
permstr ?: "<format-failure>");
|
||||
|
||||
free(permstr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,6 +297,11 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
|
||||
}
|
||||
|
||||
perms = sepol_av_to_string(pdb, class->s.value, curr->permissions);
|
||||
if (!perms) {
|
||||
ERR(NULL, "Failed to generate permission string");
|
||||
rc = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (is_mls) {
|
||||
key_word = "mlsconstrain";
|
||||
@ -307,6 +312,7 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
|
||||
}
|
||||
|
||||
rc = strs_create_and_add(strs, "(%s (%s (%s)) %s)", key_word, classkey, perms+1, expr);
|
||||
free(perms);
|
||||
free(expr);
|
||||
if (rc != 0) {
|
||||
goto exit;
|
||||
@ -1771,6 +1777,7 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat
|
||||
}
|
||||
rule = create_str("(%s %s %s (%s (%s)))",
|
||||
flavor, src, tgt, class, perms+1);
|
||||
free(perms);
|
||||
} else if (key->specified & AVTAB_XPERMS) {
|
||||
perms = xperms_to_str(datum->xperms);
|
||||
if (perms == NULL) {
|
||||
|
@ -292,6 +292,11 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
|
||||
}
|
||||
|
||||
perms = sepol_av_to_string(pdb, class->s.value, curr->permissions);
|
||||
if (!perms) {
|
||||
ERR(NULL, "Failed to generate permission string");
|
||||
rc = -1;
|
||||
goto exit;
|
||||
}
|
||||
if (strchr(perms, ' ')) {
|
||||
perm_prefix = "{ ";
|
||||
perm_suffix = " }";
|
||||
@ -311,6 +316,7 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
|
||||
flavor, classkey,
|
||||
perm_prefix, perms+1, perm_suffix,
|
||||
expr);
|
||||
free(perms);
|
||||
free(expr);
|
||||
if (rc != 0) {
|
||||
goto exit;
|
||||
@ -1682,7 +1688,7 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat
|
||||
{
|
||||
uint32_t data = datum->data;
|
||||
type_datum_t *type;
|
||||
const char *flavor, *src, *tgt, *class, *perms, *new;
|
||||
const char *flavor, *src, *tgt, *class, *new;
|
||||
char *rule = NULL, *permstring;
|
||||
|
||||
switch (0xFFF & key->specified) {
|
||||
@ -1730,13 +1736,14 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat
|
||||
class = pdb->p_class_val_to_name[key->target_class - 1];
|
||||
|
||||
if (key->specified & AVTAB_AV) {
|
||||
perms = sepol_av_to_string(pdb, key->target_class, data);
|
||||
if (perms == NULL) {
|
||||
permstring = sepol_av_to_string(pdb, key->target_class, data);
|
||||
if (permstring == NULL) {
|
||||
ERR(NULL, "Failed to generate permission string");
|
||||
goto exit;
|
||||
}
|
||||
rule = create_str("%s %s %s:%s { %s };",
|
||||
flavor, src, tgt, class, perms+1);
|
||||
flavor, src, tgt, class, permstring+1);
|
||||
free(permstring);
|
||||
} else if (key->specified & AVTAB_XPERMS) {
|
||||
permstring = sepol_extended_perms_to_string(datum->xperms);
|
||||
if (permstring == NULL) {
|
||||
|
@ -597,6 +597,7 @@ static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const
|
||||
rule, src, tgt,
|
||||
pdb->p_class_val_to_name[classperm->tclass - 1],
|
||||
perms + 1);
|
||||
free(perms);
|
||||
} else {
|
||||
cil_println(indent, "(%s %s %s %s %s)",
|
||||
rule, src, tgt,
|
||||
@ -1967,7 +1968,13 @@ static int constraints_to_cil(int indent, struct policydb *pdb, char *classkey,
|
||||
|
||||
if (is_constraint) {
|
||||
perms = sepol_av_to_string(pdb, class->s.value, node->permissions);
|
||||
if (perms == NULL) {
|
||||
ERR(NULL, "Failed to generate permission string");
|
||||
rc = -1;
|
||||
goto exit;
|
||||
}
|
||||
cil_println(indent, "(%sconstrain (%s (%s)) %s)", mls, classkey, perms + 1, expr);
|
||||
free(perms);
|
||||
} else {
|
||||
cil_println(indent, "(%svalidatetrans %s %s)", mls, classkey, expr);
|
||||
}
|
||||
|
@ -347,9 +347,11 @@ static char *get_class_info(sepol_security_class_t tclass,
|
||||
p += len;
|
||||
buf_used += len;
|
||||
if (state_num < 2) {
|
||||
char *permstr = sepol_av_to_string(policydb, tclass, constraint->permissions);
|
||||
|
||||
len = snprintf(p, class_buf_len - buf_used, "{%s } (",
|
||||
sepol_av_to_string(policydb, tclass,
|
||||
constraint->permissions));
|
||||
permstr ?: "<format-failure>");
|
||||
free(permstr);
|
||||
} else {
|
||||
len = snprintf(p, class_buf_len - buf_used, "(");
|
||||
}
|
||||
@ -1237,7 +1239,25 @@ out:
|
||||
const char *sepol_av_perm_to_string(sepol_security_class_t tclass,
|
||||
sepol_access_vector_t av)
|
||||
{
|
||||
return sepol_av_to_string(policydb, tclass, av);
|
||||
static char avbuf[1024];
|
||||
char *avstr = sepol_av_to_string(policydb, tclass, av);
|
||||
size_t len;
|
||||
|
||||
memset(avbuf, 0, sizeof(avbuf));
|
||||
|
||||
if (avstr) {
|
||||
len = strlen(avstr);
|
||||
if (len < sizeof(avbuf)) {
|
||||
strcpy(avbuf, avstr);
|
||||
} else {
|
||||
sprintf(avbuf, "<access-vector overflowed buffer>");
|
||||
}
|
||||
free(avstr);
|
||||
} else {
|
||||
sprintf(avbuf, "<format-failure>");
|
||||
}
|
||||
|
||||
return avbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
struct val_to_name {
|
||||
unsigned int val;
|
||||
char *name;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/* Add an unsigned integer to a dynamically reallocated array. *cnt
|
||||
@ -82,20 +82,27 @@ static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
|
||||
char *sepol_av_to_string(const policydb_t *policydbp, sepol_security_class_t tclass,
|
||||
sepol_access_vector_t av)
|
||||
{
|
||||
struct val_to_name v;
|
||||
static char avbuf[1024];
|
||||
class_datum_t *cladatum;
|
||||
char *perm = NULL, *p;
|
||||
unsigned int i;
|
||||
const class_datum_t *cladatum = policydbp->class_val_to_struct[tclass - 1];
|
||||
uint32_t i;
|
||||
int rc;
|
||||
int avlen = 0, len;
|
||||
char *buffer = NULL, *p;
|
||||
int len;
|
||||
size_t remaining, size = 64;
|
||||
|
||||
retry:
|
||||
if (__builtin_mul_overflow(size, 2, &size))
|
||||
goto err;
|
||||
p = realloc(buffer, size);
|
||||
if (!p)
|
||||
goto err;
|
||||
*p = '\0'; /* Just in case there are no permissions */
|
||||
buffer = p;
|
||||
remaining = size;
|
||||
|
||||
memset(avbuf, 0, sizeof avbuf);
|
||||
cladatum = policydbp->class_val_to_struct[tclass - 1];
|
||||
p = avbuf;
|
||||
for (i = 0; i < cladatum->permissions.nprim; i++) {
|
||||
if (av & (UINT32_C(1) << i)) {
|
||||
v.val = i + 1;
|
||||
@ -106,22 +113,23 @@ char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
|
||||
permissions.table, perm_name,
|
||||
&v);
|
||||
}
|
||||
if (rc)
|
||||
perm = v.name;
|
||||
if (perm) {
|
||||
len =
|
||||
snprintf(p, sizeof(avbuf) - avlen, " %s",
|
||||
perm);
|
||||
if (len < 0
|
||||
|| (size_t) len >= (sizeof(avbuf) - avlen))
|
||||
return NULL;
|
||||
if (rc == 1) {
|
||||
len = snprintf(p, remaining, " %s", v.name);
|
||||
if (len < 0)
|
||||
goto err;
|
||||
if ((size_t) len >= remaining)
|
||||
goto retry;
|
||||
p += len;
|
||||
avlen += len;
|
||||
remaining -= len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return avbuf;
|
||||
return buffer;
|
||||
|
||||
err:
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define next_bit_in_range(i, p) (((i) + 1 < sizeof(p)*8) && xperm_test(((i) + 1), p))
|
||||
|
Loading…
Reference in New Issue
Block a user