mirror of
https://github.com/torvalds/linux.git
synced 2026-03-13 21:26:14 +01:00
apparmor: make str table more generic and be able to have multiple entries
The strtable is currently limited to a single entry string on unpack even though domain has the concept of multiple entries within it. Make this a reality as it will be used for tags and more advanced domain transitions. Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
parent
6fc367bfd4
commit
c140dcd124
5 changed files with 91 additions and 47 deletions
|
|
@ -529,7 +529,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
|
||||||
/* TODO: move lookup parsing to unpack time so this is a straight
|
/* TODO: move lookup parsing to unpack time so this is a straight
|
||||||
* index into the resultant label
|
* index into the resultant label
|
||||||
*/
|
*/
|
||||||
for (next = rules->file->trans.table[index]; next;
|
for (next = rules->file->trans.table[index].strs; next;
|
||||||
next = next_name(xtype, next)) {
|
next = next_name(xtype, next)) {
|
||||||
const char *lookup = (*next == '&') ? next + 1 : next;
|
const char *lookup = (*next == '&') ? next + 1 : next;
|
||||||
*name = next;
|
*name = next;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ extern struct aa_dfa *stacksplitdfa;
|
||||||
#define DEBUG_DOMAIN 4
|
#define DEBUG_DOMAIN 4
|
||||||
#define DEBUG_POLICY 8
|
#define DEBUG_POLICY 8
|
||||||
#define DEBUG_INTERFACE 0x10
|
#define DEBUG_INTERFACE 0x10
|
||||||
|
#define DEBUG_UNPACK 0x40
|
||||||
|
|
||||||
#define DEBUG_ALL 0x1f /* update if new DEBUG_X added */
|
#define DEBUG_ALL 0x1f /* update if new DEBUG_X added */
|
||||||
#define DEBUG_PARSE_ERROR (-1)
|
#define DEBUG_PARSE_ERROR (-1)
|
||||||
|
|
@ -119,13 +120,19 @@ static inline bool path_mediated_fs(struct dentry *dentry)
|
||||||
return !(dentry->d_sb->s_flags & SB_NOUSER);
|
return !(dentry->d_sb->s_flags & SB_NOUSER);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct aa_str_table {
|
struct aa_str_table_ent {
|
||||||
|
int count;
|
||||||
int size;
|
int size;
|
||||||
char **table;
|
char *strs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct aa_str_table {
|
||||||
|
int size;
|
||||||
|
struct aa_str_table_ent *table;
|
||||||
};
|
};
|
||||||
|
|
||||||
void aa_free_str_table(struct aa_str_table *table);
|
|
||||||
bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp);
|
bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp);
|
||||||
|
void aa_destroy_str_table(struct aa_str_table *table);
|
||||||
|
|
||||||
struct counted_str {
|
struct counted_str {
|
||||||
struct kref count;
|
struct kref count;
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ static struct val_table_ent debug_values_table[] = {
|
||||||
{ "domain", DEBUG_DOMAIN },
|
{ "domain", DEBUG_DOMAIN },
|
||||||
{ "policy", DEBUG_POLICY },
|
{ "policy", DEBUG_POLICY },
|
||||||
{ "interface", DEBUG_INTERFACE },
|
{ "interface", DEBUG_INTERFACE },
|
||||||
|
{ "unpack", DEBUG_UNPACK },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -118,7 +119,7 @@ int aa_print_debug_params(char *buffer)
|
||||||
|
|
||||||
bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp)
|
bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp)
|
||||||
{
|
{
|
||||||
char **n;
|
struct aa_str_table_ent *n;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (t->size == newsize)
|
if (t->size == newsize)
|
||||||
|
|
@ -129,7 +130,7 @@ bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp)
|
||||||
for (i = 0; i < min(t->size, newsize); i++)
|
for (i = 0; i < min(t->size, newsize); i++)
|
||||||
n[i] = t->table[i];
|
n[i] = t->table[i];
|
||||||
for (; i < t->size; i++)
|
for (; i < t->size; i++)
|
||||||
kfree_sensitive(t->table[i]);
|
kfree_sensitive(t->table[i].strs);
|
||||||
if (newsize > t->size)
|
if (newsize > t->size)
|
||||||
memset(&n[t->size], 0, (newsize-t->size)*sizeof(*n));
|
memset(&n[t->size], 0, (newsize-t->size)*sizeof(*n));
|
||||||
kfree_sensitive(t->table);
|
kfree_sensitive(t->table);
|
||||||
|
|
@ -140,10 +141,10 @@ bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* aa_free_str_table - free entries str table
|
* aa_destroy_str_table - free entries str table
|
||||||
* @t: the string table to free (MAYBE NULL)
|
* @t: the string table to free (MAYBE NULL)
|
||||||
*/
|
*/
|
||||||
void aa_free_str_table(struct aa_str_table *t)
|
void aa_destroy_str_table(struct aa_str_table *t)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -152,7 +153,7 @@ void aa_free_str_table(struct aa_str_table *t)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < t->size; i++)
|
for (i = 0; i < t->size; i++)
|
||||||
kfree_sensitive(t->table[i]);
|
kfree_sensitive(t->table[i].strs);
|
||||||
kfree_sensitive(t->table);
|
kfree_sensitive(t->table);
|
||||||
t->table = NULL;
|
t->table = NULL;
|
||||||
t->size = 0;
|
t->size = 0;
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ static void aa_free_pdb(struct aa_policydb *pdb)
|
||||||
if (pdb) {
|
if (pdb) {
|
||||||
aa_put_dfa(pdb->dfa);
|
aa_put_dfa(pdb->dfa);
|
||||||
kvfree(pdb->perms);
|
kvfree(pdb->perms);
|
||||||
aa_free_str_table(&pdb->trans);
|
aa_destroy_str_table(&pdb->trans);
|
||||||
kfree(pdb);
|
kfree(pdb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -450,20 +450,72 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e, int flags)
|
||||||
return dfa;
|
return dfa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int process_strs_entry(char *str, int size, bool multi)
|
||||||
|
{
|
||||||
|
int c = 1;
|
||||||
|
|
||||||
|
if (size <= 0)
|
||||||
|
return -1;
|
||||||
|
if (multi) {
|
||||||
|
if (size < 2)
|
||||||
|
return -2;
|
||||||
|
/* multi ends with double \0 */
|
||||||
|
if (str[size - 2])
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *save = str;
|
||||||
|
char *pos = str;
|
||||||
|
char *end = multi ? str + size - 2 : str + size - 1;
|
||||||
|
/* count # of internal \0 */
|
||||||
|
while (str < end) {
|
||||||
|
if (str == pos) {
|
||||||
|
/* starts with ... */
|
||||||
|
if (!*str) {
|
||||||
|
AA_DEBUG(DEBUG_UNPACK,
|
||||||
|
"starting with null save=%lu size %d c=%d",
|
||||||
|
str - save, size, c);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
if (isspace(*str))
|
||||||
|
return -5;
|
||||||
|
if (*str == ':') {
|
||||||
|
/* :ns_str\0str\0
|
||||||
|
* first character after : must be valid
|
||||||
|
*/
|
||||||
|
if (!str[1])
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
} else if (!*str) {
|
||||||
|
if (*pos == ':')
|
||||||
|
*str = ':';
|
||||||
|
else
|
||||||
|
c++;
|
||||||
|
pos = str + 1;
|
||||||
|
}
|
||||||
|
str++;
|
||||||
|
} /* while */
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* unpack_trans_table - unpack a profile transition table
|
* unpack_strs_table - unpack a profile transition table
|
||||||
* @e: serialized data extent information (NOT NULL)
|
* @e: serialized data extent information (NOT NULL)
|
||||||
|
* @name: name of table (MAY BE NULL)
|
||||||
|
* @multi: allow multiple strings on a single entry
|
||||||
* @strs: str table to unpack to (NOT NULL)
|
* @strs: str table to unpack to (NOT NULL)
|
||||||
*
|
*
|
||||||
* Returns: true if table successfully unpacked or not present
|
* Returns: true if table successfully unpacked or not present
|
||||||
*/
|
*/
|
||||||
static bool unpack_trans_table(struct aa_ext *e, struct aa_str_table *strs)
|
static bool unpack_strs_table(struct aa_ext *e, const char *name, bool multi,
|
||||||
|
struct aa_str_table *strs)
|
||||||
{
|
{
|
||||||
void *saved_pos = e->pos;
|
void *saved_pos = e->pos;
|
||||||
char **table = NULL;
|
struct aa_str_table_ent *table = NULL;
|
||||||
|
|
||||||
/* exec table is optional */
|
/* exec table is optional */
|
||||||
if (aa_unpack_nameX(e, AA_STRUCT, "xtable")) {
|
if (aa_unpack_nameX(e, AA_STRUCT, name)) {
|
||||||
u16 size;
|
u16 size;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -475,7 +527,8 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_str_table *strs)
|
||||||
* for size check here
|
* for size check here
|
||||||
*/
|
*/
|
||||||
goto fail;
|
goto fail;
|
||||||
table = kcalloc(size, sizeof(char *), GFP_KERNEL);
|
table = kcalloc(size, sizeof(struct aa_str_table_ent),
|
||||||
|
GFP_KERNEL);
|
||||||
if (!table)
|
if (!table)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
|
@ -483,41 +536,23 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_str_table *strs)
|
||||||
strs->size = size;
|
strs->size = size;
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
char *str;
|
char *str;
|
||||||
int c, j, pos, size2 = aa_unpack_strdup(e, &str, NULL);
|
int c, size2 = aa_unpack_strdup(e, &str, NULL);
|
||||||
/* aa_unpack_strdup verifies that the last character is
|
/* aa_unpack_strdup verifies that the last character is
|
||||||
* null termination byte.
|
* null termination byte.
|
||||||
*/
|
*/
|
||||||
if (!size2)
|
c = process_strs_entry(str, size2, multi);
|
||||||
|
if (c <= 0) {
|
||||||
|
AA_DEBUG(DEBUG_UNPACK, "process_strs %d", c);
|
||||||
goto fail;
|
goto fail;
|
||||||
table[i] = str;
|
|
||||||
/* verify that name doesn't start with space */
|
|
||||||
if (isspace(*str))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* count internal # of internal \0 */
|
|
||||||
for (c = j = 0; j < size2 - 1; j++) {
|
|
||||||
if (!str[j]) {
|
|
||||||
pos = j;
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (*str == ':') {
|
if (!multi && c > 1) {
|
||||||
/* first character after : must be valid */
|
AA_DEBUG(DEBUG_UNPACK, "!multi && c > 1");
|
||||||
if (!str[1])
|
|
||||||
goto fail;
|
|
||||||
/* beginning with : requires an embedded \0,
|
|
||||||
* verify that exactly 1 internal \0 exists
|
|
||||||
* trailing \0 already verified by aa_unpack_strdup
|
|
||||||
*
|
|
||||||
* convert \0 back to : for label_parse
|
|
||||||
*/
|
|
||||||
if (c == 1)
|
|
||||||
str[pos] = ':';
|
|
||||||
else if (c > 1)
|
|
||||||
goto fail;
|
|
||||||
} else if (c)
|
|
||||||
/* fail - all other cases with embedded \0 */
|
/* fail - all other cases with embedded \0 */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
table[i].strs = str;
|
||||||
|
table[i].count = c;
|
||||||
|
table[i].size = size2;
|
||||||
}
|
}
|
||||||
if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
|
if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -527,7 +562,7 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_str_table *strs)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
aa_free_str_table(strs);
|
aa_destroy_str_table(strs);
|
||||||
e->pos = saved_pos;
|
e->pos = saved_pos;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -795,13 +830,14 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
|
||||||
* transition table may be present even when the dfa is
|
* transition table may be present even when the dfa is
|
||||||
* not. For compatibility reasons unpack and discard.
|
* not. For compatibility reasons unpack and discard.
|
||||||
*/
|
*/
|
||||||
if (!unpack_trans_table(e, &pdb->trans) && required_trans) {
|
if (!unpack_strs_table(e, "xtable", false, &pdb->trans) &&
|
||||||
|
required_trans) {
|
||||||
*info = "failed to unpack profile transition table";
|
*info = "failed to unpack profile transition table";
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pdb->dfa && pdb->trans.table)
|
if (!pdb->dfa && pdb->trans.table)
|
||||||
aa_free_str_table(&pdb->trans);
|
aa_destroy_str_table(&pdb->trans);
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* - move compat mapping here, requires dfa merging first
|
* - move compat mapping here, requires dfa merging first
|
||||||
|
|
@ -1268,7 +1304,7 @@ static bool verify_perms(struct aa_policydb *pdb)
|
||||||
}
|
}
|
||||||
/* deal with incorrectly constructed string tables */
|
/* deal with incorrectly constructed string tables */
|
||||||
if (xmax == -1) {
|
if (xmax == -1) {
|
||||||
aa_free_str_table(&pdb->trans);
|
aa_destroy_str_table(&pdb->trans);
|
||||||
} else if (pdb->trans.size > xmax + 1) {
|
} else if (pdb->trans.size > xmax + 1) {
|
||||||
if (!aa_resize_str_table(&pdb->trans, xmax + 1, GFP_KERNEL))
|
if (!aa_resize_str_table(&pdb->trans, xmax + 1, GFP_KERNEL))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue