summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--security/apparmor/apparmorfs.c5
-rw-r--r--security/apparmor/domain.c9
-rw-r--r--security/apparmor/file.c23
-rw-r--r--security/apparmor/include/file.h5
-rw-r--r--security/apparmor/include/policy.h7
-rw-r--r--security/apparmor/policy_compat.c6
-rw-r--r--security/apparmor/policy_unpack.c20
7 files changed, 54 insertions, 21 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index e42ac7aadd31..65191c5fc5e3 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -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),
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index af196005d5ee..630806573793 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -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);
}
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index 81c54ffd63cb..6ce6547301dc 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -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;
}
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
index 6e8f2aa66cd6..06d9899098a6 100644
--- a/security/apparmor/include/file.h
+++ b/security/apparmor/include/file.h
@@ -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);
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 256fb27e5c3a..bfd8bf1a1ecd 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -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
diff --git a/security/apparmor/policy_compat.c b/security/apparmor/policy_compat.c
index 423227670e68..cfc2207e5a12 100644
--- a/security/apparmor/policy_compat.c
+++ b/security/apparmor/policy_compat.c
@@ -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 */
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 287e08ac4b4b..7813920a21e5 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -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;