Commit 637f688d authored by John Johansen's avatar John Johansen

apparmor: switch from profiles to using labels on contexts

Begin the actual switch to using domain labels by storing them on
the context and converting the label to a singular profile where
possible.
Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
parent f1bd9041
...@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o ...@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
resource.o secid.o file.o policy_ns.o resource.o secid.o file.o policy_ns.o label.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
clean-files := capability_names.h rlim_names.h clean-files := capability_names.h rlim_names.h
......
...@@ -405,26 +405,26 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf, ...@@ -405,26 +405,26 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf,
static ssize_t policy_update(u32 mask, const char __user *buf, size_t size, static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
loff_t *pos, struct aa_ns *ns) loff_t *pos, struct aa_ns *ns)
{ {
ssize_t error;
struct aa_loaddata *data; struct aa_loaddata *data;
struct aa_profile *profile; struct aa_label *label;
ssize_t error;
profile = begin_current_profile_crit_section(); label = begin_current_label_crit_section();
/* high level check about policy management - fine grained in /* high level check about policy management - fine grained in
* below after unpack * below after unpack
*/ */
error = aa_may_manage_policy(profile, ns, mask); error = aa_may_manage_policy(label, ns, mask);
if (error) if (error)
return error; return error;
data = aa_simple_write_to_buffer(buf, size, size, pos); data = aa_simple_write_to_buffer(buf, size, size, pos);
error = PTR_ERR(data); error = PTR_ERR(data);
if (!IS_ERR(data)) { if (!IS_ERR(data)) {
error = aa_replace_profiles(ns, profile, mask, data); error = aa_replace_profiles(ns, label, mask, data);
aa_put_loaddata(data); aa_put_loaddata(data);
} }
end_current_profile_crit_section(profile); end_current_label_crit_section(label);
return error; return error;
} }
...@@ -468,15 +468,15 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, ...@@ -468,15 +468,15 @@ static ssize_t profile_remove(struct file *f, const char __user *buf,
size_t size, loff_t *pos) size_t size, loff_t *pos)
{ {
struct aa_loaddata *data; struct aa_loaddata *data;
struct aa_profile *profile; struct aa_label *label;
ssize_t error; ssize_t error;
struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
profile = begin_current_profile_crit_section(); label = begin_current_label_crit_section();
/* high level check about policy management - fine grained in /* high level check about policy management - fine grained in
* below after unpack * below after unpack
*/ */
error = aa_may_manage_policy(profile, ns, AA_MAY_REMOVE_POLICY); error = aa_may_manage_policy(label, ns, AA_MAY_REMOVE_POLICY);
if (error) if (error)
goto out; goto out;
...@@ -489,11 +489,11 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, ...@@ -489,11 +489,11 @@ static ssize_t profile_remove(struct file *f, const char __user *buf,
error = PTR_ERR(data); error = PTR_ERR(data);
if (!IS_ERR(data)) { if (!IS_ERR(data)) {
data->data[size] = 0; data->data[size] = 0;
error = aa_remove_profiles(ns, profile, data->data, size); error = aa_remove_profiles(ns, label, data->data, size);
aa_put_loaddata(data); aa_put_loaddata(data);
} }
out: out:
end_current_profile_crit_section(profile); end_current_label_crit_section(label);
aa_put_ns(ns); aa_put_ns(ns);
return error; return error;
} }
...@@ -605,7 +605,7 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms, ...@@ -605,7 +605,7 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms,
struct aa_dfa *dfa; struct aa_dfa *dfa;
unsigned int state = 0; unsigned int state = 0;
if (unconfined(profile)) if (profile_unconfined(profile))
return; return;
if (profile->file.dfa && *match_str == AA_CLASS_FILE) { if (profile->file.dfa && *match_str == AA_CLASS_FILE) {
dfa = profile->file.dfa; dfa = profile->file.dfa;
...@@ -655,7 +655,7 @@ static ssize_t query_data(char *buf, size_t buf_len, ...@@ -655,7 +655,7 @@ static ssize_t query_data(char *buf, size_t buf_len,
{ {
char *out; char *out;
const char *key; const char *key;
struct aa_profile *profile, *curr; struct aa_label *label, *curr;
struct aa_data *data; struct aa_data *data;
u32 bytes, blocks; u32 bytes, blocks;
__le32 outle32; __le32 outle32;
...@@ -672,11 +672,11 @@ static ssize_t query_data(char *buf, size_t buf_len, ...@@ -672,11 +672,11 @@ static ssize_t query_data(char *buf, size_t buf_len,
if (buf_len < sizeof(bytes) + sizeof(blocks)) if (buf_len < sizeof(bytes) + sizeof(blocks))
return -EINVAL; /* not enough space */ return -EINVAL; /* not enough space */
curr = begin_current_profile_crit_section(); curr = begin_current_label_crit_section();
profile = aa_fqlookupn_profile(curr, query, strnlen(query, query_len)); label = aa_label_parse(curr, query, GFP_KERNEL, false, false);
end_current_profile_crit_section(curr); end_current_label_crit_section(curr);
if (!profile) if (IS_ERR(label))
return -ENOENT; return PTR_ERR(label);
/* We are going to leave space for two numbers. The first is the total /* We are going to leave space for two numbers. The first is the total
* number of bytes we are writing after the first number. This is so * number of bytes we are writing after the first number. This is so
...@@ -690,13 +690,16 @@ static ssize_t query_data(char *buf, size_t buf_len, ...@@ -690,13 +690,16 @@ static ssize_t query_data(char *buf, size_t buf_len,
out = buf + sizeof(bytes) + sizeof(blocks); out = buf + sizeof(bytes) + sizeof(blocks);
blocks = 0; blocks = 0;
if (profile->data) { if (labels_profile(label)->data) {
data = rhashtable_lookup_fast(profile->data, &key, data = rhashtable_lookup_fast(labels_profile(label)->data, &key,
profile->data->p); labels_profile(label)->data->p);
if (data) { if (data) {
if (out + sizeof(outle32) + data->size > buf + buf_len) if (out + sizeof(outle32) + data->size >
buf + buf_len) {
aa_put_label(label);
return -EINVAL; /* not enough space */ return -EINVAL; /* not enough space */
}
outle32 = __cpu_to_le32(data->size); outle32 = __cpu_to_le32(data->size);
memcpy(out, &outle32, sizeof(outle32)); memcpy(out, &outle32, sizeof(outle32));
out += sizeof(outle32); out += sizeof(outle32);
...@@ -705,7 +708,7 @@ static ssize_t query_data(char *buf, size_t buf_len, ...@@ -705,7 +708,7 @@ static ssize_t query_data(char *buf, size_t buf_len,
blocks++; blocks++;
} }
} }
aa_put_profile(profile); aa_put_label(label);
outle32 = __cpu_to_le32(out - buf - sizeof(bytes)); outle32 = __cpu_to_le32(out - buf - sizeof(bytes));
memcpy(buf, &outle32, sizeof(outle32)); memcpy(buf, &outle32, sizeof(outle32));
...@@ -738,7 +741,7 @@ static ssize_t query_data(char *buf, size_t buf_len, ...@@ -738,7 +741,7 @@ static ssize_t query_data(char *buf, size_t buf_len,
static ssize_t query_label(char *buf, size_t buf_len, static ssize_t query_label(char *buf, size_t buf_len,
char *query, size_t query_len, bool view_only) char *query, size_t query_len, bool view_only)
{ {
struct aa_profile *profile, *curr; struct aa_label *label, *curr;
char *label_name, *match_str; char *label_name, *match_str;
size_t label_name_len, match_len; size_t label_name_len, match_len;
struct aa_perms perms; struct aa_perms perms;
...@@ -760,14 +763,14 @@ static ssize_t query_label(char *buf, size_t buf_len, ...@@ -760,14 +763,14 @@ static ssize_t query_label(char *buf, size_t buf_len,
match_str = label_name + label_name_len + 1; match_str = label_name + label_name_len + 1;
match_len = query_len - label_name_len - 1; match_len = query_len - label_name_len - 1;
curr = begin_current_profile_crit_section(); curr = begin_current_label_crit_section();
profile = aa_fqlookupn_profile(curr, label_name, label_name_len); label = aa_label_parse(curr, label_name, GFP_KERNEL, false, false);
end_current_profile_crit_section(curr); end_current_label_crit_section(curr);
if (!profile) if (IS_ERR(label))
return -ENOENT; return PTR_ERR(label);
perms = allperms; perms = allperms;
profile_query_cb(profile, &perms, match_str, match_len); profile_query_cb(labels_profile(label), &perms, match_str, match_len);
return scnprintf(buf, buf_len, return scnprintf(buf, buf_len,
"allow 0x%08x\ndeny 0x%08x\naudit 0x%08x\nquiet 0x%08x\n", "allow 0x%08x\ndeny 0x%08x\naudit 0x%08x\nquiet 0x%08x\n",
...@@ -1026,9 +1029,10 @@ static int seq_profile_release(struct inode *inode, struct file *file) ...@@ -1026,9 +1029,10 @@ static int seq_profile_release(struct inode *inode, struct file *file)
static int seq_profile_name_show(struct seq_file *seq, void *v) static int seq_profile_name_show(struct seq_file *seq, void *v)
{ {
struct aa_proxy *proxy = seq->private; struct aa_proxy *proxy = seq->private;
struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); struct aa_label *label = aa_get_label_rcu(&proxy->label);
struct aa_profile *profile = labels_profile(label);
seq_printf(seq, "%s\n", profile->base.name); seq_printf(seq, "%s\n", profile->base.name);
aa_put_profile(profile); aa_put_label(label);
return 0; return 0;
} }
...@@ -1036,9 +1040,10 @@ static int seq_profile_name_show(struct seq_file *seq, void *v) ...@@ -1036,9 +1040,10 @@ static int seq_profile_name_show(struct seq_file *seq, void *v)
static int seq_profile_mode_show(struct seq_file *seq, void *v) static int seq_profile_mode_show(struct seq_file *seq, void *v)
{ {
struct aa_proxy *proxy = seq->private; struct aa_proxy *proxy = seq->private;
struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); struct aa_label *label = aa_get_label_rcu(&proxy->label);
struct aa_profile *profile = labels_profile(label);
seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]); seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]);
aa_put_profile(profile); aa_put_label(label);
return 0; return 0;
} }
...@@ -1046,14 +1051,15 @@ static int seq_profile_mode_show(struct seq_file *seq, void *v) ...@@ -1046,14 +1051,15 @@ static int seq_profile_mode_show(struct seq_file *seq, void *v)
static int seq_profile_attach_show(struct seq_file *seq, void *v) static int seq_profile_attach_show(struct seq_file *seq, void *v)
{ {
struct aa_proxy *proxy = seq->private; struct aa_proxy *proxy = seq->private;
struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); struct aa_label *label = aa_get_label_rcu(&proxy->label);
struct aa_profile *profile = labels_profile(label);
if (profile->attach) if (profile->attach)
seq_printf(seq, "%s\n", profile->attach); seq_printf(seq, "%s\n", profile->attach);
else if (profile->xmatch) else if (profile->xmatch)
seq_puts(seq, "<unknown>\n"); seq_puts(seq, "<unknown>\n");
else else
seq_printf(seq, "%s\n", profile->base.name); seq_printf(seq, "%s\n", profile->base.name);
aa_put_profile(profile); aa_put_label(label);
return 0; return 0;
} }
...@@ -1061,7 +1067,8 @@ static int seq_profile_attach_show(struct seq_file *seq, void *v) ...@@ -1061,7 +1067,8 @@ static int seq_profile_attach_show(struct seq_file *seq, void *v)
static int seq_profile_hash_show(struct seq_file *seq, void *v) static int seq_profile_hash_show(struct seq_file *seq, void *v)
{ {
struct aa_proxy *proxy = seq->private; struct aa_proxy *proxy = seq->private;
struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); struct aa_label *label = aa_get_label_rcu(&proxy->label);
struct aa_profile *profile = labels_profile(label);
unsigned int i, size = aa_hash_size(); unsigned int i, size = aa_hash_size();
if (profile->hash) { if (profile->hash) {
...@@ -1069,7 +1076,7 @@ static int seq_profile_hash_show(struct seq_file *seq, void *v) ...@@ -1069,7 +1076,7 @@ static int seq_profile_hash_show(struct seq_file *seq, void *v)
seq_printf(seq, "%.2x", profile->hash[i]); seq_printf(seq, "%.2x", profile->hash[i]);
seq_putc(seq, '\n'); seq_putc(seq, '\n');
} }
aa_put_profile(profile); aa_put_label(label);
return 0; return 0;
} }
...@@ -1101,22 +1108,22 @@ static const struct file_operations seq_ns_ ##NAME ##_fops = { \ ...@@ -1101,22 +1108,22 @@ static const struct file_operations seq_ns_ ##NAME ##_fops = { \
static int seq_ns_level_show(struct seq_file *seq, void *v) static int seq_ns_level_show(struct seq_file *seq, void *v)
{ {
struct aa_profile *profile; struct aa_label *label;
profile = begin_current_profile_crit_section(); label = begin_current_label_crit_section();
seq_printf(seq, "%d\n", profile->ns->level); seq_printf(seq, "%d\n", labels_ns(label)->level);
end_current_profile_crit_section(profile); end_current_label_crit_section(label);
return 0; return 0;
} }
static int seq_ns_name_show(struct seq_file *seq, void *v) static int seq_ns_name_show(struct seq_file *seq, void *v)
{ {
struct aa_profile *profile; struct aa_label *label = begin_current_label_crit_section();
profile = begin_current_profile_crit_section(); seq_printf(seq, "%s\n", aa_ns_name(labels_ns(label),
seq_printf(seq, "%s\n", aa_ns_name(profile->ns, profile->ns, true)); labels_ns(label), true));
end_current_profile_crit_section(profile); end_current_label_crit_section(label);
return 0; return 0;
} }
...@@ -1380,7 +1387,7 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name, ...@@ -1380,7 +1387,7 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name,
struct aa_profile *profile, struct aa_profile *profile,
const struct file_operations *fops) const struct file_operations *fops)
{ {
struct aa_proxy *proxy = aa_get_proxy(profile->proxy); struct aa_proxy *proxy = aa_get_proxy(profile->label.proxy);
struct dentry *dent; struct dentry *dent;
dent = aafs_create_file(name, S_IFREG | 0444, dir, proxy, fops); dent = aafs_create_file(name, S_IFREG | 0444, dir, proxy, fops);
...@@ -1541,9 +1548,12 @@ static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -1541,9 +1548,12 @@ static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode)
{ {
struct aa_ns *ns, *parent; struct aa_ns *ns, *parent;
/* TODO: improve permission check */ /* TODO: improve permission check */
struct aa_profile *profile = begin_current_profile_crit_section(); struct aa_label *label;
int error = aa_may_manage_policy(profile, NULL, AA_MAY_LOAD_POLICY); int error;
end_current_profile_crit_section(profile);
label = begin_current_label_crit_section();
error = aa_may_manage_policy(label, NULL, AA_MAY_LOAD_POLICY);
end_current_label_crit_section(label);
if (error) if (error)
return error; return error;
...@@ -1587,13 +1597,16 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) ...@@ -1587,13 +1597,16 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry)
{ {
struct aa_ns *ns, *parent; struct aa_ns *ns, *parent;
/* TODO: improve permission check */ /* TODO: improve permission check */
struct aa_profile *profile = begin_current_profile_crit_section(); struct aa_label *label;
int error = aa_may_manage_policy(profile, NULL, AA_MAY_LOAD_POLICY); int error;
end_current_profile_crit_section(profile);
label = begin_current_label_crit_section();
error = aa_may_manage_policy(label, NULL, AA_MAY_LOAD_POLICY);
end_current_label_crit_section(label);
if (error) if (error)
return error; return error;
parent = aa_get_ns(dir->i_private); parent = aa_get_ns(dir->i_private);
/* rmdir calls the generic securityfs functions to remove files /* rmdir calls the generic securityfs functions to remove files
* from the apparmor dir. It is up to the apparmor ns locking * from the apparmor dir. It is up to the apparmor ns locking
* to avoid races. * to avoid races.
...@@ -1999,10 +2012,9 @@ static int seq_show_profile(struct seq_file *f, void *p) ...@@ -1999,10 +2012,9 @@ static int seq_show_profile(struct seq_file *f, void *p)
struct aa_profile *profile = (struct aa_profile *)p; struct aa_profile *profile = (struct aa_profile *)p;
struct aa_ns *root = f->private; struct aa_ns *root = f->private;
if (profile->ns != root) aa_label_seq_xprint(f, root, &profile->label,
seq_printf(f, ":%s://", aa_ns_name(root, profile->ns, true)); FLAG_SHOW_MODE | FLAG_VIEW_SUBNS, GFP_KERNEL);
seq_printf(f, "%s (%s)\n", profile->base.hname, seq_putc(f, '\n');
aa_profile_mode_names[profile->mode]);
return 0; return 0;
} }
......
...@@ -77,14 +77,24 @@ static void audit_pre(struct audit_buffer *ab, void *ca) ...@@ -77,14 +77,24 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
audit_log_format(ab, " error=%d", aad(sa)->error); audit_log_format(ab, " error=%d", aad(sa)->error);
} }
if (aad(sa)->profile) { if (aad(sa)->label) {
struct aa_profile *profile = aad(sa)->profile; struct aa_label *label = aad(sa)->label;
if (profile->ns != root_ns) {
audit_log_format(ab, " namespace="); if (label_isprofile(label)) {
audit_log_untrustedstring(ab, profile->ns->base.hname); struct aa_profile *profile = labels_profile(label);
if (profile->ns != root_ns) {
audit_log_format(ab, " namespace=");
audit_log_untrustedstring(ab,
profile->ns->base.hname);
}
audit_log_format(ab, " profile=");
audit_log_untrustedstring(ab, profile->base.hname);
} else {
audit_log_format(ab, " label=");
aa_label_xaudit(ab, root_ns, label, FLAG_VIEW_SUBNS,
GFP_ATOMIC);
} }
audit_log_format(ab, " profile=");
audit_log_untrustedstring(ab, profile->base.hname);
} }
if (aad(sa)->name) { if (aad(sa)->name) {
...@@ -139,8 +149,7 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, ...@@ -139,8 +149,7 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
type = AUDIT_APPARMOR_KILL; type = AUDIT_APPARMOR_KILL;
if (!unconfined(profile)) aad(sa)->label = &profile->label;
aad(sa)->profile = profile;
aa_audit_msg(type, sa, cb); aa_audit_msg(type, sa, cb);
......
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
* *
* *
* AppArmor sets confinement on every task, via the the aa_task_ctx and * AppArmor sets confinement on every task, via the the aa_task_ctx and
* the aa_task_ctx.profile, both of which are required and are not allowed * the aa_task_ctx.label, both of which are required and are not allowed
* to be NULL. The aa_task_ctx is not reference counted and is unique * to be NULL. The aa_task_ctx is not reference counted and is unique
* to each cred (which is reference count). The profile pointed to by * to each cred (which is reference count). The label pointed to by
* the task_ctx is reference counted. * the task_ctx is reference counted.
* *
* TODO * TODO
...@@ -47,9 +47,9 @@ struct aa_task_ctx *aa_alloc_task_context(gfp_t flags) ...@@ -47,9 +47,9 @@ struct aa_task_ctx *aa_alloc_task_context(gfp_t flags)
void aa_free_task_context(struct aa_task_ctx *ctx) void aa_free_task_context(struct aa_task_ctx *ctx)
{ {
if (ctx) { if (ctx) {
aa_put_profile(ctx->profile); aa_put_label(ctx->label);
aa_put_profile(ctx->previous); aa_put_label(ctx->previous);
aa_put_profile(ctx->onexec); aa_put_label(ctx->onexec);
kzfree(ctx); kzfree(ctx);
} }
...@@ -63,41 +63,41 @@ void aa_free_task_context(struct aa_task_ctx *ctx) ...@@ -63,41 +63,41 @@ void aa_free_task_context(struct aa_task_ctx *ctx)
void aa_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old) void aa_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old)
{ {
*new = *old; *new = *old;
aa_get_profile(new->profile); aa_get_label(new->label);
aa_get_profile(new->previous); aa_get_label(new->previous);
aa_get_profile(new->onexec); aa_get_label(new->onexec);
} }
/** /**
* aa_get_task_profile - Get another task's profile * aa_get_task_label - Get another task's label
* @task: task to query (NOT NULL) * @task: task to query (NOT NULL)
* *
* Returns: counted reference to @task's profile * Returns: counted reference to @task's label
*/ */
struct aa_profile *aa_get_task_profile(struct task_struct *task) struct aa_label *aa_get_task_label(struct task_struct *task)
{ {
struct aa_profile *p; struct aa_label *p;
rcu_read_lock(); rcu_read_lock();
p = aa_get_newest_profile(__aa_task_raw_profile(task)); p = aa_get_newest_label(__aa_task_raw_label(task));
rcu_read_unlock(); rcu_read_unlock();
return p; return p;
} }
/** /**
* aa_replace_current_profile - replace the current tasks profiles * aa_replace_current_label - replace the current tasks label
* @profile: new profile (NOT NULL) * @label: new label (NOT NULL)
* *
* Returns: 0 or error on failure * Returns: 0 or error on failure
*/ */
int aa_replace_current_profile(struct aa_profile *profile) int aa_replace_current_label(struct aa_label *label)
{ {
struct aa_task_ctx *ctx = current_ctx(); struct aa_task_ctx *ctx = current_ctx();
struct cred *new; struct cred *new;
AA_BUG(!profile); AA_BUG(!label);
if (ctx->profile == profile) if (ctx->label == label)
return 0; return 0;
if (current_cred() != current_real_cred()) if (current_cred() != current_real_cred())
...@@ -108,8 +108,8 @@ int aa_replace_current_profile(struct aa_profile *profile) ...@@ -108,8 +108,8 @@ int aa_replace_current_profile(struct aa_profile *profile)
return -ENOMEM; return -ENOMEM;
ctx = cred_ctx(new); ctx = cred_ctx(new);
if (unconfined(profile) || (ctx->profile->ns != profile->ns)) if (unconfined(label) || (labels_ns(ctx->label) != labels_ns(label)))
/* if switching to unconfined or a different profile namespace /* if switching to unconfined or a different label namespace
* clear out context state * clear out context state
*/ */
aa_clear_task_ctx_trans(ctx); aa_clear_task_ctx_trans(ctx);
...@@ -120,9 +120,9 @@ int aa_replace_current_profile(struct aa_profile *profile) ...@@ -120,9 +120,9 @@ int aa_replace_current_profile(struct aa_profile *profile)
* keeping @profile valid, so make sure to get its reference before * keeping @profile valid, so make sure to get its reference before
* dropping the reference on ctx->profile * dropping the reference on ctx->profile
*/ */
aa_get_profile(profile); aa_get_label(label);
aa_put_profile(ctx->profile); aa_put_label(ctx->label);
ctx->profile = profile; ctx->label = label;
commit_creds(new); commit_creds(new);
return 0; return 0;
...@@ -130,11 +130,11 @@ int aa_replace_current_profile(struct aa_profile *profile) ...@@ -130,11 +130,11 @@ int aa_replace_current_profile(struct aa_profile *profile)
/** /**
* aa_set_current_onexec - set the tasks change_profile to happen onexec * aa_set_current_onexec - set the tasks change_profile to happen onexec
* @profile: system profile to set at exec (MAYBE NULL to clear value) * @label: system label to set at exec (MAYBE NULL to clear value)
* * @stack: whether stacking should be done
* Returns: 0 or error on failure * Returns: 0 or error on failure
*/ */
int aa_set_current_onexec(struct aa_profile *profile) int aa_set_current_onexec(struct aa_label *label, bool stack)
{ {
struct aa_task_ctx *ctx; struct aa_task_ctx *ctx;
struct cred *new = prepare_creds(); struct cred *new = prepare_creds();
...@@ -142,9 +142,10 @@ int aa_set_current_onexec(struct aa_profile *profile) ...@@ -142,9 +142,10 @@ int aa_set_current_onexec(struct aa_profile *profile)
return -ENOMEM; return -ENOMEM;
ctx = cred_ctx(new); ctx = cred_ctx(new);
aa_get_profile(profile); aa_get_label(label);
aa_put_profile(ctx->onexec); aa_clear_task_ctx_trans(ctx);
ctx->onexec = profile; ctx->onexec = label;
ctx->token = stack;
commit_creds(new); commit_creds(new);
return 0; return 0;
...@@ -152,7 +153,7 @@ int aa_set_current_onexec(struct aa_profile *profile) ...@@ -152,7 +153,7 @@ int aa_set_current_onexec(struct aa_profile *profile)
/** /**
* aa_set_current_hat - set the current tasks hat * aa_set_current_hat - set the current tasks hat
* @profile: profile to set as the current hat (NOT NULL) * @label: label to set as the current hat (NOT NULL)
* @token: token value that must be specified to change from the hat * @token: token value that must be specified to change from the hat
* *
* Do switch of tasks hat. If the task is currently in a hat * Do switch of tasks hat. If the task is currently in a hat
...@@ -160,29 +161,29 @@ int aa_set_current_onexec(struct aa_profile *profile) ...@@ -160,29 +161,29 @@ int aa_set_current_onexec(struct aa_profile *profile)
* *
* Returns: 0 or error on failure * Returns: 0 or error on failure
*/ */
int aa_set_current_hat(struct aa_profile *profile, u64 token) int aa_set_current_hat(struct aa_label *label, u64 token)
{ {
struct aa_task_ctx *ctx; struct aa_task_ctx *ctx;
struct cred *new = prepare_creds(); struct cred *new = prepare_creds();
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
AA_BUG(!profile); AA_BUG(!label);
ctx = cred_ctx(new); ctx = cred_ctx(new);
if (!ctx->previous) { if (!ctx->previous) {
/* transfer refcount */ /* transfer refcount */
ctx->previous = ctx->profile; ctx->previous = ctx->label;
ctx->token = token; ctx->token = token;
} else if (ctx->token == token) { } else if (ctx->token == token) {
aa_put_profile(ctx->profile); aa_put_label(ctx->label);
} else { } else {
/* previous_profile && ctx->token != token */ /* previous_profile && ctx->token != token */
abort_creds(new); abort_creds(new);
return -EACCES; return -EACCES;
} }
ctx->profile = aa_get_newest_profile(profile); ctx->label = aa_get_newest_label(label);
/* clear exec on switching context */ /* clear exec on switching context */
aa_put_profile(ctx->onexec); aa_put_label(ctx->onexec);
ctx->onexec = NULL; ctx->onexec = NULL;
commit_creds(new); commit_creds(new);
...@@ -190,15 +191,15 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token) ...@@ -190,15 +191,15 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token)
} }
/** /**
* aa_restore_previous_profile - exit from hat context restoring the profile * aa_restore_previous_label - exit from hat context restoring previous label
* @token: the token that must be matched to exit hat context * @token: the token that must be matched to exit hat context
* *
* Attempt to return out of a hat to the previous profile. The token * Attempt to return out of a hat to the previous label. The token
* must match the stored token value. * must match the stored token value.
* *
* Returns: 0 or error of failure * Returns: 0 or error of failure
*/ */
int aa_restore_previous_profile(u64 token) int aa_restore_previous_label(u64 token)
{ {
struct aa_task_ctx *ctx; struct aa_task_ctx *ctx;
struct cred *new = prepare_creds(); struct cred *new = prepare_creds();
...@@ -210,15 +211,15 @@ int aa_restore_previous_profile(u64 token) ...@@ -210,15 +211,15 @@ int aa_restore_previous_profile(u64 token)
abort_creds(new); abort_creds(new);
return -EACCES; return -EACCES;
} }
/* ignore restores when there is no saved profile */ /* ignore restores when there is no saved label */
if (!ctx->previous) { if (!ctx->previous) {
abort_creds(new); abort_creds(new);
return 0; return 0;
} }
aa_put_profile(ctx->profile); aa_put_label(ctx->label);
ctx->profile = aa_get_newest_profile(ctx->previous); ctx->label = aa_get_newest_label(ctx->previous);
AA_BUG(!ctx->profile); AA_BUG(!ctx->label);
/* clear exec && prev information when restoring to previous context */ /* clear exec && prev information when restoring to previous context */
aa_clear_task_ctx_trans(ctx); aa_clear_task_ctx_trans(ctx);
......
...@@ -61,24 +61,25 @@ void aa_free_domain_entries(struct aa_domain *domain) ...@@ -61,24 +61,25 @@ void aa_free_domain_entries(struct aa_domain *domain)
static int may_change_ptraced_domain(struct aa_profile *to_profile) static int may_change_ptraced_domain(struct aa_profile *to_profile)
{ {
struct task_struct *tracer; struct task_struct *tracer;
struct aa_profile *tracerp = NULL; struct aa_label *tracerl = NULL;
int error = 0; int error = 0;
rcu_read_lock(); rcu_read_lock();
tracer = ptrace_parent(current); tracer = ptrace_parent(current);
if (tracer) if (tracer)
/* released below */ /* released below */
tracerp = aa_get_task_profile(tracer); tracerl = aa_get_task_label(tracer);
/* not ptraced */ /* not ptraced */
if (!tracer || unconfined(tracerp)) if (!tracer || unconfined(tracerl))
goto out; goto out;
error = aa_may_ptrace(tracerp, to_profile, PTRACE_MODE_ATTACH); error = aa_may_ptrace(labels_profile(tracerl), to_profile,
PTRACE_MODE_ATTACH);
out: out:
rcu_read_unlock(); rcu_read_unlock();
aa_put_profile(tracerp); aa_put_label(tracerl);
return error; return error;
} }
...@@ -102,7 +103,7 @@ static struct aa_perms change_profile_perms(struct aa_profile *profile, ...@@ -102,7 +103,7 @@ static struct aa_perms change_profile_perms(struct aa_profile *profile,
struct path_cond cond = { }; struct path_cond cond = { };
unsigned int state; unsigned int state;
if (unconfined(profile)) { if (profile_unconfined(profile)) {
perms.allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC; perms.allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC;
perms.audit = perms.quiet = perms.kill = 0; perms.audit = perms.quiet = perms.kill = 0;
return perms; return perms;
...@@ -144,7 +145,7 @@ static struct aa_profile *__attach_match(const char *name, ...@@ -144,7 +145,7 @@ static struct aa_profile *__attach_match(const char *name,
struct aa_profile *profile, *candidate = NULL; struct aa_profile *profile, *candidate = NULL;
list_for_each_entry_rcu(profile, head, base.list) { list_for_each_entry_rcu(profile, head, base.list) {
if (profile->flags & PFLAG_NULL) if (profile->label.flags & FLAG_NULL)
continue; continue;
if (profile->xmatch && profile->xmatch_len > len) { if (profile->xmatch && profile->xmatch_len > len) {
unsigned int state = aa_dfa_match(profile->xmatch, unsigned int state = aa_dfa_match(profile->xmatch,
...@@ -338,6 +339,7 @@ static struct aa_profile *x_to_profile(struct aa_profile *profile, ...@@ -338,6 +339,7 @@ static struct aa_profile *x_to_profile(struct aa_profile *profile,
int apparmor_bprm_set_creds(struct linux_binprm *bprm) int apparmor_bprm_set_creds(struct linux_binprm *bprm)
{ {
struct aa_task_ctx *ctx; struct aa_task_ctx *ctx;
struct aa_label *label;
struct aa_profile *profile, *new_profile = NULL; struct aa_profile *profile, *new_profile = NULL;
struct aa_ns *ns; struct aa_ns *ns;
char *buffer = NULL; char *buffer = NULL;
...@@ -356,7 +358,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -356,7 +358,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
ctx = cred_ctx(bprm->cred); ctx = cred_ctx(bprm->cred);
AA_BUG(!ctx); AA_BUG(!ctx);
profile = aa_get_newest_profile(ctx->profile); label = aa_get_newest_label(ctx->label);
profile = labels_profile(label);
/* buffer freed below, name is pointer into buffer */ /* buffer freed below, name is pointer into buffer */
get_buffers(buffer); get_buffers(buffer);
...@@ -370,8 +373,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -370,8 +373,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
error = aa_path_name(&bprm->file->f_path, profile->path_flags, buffer, error = aa_path_name(&bprm->file->f_path, profile->path_flags, buffer,
&name, &info, profile->disconnected); &name, &info, profile->disconnected);
if (error) { if (error) {
if (unconfined(profile) || if (profile_unconfined(profile) ||
(profile->flags & PFLAG_IX_ON_NAME_ERROR)) (profile->label.flags & FLAG_IX_ON_NAME_ERROR))
error = 0; error = 0;
name = bprm->filename; name = bprm->filename;
goto audit; goto audit;
...@@ -380,11 +383,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -380,11 +383,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
/* Test for onexec first as onexec directives override other /* Test for onexec first as onexec directives override other
* x transitions. * x transitions.
*/ */
if (unconfined(profile)) { if (profile_unconfined(profile)) {
/* unconfined task */ /* unconfined task */
if (ctx->onexec) if (ctx->onexec)
/* change_profile on exec already been granted */ /* change_profile on exec already been granted */
new_profile = aa_get_profile(ctx->onexec); new_profile = labels_profile(aa_get_label(ctx->onexec));
else else
new_profile = find_attach(ns, &ns->base.profiles, name); new_profile = find_attach(ns, &ns->base.profiles, name);
if (!new_profile) if (!new_profile)
...@@ -402,7 +405,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -402,7 +405,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
if (ctx->onexec) { if (ctx->onexec) {
struct aa_perms cp; struct aa_perms cp;
info = "change_profile onexec"; info = "change_profile onexec";
new_profile = aa_get_newest_profile(ctx->onexec); new_profile = labels_profile(aa_get_newest_label(ctx->onexec));
if (!(perms.allow & AA_MAY_ONEXEC)) if (!(perms.allow & AA_MAY_ONEXEC))
goto audit; goto audit;
...@@ -411,9 +414,9 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -411,9 +414,9 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
* exec\0change_profile * exec\0change_profile
*/ */
state = aa_dfa_null_transition(profile->file.dfa, state); state = aa_dfa_null_transition(profile->file.dfa, state);
cp = change_profile_perms(profile, ctx->onexec->ns, cp = change_profile_perms(profile, labels_ns(ctx->onexec),
ctx->onexec->base.name, labels_profile(ctx->onexec)->base.name,
AA_MAY_ONEXEC, state); AA_MAY_ONEXEC, state);
if (!(cp.allow & AA_MAY_ONEXEC)) if (!(cp.allow & AA_MAY_ONEXEC))
goto audit; goto audit;
...@@ -501,9 +504,9 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -501,9 +504,9 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
bprm->per_clear |= PER_CLEAR_ON_SETID; bprm->per_clear |= PER_CLEAR_ON_SETID;
x_clear: x_clear:
aa_put_profile(ctx->profile); aa_put_label(ctx->label);
/* transfer new profile reference will be released when ctx is freed */ /* transfer new profile reference will be released when ctx is freed */
ctx->profile = new_profile; ctx->label = &new_profile->label;
new_profile = NULL; new_profile = NULL;
/* clear out all temporary/transitional state from the context */ /* clear out all temporary/transitional state from the context */
...@@ -516,7 +519,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -516,7 +519,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
cleanup: cleanup:
aa_put_profile(new_profile); aa_put_profile(new_profile);
aa_put_profile(profile); aa_put_label(label);
put_buffers(buffer); put_buffers(buffer);
return error; return error;
...@@ -576,7 +579,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) ...@@ -576,7 +579,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
{ {
const struct cred *cred; const struct cred *cred;
struct aa_task_ctx *ctx; struct aa_task_ctx *ctx;
struct aa_profile *profile, *previous_profile, *hat = NULL; struct aa_label *label, *previous_label;
struct aa_profile *profile, *hat = NULL;
char *name = NULL; char *name = NULL;
int i; int i;
struct aa_perms perms = {}; struct aa_perms perms = {};
...@@ -594,10 +598,11 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) ...@@ -594,10 +598,11 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
/* released below */ /* released below */
cred = get_current_cred(); cred = get_current_cred();
ctx = cred_ctx(cred); ctx = cred_ctx(cred);
profile = aa_get_newest_cred_profile(cred); label = aa_get_newest_cred_label(cred);
previous_profile = aa_get_newest_profile(ctx->previous); previous_label = aa_get_newest_label(ctx->previous);
profile = labels_profile(label);
if (unconfined(profile)) { if (unconfined(label)) {
info = "unconfined"; info = "unconfined";
error = -EPERM; error = -EPERM;
goto audit; goto audit;
...@@ -664,7 +669,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) ...@@ -664,7 +669,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
} }
if (!(flags & AA_CHANGE_TEST)) { if (!(flags & AA_CHANGE_TEST)) {
error = aa_set_current_hat(hat, token); error = aa_set_current_hat(&hat->label, token);
if (error == -EACCES) if (error == -EACCES)
/* kill task in case of brute force attacks */ /* kill task in case of brute force attacks */
perms.kill = AA_MAY_CHANGEHAT; perms.kill = AA_MAY_CHANGEHAT;
...@@ -672,12 +677,12 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) ...@@ -672,12 +677,12 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
/* reset error for learning of new hats */ /* reset error for learning of new hats */
error = -ENOENT; error = -ENOENT;
} }
} else if (previous_profile) { } else if (previous_label) {
/* Return to saved profile. Kill task if restore fails /* Return to saved profile. Kill task if restore fails
* to avoid brute force attacks * to avoid brute force attacks
*/ */
target = previous_profile->base.hname; target = previous_label->hname;
error = aa_restore_previous_profile(token); error = aa_restore_previous_label(token);
perms.kill = AA_MAY_CHANGEHAT; perms.kill = AA_MAY_CHANGEHAT;
} else } else
/* ignore restores when there is no saved profile */ /* ignore restores when there is no saved profile */
...@@ -692,8 +697,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) ...@@ -692,8 +697,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
out: out:
aa_put_profile(hat); aa_put_profile(hat);
kfree(name); kfree(name);
aa_put_profile(profile); aa_put_label(label);
aa_put_profile(previous_profile); aa_put_label(previous_label);
put_cred(cred); put_cred(cred);
return error; return error;
...@@ -716,6 +721,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) ...@@ -716,6 +721,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
int aa_change_profile(const char *fqname, int flags) int aa_change_profile(const char *fqname, int flags)
{ {
const struct cred *cred; const struct cred *cred;
struct aa_label *label;
struct aa_profile *profile, *target = NULL; struct aa_profile *profile, *target = NULL;
struct aa_perms perms = {}; struct aa_perms perms = {};
const char *info = NULL, *op; const char *info = NULL, *op;
...@@ -736,7 +742,8 @@ int aa_change_profile(const char *fqname, int flags) ...@@ -736,7 +742,8 @@ int aa_change_profile(const char *fqname, int flags)
} }
cred = get_current_cred(); cred = get_current_cred();
profile = aa_get_newest_cred_profile(cred); label = aa_get_newest_cred_label(cred);
profile = labels_profile(label);
/* /*
* Fail explicitly requested domain transitions if no_new_privs * Fail explicitly requested domain transitions if no_new_privs
...@@ -745,12 +752,12 @@ int aa_change_profile(const char *fqname, int flags) ...@@ -745,12 +752,12 @@ int aa_change_profile(const char *fqname, int flags)
* no_new_privs is set because this aways results in a reduction * no_new_privs is set because this aways results in a reduction
* of permissions. * of permissions.
*/ */
if (task_no_new_privs(current) && !unconfined(profile)) { if (task_no_new_privs(current) && !profile_unconfined(profile)) {
put_cred(cred); put_cred(cred);
return -EPERM; return -EPERM;
} }
target = aa_fqlookupn_profile(profile, fqname, strlen(fqname)); target = aa_fqlookupn_profile(label, fqname, strlen(fqname));
if (!target) { if (!target) {
info = "profile not found"; info = "profile not found";
error = -ENOENT; error = -ENOENT;
...@@ -785,9 +792,9 @@ int aa_change_profile(const char *fqname, int flags) ...@@ -785,9 +792,9 @@ int aa_change_profile(const char *fqname, int flags)
goto audit; goto audit;
if (flags & AA_CHANGE_ONEXEC) if (flags & AA_CHANGE_ONEXEC)
error = aa_set_current_onexec(target); error = aa_set_current_onexec(&target->label, 0);
else else
error = aa_replace_current_profile(target); error = aa_replace_current_label(&target->label);
audit: audit:
if (!(flags & AA_CHANGE_TEST)) if (!(flags & AA_CHANGE_TEST))
...@@ -795,7 +802,7 @@ int aa_change_profile(const char *fqname, int flags) ...@@ -795,7 +802,7 @@ int aa_change_profile(const char *fqname, int flags)
fqname, GLOBAL_ROOT_UID, info, error); fqname, GLOBAL_ROOT_UID, info, error);
aa_put_profile(target); aa_put_profile(target);
aa_put_profile(profile); aa_put_label(label);
put_cred(cred); put_cred(cred);
return error; return error;
......
...@@ -451,7 +451,7 @@ int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file, ...@@ -451,7 +451,7 @@ int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file,
request, &cond); request, &cond);
} }
static void revalidate_tty(struct aa_profile *profile) static void revalidate_tty(struct aa_label *label)
{ {
struct tty_struct *tty; struct tty_struct *tty;
int drop_tty = 0; int drop_tty = 0;
...@@ -469,7 +469,7 @@ static void revalidate_tty(struct aa_profile *profile) ...@@ -469,7 +469,7 @@ static void revalidate_tty(struct aa_profile *profile)
struct tty_file_private, list); struct tty_file_private, list);
file = file_priv->file; file = file_priv->file;
if (aa_file_perm(OP_INHERIT, profile, file, if (aa_file_perm(OP_INHERIT, labels_profile(label), file,
MAY_READ | MAY_WRITE)) MAY_READ | MAY_WRITE))
drop_tty = 1; drop_tty = 1;
} }
...@@ -482,9 +482,9 @@ static void revalidate_tty(struct aa_profile *profile) ...@@ -482,9 +482,9 @@ static void revalidate_tty(struct aa_profile *profile)
static int match_file(const void *p, struct file *file, unsigned int fd) static int match_file(const void *p, struct file *file, unsigned int fd)
{ {
struct aa_profile *profile = (struct aa_profile *)p; struct aa_label *label = (struct aa_label *)p;
if (aa_file_perm(OP_INHERIT, profile, file, if (aa_file_perm(OP_INHERIT, labels_profile(label), file,
aa_map_file_to_perms(file))) aa_map_file_to_perms(file)))
return fd + 1; return fd + 1;
return 0; return 0;
...@@ -494,14 +494,14 @@ static int match_file(const void *p, struct file *file, unsigned int fd) ...@@ -494,14 +494,14 @@ static int match_file(const void *p, struct file *file, unsigned int fd)
/* based on selinux's flush_unauthorized_files */ /* based on selinux's flush_unauthorized_files */
void aa_inherit_files(const struct cred *cred, struct files_struct *files) void aa_inherit_files(const struct cred *cred, struct files_struct *files)
{ {
struct aa_profile *profile = aa_get_newest_cred_profile(cred); struct aa_label *label = aa_get_newest_cred_label(cred);
struct file *devnull = NULL; struct file *devnull = NULL;
unsigned int n; unsigned int n;
revalidate_tty(profile); revalidate_tty(label);
/* Revalidate access to inherited open files. */ /* Revalidate access to inherited open files. */
n = iterate_fd(files, 0, match_file, profile); n = iterate_fd(files, 0, match_file, label);
if (!n) /* none found? */ if (!n) /* none found? */
goto out; goto out;
...@@ -511,9 +511,9 @@ void aa_inherit_files(const struct cred *cred, struct files_struct *files) ...@@ -511,9 +511,9 @@ void aa_inherit_files(const struct cred *cred, struct files_struct *files)
/* replace all the matching ones with this */ /* replace all the matching ones with this */
do { do {
replace_fd(n - 1, devnull, 0); replace_fd(n - 1, devnull, 0);
} while ((n = iterate_fd(files, n, match_file, profile)) != 0); } while ((n = iterate_fd(files, n, match_file, label)) != 0);
if (devnull) if (devnull)
fput(devnull); fput(devnull);
out: out:
aa_put_profile(profile); aa_put_label(label);
} }
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This file contains AppArmor basic global * This file contains AppArmor basic global
* *
* Copyright (C) 1998-2008 Novell/SUSE * Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd. * Copyright 2009-2017 Canonical Ltd.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -27,8 +27,9 @@ ...@@ -27,8 +27,9 @@
#define AA_CLASS_NET 4 #define AA_CLASS_NET 4
#define AA_CLASS_RLIMITS 5 #define AA_CLASS_RLIMITS 5
#define AA_CLASS_DOMAIN 6 #define AA_CLASS_DOMAIN 6
#define AA_CLASS_LABEL 16
#define AA_CLASS_LAST AA_CLASS_DOMAIN #define AA_CLASS_LAST AA_CLASS_LABEL
/* Control parameters settable through module/boot flags */ /* Control parameters settable through module/boot flags */
extern enum audit_mode aa_g_audit; extern enum audit_mode aa_g_audit;
......
...@@ -22,8 +22,7 @@ ...@@ -22,8 +22,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include "file.h" #include "file.h"
#include "label.h"
struct aa_profile;
extern const char *const audit_mode_names[]; extern const char *const audit_mode_names[];
#define AUDIT_MAX_INDEX 5 #define AUDIT_MAX_INDEX 5
...@@ -103,9 +102,9 @@ enum audit_type { ...@@ -103,9 +102,9 @@ enum audit_type {
struct apparmor_audit_data { struct apparmor_audit_data {
int error; int error;
const char *op;
int type; int type;
void *profile; const char *op;
struct aa_label *label;
const char *name; const char *name;
const char *info; const char *info;
u32 request; u32 request;
...@@ -113,7 +112,7 @@ struct apparmor_audit_data { ...@@ -113,7 +112,7 @@ struct apparmor_audit_data {
union { union {
/* these entries require a custom callback fn */ /* these entries require a custom callback fn */
struct { struct {
struct aa_profile *peer; struct aa_label *peer;
struct { struct {
const char *target; const char *target;
kuid_t ouid; kuid_t ouid;
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sched.h> #include <linux/sched.h>
#include "policy.h" #include "label.h"
#include "policy_ns.h" #include "policy_ns.h"
#define cred_ctx(X) ((X)->security) #define cred_ctx(X) ((X)->security)
...@@ -27,20 +27,20 @@ ...@@ -27,20 +27,20 @@
/** /**
* struct aa_task_ctx - primary label for confined tasks * struct aa_task_ctx - primary label for confined tasks
* @profile: the current profile (NOT NULL) * @label: the current label (NOT NULL)
* @exec: profile to transition to on next exec (MAYBE NULL) * @exec: label to transition to on next exec (MAYBE NULL)
* @previous: profile the task may return to (MAYBE NULL) * @previous: label the task may return to (MAYBE NULL)
* @token: magic value the task must know for returning to @previous_profile * @token: magic value the task must know for returning to @previous
* *
* Contains the task's current profile (which could change due to * Contains the task's current label (which could change due to
* change_hat). Plus the hat_magic needed during change_hat. * change_hat). Plus the hat_magic needed during change_hat.
* *
* TODO: make so a task can be confined by a stack of contexts * TODO: make so a task can be confined by a stack of contexts
*/ */
struct aa_task_ctx { struct aa_task_ctx {
struct aa_profile *profile; struct aa_label *label;
struct aa_profile *onexec; struct aa_label *onexec;
struct aa_profile *previous; struct aa_label *previous;
u64 token; u64 token;
}; };
...@@ -48,52 +48,51 @@ struct aa_task_ctx *aa_alloc_task_context(gfp_t flags); ...@@ -48,52 +48,51 @@ struct aa_task_ctx *aa_alloc_task_context(gfp_t flags);
void aa_free_task_context(struct aa_task_ctx *ctx); void aa_free_task_context(struct aa_task_ctx *ctx);
void aa_dup_task_context(struct aa_task_ctx *new, void aa_dup_task_context(struct aa_task_ctx *new,
const struct aa_task_ctx *old); const struct aa_task_ctx *old);
int aa_replace_current_profile(struct aa_profile *profile); int aa_replace_current_label(struct aa_label *label);
int aa_set_current_onexec(struct aa_profile *profile); int aa_set_current_onexec(struct aa_label *label, bool stack);
int aa_set_current_hat(struct aa_profile *profile, u64 token); int aa_set_current_hat(struct aa_label *label, u64 token);
int aa_restore_previous_profile(u64 cookie); int aa_restore_previous_label(u64 cookie);
struct aa_profile *aa_get_task_profile(struct task_struct *task); struct aa_label *aa_get_task_label(struct task_struct *task);
/** /**
* aa_cred_raw_profile - obtain cred's profiles * aa_cred_raw_label - obtain cred's label
* @cred: cred to obtain profiles from (NOT NULL) * @cred: cred to obtain label from (NOT NULL)
* *
* Returns: confining profile * Returns: confining label
* *
* does NOT increment reference count * does NOT increment reference count
*/ */
static inline struct aa_profile *aa_cred_raw_profile(const struct cred *cred) static inline struct aa_label *aa_cred_raw_label(const struct cred *cred)
{ {
struct aa_task_ctx *ctx = cred_ctx(cred); struct aa_task_ctx *ctx = cred_ctx(cred);
AA_BUG(!ctx || !ctx->profile); AA_BUG(!ctx || !ctx->label);
return ctx->profile; return ctx->label;
} }
/** /**
* aa_get_newest_cred_profile - obtain the newest profile on a cred * aa_get_newest_cred_label - obtain the newest label on a cred
* @cred: cred to obtain profile from (NOT NULL) * @cred: cred to obtain label from (NOT NULL)
* *
* Returns: newest version of confining profile * Returns: newest version of confining label
*/ */
static inline static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred)
struct aa_profile *aa_get_newest_cred_profile(const struct cred *cred)
{ {
return aa_get_newest_profile(aa_cred_raw_profile(cred)); return aa_get_newest_label(aa_cred_raw_label(cred));
} }
/** /**
* __aa_task_raw_profile - retrieve another task's profile * __aa_task_raw_label - retrieve another task's label
* @task: task to query (NOT NULL) * @task: task to query (NOT NULL)
* *
* Returns: @task's profile without incrementing its ref count * Returns: @task's label without incrementing its ref count
* *
* If @task != current needs to be called in RCU safe critical section * If @task != current needs to be called in RCU safe critical section
*/ */
static inline struct aa_profile *__aa_task_raw_profile(struct task_struct *task) static inline struct aa_label *__aa_task_raw_label(struct task_struct *task)
{ {
return aa_cred_raw_profile(__task_cred(task)); return aa_cred_raw_label(__task_cred(task));
} }
/** /**
...@@ -104,113 +103,112 @@ static inline struct aa_profile *__aa_task_raw_profile(struct task_struct *task) ...@@ -104,113 +103,112 @@ static inline struct aa_profile *__aa_task_raw_profile(struct task_struct *task)
*/ */
static inline bool __aa_task_is_confined(struct task_struct *task) static inline bool __aa_task_is_confined(struct task_struct *task)
{ {
return !unconfined(__aa_task_raw_profile(task)); return !unconfined(__aa_task_raw_label(task));
} }
/** /**
* aa_current_raw_profile - find the current tasks confining profile * aa_current_raw_label - find the current tasks confining label
* *
* Returns: up to date confining profile or the ns unconfined profile (NOT NULL) * Returns: up to date confining label or the ns unconfined label (NOT NULL)
* *
* This fn will not update the tasks cred to the most up to date version * This fn will not update the tasks cred to the most up to date version
* of the profile so it is safe to call when inside of locks. * of the label so it is safe to call when inside of locks.
*/ */
static inline struct aa_profile *aa_current_raw_profile(void) static inline struct aa_label *aa_current_raw_label(void)
{ {
return aa_cred_raw_profile(current_cred()); return aa_cred_raw_label(current_cred());
} }
/** /**
* aa_get_current_profile - get the newest version of the current tasks profile * aa_get_current_label - get the newest version of the current tasks label
* *
* Returns: newest version of confining profile (NOT NULL) * Returns: newest version of confining label (NOT NULL)
* *
* This fn will not update the tasks cred, so it is safe inside of locks * This fn will not update the tasks cred, so it is safe inside of locks
* *
* The returned reference must be put with aa_put_profile() * The returned reference must be put with aa_put_label()
*/ */
static inline struct aa_profile *aa_get_current_profile(void) static inline struct aa_label *aa_get_current_label(void)
{ {
struct aa_profile *p = aa_current_raw_profile(); struct aa_label *l = aa_current_raw_label();
if (profile_is_stale(p)) if (label_is_stale(l))
return aa_get_newest_profile(p); return aa_get_newest_label(l);
return aa_get_profile(p); return aa_get_label(l);
} }
#define __end_current_profile_crit_section(X) \ #define __end_current_label_crit_section(X) end_current_label_crit_section(X)
end_current_profile_crit_section(X)
/** /**
* end_profile_crit_section - put a reference found with begin_current_profile.. * end_label_crit_section - put a reference found with begin_current_label..
* @profile: profile reference to put * @label: label reference to put
* *
* Should only be used with a reference obtained with * Should only be used with a reference obtained with
* begin_current_profile_crit_section and never used in situations where the * begin_current_label_crit_section and never used in situations where the
* task cred may be updated * task cred may be updated
*/ */
static inline void end_current_profile_crit_section(struct aa_profile *profile) static inline void end_current_label_crit_section(struct aa_label *label)
{ {
if (profile != aa_current_raw_profile()) if (label != aa_current_raw_label())
aa_put_profile(profile); aa_put_label(label);
} }
/** /**
* __begin_current_profile_crit_section - current's confining profile * __begin_current_label_crit_section - current's confining label
* *
* Returns: up to date confining profile or the ns unconfined profile (NOT NULL) * Returns: up to date confining label or the ns unconfined label (NOT NULL)
* *
* safe to call inside locks * safe to call inside locks
* *
* The returned reference must be put with __end_current_profile_crit_section() * The returned reference must be put with __end_current_label_crit_section()
* This must NOT be used if the task cred could be updated within the * This must NOT be used if the task cred could be updated within the
* critical section between __begin_current_profile_crit_section() .. * critical section between __begin_current_label_crit_section() ..
* __end_current_profile_crit_section() * __end_current_label_crit_section()
*/ */
static inline struct aa_profile *__begin_current_profile_crit_section(void) static inline struct aa_label *__begin_current_label_crit_section(void)
{ {
struct aa_profile *profile = aa_current_raw_profile(); struct aa_label *label = aa_current_raw_label();
if (profile_is_stale(profile)) if (label_is_stale(label))
profile = aa_get_newest_profile(profile); label = aa_get_newest_label(label);
return profile; return label;
} }
/** /**
* begin_current_profile_crit_section - current's profile and update if needed * begin_current_label_crit_section - current's confining label and update it
* *
* Returns: up to date confining profile or the ns unconfined profile (NOT NULL) * Returns: up to date confining label or the ns unconfined label (NOT NULL)
* *
* Not safe to call inside locks * Not safe to call inside locks
* *
* The returned reference must be put with end_current_profile_crit_section() * The returned reference must be put with end_current_label_crit_section()
* This must NOT be used if the task cred could be updated within the * This must NOT be used if the task cred could be updated within the
* critical section between begin_current_profile_crit_section() .. * critical section between begin_current_label_crit_section() ..
* end_current_profile_crit_section() * end_current_label_crit_section()
*/ */
static inline struct aa_profile *begin_current_profile_crit_section(void) static inline struct aa_label *begin_current_label_crit_section(void)
{ {
struct aa_profile *profile = aa_current_raw_profile(); struct aa_label *label = aa_current_raw_label();
if (profile_is_stale(profile)) { if (label_is_stale(label)) {
profile = aa_get_newest_profile(profile); label = aa_get_newest_label(label);
if (aa_replace_current_profile(profile) == 0) if (aa_replace_current_label(label) == 0)
/* task cred will keep the reference */ /* task cred will keep the reference */
aa_put_profile(profile); aa_put_label(label);
} }
return profile; return label;
} }
static inline struct aa_ns *aa_get_current_ns(void) static inline struct aa_ns *aa_get_current_ns(void)
{ {
struct aa_profile *profile; struct aa_label *label;
struct aa_ns *ns; struct aa_ns *ns;
profile = __begin_current_profile_crit_section(); label = __begin_current_label_crit_section();
ns = aa_get_ns(profile->ns); ns = aa_get_ns(labels_ns(label));
__end_current_profile_crit_section(profile); __end_current_label_crit_section(label);
return ns; return ns;
} }
...@@ -221,8 +219,8 @@ static inline struct aa_ns *aa_get_current_ns(void) ...@@ -221,8 +219,8 @@ static inline struct aa_ns *aa_get_current_ns(void)
*/ */
static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx)
{ {
aa_put_profile(ctx->previous); aa_put_label(ctx->previous);
aa_put_profile(ctx->onexec); aa_put_label(ctx->onexec);
ctx->previous = NULL; ctx->previous = NULL;
ctx->onexec = NULL; ctx->onexec = NULL;
ctx->token = 0; ctx->token = 0;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#define __AA_PERM_H #define __AA_PERM_H
#include <linux/fs.h> #include <linux/fs.h>
#include "label.h"
#define AA_MAY_EXEC MAY_EXEC #define AA_MAY_EXEC MAY_EXEC
#define AA_MAY_WRITE MAY_WRITE #define AA_MAY_WRITE MAY_WRITE
...@@ -101,5 +102,14 @@ void aa_apply_modes_to_perms(struct aa_profile *profile, ...@@ -101,5 +102,14 @@ void aa_apply_modes_to_perms(struct aa_profile *profile,
struct aa_perms *perms); struct aa_perms *perms);
void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
struct aa_perms *perms); 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,
int type, u32 request, struct aa_perms *perms);
int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
u32 request, int type, u32 *deny,
struct common_audit_data *sa);
int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
u32 request, struct common_audit_data *sa,
void (*cb)(struct audit_buffer *, void *));
#endif /* __AA_PERM_H */ #endif /* __AA_PERM_H */
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "domain.h" #include "domain.h"
#include "file.h" #include "file.h"
#include "lib.h" #include "lib.h"
#include "label.h"
#include "perms.h" #include "perms.h"
#include "resource.h" #include "resource.h"
...@@ -48,9 +49,9 @@ extern const char *const aa_profile_mode_names[]; ...@@ -48,9 +49,9 @@ extern const char *const aa_profile_mode_names[];
#define KILL_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_KILL) #define KILL_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_KILL)
#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT) #define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT)
#define profile_is_stale(_profile) ((_profile)->flags & PFLAG_STALE) #define profile_is_stale(_profile) (label_is_stale(&(_profile)->label))
#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)
...@@ -67,22 +68,6 @@ enum profile_mode { ...@@ -67,22 +68,6 @@ enum profile_mode {
APPARMOR_UNCONFINED, /* profile set to unconfined */ APPARMOR_UNCONFINED, /* profile set to unconfined */
}; };
enum profile_flags {
PFLAG_HAT = 1, /* profile is a hat */
PFLAG_NULL = 4, /* profile is null learning profile */
PFLAG_IX_ON_NAME_ERROR = 8, /* fallback to ix on name lookup fail */
PFLAG_IMMUTABLE = 0x10, /* don't allow changes/replacement */
PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */
PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */
PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */
PFLAG_STALE = 0x200, /* profile replaced/removed */
PFLAG_NS_COUNT = 0x400, /* carries NS ref count */
/* These flags must correspond with PATH_flags */
PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
};
struct aa_profile;
/* struct aa_policydb - match engine for a policy /* struct aa_policydb - match engine for a policy
* dfa: dfa pattern match * dfa: dfa pattern match
...@@ -95,11 +80,6 @@ struct aa_policydb { ...@@ -95,11 +80,6 @@ struct aa_policydb {
}; };
struct aa_proxy {
struct kref count;
struct aa_profile __rcu *profile;
};
/* struct aa_data - generic data structure /* struct aa_data - generic data structure
* key: name for retrieving this data * key: name for retrieving this data
* size: size of data in bytes * size: size of data in bytes
...@@ -116,18 +96,15 @@ struct aa_data { ...@@ -116,18 +96,15 @@ struct aa_data {
/* struct aa_profile - basic confinement data /* struct aa_profile - basic confinement data
* @base - base components of the profile (name, refcount, lists, lock ...) * @base - base components of the profile (name, refcount, lists, lock ...)
* @count: reference count of the obj * @label - label this profile is an extension of
* @rcu: rcu head used when removing from @list
* @parent: parent of profile * @parent: parent of profile
* @ns: namespace the profile is in * @ns: namespace the profile is in
* @proxy: is set to the profile that replaced this profile
* @rename: optional profile name that this profile renamed * @rename: optional profile name that this profile renamed
* @attach: human readable attachment string * @attach: human readable attachment string
* @xmatch: optional extended matching for unconfined executables names * @xmatch: optional extended matching for unconfined executables names
* @xmatch_len: xmatch prefix len, used to determine xmatch priority * @xmatch_len: xmatch prefix len, used to determine xmatch priority
* @audit: the auditing mode of the profile * @audit: the auditing mode of the profile
* @mode: the enforcement mode of the profile * @mode: the enforcement mode of the profile
* @flags: flags controlling profile behavior
* @path_flags: flags controlling path generation behavior * @path_flags: flags controlling path generation behavior
* @disconnected: what to prepend if attach_disconnected is specified * @disconnected: what to prepend if attach_disconnected is specified
* @size: the memory consumed by this profiles rules * @size: the memory consumed by this profiles rules
...@@ -145,8 +122,6 @@ struct aa_data { ...@@ -145,8 +122,6 @@ struct aa_data {
* used to determine profile attachment against unconfined tasks. All other * used to determine profile attachment against unconfined tasks. All other
* attachments are determined by profile X transition rules. * attachments are determined by profile X transition rules.
* *
* The @proxy struct is write protected by the profile lock.
*
* Profiles have a hierarchy where hats and children profiles keep * Profiles have a hierarchy where hats and children profiles keep
* a reference to their parent. * a reference to their parent.
* *
...@@ -156,12 +131,9 @@ struct aa_data { ...@@ -156,12 +131,9 @@ struct aa_data {
*/ */
struct aa_profile { struct aa_profile {
struct aa_policy base; struct aa_policy base;
struct kref count;
struct rcu_head rcu;
struct aa_profile __rcu *parent; struct aa_profile __rcu *parent;
struct aa_ns *ns; struct aa_ns *ns;
struct aa_proxy *proxy;
const char *rename; const char *rename;
const char *attach; const char *attach;
...@@ -169,7 +141,6 @@ struct aa_profile { ...@@ -169,7 +141,6 @@ struct aa_profile {
int xmatch_len; int xmatch_len;
enum audit_mode audit; enum audit_mode audit;
long mode; long mode;
long flags;
u32 path_flags; u32 path_flags;
const char *disconnected; const char *disconnected;
int size; int size;
...@@ -184,6 +155,7 @@ struct aa_profile { ...@@ -184,6 +155,7 @@ struct aa_profile {
char *dirname; char *dirname;
struct dentry *dents[AAFS_PROF_SIZEOF]; struct dentry *dents[AAFS_PROF_SIZEOF];
struct rhashtable *data; struct rhashtable *data;
struct aa_label label;
}; };
extern enum profile_mode aa_g_profile_mode; extern enum profile_mode aa_g_profile_mode;
...@@ -192,13 +164,15 @@ extern enum profile_mode aa_g_profile_mode; ...@@ -192,13 +164,15 @@ extern enum profile_mode aa_g_profile_mode;
#define AA_MAY_REPLACE_POLICY AA_MAY_WRITE #define AA_MAY_REPLACE_POLICY AA_MAY_WRITE
#define AA_MAY_REMOVE_POLICY AA_MAY_DELETE #define AA_MAY_REMOVE_POLICY AA_MAY_DELETE
void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new); #define profiles_ns(P) ((P)->ns)
#define name_is_shared(A, B) ((A)->hname && (A)->hname == (B)->hname)
void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
void aa_free_proxy_kref(struct kref *kref); void aa_free_proxy_kref(struct kref *kref);
struct aa_profile *aa_alloc_profile(const char *name, 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, struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
const char *base, gfp_t gfp); const char *base, gfp_t gfp);
void aa_free_profile(struct aa_profile *profile); void aa_free_profile(struct aa_profile *profile);
...@@ -207,20 +181,33 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); ...@@ -207,20 +181,33 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname,
size_t n); size_t n);
struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name); struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name);
struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
const char *fqname, size_t n); const char *fqname, size_t n);
struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name);
ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_label *label,
u32 mask, struct aa_loaddata *udata); u32 mask, struct aa_loaddata *udata);
ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *profile, ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_label *label,
char *name, size_t size); char *name, size_t size);
void __aa_profile_list_release(struct list_head *head); void __aa_profile_list_release(struct list_head *head);
#define PROF_ADD 1 #define PROF_ADD 1
#define PROF_REPLACE 0 #define PROF_REPLACE 0
#define unconfined(X) ((X)->mode == APPARMOR_UNCONFINED) #define profile_unconfined(X) ((X)->mode == APPARMOR_UNCONFINED)
/**
* aa_get_newest_profile - simple wrapper fn to wrap the label version
* @p: profile (NOT NULL)
*
* Returns refcount to newest version of the profile (maybe @p)
*
* Requires: @p must be held with a valid refcount
*/
static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
{
return labels_profile(aa_get_newest_label(&p->label));
}
#define PROFILE_MEDIATES(P, T) ((P)->policy.start[(T)]) #define PROFILE_MEDIATES(P, T) ((P)->policy.start[(T)])
/* safe version of POLICY_MEDIATES for full range input */ /* safe version of POLICY_MEDIATES for full range input */
...@@ -243,7 +230,7 @@ static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile, ...@@ -243,7 +230,7 @@ static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile,
static inline struct aa_profile *aa_get_profile(struct aa_profile *p) static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
{ {
if (p) if (p)
kref_get(&(p->count)); kref_get(&(p->label.count));
return p; return p;
} }
...@@ -257,7 +244,7 @@ static inline struct aa_profile *aa_get_profile(struct aa_profile *p) ...@@ -257,7 +244,7 @@ static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
*/ */
static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p) static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p)
{ {
if (p && kref_get_unless_zero(&p->count)) if (p && kref_get_unless_zero(&p->label.count))
return p; return p;
return NULL; return NULL;
...@@ -277,31 +264,12 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p) ...@@ -277,31 +264,12 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p)
rcu_read_lock(); rcu_read_lock();
do { do {
c = rcu_dereference(*p); c = rcu_dereference(*p);
} while (c && !kref_get_unless_zero(&c->count)); } while (c && !kref_get_unless_zero(&c->label.count));
rcu_read_unlock(); rcu_read_unlock();
return c; return c;
} }
/**
* aa_get_newest_profile - find the newest version of @profile
* @profile: the profile to check for newer versions of
*
* Returns: refcounted newest version of @profile taking into account
* replacement, renames and removals
* return @profile.
*/
static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
{
if (!p)
return NULL;
if (profile_is_stale(p))
return aa_get_profile_rcu(&p->proxy->profile);
return aa_get_profile(p);
}
/** /**
* aa_put_profile - decrement refcount on profile @p * aa_put_profile - decrement refcount on profile @p
* @p: profile (MAYBE NULL) * @p: profile (MAYBE NULL)
...@@ -309,21 +277,7 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) ...@@ -309,21 +277,7 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
static inline void aa_put_profile(struct aa_profile *p) static inline void aa_put_profile(struct aa_profile *p)
{ {
if (p) if (p)
kref_put(&p->count, aa_free_profile_kref); kref_put(&p->label.count, aa_label_kref);
}
static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *p)
{
if (p)
kref_get(&(p->count));
return p;
}
static inline void aa_put_proxy(struct aa_proxy *p)
{
if (p)
kref_put(&p->count, aa_free_proxy_kref);
} }
static inline int AUDIT_MODE(struct aa_profile *profile) static inline int AUDIT_MODE(struct aa_profile *profile)
...@@ -336,7 +290,7 @@ static inline int AUDIT_MODE(struct aa_profile *profile) ...@@ -336,7 +290,7 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
bool policy_view_capable(struct aa_ns *ns); bool policy_view_capable(struct aa_ns *ns);
bool policy_admin_capable(struct aa_ns *ns); bool policy_admin_capable(struct aa_ns *ns);
int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns,
u32 mask); u32 mask);
#endif /* __AA_POLICY_H */ #endif /* __AA_POLICY_H */
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "apparmor.h" #include "apparmor.h"
#include "apparmorfs.h" #include "apparmorfs.h"
#include "label.h"
#include "policy.h" #include "policy.h"
...@@ -71,6 +72,7 @@ struct aa_ns { ...@@ -71,6 +72,7 @@ struct aa_ns {
long revision; long revision;
wait_queue_head_t wait; wait_queue_head_t wait;
struct aa_labelset labels;
struct list_head rawdata_list; struct list_head rawdata_list;
struct dentry *dents[AAFS_NS_SIZEOF]; struct dentry *dents[AAFS_NS_SIZEOF];
...@@ -80,6 +82,8 @@ extern struct aa_ns *root_ns; ...@@ -80,6 +82,8 @@ extern struct aa_ns *root_ns;
extern const char *aa_hidden_ns_name; extern const char *aa_hidden_ns_name;
#define ns_unconfined(NS) (&(NS)->unconfined->label)
bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns); bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns);
const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child, bool subns); const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child, bool subns);
void aa_free_ns(struct aa_ns *ns); void aa_free_ns(struct aa_ns *ns);
......
...@@ -22,11 +22,12 @@ ...@@ -22,11 +22,12 @@
#include "include/ipc.h" #include "include/ipc.h"
/* call back to audit ptrace fields */ /* call back to audit ptrace fields */
static void audit_cb(struct audit_buffer *ab, void *va) static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
{ {
struct common_audit_data *sa = va; struct common_audit_data *sa = va;
audit_log_format(ab, " peer="); audit_log_format(ab, " peer=");
audit_log_untrustedstring(ab, aad(sa)->peer->base.hname); aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
FLAGS_NONE, GFP_ATOMIC);
} }
/** /**
...@@ -42,10 +43,10 @@ static int aa_audit_ptrace(struct aa_profile *profile, ...@@ -42,10 +43,10 @@ static int aa_audit_ptrace(struct aa_profile *profile,
{ {
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE);
aad(&sa)->peer = target; aad(&sa)->peer = &target->label;
aad(&sa)->error = error; aad(&sa)->error = error;
return aa_audit(AUDIT_APPARMOR_AUTO, profile, &sa, audit_cb); return aa_audit(AUDIT_APPARMOR_AUTO, profile, &sa, audit_ptrace_cb);
} }
/** /**
...@@ -64,7 +65,7 @@ int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee, ...@@ -64,7 +65,7 @@ int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee,
* Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH * Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH
*/ */
if (unconfined(tracer) || tracer == tracee) if (profile_unconfined(tracer) || tracer == tracee)
return 0; return 0;
/* log this capability request */ /* log this capability request */
return aa_capable(tracer, CAP_SYS_PTRACE, 1); return aa_capable(tracer, CAP_SYS_PTRACE, 1);
...@@ -90,18 +91,22 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, ...@@ -90,18 +91,22 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
* - tracer profile has CAP_SYS_PTRACE * - tracer profile has CAP_SYS_PTRACE
*/ */
struct aa_profile *tracer_p = aa_get_task_profile(tracer); struct aa_label *tracer_l = aa_get_task_label(tracer);
int error = 0; int error = 0;
if (!unconfined(tracer_p)) { if (!unconfined(tracer_l)) {
struct aa_profile *tracee_p = aa_get_task_profile(tracee); struct aa_label *tracee_l = aa_get_task_label(tracee);
error = aa_may_ptrace(tracer_p, tracee_p, mode); error = aa_may_ptrace(labels_profile(tracer_l),
error = aa_audit_ptrace(tracer_p, tracee_p, error); labels_profile(tracee_l),
mode);
error = aa_audit_ptrace(labels_profile(tracer_l),
labels_profile(tracee_l),
error);
aa_put_profile(tracee_p); aa_put_label(tracee_l);
} }
aa_put_profile(tracer_p); aa_put_label(tracer_l);
return error; return error;
} }
...@@ -246,6 +246,32 @@ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, ...@@ -246,6 +246,32 @@ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
audit_log_format(ab, "\""); audit_log_format(ab, "\"");
} }
/**
* aa_audit_perms_cb - generic callback fn for auditing perms
* @ab: audit buffer (NOT NULL)
* @va: audit struct to audit values of (NOT NULL)
*/
static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
if (aad(sa)->request) {
audit_log_format(ab, " requested_mask=");
aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
PERMS_CHRS_MASK, aa_file_perm_names,
PERMS_NAMES_MASK);
}
if (aad(sa)->denied) {
audit_log_format(ab, "denied_mask=");
aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
PERMS_CHRS_MASK, aa_file_perm_names,
PERMS_NAMES_MASK);
}
audit_log_format(ab, " peer=");
aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
FLAGS_NONE, GFP_ATOMIC);
}
/** /**
* aa_apply_modes_to_perms - apply namespace and profile flags to perms * aa_apply_modes_to_perms - apply namespace and profile flags to perms
* @profile: that perms where computed from * @profile: that perms where computed from
...@@ -309,6 +335,143 @@ void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, ...@@ -309,6 +335,143 @@ void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
// perms->xindex = dfa_user_xindex(dfa, state); // perms->xindex = dfa_user_xindex(dfa, state);
} }
/**
* aa_perms_accum_raw - accumulate perms with out masking off overlapping perms
* @accum - perms struct to accumulate into
* @addend - perms struct to add to @accum
*/
void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
{
accum->deny |= addend->deny;
accum->allow &= addend->allow & ~addend->deny;
accum->audit |= addend->audit & addend->allow;
accum->quiet &= addend->quiet & ~addend->allow;
accum->kill |= addend->kill & ~addend->allow;
accum->stop |= addend->stop & ~addend->allow;
accum->complain |= addend->complain & ~addend->allow & ~addend->deny;
accum->cond |= addend->cond & ~addend->allow & ~addend->deny;
accum->hide &= addend->hide & ~addend->allow;
accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny;
}
/**
* aa_perms_accum - accumulate perms, masking off overlapping perms
* @accum - perms struct to accumulate into
* @addend - perms struct to add to @accum
*/
void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
{
accum->deny |= addend->deny;
accum->allow &= addend->allow & ~accum->deny;
accum->audit |= addend->audit & accum->allow;
accum->quiet &= addend->quiet & ~accum->allow;
accum->kill |= addend->kill & ~accum->allow;
accum->stop |= addend->stop & ~accum->allow;
accum->complain |= addend->complain & ~accum->allow & ~accum->deny;
accum->cond |= addend->cond & ~accum->allow & ~accum->deny;
accum->hide &= addend->hide & ~accum->allow;
accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny;
}
void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
int type, u32 request, struct aa_perms *perms)
{
/* TODO: doesn't yet handle extended types */
unsigned int state;
state = aa_dfa_next(profile->policy.dfa,
profile->policy.start[AA_CLASS_LABEL],
type);
aa_label_match(profile, label, state, false, request, perms);
}
/* currently unused */
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_perms perms;
aad(sa)->label = &profile->label;
aad(sa)->peer = &target->label;
aad(sa)->request = request;
aa_profile_match_label(profile, &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);
}
/**
* aa_check_perms - do audit mode selection based on perms set
* @profile: profile being checked
* @perms: perms computed for the request
* @request: requested perms
* @deny: Returns: explicit deny set
* @sa: initialized audit structure (MAY BE NULL if not auditing)
* @cb: callback fn for tpye specific fields (MAY BE NULL)
*
* Returns: 0 if permission else error code
*
* Note: profile audit modes need to be set before calling by setting the
* perm masks appropriately.
*
* If not auditing then complain mode is not enabled and the
* error code will indicate whether there was an explicit deny
* with a positive value.
*/
int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
u32 request, struct common_audit_data *sa,
void (*cb)(struct audit_buffer *, void *))
{
int type, error;
bool stop = false;
u32 denied = request & (~perms->allow | perms->deny);
if (likely(!denied)) {
/* mask off perms that are not being force audited */
request &= perms->audit;
if (!request || !sa)
return 0;
type = AUDIT_APPARMOR_AUDIT;
error = 0;
} else {
error = -EACCES;
if (denied & perms->kill)
type = AUDIT_APPARMOR_KILL;
else if (denied == (denied & perms->complain))
type = AUDIT_APPARMOR_ALLOWED;
else
type = AUDIT_APPARMOR_DENIED;
if (denied & perms->stop)
stop = true;
if (denied == (denied & perms->hide))
error = -ENOENT;
denied &= ~perms->quiet;
if (!sa || !denied)
return error;
}
if (sa) {
aad(sa)->label = &profile->label;
aad(sa)->request = request;
aad(sa)->denied = denied;
aad(sa)->error = error;
aa_audit_msg(type, sa, cb);
}
if (type == AUDIT_APPARMOR_ALLOWED)
error = 0;
return error;
}
/** /**
* aa_policy_init - initialize a policy structure * aa_policy_init - initialize a policy structure
* @policy: policy to initialize (NOT NULL) * @policy: policy to initialize (NOT NULL)
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "include/file.h" #include "include/file.h"
#include "include/ipc.h" #include "include/ipc.h"
#include "include/path.h" #include "include/path.h"
#include "include/label.h"
#include "include/policy.h" #include "include/policy.h"
#include "include/policy_ns.h" #include "include/policy_ns.h"
#include "include/procattr.h" #include "include/procattr.h"
...@@ -49,7 +50,7 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers); ...@@ -49,7 +50,7 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers);
*/ */
/* /*
* free the associated aa_task_ctx and put its profiles * free the associated aa_task_ctx and put its labels
*/ */
static void apparmor_cred_free(struct cred *cred) static void apparmor_cred_free(struct cred *cred)
{ {
...@@ -115,23 +116,24 @@ static int apparmor_ptrace_traceme(struct task_struct *parent) ...@@ -115,23 +116,24 @@ static int apparmor_ptrace_traceme(struct task_struct *parent)
static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted) kernel_cap_t *inheritable, kernel_cap_t *permitted)
{ {
struct aa_label *label;
struct aa_profile *profile; struct aa_profile *profile;
const struct cred *cred; const struct cred *cred;
rcu_read_lock(); rcu_read_lock();
cred = __task_cred(target); cred = __task_cred(target);
profile = aa_get_newest_cred_profile(cred); label = aa_get_newest_cred_label(cred);
profile = labels_profile(label);
/* /*
* cap_capget is stacked ahead of this and will * cap_capget is stacked ahead of this and will
* initialize effective and permitted. * initialize effective and permitted.
*/ */
if (!unconfined(profile) && !COMPLAIN_MODE(profile)) { if (!profile_unconfined(profile) && !COMPLAIN_MODE(profile)) {
*effective = cap_intersect(*effective, profile->caps.allow); *effective = cap_intersect(*effective, profile->caps.allow);
*permitted = cap_intersect(*permitted, profile->caps.allow); *permitted = cap_intersect(*permitted, profile->caps.allow);
} }
rcu_read_unlock(); rcu_read_unlock();
aa_put_profile(profile); aa_put_label(label);
return 0; return 0;
} }
...@@ -139,13 +141,13 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, ...@@ -139,13 +141,13 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
int cap, int audit) int cap, int audit)
{ {
struct aa_profile *profile; struct aa_label *label;
int error = 0; int error = 0;
profile = aa_get_newest_cred_profile(cred); label = aa_get_newest_cred_label(cred);
if (!unconfined(profile)) if (!unconfined(label))
error = aa_capable(profile, cap, audit); error = aa_capable(labels_profile(label), cap, audit);
aa_put_profile(profile); aa_put_label(label);
return error; return error;
} }
...@@ -162,13 +164,14 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, ...@@ -162,13 +164,14 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
static int common_perm(const char *op, const struct path *path, u32 mask, static int common_perm(const char *op, const struct path *path, u32 mask,
struct path_cond *cond) struct path_cond *cond)
{ {
struct aa_profile *profile; struct aa_label *label;
int error = 0; int error = 0;
profile = __begin_current_profile_crit_section(); label = __begin_current_label_crit_section();
if (!unconfined(profile)) if (!unconfined(label))
error = aa_path_perm(op, profile, path, 0, mask, cond); error = aa_path_perm(op, labels_profile(label), path, 0, mask,
__end_current_profile_crit_section(profile); cond);
__end_current_label_crit_section(label);
return error; return error;
} }
...@@ -295,16 +298,17 @@ static int apparmor_path_symlink(const struct path *dir, struct dentry *dentry, ...@@ -295,16 +298,17 @@ static int apparmor_path_symlink(const struct path *dir, struct dentry *dentry,
static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_dir, static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_dir,
struct dentry *new_dentry) struct dentry *new_dentry)
{ {
struct aa_profile *profile; struct aa_label *label;
int error = 0; int error = 0;
if (!path_mediated_fs(old_dentry)) if (!path_mediated_fs(old_dentry))
return 0; return 0;
profile = begin_current_profile_crit_section(); label = begin_current_label_crit_section();
if (!unconfined(profile)) if (!unconfined(label))
error = aa_path_link(profile, old_dentry, new_dir, new_dentry); error = aa_path_link(labels_profile(label), old_dentry, new_dir,
end_current_profile_crit_section(profile); new_dentry);
end_current_label_crit_section(label);
return error; return error;
} }
...@@ -312,14 +316,14 @@ static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_ ...@@ -312,14 +316,14 @@ static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_
static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_dentry, static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_dentry,
const struct path *new_dir, struct dentry *new_dentry) const struct path *new_dir, struct dentry *new_dentry)
{ {
struct aa_profile *profile; struct aa_label *label;
int error = 0; int error = 0;
if (!path_mediated_fs(old_dentry)) if (!path_mediated_fs(old_dentry))
return 0; return 0;
profile = begin_current_profile_crit_section(); label = begin_current_label_crit_section();
if (!unconfined(profile)) { if (!unconfined(label)) {
struct path old_path = { .mnt = old_dir->mnt, struct path old_path = { .mnt = old_dir->mnt,
.dentry = old_dentry }; .dentry = old_dentry };
struct path new_path = { .mnt = new_dir->mnt, struct path new_path = { .mnt = new_dir->mnt,
...@@ -328,17 +332,20 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d ...@@ -328,17 +332,20 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
d_backing_inode(old_dentry)->i_mode d_backing_inode(old_dentry)->i_mode
}; };
error = aa_path_perm(OP_RENAME_SRC, profile, &old_path, 0, error = aa_path_perm(OP_RENAME_SRC, labels_profile(label),
&old_path, 0,
MAY_READ | AA_MAY_GETATTR | MAY_WRITE | MAY_READ | AA_MAY_GETATTR | MAY_WRITE |
AA_MAY_SETATTR | AA_MAY_DELETE, AA_MAY_SETATTR | AA_MAY_DELETE,
&cond); &cond);
if (!error) if (!error)
error = aa_path_perm(OP_RENAME_DEST, profile, &new_path, error = aa_path_perm(OP_RENAME_DEST,
labels_profile(label),
&new_path,
0, MAY_WRITE | AA_MAY_SETATTR | 0, MAY_WRITE | AA_MAY_SETATTR |
AA_MAY_CREATE, &cond); AA_MAY_CREATE, &cond);
} }
end_current_profile_crit_section(profile); end_current_label_crit_section(label);
return error; return error;
} }
...@@ -360,8 +367,8 @@ static int apparmor_inode_getattr(const struct path *path) ...@@ -360,8 +367,8 @@ static int apparmor_inode_getattr(const struct path *path)
static int apparmor_file_open(struct file *file, const struct cred *cred) static int apparmor_file_open(struct file *file, const struct cred *cred)
{ {
struct aa_file_ctx *fctx = file->f_security; struct aa_file_ctx *fctx = file_ctx(file);
struct aa_profile *profile; struct aa_label *label;
int error = 0; int error = 0;
if (!path_mediated_fs(file->f_path.dentry)) if (!path_mediated_fs(file->f_path.dentry))
...@@ -377,17 +384,18 @@ static int apparmor_file_open(struct file *file, const struct cred *cred) ...@@ -377,17 +384,18 @@ static int apparmor_file_open(struct file *file, const struct cred *cred)
return 0; return 0;
} }
profile = aa_get_newest_cred_profile(cred); label = aa_get_newest_cred_label(cred);
if (!unconfined(profile)) { if (!unconfined(label)) {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct path_cond cond = { inode->i_uid, inode->i_mode }; struct path_cond cond = { inode->i_uid, inode->i_mode };
error = aa_path_perm(OP_OPEN, profile, &file->f_path, 0, error = aa_path_perm(OP_OPEN, labels_profile(label),
&file->f_path, 0,
aa_map_file_to_perms(file), &cond); aa_map_file_to_perms(file), &cond);
/* todo cache full allowed permissions set and state */ /* todo cache full allowed permissions set and state */
fctx->allow = aa_map_file_to_perms(file); fctx->allow = aa_map_file_to_perms(file);
} }
aa_put_profile(profile); aa_put_label(label);
return error; return error;
} }
...@@ -397,11 +405,11 @@ static int apparmor_file_alloc_security(struct file *file) ...@@ -397,11 +405,11 @@ static int apparmor_file_alloc_security(struct file *file)
int error = 0; int error = 0;
/* freed by apparmor_file_free_security */ /* freed by apparmor_file_free_security */
struct aa_profile *profile = begin_current_profile_crit_section(); struct aa_label *label = begin_current_label_crit_section();
file->f_security = aa_alloc_file_ctx(GFP_KERNEL); file->f_security = aa_alloc_file_ctx(GFP_KERNEL);
if (!file_ctx(file)) if (!file_ctx(file))
error = -ENOMEM; error = -ENOMEM;
end_current_profile_crit_section(profile); end_current_label_crit_section(label);
return error; return error;
} }
...@@ -414,21 +422,21 @@ static void apparmor_file_free_security(struct file *file) ...@@ -414,21 +422,21 @@ static void apparmor_file_free_security(struct file *file)
static int common_file_perm(const char *op, struct file *file, u32 mask) static int common_file_perm(const char *op, struct file *file, u32 mask)
{ {
struct aa_file_ctx *fctx = file->f_security; struct aa_file_ctx *fctx = file->f_security;
struct aa_profile *profile, *fprofile; struct aa_label *label, *flabel;
int error = 0; int error = 0;
/* don't reaudit files closed during inheritance */ /* don't reaudit files closed during inheritance */
if (file->f_path.dentry == aa_null.dentry) if (file->f_path.dentry == aa_null.dentry)
return -EACCES; return -EACCES;
fprofile = aa_cred_raw_profile(file->f_cred); flabel = aa_cred_raw_label(file->f_cred);
AA_BUG(!fprofile); AA_BUG(!flabel);
if (!file->f_path.mnt || if (!file->f_path.mnt ||
!path_mediated_fs(file->f_path.dentry)) !path_mediated_fs(file->f_path.dentry))
return 0; return 0;
profile = __begin_current_profile_crit_section(); label = __begin_current_label_crit_section();
/* revalidate access, if task is unconfined, or the cached cred /* revalidate access, if task is unconfined, or the cached cred
* doesn't match or if the request is for more permissions than * doesn't match or if the request is for more permissions than
...@@ -437,10 +445,10 @@ static int common_file_perm(const char *op, struct file *file, u32 mask) ...@@ -437,10 +445,10 @@ static int common_file_perm(const char *op, struct file *file, u32 mask)
* Note: the test for !unconfined(fprofile) is to handle file * Note: the test for !unconfined(fprofile) is to handle file
* delegation from unconfined tasks * delegation from unconfined tasks
*/ */
if (!unconfined(profile) && !unconfined(fprofile) && if (!unconfined(label) && !unconfined(flabel) &&
((fprofile != profile) || (mask & ~fctx->allow))) ((flabel != label) || (mask & ~fctx->allow)))
error = aa_file_perm(op, profile, file, mask); error = aa_file_perm(op, labels_profile(label), file, mask);
__end_current_profile_crit_section(profile); __end_current_label_crit_section(label);
return error; return error;
} }
...@@ -465,7 +473,7 @@ static int common_mmap(const char *op, struct file *file, unsigned long prot, ...@@ -465,7 +473,7 @@ static int common_mmap(const char *op, struct file *file, unsigned long prot,
{ {
int mask = 0; int mask = 0;
if (!file || !file->f_security) if (!file || !file_ctx(file))
return 0; return 0;
if (prot & PROT_READ) if (prot & PROT_READ)
...@@ -502,21 +510,21 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, ...@@ -502,21 +510,21 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
/* released below */ /* released below */
const struct cred *cred = get_task_cred(task); const struct cred *cred = get_task_cred(task);
struct aa_task_ctx *ctx = cred_ctx(cred); struct aa_task_ctx *ctx = cred_ctx(cred);
struct aa_profile *profile = NULL; struct aa_label *label = NULL;
if (strcmp(name, "current") == 0) if (strcmp(name, "current") == 0)
profile = aa_get_newest_profile(ctx->profile); label = aa_get_newest_label(ctx->label);
else if (strcmp(name, "prev") == 0 && ctx->previous) else if (strcmp(name, "prev") == 0 && ctx->previous)
profile = aa_get_newest_profile(ctx->previous); label = aa_get_newest_label(ctx->previous);
else if (strcmp(name, "exec") == 0 && ctx->onexec) else if (strcmp(name, "exec") == 0 && ctx->onexec)
profile = aa_get_newest_profile(ctx->onexec); label = aa_get_newest_label(ctx->onexec);
else else
error = -EINVAL; error = -EINVAL;
if (profile) if (label)
error = aa_getprocattr(profile, value); error = aa_getprocattr(labels_profile(label), value);
aa_put_profile(profile); aa_put_label(label);
put_cred(cred); put_cred(cred);
return error; return error;
...@@ -582,11 +590,11 @@ static int apparmor_setprocattr(const char *name, void *value, ...@@ -582,11 +590,11 @@ static int apparmor_setprocattr(const char *name, void *value,
return error; return error;
fail: fail:
aad(&sa)->profile = begin_current_profile_crit_section(); aad(&sa)->label = begin_current_label_crit_section();
aad(&sa)->info = name; aad(&sa)->info = name;
aad(&sa)->error = error = -EINVAL; aad(&sa)->error = error = -EINVAL;
aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL); aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL);
end_current_profile_crit_section(aad(&sa)->profile); end_current_label_crit_section(aad(&sa)->label);
goto out; goto out;
} }
...@@ -596,20 +604,21 @@ static int apparmor_setprocattr(const char *name, void *value, ...@@ -596,20 +604,21 @@ static int apparmor_setprocattr(const char *name, void *value,
*/ */
static void apparmor_bprm_committing_creds(struct linux_binprm *bprm) static void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
{ {
struct aa_profile *profile = aa_current_raw_profile(); struct aa_label *label = aa_current_raw_label();
struct aa_task_ctx *new_ctx = cred_ctx(bprm->cred); struct aa_task_ctx *new_ctx = cred_ctx(bprm->cred);
/* bail out if unconfined or not changing profile */ /* bail out if unconfined or not changing profile */
if ((new_ctx->profile == profile) || if ((new_ctx->label->proxy == label->proxy) ||
(unconfined(new_ctx->profile))) (unconfined(new_ctx->label)))
return; return;
aa_inherit_files(bprm->cred, current->files); aa_inherit_files(bprm->cred, current->files);
current->pdeath_signal = 0; current->pdeath_signal = 0;
/* reset soft limits and set hard limits for the new profile */ /* reset soft limits and set hard limits for the new label */
__aa_transition_rlimits(profile, new_ctx->profile); __aa_transition_rlimits(labels_profile(label),
labels_profile(new_ctx->label));
} }
/** /**
...@@ -625,12 +634,13 @@ static void apparmor_bprm_committed_creds(struct linux_binprm *bprm) ...@@ -625,12 +634,13 @@ static void apparmor_bprm_committed_creds(struct linux_binprm *bprm)
static int apparmor_task_setrlimit(struct task_struct *task, static int apparmor_task_setrlimit(struct task_struct *task,
unsigned int resource, struct rlimit *new_rlim) unsigned int resource, struct rlimit *new_rlim)
{ {
struct aa_profile *profile = __begin_current_profile_crit_section(); struct aa_label *label = __begin_current_label_crit_section();
int error = 0; int error = 0;
if (!unconfined(profile)) if (!unconfined(label))
error = aa_task_setrlimit(profile, task, resource, new_rlim); error = aa_task_setrlimit(labels_profile(label), task,
__end_current_profile_crit_section(profile); resource, new_rlim);
__end_current_label_crit_section(label);
return error; return error;
} }
...@@ -924,7 +934,7 @@ static int __init set_init_ctx(void) ...@@ -924,7 +934,7 @@ static int __init set_init_ctx(void)
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
ctx->profile = aa_get_profile(root_ns->unconfined); ctx->label = aa_get_label(ns_unconfined(root_ns));
cred_ctx(cred) = ctx; cred_ctx(cred) = ctx;
return 0; return 0;
......
...@@ -101,20 +101,9 @@ const char *const aa_profile_mode_names[] = { ...@@ -101,20 +101,9 @@ const char *const aa_profile_mode_names[] = {
"unconfined", "unconfined",
}; };
/* requires profile list write lock held */
void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new)
{
struct aa_profile *tmp;
tmp = rcu_dereference_protected(orig->proxy->profile,
mutex_is_locked(&orig->ns->lock));
rcu_assign_pointer(orig->proxy->profile, aa_get_profile(new));
orig->flags |= PFLAG_STALE;
aa_put_profile(tmp);
}
/** /**
* __list_add_profile - add a profile to a list * __add_profile - add a profiles to list and label tree
* @list: list to add it to (NOT NULL) * @list: list to add it to (NOT NULL)
* @profile: the profile to add (NOT NULL) * @profile: the profile to add (NOT NULL)
* *
...@@ -122,12 +111,21 @@ void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new) ...@@ -122,12 +111,21 @@ void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new)
* *
* Requires: namespace lock be held, or list not be shared * Requires: namespace lock be held, or list not be shared
*/ */
static void __list_add_profile(struct list_head *list, static void __add_profile(struct list_head *list, struct aa_profile *profile)
struct aa_profile *profile)
{ {
struct aa_label *l;
AA_BUG(!list);
AA_BUG(!profile);
AA_BUG(!profile->ns);
AA_BUG(!mutex_is_locked(&profile->ns->lock));
list_add_rcu(&profile->base.list, list); list_add_rcu(&profile->base.list, list);
/* get list reference */ /* get list reference */
aa_get_profile(profile); aa_get_profile(profile);
l = aa_label_insert(&profile->ns->labels, &profile->label);
AA_BUG(l != &profile->label);
aa_put_label(l);
} }
/** /**
...@@ -144,6 +142,10 @@ static void __list_add_profile(struct list_head *list, ...@@ -144,6 +142,10 @@ static void __list_add_profile(struct list_head *list,
*/ */
static void __list_remove_profile(struct aa_profile *profile) static void __list_remove_profile(struct aa_profile *profile)
{ {
AA_BUG(!profile);
AA_BUG(!profile->ns);
AA_BUG(!mutex_is_locked(&profile->ns->lock));
list_del_rcu(&profile->base.list); list_del_rcu(&profile->base.list);
aa_put_profile(profile); aa_put_profile(profile);
} }
...@@ -156,10 +158,14 @@ static void __list_remove_profile(struct aa_profile *profile) ...@@ -156,10 +158,14 @@ static void __list_remove_profile(struct aa_profile *profile)
*/ */
static void __remove_profile(struct aa_profile *profile) static void __remove_profile(struct aa_profile *profile)
{ {
AA_BUG(!profile);
AA_BUG(!profile->ns);
AA_BUG(!mutex_is_locked(&profile->ns->lock));
/* release any children lists first */ /* release any children lists first */
__aa_profile_list_release(&profile->base.profiles); __aa_profile_list_release(&profile->base.profiles);
/* released by free_profile */ /* released by free_profile */
__aa_update_proxy(profile, profile->ns->unconfined); aa_label_remove(&profile->label);
__aafs_profile_rmdir(profile); __aafs_profile_rmdir(profile);
__list_remove_profile(profile); __list_remove_profile(profile);
} }
...@@ -177,24 +183,6 @@ void __aa_profile_list_release(struct list_head *head) ...@@ -177,24 +183,6 @@ void __aa_profile_list_release(struct list_head *head)
__remove_profile(profile); __remove_profile(profile);
} }
static void free_proxy(struct aa_proxy *p)
{
if (p) {
/* r->profile will not be updated any more as r is dead */
aa_put_profile(rcu_dereference_protected(p->profile, true));
kzfree(p);
}
}
void aa_free_proxy_kref(struct kref *kref)
{
struct aa_proxy *p = container_of(kref, struct aa_proxy, count);
free_proxy(p);
}
/** /**
* aa_free_data - free a data blob * aa_free_data - free a data blob
* @ptr: data to free * @ptr: data to free
...@@ -242,7 +230,6 @@ void aa_free_profile(struct aa_profile *profile) ...@@ -242,7 +230,6 @@ void aa_free_profile(struct aa_profile *profile)
kzfree(profile->dirname); kzfree(profile->dirname);
aa_put_dfa(profile->xmatch); aa_put_dfa(profile->xmatch);
aa_put_dfa(profile->policy.dfa); aa_put_dfa(profile->policy.dfa);
aa_put_proxy(profile->proxy);
if (profile->data) { if (profile->data) {
rht = profile->data; rht = profile->data;
...@@ -253,30 +240,8 @@ void aa_free_profile(struct aa_profile *profile) ...@@ -253,30 +240,8 @@ void aa_free_profile(struct aa_profile *profile)
kzfree(profile->hash); kzfree(profile->hash);
aa_put_loaddata(profile->rawdata); aa_put_loaddata(profile->rawdata);
kzfree(profile);
}
/** kzfree(profile);
* aa_free_profile_rcu - free aa_profile by rcu (called by aa_free_profile_kref)
* @head: rcu_head callback for freeing of a profile (NOT NULL)
*/
static void aa_free_profile_rcu(struct rcu_head *head)
{
struct aa_profile *p = container_of(head, struct aa_profile, rcu);
if (p->flags & PFLAG_NS_COUNT)
aa_free_ns(p->ns);
else
aa_free_profile(p);
}
/**
* aa_free_profile_kref - free aa_profile by kref (called by aa_put_profile)
* @kr: kref callback for freeing of a profile (NOT NULL)
*/
void aa_free_profile_kref(struct kref *kref)
{
struct aa_profile *p = container_of(kref, struct aa_profile, count);
call_rcu(&p->rcu, aa_free_profile_rcu);
} }
/** /**
...@@ -286,30 +251,40 @@ void aa_free_profile_kref(struct kref *kref) ...@@ -286,30 +251,40 @@ void aa_free_profile_kref(struct kref *kref)
* *
* Returns: refcount profile or NULL on failure * Returns: refcount profile or NULL on failure
*/ */
struct aa_profile *aa_alloc_profile(const char *hname, gfp_t gfp) struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy,
gfp_t gfp)
{ {
struct aa_profile *profile; struct aa_profile *profile;
/* freed by free_profile - usually through aa_put_profile */ /* freed by free_profile - usually through aa_put_profile */
profile = kzalloc(sizeof(*profile), gfp); profile = kzalloc(sizeof(*profile) + sizeof(struct aa_profile *) * 2,
gfp);
if (!profile) if (!profile)
return NULL; return NULL;
profile->proxy = kzalloc(sizeof(struct aa_proxy), gfp);
if (!profile->proxy)
goto fail;
kref_init(&profile->proxy->count);
if (!aa_policy_init(&profile->base, NULL, hname, gfp)) if (!aa_policy_init(&profile->base, NULL, hname, gfp))
goto fail; goto fail;
kref_init(&profile->count); if (!aa_label_init(&profile->label, 1))
goto fail;
/* update being set needed by fs interface */
if (!proxy) {
proxy = aa_alloc_proxy(&profile->label, gfp);
if (!proxy)
goto fail;
} else
aa_get_proxy(proxy);
profile->label.proxy = proxy;
profile->label.hname = profile->base.hname;
profile->label.flags |= FLAG_PROFILE;
profile->label.vec[0] = profile;
/* refcount released by caller */ /* refcount released by caller */
return profile; return profile;
fail: fail:
kzfree(profile->proxy); aa_free_profile(profile);
kzfree(profile);
return NULL; return NULL;
} }
...@@ -362,14 +337,14 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, ...@@ -362,14 +337,14 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
if (profile) if (profile)
goto out; goto out;
profile = aa_alloc_profile(name, gfp); profile = aa_alloc_profile(name, NULL, gfp);
if (!profile) if (!profile)
goto fail; goto fail;
profile->mode = APPARMOR_COMPLAIN; profile->mode = APPARMOR_COMPLAIN;
profile->flags |= PFLAG_NULL; profile->label.flags |= FLAG_NULL;
if (hat) if (hat)
profile->flags |= PFLAG_HAT; profile->label.flags |= FLAG_HAT;
profile->path_flags = parent->path_flags; profile->path_flags = parent->path_flags;
/* released on free_profile */ /* released on free_profile */
...@@ -379,7 +354,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, ...@@ -379,7 +354,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
profile->policy.dfa = aa_get_dfa(nulldfa); profile->policy.dfa = aa_get_dfa(nulldfa);
mutex_lock(&profile->ns->lock); mutex_lock(&profile->ns->lock);
__list_add_profile(&parent->base.profiles, profile); __add_profile(&parent->base.profiles, profile);
mutex_unlock(&profile->ns->lock); mutex_unlock(&profile->ns->lock);
/* refcount released by caller */ /* refcount released by caller */
...@@ -389,7 +364,6 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, ...@@ -389,7 +364,6 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
return profile; return profile;
fail: fail:
kfree(name);
aa_free_profile(profile); aa_free_profile(profile);
return NULL; return NULL;
} }
...@@ -556,7 +530,7 @@ struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname) ...@@ -556,7 +530,7 @@ struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname)
return aa_lookupn_profile(ns, hname, strlen(hname)); return aa_lookupn_profile(ns, hname, strlen(hname));
} }
struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
const char *fqname, size_t n) const char *fqname, size_t n)
{ {
struct aa_profile *profile; struct aa_profile *profile;
...@@ -566,11 +540,11 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, ...@@ -566,11 +540,11 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base,
name = aa_splitn_fqname(fqname, n, &ns_name, &ns_len); name = aa_splitn_fqname(fqname, n, &ns_name, &ns_len);
if (ns_name) { if (ns_name) {
ns = aa_lookupn_ns(base->ns, ns_name, ns_len); ns = aa_lookupn_ns(labels_ns(base), ns_name, ns_len);
if (!ns) if (!ns)
return NULL; return NULL;
} else } else
ns = aa_get_ns(base->ns); ns = aa_get_ns(labels_ns(base));
if (name) if (name)
profile = aa_lookupn_profile(ns, name, n - (name - fqname)); profile = aa_lookupn_profile(ns, name, n - (name - fqname));
...@@ -596,7 +570,7 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace, ...@@ -596,7 +570,7 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace,
const char **info) const char **info)
{ {
if (profile) { if (profile) {
if (profile->flags & PFLAG_IMMUTABLE) { if (profile->label.flags & FLAG_IMMUTIBLE) {
*info = "cannot replace immutible profile"; *info = "cannot replace immutible profile";
return -EPERM; return -EPERM;
} else if (noreplace) { } else if (noreplace) {
...@@ -619,29 +593,31 @@ static void audit_cb(struct audit_buffer *ab, void *va) ...@@ -619,29 +593,31 @@ static void audit_cb(struct audit_buffer *ab, void *va)
} }
/** /**
* aa_audit_policy - Do auditing of policy changes * audit_policy - Do auditing of policy changes
* @profile: profile to check if it can manage policy * @label: label to check if it can manage policy
* @op: policy operation being performed * @op: policy operation being performed
* @gfp: memory allocation flags * @ns_name: name of namespace being manipulated
* @nsname: name of the ns being manipulated (MAY BE NULL)
* @name: name of profile being manipulated (NOT NULL) * @name: name of profile being manipulated (NOT NULL)
* @info: any extra information to be audited (MAYBE NULL) * @info: any extra information to be audited (MAYBE NULL)
* @error: error code * @error: error code
* *
* Returns: the error to be returned after audit is done * Returns: the error to be returned after audit is done
*/ */
static int audit_policy(struct aa_profile *profile, const char *op, static int audit_policy(struct aa_label *label, const char *op,
const char *nsname, const char *name, const char *ns_name, const char *name,
const char *info, int error) const char *info, int error)
{ {
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op); DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
aad(&sa)->iface.ns = nsname; aad(&sa)->iface.ns = ns_name;
aad(&sa)->name = name; aad(&sa)->name = name;
aad(&sa)->info = info; aad(&sa)->info = info;
aad(&sa)->error = error; aad(&sa)->error = error;
aad(&sa)->label = label;
return aa_audit(AUDIT_APPARMOR_STATUS, profile, &sa, audit_cb); aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, audit_cb);
return error;
} }
/** /**
...@@ -685,12 +661,12 @@ bool policy_admin_capable(struct aa_ns *ns) ...@@ -685,12 +661,12 @@ bool policy_admin_capable(struct aa_ns *ns)
/** /**
* aa_may_manage_policy - can the current task manage policy * aa_may_manage_policy - can the current task manage policy
* @profile: profile to check if it can manage policy * @label: label to check if it can manage policy
* @op: the policy manipulation operation being done * @op: the policy manipulation operation being done
* *
* Returns: 0 if the task is allowed to manipulate policy else error * Returns: 0 if the task is allowed to manipulate policy else error
*/ */
int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, u32 mask) int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask)
{ {
const char *op; const char *op;
...@@ -703,11 +679,11 @@ int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, u32 mask) ...@@ -703,11 +679,11 @@ int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, u32 mask)
/* check if loading policy is locked out */ /* check if loading policy is locked out */
if (aa_g_lock_policy) if (aa_g_lock_policy)
return audit_policy(profile, op, NULL, NULL, "policy_locked", return audit_policy(label, op, NULL, NULL, "policy_locked",
-EACCES); -EACCES);
if (!policy_admin_capable(ns)) if (!policy_admin_capable(ns))
return audit_policy(profile, op, NULL, NULL, "not policy admin", return audit_policy(label, op, NULL, NULL, "not policy admin",
-EACCES); -EACCES);
/* TODO: add fine grained mediation of policy loads */ /* TODO: add fine grained mediation of policy loads */
...@@ -750,8 +726,7 @@ static struct aa_profile *__list_lookup_parent(struct list_head *lh, ...@@ -750,8 +726,7 @@ static struct aa_profile *__list_lookup_parent(struct list_head *lh,
* *
* Requires: namespace list lock be held, or list not be shared * Requires: namespace list lock be held, or list not be shared
*/ */
static void __replace_profile(struct aa_profile *old, struct aa_profile *new, static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
bool share_proxy)
{ {
struct aa_profile *child, *tmp; struct aa_profile *child, *tmp;
...@@ -766,7 +741,7 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new, ...@@ -766,7 +741,7 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
p = __find_child(&new->base.profiles, child->base.name); p = __find_child(&new->base.profiles, child->base.name);
if (p) { if (p) {
/* @p replaces @child */ /* @p replaces @child */
__replace_profile(child, p, share_proxy); __replace_profile(child, p);
continue; continue;
} }
...@@ -784,14 +759,8 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new, ...@@ -784,14 +759,8 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
struct aa_profile *parent = aa_deref_parent(old); struct aa_profile *parent = aa_deref_parent(old);
rcu_assign_pointer(new->parent, aa_get_profile(parent)); rcu_assign_pointer(new->parent, aa_get_profile(parent));
} }
__aa_update_proxy(old, new); aa_label_replace(&old->label, &new->label);
if (share_proxy) { /* migrate dents must come after label replacement b/c update */
aa_put_proxy(new->proxy);
new->proxy = aa_get_proxy(old->proxy);
} else if (!rcu_access_pointer(new->proxy->profile))
/* aafs interface uses proxy */
rcu_assign_pointer(new->proxy->profile,
aa_get_profile(new));
__aafs_profile_migrate_dents(old, new); __aafs_profile_migrate_dents(old, new);
if (list_empty(&new->base.list)) { if (list_empty(&new->base.list)) {
...@@ -835,6 +804,7 @@ static void share_name(struct aa_profile *old, struct aa_profile *new) ...@@ -835,6 +804,7 @@ static void share_name(struct aa_profile *old, struct aa_profile *new)
aa_get_str(old->base.hname); aa_get_str(old->base.hname);
new->base.hname = old->base.hname; new->base.hname = old->base.hname;
new->base.name = old->base.name; new->base.name = old->base.name;
new->label.hname = old->label.hname;
} }
/* Update to newest version of parent after previous replacements /* Update to newest version of parent after previous replacements
...@@ -871,7 +841,7 @@ static struct aa_profile *update_to_newest_parent(struct aa_profile *new) ...@@ -871,7 +841,7 @@ static struct aa_profile *update_to_newest_parent(struct aa_profile *new)
* *
* Returns: size of data consumed else error code on failure. * Returns: size of data consumed else error code on failure.
*/ */
ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
u32 mask, struct aa_loaddata *udata) u32 mask, struct aa_loaddata *udata)
{ {
const char *ns_name, *info = NULL; const char *ns_name, *info = NULL;
...@@ -914,7 +884,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, ...@@ -914,7 +884,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile,
count++; count++;
} }
if (ns_name) { if (ns_name) {
ns = aa_prepare_ns(policy_ns ? policy_ns : profile->ns, ns = aa_prepare_ns(policy_ns ? policy_ns : labels_ns(label),
ns_name); ns_name);
if (IS_ERR(ns)) { if (IS_ERR(ns)) {
op = OP_PROF_LOAD; op = OP_PROF_LOAD;
...@@ -925,7 +895,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, ...@@ -925,7 +895,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile,
goto fail; goto fail;
} }
} else } else
ns = aa_get_ns(policy_ns ? policy_ns : profile->ns); ns = aa_get_ns(policy_ns ? policy_ns : labels_ns(label));
mutex_lock(&ns->lock); mutex_lock(&ns->lock);
/* check for duplicate rawdata blobs: space and file dedup */ /* check for duplicate rawdata blobs: space and file dedup */
...@@ -955,8 +925,8 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, ...@@ -955,8 +925,8 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile,
if (ent->new->rename) { if (ent->new->rename) {
error = __lookup_replace(ns, ent->new->rename, error = __lookup_replace(ns, ent->new->rename,
!(mask & AA_MAY_REPLACE_POLICY), !(mask & AA_MAY_REPLACE_POLICY),
&ent->rename, &info); &ent->rename, &info);
if (error) if (error)
goto fail_lock; goto fail_lock;
} }
...@@ -1021,7 +991,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, ...@@ -1021,7 +991,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile,
if (ent->old && ent->old->rawdata == ent->new->rawdata) { if (ent->old && ent->old->rawdata == ent->new->rawdata) {
/* dedup actual profile replacement */ /* dedup actual profile replacement */
audit_policy(profile, op, ns_name, ent->new->base.hname, audit_policy(label, op, ns_name, ent->new->base.hname,
"same as current profile, skipping", "same as current profile, skipping",
error); error);
goto skip; goto skip;
...@@ -1031,12 +1001,12 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, ...@@ -1031,12 +1001,12 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile,
* TODO: finer dedup based on profile range in data. Load set * TODO: finer dedup based on profile range in data. Load set
* can differ but profile may remain unchanged * can differ but profile may remain unchanged
*/ */
audit_policy(profile, op, NULL, ent->new->base.hname, audit_policy(label, op, ns_name, ent->new->base.hname, NULL,
NULL, error); error);
if (ent->old) { if (ent->old) {
share_name(ent->old, ent->new); share_name(ent->old, ent->new);
__replace_profile(ent->old, ent->new, 1); __replace_profile(ent->old, ent->new);
} else { } else {
struct list_head *lh; struct list_head *lh;
...@@ -1047,11 +1017,12 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, ...@@ -1047,11 +1017,12 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile,
lh = &parent->base.profiles; lh = &parent->base.profiles;
} else } else
lh = &ns->base.profiles; lh = &ns->base.profiles;
__list_add_profile(lh, ent->new); __add_profile(lh, ent->new);
} }
skip: skip:
aa_load_ent_free(ent); aa_load_ent_free(ent);
} }
__aa_labelset_update_subtree(ns);
mutex_unlock(&ns->lock); mutex_unlock(&ns->lock);
out: out:
...@@ -1068,8 +1039,8 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, ...@@ -1068,8 +1039,8 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile,
/* audit cause of failure */ /* audit cause of failure */
op = (ent && !ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; op = (ent && !ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
fail: fail:
audit_policy(profile, op, ns_name, ent ? ent->new->base.hname : NULL, audit_policy(label, op, ns_name, ent ? ent->new->base.hname : NULL,
info, error); info, error);
/* audit status that rest of profiles in the atomic set failed too */ /* audit status that rest of profiles in the atomic set failed too */
info = "valid profile in failed atomic policy load"; info = "valid profile in failed atomic policy load";
list_for_each_entry(tmp, &lh, list) { list_for_each_entry(tmp, &lh, list) {
...@@ -1079,8 +1050,8 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, ...@@ -1079,8 +1050,8 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile,
continue; continue;
} }
op = (!tmp->old) ? OP_PROF_LOAD : OP_PROF_REPL; op = (!tmp->old) ? OP_PROF_LOAD : OP_PROF_REPL;
audit_policy(profile, op, ns_name, audit_policy(label, op, ns_name, tmp->new->base.hname, info,
tmp->new->base.hname, info, error); error);
} }
list_for_each_entry_safe(ent, tmp, &lh, list) { list_for_each_entry_safe(ent, tmp, &lh, list) {
list_del_init(&ent->list); list_del_init(&ent->list);
...@@ -1093,7 +1064,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, ...@@ -1093,7 +1064,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile,
/** /**
* aa_remove_profiles - remove profile(s) from the system * aa_remove_profiles - remove profile(s) from the system
* @policy_ns: namespace the remove is being done from * @policy_ns: namespace the remove is being done from
* @subj: profile attempting to remove policy * @subj: label attempting to remove policy
* @fqname: name of the profile or namespace to remove (NOT NULL) * @fqname: name of the profile or namespace to remove (NOT NULL)
* @size: size of the name * @size: size of the name
* *
...@@ -1104,7 +1075,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, ...@@ -1104,7 +1075,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile,
* *
* Returns: size of data consume else error code if fails * Returns: size of data consume else error code if fails
*/ */
ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_profile *subj, ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_label *subj,
char *fqname, size_t size) char *fqname, size_t size)
{ {
struct aa_ns *ns = NULL; struct aa_ns *ns = NULL;
...@@ -1124,8 +1095,8 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_profile *subj, ...@@ -1124,8 +1095,8 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_profile *subj,
name = aa_splitn_fqname(fqname, size, &ns_name, &ns_len); name = aa_splitn_fqname(fqname, size, &ns_name, &ns_len);
/* released below */ /* released below */
ns = aa_lookupn_ns(policy_ns ? policy_ns : subj->ns, ns_name, ns = aa_lookupn_ns(policy_ns ? policy_ns : labels_ns(subj),
ns_len); ns_name, ns_len);
if (!ns) { if (!ns) {
info = "namespace does not exist"; info = "namespace does not exist";
error = -ENOENT; error = -ENOENT;
...@@ -1133,7 +1104,7 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_profile *subj, ...@@ -1133,7 +1104,7 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_profile *subj,
} }
} else } else
/* released below */ /* released below */
ns = aa_get_ns(policy_ns ? policy_ns : subj->ns); ns = aa_get_ns(policy_ns ? policy_ns : labels_ns(subj));
if (!name) { if (!name) {
/* remove namespace - can only happen if fqname[0] == ':' */ /* remove namespace - can only happen if fqname[0] == ':' */
...@@ -1152,6 +1123,7 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_profile *subj, ...@@ -1152,6 +1123,7 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_profile *subj,
} }
name = profile->base.hname; name = profile->base.hname;
__remove_profile(profile); __remove_profile(profile);
__aa_labelset_update_subtree(ns);
__aa_bump_ns_revision(ns); __aa_bump_ns_revision(ns);
mutex_unlock(&ns->lock); mutex_unlock(&ns->lock);
} }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "include/apparmor.h" #include "include/apparmor.h"
#include "include/context.h" #include "include/context.h"
#include "include/policy_ns.h" #include "include/policy_ns.h"
#include "include/label.h"
#include "include/policy.h" #include "include/policy.h"
/* root profile namespace */ /* root profile namespace */
...@@ -104,12 +105,12 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name) ...@@ -104,12 +105,12 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name)
init_waitqueue_head(&ns->wait); init_waitqueue_head(&ns->wait);
/* released by aa_free_ns() */ /* released by aa_free_ns() */
ns->unconfined = aa_alloc_profile("unconfined", GFP_KERNEL); ns->unconfined = aa_alloc_profile("unconfined", NULL, GFP_KERNEL);
if (!ns->unconfined) if (!ns->unconfined)
goto fail_unconfined; goto fail_unconfined;
ns->unconfined->flags = PFLAG_IX_ON_NAME_ERROR | ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR |
PFLAG_IMMUTABLE | PFLAG_NS_COUNT; FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
ns->unconfined->mode = APPARMOR_UNCONFINED; ns->unconfined->mode = APPARMOR_UNCONFINED;
/* ns and ns->unconfined share ns->unconfined refcount */ /* ns and ns->unconfined share ns->unconfined refcount */
...@@ -117,6 +118,8 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name) ...@@ -117,6 +118,8 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name)
atomic_set(&ns->uniq_null, 0); atomic_set(&ns->uniq_null, 0);
aa_labelset_init(&ns->labels);
return ns; return ns;
fail_unconfined: fail_unconfined:
...@@ -139,6 +142,7 @@ void aa_free_ns(struct aa_ns *ns) ...@@ -139,6 +142,7 @@ void aa_free_ns(struct aa_ns *ns)
return; return;
aa_policy_destroy(&ns->base); aa_policy_destroy(&ns->base);
aa_labelset_destroy(&ns->labels);
aa_put_ns(ns->parent); aa_put_ns(ns->parent);
ns->unconfined->ns = NULL; ns->unconfined->ns = NULL;
...@@ -337,8 +341,14 @@ static void destroy_ns(struct aa_ns *ns) ...@@ -337,8 +341,14 @@ static void destroy_ns(struct aa_ns *ns)
/* release all sub namespaces */ /* release all sub namespaces */
__ns_list_release(&ns->sub_ns); __ns_list_release(&ns->sub_ns);
if (ns->parent) if (ns->parent) {
__aa_update_proxy(ns->unconfined, ns->parent->unconfined); unsigned long flags;
write_lock_irqsave(&ns->labels.lock, flags);
__aa_proxy_redirect(ns_unconfined(ns),
ns_unconfined(ns->parent));
write_unlock_irqrestore(&ns->labels.lock, flags);
}
__aafs_ns_rmdir(ns); __aafs_ns_rmdir(ns);
mutex_unlock(&ns->lock); mutex_unlock(&ns->lock);
} }
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "include/context.h" #include "include/context.h"
#include "include/crypto.h" #include "include/crypto.h"
#include "include/match.h" #include "include/match.h"
#include "include/path.h"
#include "include/policy.h" #include "include/policy.h"
#include "include/policy_unpack.h" #include "include/policy_unpack.h"
...@@ -107,7 +108,7 @@ static int audit_iface(struct aa_profile *new, const char *ns_name, ...@@ -107,7 +108,7 @@ static int audit_iface(struct aa_profile *new, const char *ns_name,
const char *name, const char *info, struct aa_ext *e, const char *name, const char *info, struct aa_ext *e,
int error) int error)
{ {
struct aa_profile *profile = aa_current_raw_profile(); struct aa_profile *profile = labels_profile(aa_current_raw_label());
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL); DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
if (e) if (e)
aad(&sa)->iface.pos = e->pos - e->start; aad(&sa)->iface.pos = e->pos - e->start;
...@@ -602,7 +603,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) ...@@ -602,7 +603,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
name = tmpname; name = tmpname;
} }
profile = aa_alloc_profile(name, GFP_KERNEL); profile = aa_alloc_profile(name, NULL, GFP_KERNEL);
if (!profile) if (!profile)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -635,7 +636,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) ...@@ -635,7 +636,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
if (!unpack_u32(e, &tmp, NULL)) if (!unpack_u32(e, &tmp, NULL))
goto fail; goto fail;
if (tmp & PACKED_FLAG_HAT) if (tmp & PACKED_FLAG_HAT)
profile->flags |= PFLAG_HAT; profile->label.flags |= FLAG_HAT;
if (!unpack_u32(e, &tmp, NULL)) if (!unpack_u32(e, &tmp, NULL))
goto fail; goto fail;
if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG))
...@@ -654,10 +655,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) ...@@ -654,10 +655,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
/* path_flags is optional */ /* path_flags is optional */
if (unpack_u32(e, &profile->path_flags, "path_flags")) if (unpack_u32(e, &profile->path_flags, "path_flags"))
profile->path_flags |= profile->flags & PFLAG_MEDIATE_DELETED; profile->path_flags |= profile->label.flags &
PATH_MEDIATE_DELETED;
else else
/* set a default value if path_flags field is not present */ /* set a default value if path_flags field is not present */
profile->path_flags = PFLAG_MEDIATE_DELETED; profile->path_flags = PATH_MEDIATE_DELETED;
if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL)) if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
goto fail; goto fail;
......
...@@ -55,7 +55,7 @@ int aa_getprocattr(struct aa_profile *profile, char **string) ...@@ -55,7 +55,7 @@ int aa_getprocattr(struct aa_profile *profile, char **string)
ns_len += 4; ns_len += 4;
/* unconfined profiles don't have a mode string appended */ /* unconfined profiles don't have a mode string appended */
if (!unconfined(profile)) if (!profile_unconfined(profile))
mode_len = strlen(mode_str) + 3; /* + 3 for _() */ mode_len = strlen(mode_str) + 3; /* + 3 for _() */
name_len = strlen(profile->base.hname); name_len = strlen(profile->base.hname);
...@@ -69,7 +69,7 @@ int aa_getprocattr(struct aa_profile *profile, char **string) ...@@ -69,7 +69,7 @@ int aa_getprocattr(struct aa_profile *profile, char **string)
sprintf(s, ":%s://", ns_name); sprintf(s, ":%s://", ns_name);
s += ns_len; s += ns_len;
} }
if (unconfined(profile)) if (profile_unconfined(profile))
/* mode string not being appended */ /* mode string not being appended */
sprintf(s, "%s\n", profile->base.hname); sprintf(s, "%s\n", profile->base.hname);
else else
......
...@@ -86,11 +86,11 @@ int aa_map_resource(int resource) ...@@ -86,11 +86,11 @@ int aa_map_resource(int resource)
int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task, int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task,
unsigned int resource, struct rlimit *new_rlim) unsigned int resource, struct rlimit *new_rlim)
{ {
struct aa_profile *task_profile; struct aa_label *task_label;
int error = 0; int error = 0;
rcu_read_lock(); rcu_read_lock();
task_profile = aa_get_newest_cred_profile((__task_cred(task))); task_label = aa_get_newest_cred_label((__task_cred(task)));
rcu_read_unlock(); rcu_read_unlock();
/* TODO: extend resource control to handle other (non current) /* TODO: extend resource control to handle other (non current)
...@@ -99,13 +99,13 @@ int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task, ...@@ -99,13 +99,13 @@ int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task,
* the same profile or that the task setting the resource of another * the same profile or that the task setting the resource of another
* task has CAP_SYS_RESOURCE. * task has CAP_SYS_RESOURCE.
*/ */
if ((profile != task_profile && if ((profile != labels_profile(task_label) &&
aa_capable(profile, CAP_SYS_RESOURCE, 1)) || aa_capable(profile, CAP_SYS_RESOURCE, 1)) ||
(profile->rlimits.mask & (1 << resource) && (profile->rlimits.mask & (1 << resource) &&
new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)) new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max))
error = -EACCES; error = -EACCES;
aa_put_profile(task_profile); aa_put_label(task_label);
return audit_resource(profile, resource, new_rlim->rlim_max, error); return audit_resource(profile, resource, new_rlim->rlim_max, error);
} }
......
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