state = aa_dfa_match_len(dfa, profile->policy.start[0],
match_str, match_len);
if (state)
- aa_compute_perms(dfa, state, &tmp);
+ tmp = *aa_lookup_perms(profile->policy.perms, state);
}
aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum_raw(perms, &tmp);
xcheck(fn_for_each((L1), (P), (FN1)), fn_for_each((L2), (P), (FN2)))
+extern struct aa_perms default_perms;
+
+static inline struct aa_perms *aa_lookup_perms(struct aa_perms *perms,
+ unsigned int state)
+{
+ if (!(perms))
+ return &default_perms;
+
+ return &(perms[state]);
+}
+
void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs,
u32 mask);
void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
u32 chrsmask, const char * const *names, u32 namesmask);
void aa_apply_modes_to_perms(struct aa_profile *profile,
struct aa_perms *perms);
-void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
- struct aa_perms *perms);
void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend);
void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend);
void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
struct aa_policydb {
/* Generic policy DFA specific rule types will be subsections of it */
struct aa_dfa *dfa;
+ struct aa_perms *perms;
unsigned int start[AA_CLASS_LAST + 1];
};
if (!state)
goto fail;
}
- aa_compute_perms(profile->policy.dfa, state, perms);
+ *perms = *aa_lookup_perms(profile->policy.perms, state);
aa_apply_modes_to_perms(profile, perms);
if ((perms->allow & request) != request)
return -EACCES;
return 0;
next:
- aa_compute_perms(profile->policy.dfa, state, &tmp);
+ tmp = *aa_lookup_perms(profile->policy.perms, state);
aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp);
label_for_each_cont(i, label, tp) {
state = match_component(profile, tp, start);
if (!state)
goto fail;
- aa_compute_perms(profile->policy.dfa, state, &tmp);
+ tmp = *aa_lookup_perms(profile->policy.perms, state);
aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp);
}
*/
}
-static u32 map_other(u32 x)
-{
- return ((x & 0x3) << 8) | /* SETATTR/GETATTR */
- ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */
- ((x & 0x60) << 19); /* SETOPT/GETOPT */
-}
-
-static u32 map_xbits(u32 x)
-{
- return ((x & 0x1) << 7) |
- ((x & 0x7e) << 9);
-}
-
-void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
- struct aa_perms *perms)
-{
- /* This mapping is convulated due to history.
- * v1-v4: only file perms
- * v5: added policydb which dropped in perm user conditional to
- * gain new perm bits, but had to map around the xbits because
- * the userspace compiler was still munging them.
- * v9: adds using the xbits in policydb because the compiler now
- * supports treating policydb permission bits different.
- * Unfortunately there is not way to force auditing on the
- * perms represented by the xbits
- */
- *perms = (struct aa_perms) {
- .allow = dfa_user_allow(dfa, state) |
- map_xbits(dfa_user_xbits(dfa, state)),
- .audit = dfa_user_audit(dfa, state),
- .quiet = dfa_user_quiet(dfa, state) |
- map_xbits(dfa_other_xbits(dfa, state)),
- };
-
- /* for v5-v9 perm mapping in the policydb, the other set is used
- * to extend the general perm set
- */
- perms->allow |= map_other(dfa_other_allow(dfa, state));
- perms->audit |= map_other(dfa_other_audit(dfa, state));
- perms->quiet |= map_other(dfa_other_quiet(dfa, state));
-}
-
/**
* aa_perms_accum_raw - accumulate perms with out masking off overlapping perms
* @accum - perms struct to accumulate into
return state;
}
-/**
- * compute_mnt_perms - compute mount permission associated with @state
- * @dfa: dfa to match against (NOT NULL)
- * @state: state match finished in
- *
- * Returns: mount permissions
- */
-static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa,
- unsigned int state)
-{
- struct aa_perms perms = {
- .allow = dfa_user_allow(dfa, state),
- .audit = dfa_user_audit(dfa, state),
- .quiet = dfa_user_quiet(dfa, state),
- };
-
- return perms;
-}
-
static const char * const mnt_info_table[] = {
"match succeeded",
"failed mntpnt match",
* Returns 0 on success else element that match failed in, this is the
* index into the mnt_info_table above
*/
-static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
+static int do_match_mnt(struct aa_policydb *policy, unsigned int start,
const char *mntpnt, const char *devname,
const char *type, unsigned long flags,
void *data, bool binary, struct aa_perms *perms)
{
unsigned int state;
- AA_BUG(!dfa);
+ AA_BUG(!policy);
+ AA_BUG(!policy->dfa);
+ AA_BUG(!policy->perms);
AA_BUG(!perms);
- state = aa_dfa_match(dfa, start, mntpnt);
- state = aa_dfa_null_transition(dfa, state);
+ state = aa_dfa_match(policy->dfa, start, mntpnt);
+ state = aa_dfa_null_transition(policy->dfa, state);
if (!state)
return 1;
if (devname)
- state = aa_dfa_match(dfa, state, devname);
- state = aa_dfa_null_transition(dfa, state);
+ state = aa_dfa_match(policy->dfa, state, devname);
+ state = aa_dfa_null_transition(policy->dfa, state);
if (!state)
return 2;
if (type)
- state = aa_dfa_match(dfa, state, type);
- state = aa_dfa_null_transition(dfa, state);
+ state = aa_dfa_match(policy->dfa, state, type);
+ state = aa_dfa_null_transition(policy->dfa, state);
if (!state)
return 3;
- state = match_mnt_flags(dfa, state, flags);
+ state = match_mnt_flags(policy->dfa, state, flags);
if (!state)
return 4;
- *perms = compute_mnt_perms(dfa, state);
+ *perms = *aa_lookup_perms(policy->perms, state);
if (perms->allow & AA_MAY_MOUNT)
return 0;
/* only match data if not binary and the DFA flags data is expected */
if (data && !binary && (perms->allow & AA_MNT_CONT_MATCH)) {
- state = aa_dfa_null_transition(dfa, state);
+ state = aa_dfa_null_transition(policy->dfa, state);
if (!state)
return 4;
- state = aa_dfa_match(dfa, state, data);
+ state = aa_dfa_match(policy->dfa, state, data);
if (!state)
return 5;
- *perms = compute_mnt_perms(dfa, state);
+ *perms = *aa_lookup_perms(policy->perms, state);
if (perms->allow & AA_MAY_MOUNT)
return 0;
}
}
error = -EACCES;
- pos = do_match_mnt(profile->policy.dfa,
+ pos = do_match_mnt(&profile->policy,
profile->policy.start[AA_CLASS_MOUNT],
mntpnt, devname, type, flags, data, binary, &perms);
if (pos) {
state = aa_dfa_match(profile->policy.dfa,
profile->policy.start[AA_CLASS_MOUNT],
name);
- perms = compute_mnt_perms(profile->policy.dfa, state);
+ perms = *aa_lookup_perms(profile->policy.perms, state);
if (AA_MAY_UMOUNT & ~perms.allow)
error = -EACCES;
new_name);
state = aa_dfa_null_transition(profile->policy.dfa, state);
state = aa_dfa_match(profile->policy.dfa, state, old_name);
- perms = compute_mnt_perms(profile->policy.dfa, state);
+ perms = *aa_lookup_perms(profile->policy.perms, state);
if (AA_MAY_PIVOTROOT & perms.allow)
error = 0;
buffer[1] = cpu_to_be16((u16) type);
state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer,
4);
- aa_compute_perms(profile->policy.dfa, state, &perms);
+ perms = *aa_lookup_perms(profile->policy.perms, state);
aa_apply_modes_to_perms(profile, &perms);
return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
aa_put_dfa(profile->xmatch);
kvfree(profile->xmatch_perms);
aa_put_dfa(profile->policy.dfa);
-
+ kvfree(profile->policy.perms);
if (profile->data) {
rht = profile->data;
profile->data = NULL;
state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
/* DFAs are restricted from having a state_count of less than 2 */
- table = kvzalloc(state_count * 2 * sizeof(struct aa_perms), GFP_KERNEL);
+ table = kvcalloc(state_count * 2, sizeof(struct aa_perms), GFP_KERNEL);
if (!table)
return NULL;
return perms_table;
}
+static u32 map_other(u32 x)
+{
+ return ((x & 0x3) << 8) | /* SETATTR/GETATTR */
+ ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */
+ ((x & 0x60) << 19); /* SETOPT/GETOPT */
+}
+
+static struct aa_perms compute_perms_entry(struct aa_dfa *dfa,
+ unsigned int state)
+{
+ struct aa_perms perms = { };
+
+ perms.allow = dfa_user_allow(dfa, state);
+ perms.audit = dfa_user_audit(dfa, state);
+ perms.quiet = dfa_user_quiet(dfa, state);
+
+ /* for v5 perm mapping in the policydb, the other set is used
+ * to extend the general perm set
+ */
+
+ perms.allow |= map_other(dfa_other_allow(dfa, state));
+ perms.audit |= map_other(dfa_other_audit(dfa, state));
+ perms.quiet |= map_other(dfa_other_quiet(dfa, state));
+
+ return perms;
+}
+
+static struct aa_perms *compute_perms(struct aa_dfa *dfa)
+{
+ int state;
+ int state_count;
+ struct aa_perms *table;
+
+ AA_BUG(!dfa);
+
+ state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
+ /* DFAs are restricted from having a state_count of less than 2 */
+ table = kvcalloc(state_count, sizeof(struct aa_perms), GFP_KERNEL);
+ if (!table)
+ return NULL;
+
+ /* zero init so skip the trap state (state == 0) */
+ for (state = 1; state < state_count; state++)
+ table[state] = compute_perms_entry(dfa, state);
+
+ return table;
+}
+
/**
* unpack_profile - unpack a serialized profile
* @e: serialized data extent information (NOT NULL)
goto fail;
} else
profile->policy.dfa = aa_get_dfa(nulldfa);
+ profile->policy.perms = compute_perms(profile->policy.dfa);
+ if (!profile->policy.perms) {
+ info = "failed to remap policydb permission table";
+ goto fail;
+ }
/* get file rules */
profile->file.dfa = unpack_dfa(e);