mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
apparmor: add additional flags to extended permission.
This is a step towards merging the file and policy state machines. With the switch to extended permissions the state machine's ACCEPT2 table became unused freeing it up to store state specific flags. The first flags to be stored are FLAG_OWNER and FLAG other which paves the way towards merging the file and policydb perms into a single permission table. Currently Lookups based on the objects ownership conditional will still need separate fns, this will be address in a following patch. Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
parent
de4754c801
commit
2e12c5f060
7 changed files with 54 additions and 21 deletions
|
@ -626,7 +626,8 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms,
|
|||
if (state) {
|
||||
struct path_cond cond = { };
|
||||
|
||||
tmp = *(aa_lookup_fperms(rules->file, state, &cond));
|
||||
tmp = *(aa_lookup_condperms(current_fsuid(),
|
||||
rules->file, state, &cond));
|
||||
}
|
||||
} else if (rules->policy->dfa) {
|
||||
if (!RULE_MEDIATES(rules, *match_str))
|
||||
|
@ -2365,7 +2366,7 @@ static struct aa_sfs_entry aa_sfs_entry_policy[] = {
|
|||
AA_SFS_FILE_BOOLEAN("set_load", 1),
|
||||
/* number of out of band transitions supported */
|
||||
AA_SFS_FILE_U64("outofband", MAX_OOB_SUPPORTED),
|
||||
AA_SFS_FILE_U64("permstable32_version", 1),
|
||||
AA_SFS_FILE_U64("permstable32_version", 3),
|
||||
AA_SFS_FILE_STRING("permstable32", PERMS32STR),
|
||||
AA_SFS_FILE_U64("state32", 1),
|
||||
AA_SFS_DIR("unconfined_restrictions", aa_sfs_entry_unconfined),
|
||||
|
|
|
@ -154,7 +154,8 @@ next:
|
|||
if (!state)
|
||||
goto fail;
|
||||
}
|
||||
*perms = *(aa_lookup_fperms(rules->file, state, &cond));
|
||||
*perms = *(aa_lookup_condperms(current_fsuid(), rules->file, state,
|
||||
&cond));
|
||||
aa_apply_modes_to_perms(profile, perms);
|
||||
if ((perms->allow & request) != request)
|
||||
return -EACCES;
|
||||
|
@ -209,7 +210,8 @@ static int label_components_match(struct aa_profile *profile,
|
|||
return 0;
|
||||
|
||||
next:
|
||||
tmp = *(aa_lookup_fperms(rules->file, state, &cond));
|
||||
tmp = *(aa_lookup_condperms(current_fsuid(), rules->file, state,
|
||||
&cond));
|
||||
aa_apply_modes_to_perms(profile, &tmp);
|
||||
aa_perms_accum(perms, &tmp);
|
||||
label_for_each_cont(i, label, tp) {
|
||||
|
@ -218,7 +220,8 @@ next:
|
|||
state = match_component(profile, tp, stack, start);
|
||||
if (!state)
|
||||
goto fail;
|
||||
tmp = *(aa_lookup_fperms(rules->file, state, &cond));
|
||||
tmp = *(aa_lookup_condperms(current_fsuid(), rules->file, state,
|
||||
&cond));
|
||||
aa_apply_modes_to_perms(profile, &tmp);
|
||||
aa_perms_accum(perms, &tmp);
|
||||
}
|
||||
|
|
|
@ -169,7 +169,8 @@ static int path_name(const char *op, const struct cred *subj_cred,
|
|||
struct aa_perms default_perms = {};
|
||||
/**
|
||||
* aa_lookup_fperms - convert dfa compressed perms to internal perms
|
||||
* @file_rules: the aa_policydb to lookup perms for (NOT NULL)
|
||||
* @subj_uid: uid to use for subject owner test
|
||||
* @rules: the aa_policydb to lookup perms for (NOT NULL)
|
||||
* @state: state in dfa
|
||||
* @cond: conditions to consider (NOT NULL)
|
||||
*
|
||||
|
@ -177,18 +178,21 @@ struct aa_perms default_perms = {};
|
|||
*
|
||||
* Returns: a pointer to a file permission set
|
||||
*/
|
||||
struct aa_perms *aa_lookup_fperms(struct aa_policydb *file_rules,
|
||||
aa_state_t state, struct path_cond *cond)
|
||||
struct aa_perms *aa_lookup_condperms(kuid_t subj_uid, struct aa_policydb *rules,
|
||||
aa_state_t state, struct path_cond *cond)
|
||||
{
|
||||
unsigned int index = ACCEPT_TABLE(file_rules->dfa)[state];
|
||||
unsigned int index = ACCEPT_TABLE(rules->dfa)[state];
|
||||
|
||||
if (!(file_rules->perms))
|
||||
if (!(rules->perms))
|
||||
return &default_perms;
|
||||
|
||||
if (uid_eq(current_fsuid(), cond->uid))
|
||||
return &(file_rules->perms[index]);
|
||||
if ((ACCEPT_TABLE2(rules->dfa)[state] & ACCEPT_FLAG_OWNER)) {
|
||||
if (uid_eq(subj_uid, cond->uid))
|
||||
return &(rules->perms[index]);
|
||||
return &(rules->perms[index + 1]);
|
||||
}
|
||||
|
||||
return &(file_rules->perms[index + 1]);
|
||||
return &(rules->perms[index]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,7 +211,8 @@ aa_state_t aa_str_perms(struct aa_policydb *file_rules, aa_state_t start,
|
|||
{
|
||||
aa_state_t state;
|
||||
state = aa_dfa_match(file_rules->dfa, start, name);
|
||||
*perms = *(aa_lookup_fperms(file_rules, state, cond));
|
||||
*perms = *(aa_lookup_condperms(current_fsuid(), file_rules, state,
|
||||
cond));
|
||||
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -77,8 +77,9 @@ int aa_audit_file(const struct cred *cred,
|
|||
const char *target, struct aa_label *tlabel, kuid_t ouid,
|
||||
const char *info, int error);
|
||||
|
||||
struct aa_perms *aa_lookup_fperms(struct aa_policydb *file_rules,
|
||||
aa_state_t state, struct path_cond *cond);
|
||||
struct aa_perms *aa_lookup_condperms(kuid_t subj_uid,
|
||||
struct aa_policydb *file_rules,
|
||||
aa_state_t state, struct path_cond *cond);
|
||||
aa_state_t aa_str_perms(struct aa_policydb *file_rules, aa_state_t start,
|
||||
const char *name, struct path_cond *cond,
|
||||
struct aa_perms *perms);
|
||||
|
|
|
@ -59,6 +59,11 @@ extern const char *const aa_profile_mode_names[];
|
|||
|
||||
#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)
|
||||
|
||||
/* flags in the dfa accept2 table */
|
||||
enum dfa_accept_flags {
|
||||
ACCEPT_FLAG_OWNER = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* FIXME: currently need a clean way to replace and remove profiles as a
|
||||
* set. It should be done at the namespace level.
|
||||
|
@ -124,6 +129,7 @@ static inline void aa_put_pdb(struct aa_policydb *pdb)
|
|||
kref_put(&pdb->count, aa_pdb_free_kref);
|
||||
}
|
||||
|
||||
/* lookup perm that doesn't have and object conditional */
|
||||
static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy,
|
||||
aa_state_t state)
|
||||
{
|
||||
|
@ -135,7 +141,6 @@ static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy,
|
|||
return &(policy->perms[index]);
|
||||
}
|
||||
|
||||
|
||||
/* struct aa_data - generic data structure
|
||||
* key: name for retrieving this data
|
||||
* size: size of data in bytes
|
||||
|
|
|
@ -286,10 +286,10 @@ static void remap_dfa_accept(struct aa_dfa *dfa, unsigned int factor)
|
|||
|
||||
AA_BUG(!dfa);
|
||||
|
||||
for (state = 0; state < state_count; state++)
|
||||
for (state = 0; state < state_count; state++) {
|
||||
ACCEPT_TABLE(dfa)[state] = state * factor;
|
||||
kvfree(dfa->tables[YYTD_ID_ACCEPT2]);
|
||||
dfa->tables[YYTD_ID_ACCEPT2] = NULL;
|
||||
ACCEPT_TABLE2(dfa)[state] = factor > 1 ? ACCEPT_FLAG_OWNER : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: merge different dfa mappings into single map_policy fn */
|
||||
|
|
|
@ -716,6 +716,7 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
|
|||
void *pos = e->pos;
|
||||
int i, flags, error = -EPROTO;
|
||||
ssize_t size;
|
||||
u32 version = 0;
|
||||
|
||||
pdb = aa_alloc_pdb(GFP_KERNEL);
|
||||
if (!pdb)
|
||||
|
@ -733,6 +734,9 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
|
|||
if (pdb->perms) {
|
||||
/* perms table present accept is index */
|
||||
flags = TO_ACCEPT1_FLAG(YYTD_DATA32);
|
||||
if (aa_unpack_u32(e, &version, "permsv") && version > 2)
|
||||
/* accept2 used for dfa flags */
|
||||
flags |= TO_ACCEPT2_FLAG(YYTD_DATA32);
|
||||
} else {
|
||||
/* packed perms in accept1 and accept2 */
|
||||
flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
|
||||
|
@ -770,6 +774,20 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
|
|||
}
|
||||
}
|
||||
|
||||
if (pdb->perms && version <= 2) {
|
||||
/* add dfa flags table missing in v2 */
|
||||
u32 noents = pdb->dfa->tables[YYTD_ID_ACCEPT]->td_lolen;
|
||||
u16 tdflags = pdb->dfa->tables[YYTD_ID_ACCEPT]->td_flags;
|
||||
size_t tsize = table_size(noents, tdflags);
|
||||
|
||||
pdb->dfa->tables[YYTD_ID_ACCEPT2] = kvzalloc(tsize, GFP_KERNEL);
|
||||
if (!pdb->dfa->tables[YYTD_ID_ACCEPT2]) {
|
||||
*info = "failed to alloc dfa flags table";
|
||||
goto out;
|
||||
}
|
||||
pdb->dfa->tables[YYTD_ID_ACCEPT2]->td_lolen = noents;
|
||||
pdb->dfa->tables[YYTD_ID_ACCEPT2]->td_flags = tdflags;
|
||||
}
|
||||
/*
|
||||
* Unfortunately due to a bug in earlier userspaces, a
|
||||
* transition table may be present even when the dfa is
|
||||
|
@ -785,7 +803,7 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
|
|||
|
||||
/* TODO: move compat mapping here, requires dfa merging first */
|
||||
/* TODO: move verify here, it has to be done after compat mappings */
|
||||
|
||||
out:
|
||||
*policy = pdb;
|
||||
return 0;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue