diff options
author | John Johansen <john.johansen@canonical.com> | 2017-06-09 08:14:28 -0700 |
---|---|---|
committer | John Johansen <john.johansen@canonical.com> | 2017-06-10 17:11:38 -0700 |
commit | 637f688dc3dc304a89f441d76f49a0e35bc49c08 (patch) | |
tree | 78fee8a7aa212140c4c6b6a9b722bbba61802cab /security | |
parent | f1bd904175e8190ce14aedee37e207ab51fe3b30 (diff) | |
download | linux-stable-637f688dc3dc304a89f441d76f49a0e35bc49c08.tar.gz linux-stable-637f688dc3dc304a89f441d76f49a0e35bc49c08.tar.bz2 linux-stable-637f688dc3dc304a89f441d76f49a0e35bc49c08.zip |
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: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security')
-rw-r--r-- | security/apparmor/Makefile | 2 | ||||
-rw-r--r-- | security/apparmor/apparmorfs.c | 128 | ||||
-rw-r--r-- | security/apparmor/audit.c | 27 | ||||
-rw-r--r-- | security/apparmor/context.c | 87 | ||||
-rw-r--r-- | security/apparmor/domain.c | 77 | ||||
-rw-r--r-- | security/apparmor/file.c | 18 | ||||
-rw-r--r-- | security/apparmor/include/apparmor.h | 5 | ||||
-rw-r--r-- | security/apparmor/include/audit.h | 9 | ||||
-rw-r--r-- | security/apparmor/include/context.h | 158 | ||||
-rw-r--r-- | security/apparmor/include/perms.h | 12 | ||||
-rw-r--r-- | security/apparmor/include/policy.h | 110 | ||||
-rw-r--r-- | security/apparmor/include/policy_ns.h | 4 | ||||
-rw-r--r-- | security/apparmor/ipc.c | 29 | ||||
-rw-r--r-- | security/apparmor/lib.c | 163 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 134 | ||||
-rw-r--r-- | security/apparmor/policy.c | 208 | ||||
-rw-r--r-- | security/apparmor/policy_ns.c | 20 | ||||
-rw-r--r-- | security/apparmor/policy_unpack.c | 12 | ||||
-rw-r--r-- | security/apparmor/procattr.c | 4 | ||||
-rw-r--r-- | security/apparmor/resource.c | 8 |
20 files changed, 686 insertions, 529 deletions
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile index b3e7c04b7e7b..a16b195274de 100644 --- a/security/apparmor/Makefile +++ b/security/apparmor/Makefile @@ -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 \ 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 clean-files := capability_names.h rlim_names.h diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index e2919a0766b0..976af6da45c3 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -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, loff_t *pos, struct aa_ns *ns) { - ssize_t error; 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 * below after unpack */ - error = aa_may_manage_policy(profile, ns, mask); + error = aa_may_manage_policy(label, ns, mask); if (error) return error; data = aa_simple_write_to_buffer(buf, size, size, pos); error = PTR_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); } - end_current_profile_crit_section(profile); + end_current_label_crit_section(label); return error; } @@ -468,15 +468,15 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, size_t size, loff_t *pos) { struct aa_loaddata *data; - struct aa_profile *profile; + struct aa_label *label; ssize_t error; 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 * 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) goto out; @@ -489,11 +489,11 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, error = PTR_ERR(data); if (!IS_ERR(data)) { 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); } out: - end_current_profile_crit_section(profile); + end_current_label_crit_section(label); aa_put_ns(ns); return error; } @@ -605,7 +605,7 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms, struct aa_dfa *dfa; unsigned int state = 0; - if (unconfined(profile)) + if (profile_unconfined(profile)) return; if (profile->file.dfa && *match_str == AA_CLASS_FILE) { dfa = profile->file.dfa; @@ -655,7 +655,7 @@ static ssize_t query_data(char *buf, size_t buf_len, { char *out; const char *key; - struct aa_profile *profile, *curr; + struct aa_label *label, *curr; struct aa_data *data; u32 bytes, blocks; __le32 outle32; @@ -672,11 +672,11 @@ static ssize_t query_data(char *buf, size_t buf_len, if (buf_len < sizeof(bytes) + sizeof(blocks)) return -EINVAL; /* not enough space */ - curr = begin_current_profile_crit_section(); - profile = aa_fqlookupn_profile(curr, query, strnlen(query, query_len)); - end_current_profile_crit_section(curr); - if (!profile) - return -ENOENT; + curr = begin_current_label_crit_section(); + label = aa_label_parse(curr, query, GFP_KERNEL, false, false); + end_current_label_crit_section(curr); + if (IS_ERR(label)) + return PTR_ERR(label); /* 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 @@ -690,13 +690,16 @@ static ssize_t query_data(char *buf, size_t buf_len, out = buf + sizeof(bytes) + sizeof(blocks); blocks = 0; - if (profile->data) { - data = rhashtable_lookup_fast(profile->data, &key, - profile->data->p); + if (labels_profile(label)->data) { + data = rhashtable_lookup_fast(labels_profile(label)->data, &key, + labels_profile(label)->data->p); 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 */ + } outle32 = __cpu_to_le32(data->size); memcpy(out, &outle32, sizeof(outle32)); out += sizeof(outle32); @@ -705,7 +708,7 @@ static ssize_t query_data(char *buf, size_t buf_len, blocks++; } } - aa_put_profile(profile); + aa_put_label(label); outle32 = __cpu_to_le32(out - buf - sizeof(bytes)); memcpy(buf, &outle32, sizeof(outle32)); @@ -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, char *query, size_t query_len, bool view_only) { - struct aa_profile *profile, *curr; + struct aa_label *label, *curr; char *label_name, *match_str; size_t label_name_len, match_len; struct aa_perms perms; @@ -760,14 +763,14 @@ static ssize_t query_label(char *buf, size_t buf_len, match_str = label_name + label_name_len + 1; match_len = query_len - label_name_len - 1; - curr = begin_current_profile_crit_section(); - profile = aa_fqlookupn_profile(curr, label_name, label_name_len); - end_current_profile_crit_section(curr); - if (!profile) - return -ENOENT; + curr = begin_current_label_crit_section(); + label = aa_label_parse(curr, label_name, GFP_KERNEL, false, false); + end_current_label_crit_section(curr); + if (IS_ERR(label)) + return PTR_ERR(label); 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, "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) static int seq_profile_name_show(struct seq_file *seq, void *v) { 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); - aa_put_profile(profile); + aa_put_label(label); return 0; } @@ -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) { 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]); - aa_put_profile(profile); + aa_put_label(label); return 0; } @@ -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) { 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) seq_printf(seq, "%s\n", profile->attach); else if (profile->xmatch) seq_puts(seq, "<unknown>\n"); else seq_printf(seq, "%s\n", profile->base.name); - aa_put_profile(profile); + aa_put_label(label); return 0; } @@ -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) { 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(); if (profile->hash) { @@ -1069,7 +1076,7 @@ static int seq_profile_hash_show(struct seq_file *seq, void *v) seq_printf(seq, "%.2x", profile->hash[i]); seq_putc(seq, '\n'); } - aa_put_profile(profile); + aa_put_label(label); return 0; } @@ -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) { - struct aa_profile *profile; + struct aa_label *label; - profile = begin_current_profile_crit_section(); - seq_printf(seq, "%d\n", profile->ns->level); - end_current_profile_crit_section(profile); + label = begin_current_label_crit_section(); + seq_printf(seq, "%d\n", labels_ns(label)->level); + end_current_label_crit_section(label); return 0; } 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(profile->ns, profile->ns, true)); - end_current_profile_crit_section(profile); + seq_printf(seq, "%s\n", aa_ns_name(labels_ns(label), + labels_ns(label), true)); + end_current_label_crit_section(label); return 0; } @@ -1380,7 +1387,7 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name, struct aa_profile *profile, 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; 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) { struct aa_ns *ns, *parent; /* TODO: improve permission check */ - struct aa_profile *profile = begin_current_profile_crit_section(); - int error = aa_may_manage_policy(profile, NULL, AA_MAY_LOAD_POLICY); - end_current_profile_crit_section(profile); + struct aa_label *label; + int error; + + 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) return error; @@ -1587,13 +1597,16 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) { struct aa_ns *ns, *parent; /* TODO: improve permission check */ - struct aa_profile *profile = begin_current_profile_crit_section(); - int error = aa_may_manage_policy(profile, NULL, AA_MAY_LOAD_POLICY); - end_current_profile_crit_section(profile); + struct aa_label *label; + int error; + + 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) 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 * from the apparmor dir. It is up to the apparmor ns locking * to avoid races. @@ -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_ns *root = f->private; - if (profile->ns != root) - seq_printf(f, ":%s://", aa_ns_name(root, profile->ns, true)); - seq_printf(f, "%s (%s)\n", profile->base.hname, - aa_profile_mode_names[profile->mode]); + aa_label_seq_xprint(f, root, &profile->label, + FLAG_SHOW_MODE | FLAG_VIEW_SUBNS, GFP_KERNEL); + seq_putc(f, '\n'); return 0; } diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 87f40fa8c431..8f9ecac7f8de 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -77,14 +77,24 @@ static void audit_pre(struct audit_buffer *ab, void *ca) audit_log_format(ab, " error=%d", aad(sa)->error); } - if (aad(sa)->profile) { - struct aa_profile *profile = aad(sa)->profile; - if (profile->ns != root_ns) { - audit_log_format(ab, " namespace="); - audit_log_untrustedstring(ab, profile->ns->base.hname); + if (aad(sa)->label) { + struct aa_label *label = aad(sa)->label; + + if (label_isprofile(label)) { + 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) { @@ -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) type = AUDIT_APPARMOR_KILL; - if (!unconfined(profile)) - aad(sa)->profile = profile; + aad(sa)->label = &profile->label; aa_audit_msg(type, sa, cb); diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 410b9f7f68a1..c95f1ac6190b 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -14,9 +14,9 @@ * * * 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 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. * * TODO @@ -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) { if (ctx) { - aa_put_profile(ctx->profile); - aa_put_profile(ctx->previous); - aa_put_profile(ctx->onexec); + aa_put_label(ctx->label); + aa_put_label(ctx->previous); + aa_put_label(ctx->onexec); kzfree(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) { *new = *old; - aa_get_profile(new->profile); - aa_get_profile(new->previous); - aa_get_profile(new->onexec); + aa_get_label(new->label); + aa_get_label(new->previous); + 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) * - * 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(); - p = aa_get_newest_profile(__aa_task_raw_profile(task)); + p = aa_get_newest_label(__aa_task_raw_label(task)); rcu_read_unlock(); return p; } /** - * aa_replace_current_profile - replace the current tasks profiles - * @profile: new profile (NOT NULL) + * aa_replace_current_label - replace the current tasks label + * @label: new label (NOT NULL) * * 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 cred *new; - AA_BUG(!profile); + AA_BUG(!label); - if (ctx->profile == profile) + if (ctx->label == label) return 0; if (current_cred() != current_real_cred()) @@ -108,8 +108,8 @@ int aa_replace_current_profile(struct aa_profile *profile) return -ENOMEM; ctx = cred_ctx(new); - if (unconfined(profile) || (ctx->profile->ns != profile->ns)) - /* if switching to unconfined or a different profile namespace + if (unconfined(label) || (labels_ns(ctx->label) != labels_ns(label))) + /* if switching to unconfined or a different label namespace * clear out context state */ aa_clear_task_ctx_trans(ctx); @@ -120,9 +120,9 @@ int aa_replace_current_profile(struct aa_profile *profile) * keeping @profile valid, so make sure to get its reference before * dropping the reference on ctx->profile */ - aa_get_profile(profile); - aa_put_profile(ctx->profile); - ctx->profile = profile; + aa_get_label(label); + aa_put_label(ctx->label); + ctx->label = label; commit_creds(new); return 0; @@ -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 - * @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 */ -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 cred *new = prepare_creds(); @@ -142,9 +142,10 @@ int aa_set_current_onexec(struct aa_profile *profile) return -ENOMEM; ctx = cred_ctx(new); - aa_get_profile(profile); - aa_put_profile(ctx->onexec); - ctx->onexec = profile; + aa_get_label(label); + aa_clear_task_ctx_trans(ctx); + ctx->onexec = label; + ctx->token = stack; commit_creds(new); return 0; @@ -152,7 +153,7 @@ int aa_set_current_onexec(struct aa_profile *profile) /** * 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 * * 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) * * 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 cred *new = prepare_creds(); if (!new) return -ENOMEM; - AA_BUG(!profile); + AA_BUG(!label); ctx = cred_ctx(new); if (!ctx->previous) { /* transfer refcount */ - ctx->previous = ctx->profile; + ctx->previous = ctx->label; ctx->token = token; } else if (ctx->token == token) { - aa_put_profile(ctx->profile); + aa_put_label(ctx->label); } else { /* previous_profile && ctx->token != token */ abort_creds(new); return -EACCES; } - ctx->profile = aa_get_newest_profile(profile); + ctx->label = aa_get_newest_label(label); /* clear exec on switching context */ - aa_put_profile(ctx->onexec); + aa_put_label(ctx->onexec); ctx->onexec = NULL; commit_creds(new); @@ -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 * - * 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. * * 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 cred *new = prepare_creds(); @@ -210,15 +211,15 @@ int aa_restore_previous_profile(u64 token) abort_creds(new); return -EACCES; } - /* ignore restores when there is no saved profile */ + /* ignore restores when there is no saved label */ if (!ctx->previous) { abort_creds(new); return 0; } - aa_put_profile(ctx->profile); - ctx->profile = aa_get_newest_profile(ctx->previous); - AA_BUG(!ctx->profile); + aa_put_label(ctx->label); + ctx->label = aa_get_newest_label(ctx->previous); + AA_BUG(!ctx->label); /* clear exec && prev information when restoring to previous context */ aa_clear_task_ctx_trans(ctx); diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 2ec4ae029215..8d6797c849fe 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -61,24 +61,25 @@ void aa_free_domain_entries(struct aa_domain *domain) static int may_change_ptraced_domain(struct aa_profile *to_profile) { struct task_struct *tracer; - struct aa_profile *tracerp = NULL; + struct aa_label *tracerl = NULL; int error = 0; rcu_read_lock(); tracer = ptrace_parent(current); if (tracer) /* released below */ - tracerp = aa_get_task_profile(tracer); + tracerl = aa_get_task_label(tracer); /* not ptraced */ - if (!tracer || unconfined(tracerp)) + if (!tracer || unconfined(tracerl)) 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: rcu_read_unlock(); - aa_put_profile(tracerp); + aa_put_label(tracerl); return error; } @@ -102,7 +103,7 @@ static struct aa_perms change_profile_perms(struct aa_profile *profile, struct path_cond cond = { }; unsigned int state; - if (unconfined(profile)) { + if (profile_unconfined(profile)) { perms.allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC; perms.audit = perms.quiet = perms.kill = 0; return perms; @@ -144,7 +145,7 @@ static struct aa_profile *__attach_match(const char *name, struct aa_profile *profile, *candidate = NULL; list_for_each_entry_rcu(profile, head, base.list) { - if (profile->flags & PFLAG_NULL) + if (profile->label.flags & FLAG_NULL) continue; if (profile->xmatch && profile->xmatch_len > len) { unsigned int state = aa_dfa_match(profile->xmatch, @@ -338,6 +339,7 @@ static struct aa_profile *x_to_profile(struct aa_profile *profile, int apparmor_bprm_set_creds(struct linux_binprm *bprm) { struct aa_task_ctx *ctx; + struct aa_label *label; struct aa_profile *profile, *new_profile = NULL; struct aa_ns *ns; char *buffer = NULL; @@ -356,7 +358,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ctx = cred_ctx(bprm->cred); 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 */ get_buffers(buffer); @@ -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, &name, &info, profile->disconnected); if (error) { - if (unconfined(profile) || - (profile->flags & PFLAG_IX_ON_NAME_ERROR)) + if (profile_unconfined(profile) || + (profile->label.flags & FLAG_IX_ON_NAME_ERROR)) error = 0; name = bprm->filename; goto audit; @@ -380,11 +383,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) /* Test for onexec first as onexec directives override other * x transitions. */ - if (unconfined(profile)) { + if (profile_unconfined(profile)) { /* unconfined task */ if (ctx->onexec) /* change_profile on exec already been granted */ - new_profile = aa_get_profile(ctx->onexec); + new_profile = labels_profile(aa_get_label(ctx->onexec)); else new_profile = find_attach(ns, &ns->base.profiles, name); if (!new_profile) @@ -402,7 +405,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) if (ctx->onexec) { struct aa_perms cp; 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)) goto audit; @@ -411,9 +414,9 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) * exec\0change_profile */ state = aa_dfa_null_transition(profile->file.dfa, state); - cp = change_profile_perms(profile, ctx->onexec->ns, - ctx->onexec->base.name, - AA_MAY_ONEXEC, state); + cp = change_profile_perms(profile, labels_ns(ctx->onexec), + labels_profile(ctx->onexec)->base.name, + AA_MAY_ONEXEC, state); if (!(cp.allow & AA_MAY_ONEXEC)) goto audit; @@ -501,9 +504,9 @@ apply: bprm->per_clear |= PER_CLEAR_ON_SETID; x_clear: - aa_put_profile(ctx->profile); + aa_put_label(ctx->label); /* transfer new profile reference will be released when ctx is freed */ - ctx->profile = new_profile; + ctx->label = &new_profile->label; new_profile = NULL; /* clear out all temporary/transitional state from the context */ @@ -516,7 +519,7 @@ audit: cleanup: aa_put_profile(new_profile); - aa_put_profile(profile); + aa_put_label(label); put_buffers(buffer); return error; @@ -576,7 +579,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) { const struct cred *cred; 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; int i; struct aa_perms perms = {}; @@ -594,10 +598,11 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) /* released below */ cred = get_current_cred(); ctx = cred_ctx(cred); - profile = aa_get_newest_cred_profile(cred); - previous_profile = aa_get_newest_profile(ctx->previous); + label = aa_get_newest_cred_label(cred); + previous_label = aa_get_newest_label(ctx->previous); + profile = labels_profile(label); - if (unconfined(profile)) { + if (unconfined(label)) { info = "unconfined"; error = -EPERM; goto audit; @@ -664,7 +669,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) } if (!(flags & AA_CHANGE_TEST)) { - error = aa_set_current_hat(hat, token); + error = aa_set_current_hat(&hat->label, token); if (error == -EACCES) /* kill task in case of brute force attacks */ perms.kill = AA_MAY_CHANGEHAT; @@ -672,12 +677,12 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) /* reset error for learning of new hats */ error = -ENOENT; } - } else if (previous_profile) { + } else if (previous_label) { /* Return to saved profile. Kill task if restore fails * to avoid brute force attacks */ - target = previous_profile->base.hname; - error = aa_restore_previous_profile(token); + target = previous_label->hname; + error = aa_restore_previous_label(token); perms.kill = AA_MAY_CHANGEHAT; } else /* ignore restores when there is no saved profile */ @@ -692,8 +697,8 @@ audit: out: aa_put_profile(hat); kfree(name); - aa_put_profile(profile); - aa_put_profile(previous_profile); + aa_put_label(label); + aa_put_label(previous_label); put_cred(cred); return error; @@ -716,6 +721,7 @@ out: int aa_change_profile(const char *fqname, int flags) { const struct cred *cred; + struct aa_label *label; struct aa_profile *profile, *target = NULL; struct aa_perms perms = {}; const char *info = NULL, *op; @@ -736,7 +742,8 @@ int aa_change_profile(const char *fqname, int flags) } 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 @@ -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 * of permissions. */ - if (task_no_new_privs(current) && !unconfined(profile)) { + if (task_no_new_privs(current) && !profile_unconfined(profile)) { put_cred(cred); return -EPERM; } - target = aa_fqlookupn_profile(profile, fqname, strlen(fqname)); + target = aa_fqlookupn_profile(label, fqname, strlen(fqname)); if (!target) { info = "profile not found"; error = -ENOENT; @@ -785,9 +792,9 @@ int aa_change_profile(const char *fqname, int flags) goto audit; if (flags & AA_CHANGE_ONEXEC) - error = aa_set_current_onexec(target); + error = aa_set_current_onexec(&target->label, 0); else - error = aa_replace_current_profile(target); + error = aa_replace_current_label(&target->label); audit: if (!(flags & AA_CHANGE_TEST)) @@ -795,7 +802,7 @@ audit: fqname, GLOBAL_ROOT_UID, info, error); aa_put_profile(target); - aa_put_profile(profile); + aa_put_label(label); put_cred(cred); return error; diff --git a/security/apparmor/file.c b/security/apparmor/file.c index bf508791cc1f..5289c8db832b 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -451,7 +451,7 @@ int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file, request, &cond); } -static void revalidate_tty(struct aa_profile *profile) +static void revalidate_tty(struct aa_label *label) { struct tty_struct *tty; int drop_tty = 0; @@ -469,7 +469,7 @@ static void revalidate_tty(struct aa_profile *profile) struct tty_file_private, list); 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)) drop_tty = 1; } @@ -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) { - 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))) return fd + 1; return 0; @@ -494,14 +494,14 @@ static int match_file(const void *p, struct file *file, unsigned int fd) /* based on selinux's flush_unauthorized_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; unsigned int n; - revalidate_tty(profile); + revalidate_tty(label); /* 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? */ goto out; @@ -511,9 +511,9 @@ void aa_inherit_files(const struct cred *cred, struct files_struct *files) /* replace all the matching ones with this */ do { 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) fput(devnull); out: - aa_put_profile(profile); + aa_put_label(label); } diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 1750cc0721c1..c4a900488e76 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -4,7 +4,7 @@ * This file contains AppArmor basic global * * 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 * modify it under the terms of the GNU General Public License as @@ -27,8 +27,9 @@ #define AA_CLASS_NET 4 #define AA_CLASS_RLIMITS 5 #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 */ extern enum audit_mode aa_g_audit; diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index d548261dd1b7..20fa6c77db05 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -22,8 +22,7 @@ #include <linux/slab.h> #include "file.h" - -struct aa_profile; +#include "label.h" extern const char *const audit_mode_names[]; #define AUDIT_MAX_INDEX 5 @@ -103,9 +102,9 @@ enum audit_type { struct apparmor_audit_data { int error; - const char *op; int type; - void *profile; + const char *op; + struct aa_label *label; const char *name; const char *info; u32 request; @@ -113,7 +112,7 @@ struct apparmor_audit_data { union { /* these entries require a custom callback fn */ struct { - struct aa_profile *peer; + struct aa_label *peer; struct { const char *target; kuid_t ouid; diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index 7665fae7131f..6ae07e9aaa17 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -19,7 +19,7 @@ #include <linux/slab.h> #include <linux/sched.h> -#include "policy.h" +#include "label.h" #include "policy_ns.h" #define cred_ctx(X) ((X)->security) @@ -27,20 +27,20 @@ /** * struct aa_task_ctx - primary label for confined tasks - * @profile: the current profile (NOT NULL) - * @exec: profile to transition to on next exec (MAYBE NULL) - * @previous: profile the task may return to (MAYBE NULL) - * @token: magic value the task must know for returning to @previous_profile + * @label: the current label (NOT NULL) + * @exec: label to transition to on next exec (MAYBE NULL) + * @previous: label the task may return to (MAYBE NULL) + * @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. * * TODO: make so a task can be confined by a stack of contexts */ struct aa_task_ctx { - struct aa_profile *profile; - struct aa_profile *onexec; - struct aa_profile *previous; + struct aa_label *label; + struct aa_label *onexec; + struct aa_label *previous; u64 token; }; @@ -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_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old); -int aa_replace_current_profile(struct aa_profile *profile); -int aa_set_current_onexec(struct aa_profile *profile); -int aa_set_current_hat(struct aa_profile *profile, u64 token); -int aa_restore_previous_profile(u64 cookie); -struct aa_profile *aa_get_task_profile(struct task_struct *task); +int aa_replace_current_label(struct aa_label *label); +int aa_set_current_onexec(struct aa_label *label, bool stack); +int aa_set_current_hat(struct aa_label *label, u64 token); +int aa_restore_previous_label(u64 cookie); +struct aa_label *aa_get_task_label(struct task_struct *task); /** - * aa_cred_raw_profile - obtain cred's profiles - * @cred: cred to obtain profiles from (NOT NULL) + * aa_cred_raw_label - obtain cred's label + * @cred: cred to obtain label from (NOT NULL) * - * Returns: confining profile + * Returns: confining label * * 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); - AA_BUG(!ctx || !ctx->profile); - return ctx->profile; + AA_BUG(!ctx || !ctx->label); + return ctx->label; } /** - * aa_get_newest_cred_profile - obtain the newest profile on a cred - * @cred: cred to obtain profile from (NOT NULL) + * aa_get_newest_cred_label - obtain the newest label on a cred + * @cred: cred to obtain label from (NOT NULL) * - * Returns: newest version of confining profile + * Returns: newest version of confining label */ -static inline -struct aa_profile *aa_get_newest_cred_profile(const struct cred *cred) +static inline struct aa_label *aa_get_newest_cred_label(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) * - * 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 */ -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) */ 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 - * 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 * - * 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)) - return aa_get_newest_profile(p); - return aa_get_profile(p); + if (label_is_stale(l)) + return aa_get_newest_label(l); + return aa_get_label(l); } -#define __end_current_profile_crit_section(X) \ - end_current_profile_crit_section(X) +#define __end_current_label_crit_section(X) end_current_label_crit_section(X) /** - * end_profile_crit_section - put a reference found with begin_current_profile.. - * @profile: profile reference to put + * end_label_crit_section - put a reference found with begin_current_label.. + * @label: label reference to put * * 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 */ -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()) - aa_put_profile(profile); + if (label != aa_current_raw_label()) + 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 * - * 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 - * critical section between __begin_current_profile_crit_section() .. - * __end_current_profile_crit_section() + * critical section between __begin_current_label_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)) - profile = aa_get_newest_profile(profile); + if (label_is_stale(label)) + 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 * - * 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 - * critical section between begin_current_profile_crit_section() .. - * end_current_profile_crit_section() + * critical section between begin_current_label_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)) { - profile = aa_get_newest_profile(profile); - if (aa_replace_current_profile(profile) == 0) + if (label_is_stale(label)) { + label = aa_get_newest_label(label); + if (aa_replace_current_label(label) == 0) /* 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) { - struct aa_profile *profile; + struct aa_label *label; struct aa_ns *ns; - profile = __begin_current_profile_crit_section(); - ns = aa_get_ns(profile->ns); - __end_current_profile_crit_section(profile); + label = __begin_current_label_crit_section(); + ns = aa_get_ns(labels_ns(label)); + __end_current_label_crit_section(label); return ns; } @@ -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) { - aa_put_profile(ctx->previous); - aa_put_profile(ctx->onexec); + aa_put_label(ctx->previous); + aa_put_label(ctx->onexec); ctx->previous = NULL; ctx->onexec = NULL; ctx->token = 0; diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h index 82946fb81f91..0c5c2b00be02 100644 --- a/security/apparmor/include/perms.h +++ b/security/apparmor/include/perms.h @@ -15,6 +15,7 @@ #define __AA_PERM_H #include <linux/fs.h> +#include "label.h" #define AA_MAY_EXEC MAY_EXEC #define AA_MAY_WRITE MAY_WRITE @@ -101,5 +102,14 @@ void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms); void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, struct aa_perms *perms); - +void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend); +void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend); +void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label, + 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 */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index d93f475bfd8b..17fe41a9cac3 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -29,6 +29,7 @@ #include "domain.h" #include "file.h" #include "lib.h" +#include "label.h" #include "perms.h" #include "resource.h" @@ -48,9 +49,9 @@ extern const char *const aa_profile_mode_names[]; #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) @@ -67,22 +68,6 @@ enum profile_mode { 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 * dfa: dfa pattern match @@ -95,11 +80,6 @@ struct aa_policydb { }; -struct aa_proxy { - struct kref count; - struct aa_profile __rcu *profile; -}; - /* struct aa_data - generic data structure * key: name for retrieving this data * size: size of data in bytes @@ -116,18 +96,15 @@ struct aa_data { /* struct aa_profile - basic confinement data * @base - base components of the profile (name, refcount, lists, lock ...) - * @count: reference count of the obj - * @rcu: rcu head used when removing from @list + * @label - label this profile is an extension of * @parent: parent of profile * @ns: namespace the profile is in - * @proxy: is set to the profile that replaced this profile * @rename: optional profile name that this profile renamed * @attach: human readable attachment string * @xmatch: optional extended matching for unconfined executables names * @xmatch_len: xmatch prefix len, used to determine xmatch priority * @audit: the auditing mode of the profile * @mode: the enforcement mode of the profile - * @flags: flags controlling profile behavior * @path_flags: flags controlling path generation behavior * @disconnected: what to prepend if attach_disconnected is specified * @size: the memory consumed by this profiles rules @@ -145,8 +122,6 @@ struct aa_data { * used to determine profile attachment against unconfined tasks. All other * 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 * a reference to their parent. * @@ -156,12 +131,9 @@ struct aa_data { */ struct aa_profile { struct aa_policy base; - struct kref count; - struct rcu_head rcu; struct aa_profile __rcu *parent; struct aa_ns *ns; - struct aa_proxy *proxy; const char *rename; const char *attach; @@ -169,7 +141,6 @@ struct aa_profile { int xmatch_len; enum audit_mode audit; long mode; - long flags; u32 path_flags; const char *disconnected; int size; @@ -184,6 +155,7 @@ struct aa_profile { char *dirname; struct dentry *dents[AAFS_PROF_SIZEOF]; struct rhashtable *data; + struct aa_label label; }; 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_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_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, const char *base, gfp_t gfp); 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); struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, size_t n); 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); 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); -ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *profile, - char *name, size_t size); +ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_label *label, + char *name, size_t size); void __aa_profile_list_release(struct list_head *head); #define PROF_ADD 1 #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)]) /* safe version of POLICY_MEDIATES for full range input */ @@ -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) { if (p) - kref_get(&(p->count)); + kref_get(&(p->label.count)); return 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) { - if (p && kref_get_unless_zero(&p->count)) + if (p && kref_get_unless_zero(&p->label.count)) return p; return NULL; @@ -277,53 +264,20 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p) rcu_read_lock(); do { c = rcu_dereference(*p); - } while (c && !kref_get_unless_zero(&c->count)); + } while (c && !kref_get_unless_zero(&c->label.count)); rcu_read_unlock(); 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 * @p: profile (MAYBE NULL) */ static inline void aa_put_profile(struct aa_profile *p) { if (p) - kref_put(&p->count, aa_free_profile_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); + kref_put(&p->label.count, aa_label_kref); } 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_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); #endif /* __AA_POLICY_H */ diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 2f7e480a34e0..9605f18624e2 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -19,6 +19,7 @@ #include "apparmor.h" #include "apparmorfs.h" +#include "label.h" #include "policy.h" @@ -71,6 +72,7 @@ struct aa_ns { long revision; wait_queue_head_t wait; + struct aa_labelset labels; struct list_head rawdata_list; struct dentry *dents[AAFS_NS_SIZEOF]; @@ -80,6 +82,8 @@ extern struct aa_ns *root_ns; 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); const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child, bool subns); void aa_free_ns(struct aa_ns *ns); diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index edac790923c3..fa68cd42bd15 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -22,11 +22,12 @@ #include "include/ipc.h" /* 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; 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, { DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); - aad(&sa)->peer = target; + aad(&sa)->peer = &target->label; 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, * Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH */ - if (unconfined(tracer) || tracer == tracee) + if (profile_unconfined(tracer) || tracer == tracee) return 0; /* log this capability request */ return aa_capable(tracer, CAP_SYS_PTRACE, 1); @@ -90,18 +91,22 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, * - 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; - if (!unconfined(tracer_p)) { - struct aa_profile *tracee_p = aa_get_task_profile(tracee); + if (!unconfined(tracer_l)) { + struct aa_label *tracee_l = aa_get_task_label(tracee); - error = aa_may_ptrace(tracer_p, tracee_p, mode); - error = aa_audit_ptrace(tracer_p, tracee_p, error); + error = aa_may_ptrace(labels_profile(tracer_l), + 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; } diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 0ceecdbb4658..08ca26bcca77 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -247,6 +247,32 @@ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, } /** + * 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 * @profile: that perms where computed from * @perms: perms to apply mode modifiers to @@ -310,6 +336,143 @@ void aa_compute_perms(struct aa_dfa *dfa, unsigned int 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 * @policy: policy to initialize (NOT NULL) * @prefix: prefix name if any is required. (MAYBE NULL) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 7ba43c18687a..3ba08530c92e 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -34,6 +34,7 @@ #include "include/file.h" #include "include/ipc.h" #include "include/path.h" +#include "include/label.h" #include "include/policy.h" #include "include/policy_ns.h" #include "include/procattr.h" @@ -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) { @@ -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, kernel_cap_t *inheritable, kernel_cap_t *permitted) { + struct aa_label *label; struct aa_profile *profile; const struct cred *cred; rcu_read_lock(); 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 * initialize effective and permitted. */ - if (!unconfined(profile) && !COMPLAIN_MODE(profile)) { + if (!profile_unconfined(profile) && !COMPLAIN_MODE(profile)) { *effective = cap_intersect(*effective, profile->caps.allow); *permitted = cap_intersect(*permitted, profile->caps.allow); } rcu_read_unlock(); - aa_put_profile(profile); + aa_put_label(label); return 0; } @@ -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, int cap, int audit) { - struct aa_profile *profile; + struct aa_label *label; int error = 0; - profile = aa_get_newest_cred_profile(cred); - if (!unconfined(profile)) - error = aa_capable(profile, cap, audit); - aa_put_profile(profile); + label = aa_get_newest_cred_label(cred); + if (!unconfined(label)) + error = aa_capable(labels_profile(label), cap, audit); + aa_put_label(label); return error; } @@ -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, struct path_cond *cond) { - struct aa_profile *profile; + struct aa_label *label; int error = 0; - profile = __begin_current_profile_crit_section(); - if (!unconfined(profile)) - error = aa_path_perm(op, profile, path, 0, mask, cond); - __end_current_profile_crit_section(profile); + label = __begin_current_label_crit_section(); + if (!unconfined(label)) + error = aa_path_perm(op, labels_profile(label), path, 0, mask, + cond); + __end_current_label_crit_section(label); return error; } @@ -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, struct dentry *new_dentry) { - struct aa_profile *profile; + struct aa_label *label; int error = 0; if (!path_mediated_fs(old_dentry)) return 0; - profile = begin_current_profile_crit_section(); - if (!unconfined(profile)) - error = aa_path_link(profile, old_dentry, new_dir, new_dentry); - end_current_profile_crit_section(profile); + label = begin_current_label_crit_section(); + if (!unconfined(label)) + error = aa_path_link(labels_profile(label), old_dentry, new_dir, + new_dentry); + end_current_label_crit_section(label); return error; } @@ -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, const struct path *new_dir, struct dentry *new_dentry) { - struct aa_profile *profile; + struct aa_label *label; int error = 0; if (!path_mediated_fs(old_dentry)) return 0; - profile = begin_current_profile_crit_section(); - if (!unconfined(profile)) { + label = begin_current_label_crit_section(); + if (!unconfined(label)) { struct path old_path = { .mnt = old_dir->mnt, .dentry = old_dentry }; 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 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 | AA_MAY_SETATTR | AA_MAY_DELETE, &cond); 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 | AA_MAY_CREATE, &cond); } - end_current_profile_crit_section(profile); + end_current_label_crit_section(label); return error; } @@ -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) { - struct aa_file_ctx *fctx = file->f_security; - struct aa_profile *profile; + struct aa_file_ctx *fctx = file_ctx(file); + struct aa_label *label; int error = 0; if (!path_mediated_fs(file->f_path.dentry)) @@ -377,17 +384,18 @@ static int apparmor_file_open(struct file *file, const struct cred *cred) return 0; } - profile = aa_get_newest_cred_profile(cred); - if (!unconfined(profile)) { + label = aa_get_newest_cred_label(cred); + if (!unconfined(label)) { struct inode *inode = file_inode(file); 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); /* todo cache full allowed permissions set and state */ fctx->allow = aa_map_file_to_perms(file); } - aa_put_profile(profile); + aa_put_label(label); return error; } @@ -397,11 +405,11 @@ static int apparmor_file_alloc_security(struct file *file) int error = 0; /* 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); if (!file_ctx(file)) error = -ENOMEM; - end_current_profile_crit_section(profile); + end_current_label_crit_section(label); return error; } @@ -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) { struct aa_file_ctx *fctx = file->f_security; - struct aa_profile *profile, *fprofile; + struct aa_label *label, *flabel; int error = 0; /* don't reaudit files closed during inheritance */ if (file->f_path.dentry == aa_null.dentry) return -EACCES; - fprofile = aa_cred_raw_profile(file->f_cred); - AA_BUG(!fprofile); + flabel = aa_cred_raw_label(file->f_cred); + AA_BUG(!flabel); if (!file->f_path.mnt || !path_mediated_fs(file->f_path.dentry)) return 0; - profile = __begin_current_profile_crit_section(); + label = __begin_current_label_crit_section(); /* revalidate access, if task is unconfined, or the cached cred * 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) * Note: the test for !unconfined(fprofile) is to handle file * delegation from unconfined tasks */ - if (!unconfined(profile) && !unconfined(fprofile) && - ((fprofile != profile) || (mask & ~fctx->allow))) - error = aa_file_perm(op, profile, file, mask); - __end_current_profile_crit_section(profile); + if (!unconfined(label) && !unconfined(flabel) && + ((flabel != label) || (mask & ~fctx->allow))) + error = aa_file_perm(op, labels_profile(label), file, mask); + __end_current_label_crit_section(label); return error; } @@ -465,7 +473,7 @@ static int common_mmap(const char *op, struct file *file, unsigned long prot, { int mask = 0; - if (!file || !file->f_security) + if (!file || !file_ctx(file)) return 0; if (prot & PROT_READ) @@ -502,21 +510,21 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, /* released below */ const struct cred *cred = get_task_cred(task); struct aa_task_ctx *ctx = cred_ctx(cred); - struct aa_profile *profile = NULL; + struct aa_label *label = NULL; 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) - profile = aa_get_newest_profile(ctx->previous); + label = aa_get_newest_label(ctx->previous); else if (strcmp(name, "exec") == 0 && ctx->onexec) - profile = aa_get_newest_profile(ctx->onexec); + label = aa_get_newest_label(ctx->onexec); else error = -EINVAL; - if (profile) - error = aa_getprocattr(profile, value); + if (label) + error = aa_getprocattr(labels_profile(label), value); - aa_put_profile(profile); + aa_put_label(label); put_cred(cred); return error; @@ -582,11 +590,11 @@ out: return error; fail: - aad(&sa)->profile = begin_current_profile_crit_section(); + aad(&sa)->label = begin_current_label_crit_section(); aad(&sa)->info = name; aad(&sa)->error = error = -EINVAL; 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; } @@ -596,20 +604,21 @@ fail: */ 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); /* bail out if unconfined or not changing profile */ - if ((new_ctx->profile == profile) || - (unconfined(new_ctx->profile))) + if ((new_ctx->label->proxy == label->proxy) || + (unconfined(new_ctx->label))) return; aa_inherit_files(bprm->cred, current->files); current->pdeath_signal = 0; - /* reset soft limits and set hard limits for the new profile */ - __aa_transition_rlimits(profile, new_ctx->profile); + /* reset soft limits and set hard limits for the new label */ + __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) static int apparmor_task_setrlimit(struct task_struct *task, 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; - if (!unconfined(profile)) - error = aa_task_setrlimit(profile, task, resource, new_rlim); - __end_current_profile_crit_section(profile); + if (!unconfined(label)) + error = aa_task_setrlimit(labels_profile(label), task, + resource, new_rlim); + __end_current_label_crit_section(label); return error; } @@ -924,7 +934,7 @@ static int __init set_init_ctx(void) if (!ctx) return -ENOMEM; - ctx->profile = aa_get_profile(root_ns->unconfined); + ctx->label = aa_get_label(ns_unconfined(root_ns)); cred_ctx(cred) = ctx; return 0; diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 605cb5949c60..244ea4a4a8f0 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -101,20 +101,9 @@ const char *const aa_profile_mode_names[] = { "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) * @profile: the profile to add (NOT NULL) * @@ -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 */ -static void __list_add_profile(struct list_head *list, - struct aa_profile *profile) +static void __add_profile(struct list_head *list, 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); /* get list reference */ 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, */ 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); aa_put_profile(profile); } @@ -156,10 +158,14 @@ static void __list_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 */ __aa_profile_list_release(&profile->base.profiles); /* released by free_profile */ - __aa_update_proxy(profile, profile->ns->unconfined); + aa_label_remove(&profile->label); __aafs_profile_rmdir(profile); __list_remove_profile(profile); } @@ -177,24 +183,6 @@ void __aa_profile_list_release(struct list_head *head) __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 * @ptr: data to free @@ -242,7 +230,6 @@ void aa_free_profile(struct aa_profile *profile) kzfree(profile->dirname); aa_put_dfa(profile->xmatch); aa_put_dfa(profile->policy.dfa); - aa_put_proxy(profile->proxy); if (profile->data) { rht = profile->data; @@ -253,30 +240,8 @@ void aa_free_profile(struct aa_profile *profile) kzfree(profile->hash); aa_put_loaddata(profile->rawdata); - 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); + kzfree(profile); } /** @@ -286,30 +251,40 @@ void aa_free_profile_kref(struct kref *kref) * * 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; /* 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) 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)) 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 */ return profile; fail: - kzfree(profile->proxy); - kzfree(profile); + aa_free_profile(profile); return NULL; } @@ -362,14 +337,14 @@ name: if (profile) goto out; - profile = aa_alloc_profile(name, gfp); + profile = aa_alloc_profile(name, NULL, gfp); if (!profile) goto fail; profile->mode = APPARMOR_COMPLAIN; - profile->flags |= PFLAG_NULL; + profile->label.flags |= FLAG_NULL; if (hat) - profile->flags |= PFLAG_HAT; + profile->label.flags |= FLAG_HAT; profile->path_flags = parent->path_flags; /* released on free_profile */ @@ -379,7 +354,7 @@ name: profile->policy.dfa = aa_get_dfa(nulldfa); mutex_lock(&profile->ns->lock); - __list_add_profile(&parent->base.profiles, profile); + __add_profile(&parent->base.profiles, profile); mutex_unlock(&profile->ns->lock); /* refcount released by caller */ @@ -389,7 +364,6 @@ out: return profile; fail: - kfree(name); aa_free_profile(profile); return NULL; } @@ -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)); } -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) { struct aa_profile *profile; @@ -566,11 +540,11 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, name = aa_splitn_fqname(fqname, n, &ns_name, &ns_len); 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) return NULL; } else - ns = aa_get_ns(base->ns); + ns = aa_get_ns(labels_ns(base)); if (name) profile = aa_lookupn_profile(ns, name, n - (name - fqname)); @@ -596,7 +570,7 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace, const char **info) { if (profile) { - if (profile->flags & PFLAG_IMMUTABLE) { + if (profile->label.flags & FLAG_IMMUTIBLE) { *info = "cannot replace immutible profile"; return -EPERM; } else if (noreplace) { @@ -619,29 +593,31 @@ static void audit_cb(struct audit_buffer *ab, void *va) } /** - * aa_audit_policy - Do auditing of policy changes - * @profile: profile to check if it can manage policy + * audit_policy - Do auditing of policy changes + * @label: label to check if it can manage policy * @op: policy operation being performed - * @gfp: memory allocation flags - * @nsname: name of the ns being manipulated (MAY BE NULL) + * @ns_name: name of namespace being manipulated * @name: name of profile being manipulated (NOT NULL) * @info: any extra information to be audited (MAYBE NULL) * @error: error code * * Returns: the error to be returned after audit is done */ -static int audit_policy(struct aa_profile *profile, const char *op, - const char *nsname, const char *name, +static int audit_policy(struct aa_label *label, const char *op, + const char *ns_name, const char *name, const char *info, int error) { 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)->info = info; 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) /** * 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 * * 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; @@ -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 */ if (aa_g_lock_policy) - return audit_policy(profile, op, NULL, NULL, "policy_locked", + return audit_policy(label, op, NULL, NULL, "policy_locked", -EACCES); 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); /* TODO: add fine grained mediation of policy loads */ @@ -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 */ -static void __replace_profile(struct aa_profile *old, struct aa_profile *new, - bool share_proxy) +static void __replace_profile(struct aa_profile *old, struct aa_profile *new) { struct aa_profile *child, *tmp; @@ -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); if (p) { /* @p replaces @child */ - __replace_profile(child, p, share_proxy); + __replace_profile(child, p); continue; } @@ -784,14 +759,8 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new, struct aa_profile *parent = aa_deref_parent(old); rcu_assign_pointer(new->parent, aa_get_profile(parent)); } - __aa_update_proxy(old, new); - if (share_proxy) { - 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)); + aa_label_replace(&old->label, &new->label); + /* migrate dents must come after label replacement b/c update */ __aafs_profile_migrate_dents(old, new); if (list_empty(&new->base.list)) { @@ -835,6 +804,7 @@ static void share_name(struct aa_profile *old, struct aa_profile *new) aa_get_str(old->base.hname); new->base.hname = old->base.hname; new->base.name = old->base.name; + new->label.hname = old->label.hname; } /* 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) * * 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) { const char *ns_name, *info = NULL; @@ -914,7 +884,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, count++; } 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); if (IS_ERR(ns)) { op = OP_PROF_LOAD; @@ -925,7 +895,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, goto fail; } } 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); /* 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, if (ent->new->rename) { error = __lookup_replace(ns, ent->new->rename, - !(mask & AA_MAY_REPLACE_POLICY), - &ent->rename, &info); + !(mask & AA_MAY_REPLACE_POLICY), + &ent->rename, &info); if (error) goto fail_lock; } @@ -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) { /* 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", error); goto skip; @@ -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 * can differ but profile may remain unchanged */ - audit_policy(profile, op, NULL, ent->new->base.hname, - NULL, error); + audit_policy(label, op, ns_name, ent->new->base.hname, NULL, + error); if (ent->old) { share_name(ent->old, ent->new); - __replace_profile(ent->old, ent->new, 1); + __replace_profile(ent->old, ent->new); } else { struct list_head *lh; @@ -1047,11 +1017,12 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile, lh = &parent->base.profiles; } else lh = &ns->base.profiles; - __list_add_profile(lh, ent->new); + __add_profile(lh, ent->new); } skip: aa_load_ent_free(ent); } + __aa_labelset_update_subtree(ns); mutex_unlock(&ns->lock); out: @@ -1068,8 +1039,8 @@ fail_lock: /* audit cause of failure */ op = (ent && !ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; fail: - audit_policy(profile, op, ns_name, ent ? ent->new->base.hname : NULL, - info, error); + audit_policy(label, op, ns_name, ent ? ent->new->base.hname : NULL, + info, error); /* audit status that rest of profiles in the atomic set failed too */ info = "valid profile in failed atomic policy load"; list_for_each_entry(tmp, &lh, list) { @@ -1079,8 +1050,8 @@ fail: continue; } op = (!tmp->old) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(profile, op, ns_name, - tmp->new->base.hname, info, error); + audit_policy(label, op, ns_name, tmp->new->base.hname, info, + error); } list_for_each_entry_safe(ent, tmp, &lh, list) { list_del_init(&ent->list); @@ -1093,7 +1064,7 @@ fail: /** * aa_remove_profiles - remove profile(s) from the system * @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) * @size: size of the name * @@ -1104,7 +1075,7 @@ fail: * * 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) { struct aa_ns *ns = NULL; @@ -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); /* released below */ - ns = aa_lookupn_ns(policy_ns ? policy_ns : subj->ns, ns_name, - ns_len); + ns = aa_lookupn_ns(policy_ns ? policy_ns : labels_ns(subj), + ns_name, ns_len); if (!ns) { info = "namespace does not exist"; error = -ENOENT; @@ -1133,7 +1104,7 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_profile *subj, } } else /* 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) { /* 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, } name = profile->base.hname; __remove_profile(profile); + __aa_labelset_update_subtree(ns); __aa_bump_ns_revision(ns); mutex_unlock(&ns->lock); } diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index c05316809a5e..351d3bab3a3d 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -23,6 +23,7 @@ #include "include/apparmor.h" #include "include/context.h" #include "include/policy_ns.h" +#include "include/label.h" #include "include/policy.h" /* root profile namespace */ @@ -104,12 +105,12 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name) init_waitqueue_head(&ns->wait); /* 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) goto fail_unconfined; - ns->unconfined->flags = PFLAG_IX_ON_NAME_ERROR | - PFLAG_IMMUTABLE | PFLAG_NS_COUNT; + ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR | + FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED; ns->unconfined->mode = APPARMOR_UNCONFINED; /* ns and ns->unconfined share ns->unconfined refcount */ @@ -117,6 +118,8 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name) atomic_set(&ns->uniq_null, 0); + aa_labelset_init(&ns->labels); + return ns; fail_unconfined: @@ -139,6 +142,7 @@ void aa_free_ns(struct aa_ns *ns) return; aa_policy_destroy(&ns->base); + aa_labelset_destroy(&ns->labels); aa_put_ns(ns->parent); ns->unconfined->ns = NULL; @@ -337,8 +341,14 @@ static void destroy_ns(struct aa_ns *ns) /* release all sub namespaces */ __ns_list_release(&ns->sub_ns); - if (ns->parent) - __aa_update_proxy(ns->unconfined, ns->parent->unconfined); + if (ns->parent) { + 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); mutex_unlock(&ns->lock); } diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index cac69f2cb86d..f42bb9575cb5 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -26,6 +26,7 @@ #include "include/context.h" #include "include/crypto.h" #include "include/match.h" +#include "include/path.h" #include "include/policy.h" #include "include/policy_unpack.h" @@ -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, 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); if (e) 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) name = tmpname; } - profile = aa_alloc_profile(name, GFP_KERNEL); + profile = aa_alloc_profile(name, NULL, GFP_KERNEL); if (!profile) return ERR_PTR(-ENOMEM); @@ -635,7 +636,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) if (!unpack_u32(e, &tmp, NULL)) goto fail; if (tmp & PACKED_FLAG_HAT) - profile->flags |= PFLAG_HAT; + profile->label.flags |= FLAG_HAT; if (!unpack_u32(e, &tmp, NULL)) goto fail; 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) /* path_flags is optional */ 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 /* 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)) goto fail; diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index 2f0cb424927a..dce970d1f46b 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -55,7 +55,7 @@ int aa_getprocattr(struct aa_profile *profile, char **string) ns_len += 4; /* unconfined profiles don't have a mode string appended */ - if (!unconfined(profile)) + if (!profile_unconfined(profile)) mode_len = strlen(mode_str) + 3; /* + 3 for _() */ name_len = strlen(profile->base.hname); @@ -69,7 +69,7 @@ int aa_getprocattr(struct aa_profile *profile, char **string) sprintf(s, ":%s://", ns_name); s += ns_len; } - if (unconfined(profile)) + if (profile_unconfined(profile)) /* mode string not being appended */ sprintf(s, "%s\n", profile->base.hname); else diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index b26f1dac5106..ab8e104c1970 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -86,11 +86,11 @@ int aa_map_resource(int resource) int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task, unsigned int resource, struct rlimit *new_rlim) { - struct aa_profile *task_profile; + struct aa_label *task_label; int error = 0; 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(); /* 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, * the same profile or that the task setting the resource of another * task has CAP_SYS_RESOURCE. */ - if ((profile != task_profile && + if ((profile != labels_profile(task_label) && aa_capable(profile, CAP_SYS_RESOURCE, 1)) || (profile->rlimits.mask & (1 << resource) && new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)) error = -EACCES; - aa_put_profile(task_profile); + aa_put_label(task_label); return audit_resource(profile, resource, new_rlim->rlim_max, error); } |