Commit 1ad22fcc authored by John Johansen's avatar John Johansen

apparmor: rework profile->rules to be a list

Convert profile->rules to a list as the next step towards supporting
multiple rulesets in a profile. For this step only support a single
list entry item. The logic for iterating the list will come as a
separate step.
Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
parent 217af7e2
......@@ -611,7 +611,8 @@ static const struct file_operations aa_fs_ns_revision_fops = {
static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms,
const char *match_str, size_t match_len)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_perms tmp = { };
aa_state_t state = DFA_NOMATCH;
......
......@@ -64,7 +64,8 @@ static void audit_cb(struct audit_buffer *ab, void *va)
static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
int cap, int error)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct audit_cache *ent;
int type = AUDIT_APPARMOR_AUTO;
......@@ -115,7 +116,8 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
static int profile_capable(struct aa_profile *profile, int cap,
unsigned int opts, struct common_audit_data *sa)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
int error;
if (cap_raised(rules->caps.allow, cap) &&
......
......@@ -81,7 +81,8 @@ static inline aa_state_t match_component(struct aa_profile *profile,
struct aa_profile *tp,
bool stack, aa_state_t state)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
const char *ns_name;
if (stack)
......@@ -118,7 +119,8 @@ static int label_compound_match(struct aa_profile *profile,
aa_state_t state, bool subns, u32 request,
struct aa_perms *perms)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_profile *tp;
struct label_it i;
struct path_cond cond = { };
......@@ -179,7 +181,8 @@ static int label_components_match(struct aa_profile *profile,
aa_state_t start, bool subns, u32 request,
struct aa_perms *perms)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_profile *tp;
struct label_it i;
struct aa_perms tmp;
......@@ -503,7 +506,8 @@ static const char *next_name(int xtype, const char *name)
struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
const char **name)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_label *label = NULL;
u32 xtype = xindex & AA_X_TYPE_MASK;
int index = xindex & AA_X_INDEX_MASK;
......@@ -553,7 +557,8 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
const char **lookupname,
const char **info)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_label *new = NULL;
struct aa_ns *ns = profile->ns;
u32 xtype = xindex & AA_X_TYPE_MASK;
......@@ -620,7 +625,8 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
char *buffer, struct path_cond *cond,
bool *secure_exec)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_label *new = NULL;
const char *info = NULL, *name = NULL, *target = NULL;
aa_state_t state = rules->file.start[AA_CLASS_FILE];
......@@ -719,7 +725,8 @@ static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec,
char *buffer, struct path_cond *cond,
bool *secure_exec)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
aa_state_t state = rules->file.start[AA_CLASS_FILE];
struct aa_perms perms = {};
const char *xname = NULL, *info = "change_profile onexec";
......@@ -1259,7 +1266,8 @@ static int change_profile_perms_wrapper(const char *op, const char *name,
struct aa_label *target, bool stack,
u32 request, struct aa_perms *perms)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
const char *info = NULL;
int error = 0;
......
......@@ -224,7 +224,8 @@ int __aa_path_perm(const char *op, struct aa_profile *profile, const char *name,
u32 request, struct path_cond *cond, int flags,
struct aa_perms *perms)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
int e = 0;
if (profile_unconfined(profile))
......@@ -317,7 +318,8 @@ static int profile_path_link(struct aa_profile *profile,
const struct path *target, char *buffer2,
struct path_cond *cond)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
const char *lname, *tname = NULL;
struct aa_perms lperms = {}, perms;
const char *info = NULL;
......
......@@ -124,6 +124,7 @@ struct aa_data {
};
/* struct aa_ruleset - data covering mediation rules
* @list: list the rule is on
* @size: the memory consumed by this ruleset
* @policy: general match rules governing policy
* @file: The set of rules governing basic file access and domain transitions
......@@ -133,6 +134,8 @@ struct aa_data {
* @secmark: secmark label match info
*/
struct aa_ruleset {
struct list_head list;
int size;
/* TODO: merge policy and file */
......@@ -147,6 +150,7 @@ struct aa_ruleset {
};
/* struct aa_attachment - data and rules for a profiles attachment
* @list:
* @xmatch_str: human readable attachment string
* @xmatch: optional extended matching for unconfined executables names
* @xmatch_len: xmatch prefix len, used to determine xmatch priority
......@@ -204,7 +208,7 @@ struct aa_profile {
const char *disconnected;
struct aa_attachment attach;
struct aa_ruleset rules;
struct list_head rules;
struct aa_loaddata *rawdata;
unsigned char *hash;
......@@ -227,6 +231,7 @@ void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
void aa_free_proxy_kref(struct kref *kref);
struct aa_ruleset *aa_alloc_ruleset(gfp_t gfp);
struct aa_profile *aa_alloc_profile(const char *name, struct aa_proxy *proxy,
gfp_t gfp);
struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
......@@ -285,6 +290,16 @@ static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF)
return aa_dfa_match_len(rules->policy.dfa, state, (char *) &be_af, 2);
}
static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head,
unsigned char class)
{
struct aa_ruleset *rule;
/* TODO: change to list walk */
rule = list_first_entry(head, typeof(*rule), list);
return RULE_MEDIATES(rule, class);
}
/**
* aa_get_profile - increment refcount on profile @p
* @p: profile (MAYBE NULL)
......
......@@ -78,12 +78,13 @@ static int profile_signal_perm(struct aa_profile *profile,
struct aa_label *peer, u32 request,
struct common_audit_data *sa)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_perms perms;
aa_state_t state;
if (profile_unconfined(profile) ||
!RULE_MEDIATES(rules, AA_CLASS_SIGNAL))
!ANY_RULE_MEDIATES(&profile->rules, AA_CLASS_SIGNAL))
return 0;
aad(sa)->peer = peer;
......
......@@ -351,14 +351,16 @@ int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
u32 request, int type, u32 *deny,
struct common_audit_data *sa)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_perms perms;
aad(sa)->label = &profile->label;
aad(sa)->peer = &target->label;
aad(sa)->request = request;
aa_profile_match_label(profile, &profile->rules, &target->label, type,
request, &perms);
aa_profile_match_label(profile, rules, &target->label, type, request,
&perms);
aa_apply_modes_to_perms(profile, &perms);
*deny |= request & perms.deny;
return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
......
......@@ -163,12 +163,15 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
struct label_it i;
label_for_each_confined(i, label, profile) {
struct aa_ruleset *rules;
if (COMPLAIN_MODE(profile))
continue;
rules = list_first_entry(&profile->rules,
typeof(*rules), list);
*effective = cap_intersect(*effective,
profile->rules.caps.allow);
rules->caps.allow);
*permitted = cap_intersect(*permitted,
profile->rules.caps.allow);
rules->caps.allow);
}
}
rcu_read_unlock();
......
......@@ -303,7 +303,8 @@ static int match_mnt_path_str(struct aa_profile *profile,
{
struct aa_perms perms = { };
const char *mntpnt = NULL, *info = NULL;
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
int pos, error;
AA_BUG(!profile);
......@@ -359,12 +360,14 @@ static int match_mnt(struct aa_profile *profile, const struct path *path,
bool binary)
{
const char *devname = NULL, *info = NULL;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
int error = -EACCES;
AA_BUG(!profile);
AA_BUG(devpath && !devbuffer);
if (!RULE_MEDIATES(&profile->rules, AA_CLASS_MOUNT))
if (!RULE_MEDIATES(rules, AA_CLASS_MOUNT))
return 0;
if (devpath) {
......@@ -566,7 +569,8 @@ int aa_new_mount(struct aa_label *label, const char *dev_name,
static int profile_umount(struct aa_profile *profile, const struct path *path,
char *buffer)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_perms perms = { };
const char *name = NULL, *info = NULL;
aa_state_t state;
......@@ -626,7 +630,8 @@ static struct aa_label *build_pivotroot(struct aa_profile *profile,
const struct path *old_path,
char *old_buffer)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
const char *old_name, *new_name = NULL, *info = NULL;
const char *trans_name = NULL;
struct aa_perms perms = { };
......
......@@ -108,7 +108,8 @@ void audit_net_cb(struct audit_buffer *ab, void *va)
int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
u32 request, u16 family, int type)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_perms perms = { };
aa_state_t state;
__be16 buffer[2];
......@@ -217,7 +218,8 @@ static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
{
int i, ret;
struct aa_perms perms = { };
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
if (rules->secmark_count == 0)
return 0;
......
......@@ -217,6 +217,17 @@ static void free_ruleset(struct aa_ruleset *rules)
kfree_sensitive(rules->secmark);
}
struct aa_ruleset *aa_alloc_ruleset(gfp_t gfp)
{
struct aa_ruleset *rules;
rules = kzalloc(sizeof(*rules), gfp);
if (rules)
INIT_LIST_HEAD(&rules->list);
return rules;
}
/**
* aa_free_profile - free a profile
* @profile: the profile to free (MAYBE NULL)
......@@ -229,6 +240,7 @@ static void free_ruleset(struct aa_ruleset *rules)
*/
void aa_free_profile(struct aa_profile *profile)
{
struct aa_ruleset *rule, *tmp;
struct rhashtable *rht;
AA_DEBUG("%s(%p)\n", __func__, profile);
......@@ -244,7 +256,15 @@ void aa_free_profile(struct aa_profile *profile)
kfree_sensitive(profile->rename);
free_attachment(&profile->attach);
free_ruleset(&profile->rules);
/*
* at this point there are no tasks that can have a reference
* to rules
*/
list_for_each_entry_safe(rule, tmp, &profile->rules, list) {
list_del_init(&rule->list);
free_ruleset(rule);
}
kfree_sensitive(profile->dirname);
if (profile->data) {
......@@ -272,6 +292,7 @@ struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy,
gfp_t gfp)
{
struct aa_profile *profile;
struct aa_ruleset *rules;
/* freed by free_profile - usually through aa_put_profile */
profile = kzalloc(struct_size(profile, label.vec, 2), gfp);
......@@ -283,6 +304,14 @@ struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy,
if (!aa_label_init(&profile->label, 1, gfp))
goto fail;
INIT_LIST_HEAD(&profile->rules);
/* allocate the first ruleset, but leave it empty */
rules = aa_alloc_ruleset(gfp);
if (!rules)
goto fail;
list_add(&rules->list, &profile->rules);
/* update being set needed by fs interface */
if (!proxy) {
proxy = aa_alloc_proxy(&profile->label, gfp);
......@@ -516,6 +545,7 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
const char *base, gfp_t gfp)
{
struct aa_ruleset *rules;
struct aa_profile *p, *profile;
const char *bname;
char *name = NULL;
......@@ -558,8 +588,9 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
/* released on free_profile */
rcu_assign_pointer(profile->parent, aa_get_profile(parent));
profile->ns = aa_get_ns(parent->ns);
profile->rules.file.dfa = aa_get_dfa(nulldfa);
profile->rules.policy.dfa = aa_get_dfa(nulldfa);
rules = list_first_entry(&profile->rules, typeof(*rules), list);
rules->file.dfa = aa_get_dfa(nulldfa);
rules->policy.dfa = aa_get_dfa(nulldfa);
mutex_lock_nested(&profile->ns->lock, profile->ns->level);
p = __find_child(&parent->base.profiles, bname);
......
......@@ -83,6 +83,7 @@ const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns)
static struct aa_profile *alloc_unconfined(const char *name)
{
struct aa_profile *profile;
struct aa_ruleset *rules;
profile = aa_alloc_profile(name, NULL, GFP_KERNEL);
if (!profile)
......@@ -91,8 +92,9 @@ static struct aa_profile *alloc_unconfined(const char *name)
profile->label.flags |= FLAG_IX_ON_NAME_ERROR |
FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
profile->mode = APPARMOR_UNCONFINED;
profile->rules.file.dfa = aa_get_dfa(nulldfa);
profile->rules.policy.dfa = aa_get_dfa(nulldfa);
rules = list_first_entry(&profile->rules, typeof(*rules), list);
rules->file.dfa = aa_get_dfa(nulldfa);
rules->policy.dfa = aa_get_dfa(nulldfa);
return profile;
}
......
......@@ -577,9 +577,8 @@ static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
return false;
}
static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile)
static bool unpack_secmark(struct aa_ext *e, struct aa_ruleset *rules)
{
struct aa_ruleset *rules = &profile->rules;
void *pos = e->pos;
u16 size;
int i;
......@@ -624,7 +623,7 @@ static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile)
return false;
}
static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
static bool unpack_rlimits(struct aa_ext *e, struct aa_ruleset *rules)
{
void *pos = e->pos;
......@@ -635,7 +634,7 @@ static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
u32 tmp = 0;
if (!unpack_u32(e, &tmp, NULL))
goto fail;
profile->rules.rlimits.mask = tmp;
rules->rlimits.mask = tmp;
if (unpack_array(e, NULL, &size) != TRI_TRUE ||
size > RLIM_NLIMITS)
......@@ -645,7 +644,7 @@ static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
int a = aa_map_resource(i);
if (!unpack_u64(e, &tmp2, NULL))
goto fail;
profile->rules.rlimits.limits[a].rlim_max = tmp2;
rules->rlimits.limits[a].rlim_max = tmp2;
}
if (!unpack_nameX(e, AA_ARRAYEND, NULL))
goto fail;
......@@ -852,7 +851,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
profile = aa_alloc_profile(name, NULL, GFP_KERNEL);
if (!profile)
return ERR_PTR(-ENOMEM);
rules = &profile->rules;
rules = list_first_entry(&profile->rules, typeof(*rules), list);
/* profile renaming is optional */
(void) unpack_str(e, &profile->rename, "rename");
......@@ -971,12 +970,12 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
}
if (!unpack_rlimits(e, profile)) {
if (!unpack_rlimits(e, rules)) {
info = "failed to unpack profile rlimits";
goto fail;
}
if (!unpack_secmark(e, profile)) {
if (!unpack_secmark(e, rules)) {
info = "failed to unpack profile secmark rules";
goto fail;
}
......@@ -1208,23 +1207,26 @@ static bool verify_perms(struct aa_policydb *pdb)
*/
static int verify_profile(struct aa_profile *profile)
{
if ((profile->rules.file.dfa &&
!verify_dfa_xindex(profile->rules.file.dfa,
profile->rules.file.trans.size)) ||
(profile->rules.policy.dfa &&
!verify_dfa_xindex(profile->rules.policy.dfa,
profile->rules.policy.trans.size))) {
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
if (!rules)
return 0;
if ((rules->file.dfa && !verify_dfa_xindex(rules->file.dfa,
rules->file.trans.size)) ||
(rules->policy.dfa &&
!verify_dfa_xindex(rules->policy.dfa, rules->policy.trans.size))) {
audit_iface(profile, NULL, NULL,
"Unpack: Invalid named transition", NULL, -EPROTO);
return -EPROTO;
}
if (!verify_perms(&profile->rules.file)) {
if (!verify_perms(&rules->file)) {
audit_iface(profile, NULL, NULL,
"Unpack: Invalid perm index", NULL, -EPROTO);
return -EPROTO;
}
if (!verify_perms(&profile->rules.policy)) {
if (!verify_perms(&rules->policy)) {
audit_iface(profile, NULL, NULL,
"Unpack: Invalid perm index", NULL, -EPROTO);
return -EPROTO;
......
......@@ -82,7 +82,8 @@ int aa_map_resource(int resource)
static int profile_setrlimit(struct aa_profile *profile, unsigned int resource,
struct rlimit *new_rlim)
{
struct aa_ruleset *rules = &profile->rules;
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
int e = 0;
if (rules->rlimits.mask & (1 << resource) && new_rlim->rlim_max >
......@@ -154,12 +155,15 @@ void __aa_transition_rlimits(struct aa_label *old_l, struct aa_label *new_l)
* to the lesser of the tasks hard limit and the init tasks soft limit
*/
label_for_each_confined(i, old_l, old) {
if (old->rules.rlimits.mask) {
struct aa_ruleset *rules = list_first_entry(&old->rules,
typeof(*rules),
list);
if (rules->rlimits.mask) {
int j;
for (j = 0, mask = 1; j < RLIM_NLIMITS; j++,
mask <<= 1) {
if (old->rules.rlimits.mask & mask) {
if (rules->rlimits.mask & mask) {
rlim = current->signal->rlim + j;
initrlim = init_task.signal->rlim + j;
rlim->rlim_cur = min(rlim->rlim_max,
......@@ -171,17 +175,20 @@ void __aa_transition_rlimits(struct aa_label *old_l, struct aa_label *new_l)
/* set any new hard limits as dictated by the new profile */
label_for_each_confined(i, new_l, new) {
struct aa_ruleset *rules = list_first_entry(&new->rules,
typeof(*rules),
list);
int j;
if (!new->rules.rlimits.mask)
if (!rules->rlimits.mask)
continue;
for (j = 0, mask = 1; j < RLIM_NLIMITS; j++, mask <<= 1) {
if (!(new->rules.rlimits.mask & mask))
if (!(rules->rlimits.mask & mask))
continue;
rlim = current->signal->rlim + j;
rlim->rlim_max = min(rlim->rlim_max,
new->rules.rlimits.limits[j].rlim_max);
rules->rlimits.limits[j].rlim_max);
/* soft limit should not exceed hard limit */
rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
}
......
......@@ -229,11 +229,13 @@ static int profile_ptrace_perm(struct aa_profile *profile,
struct aa_label *peer, u32 request,
struct common_audit_data *sa)
{
struct aa_ruleset *rules = list_first_entry(&profile->rules,
typeof(*rules), list);
struct aa_perms perms = { };
aad(sa)->peer = peer;
aa_profile_match_label(profile, &profile->rules, peer,
AA_CLASS_PTRACE, request, &perms);
aa_profile_match_label(profile, rules, peer, AA_CLASS_PTRACE, request,
&perms);
aa_apply_modes_to_perms(profile, &perms);
return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb);
}
......@@ -243,7 +245,7 @@ static int profile_tracee_perm(struct aa_profile *tracee,
struct common_audit_data *sa)
{
if (profile_unconfined(tracee) || unconfined(tracer) ||
!RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE))
!ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE))
return 0;
return profile_ptrace_perm(tracee, tracer, request, sa);
......@@ -256,7 +258,7 @@ static int profile_tracer_perm(struct aa_profile *tracer,
if (profile_unconfined(tracer))
return 0;
if (RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE))
if (ANY_RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE))
return profile_ptrace_perm(tracer, tracee, request, sa);
/* profile uses the old style capability check for ptrace */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment