apparmor: switch from profiles to using labels on contexts
authorJohn Johansen <john.johansen@canonical.com>
Fri, 9 Jun 2017 15:14:28 +0000 (08:14 -0700)
committerJohn Johansen <john.johansen@canonical.com>
Sun, 11 Jun 2017 00:11:38 +0000 (17:11 -0700)
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>
20 files changed:
security/apparmor/Makefile
security/apparmor/apparmorfs.c
security/apparmor/audit.c
security/apparmor/context.c
security/apparmor/domain.c
security/apparmor/file.c
security/apparmor/include/apparmor.h
security/apparmor/include/audit.h
security/apparmor/include/context.h
security/apparmor/include/perms.h
security/apparmor/include/policy.h
security/apparmor/include/policy_ns.h
security/apparmor/ipc.c
security/apparmor/lib.c
security/apparmor/lsm.c
security/apparmor/policy.c
security/apparmor/policy_ns.c
security/apparmor/policy_unpack.c
security/apparmor/procattr.c
security/apparmor/resource.c

index b3e7c04b7e7bcf7749da32bfd6f337d95708c3bf..a16b195274dec2c48d3ee41e3cdad1b6460138c1 100644 (file)
@@ -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
index e2919a0766b00af91aca3aa287db9176a075701f..976af6da45c330ca26d82d7cd975dc243544e3f3 100644 (file)
@@ -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;
 }
index 87f40fa8c431c93fb63b61025d263fa9e11b86fd..8f9ecac7f8dea26f2621ba63bcb05dd781af3584 100644 (file)
@@ -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);
 
index 410b9f7f68a1dfb151e4797d64f25238310b8240..c95f1ac6190b4bf2c8fb42c739da67965f85ad41 100644 (file)
@@ -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);
 
index 2ec4ae029215e12cb1e64ddfa9cfc1519e282059..8d6797c849feeeb80e57b4141e3c3003f1136e5f 100644 (file)
@@ -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;
index bf508791cc1f13eb05c00a885b012c6cc3b84cf2..5289c8db832bcfeda912032f581337c7bfd18696 100644 (file)
@@ -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);
 }
index 1750cc0721c17d5f5a3fb0e7912a825dad9ee7b1..c4a900488e765442ea0412b40a00753d5e20b90a 100644 (file)
@@ -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;
index d548261dd1b759a7ed95bde3ec8dadb9794b9150..20fa6c77db0590b42e355b25aebced606489a2fe 100644 (file)
@@ -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;
index 7665fae7131f238fe398db2156b41c9f6540ae64..6ae07e9aaa172dac7cd8820af0b9817afdf73f8a 100644 (file)
@@ -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)
 
 /**
  * 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;
index 82946fb81f91520690345277b075d6ba2d592340..0c5c2b00be02689f23f7a101c187e27dd1a1bc2d 100644 (file)
@@ -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 */
index d93f475bfd8ba5f31ade5b8749a726beff739200..17fe41a9cac35e6d88f3ae738bf2b068de736ec1 100644 (file)
@@ -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,31 +264,12 @@ 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)
@@ -309,21 +277,7 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
 static inline void aa_put_profile(struct aa_profile *p)
 {
        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 */
index 2f7e480a34e05d55c5e763ee9e7237d4b784294c..9605f18624e248fca0502ef465b9f083fd237566 100644 (file)
@@ -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);
index edac790923c32aac77cb866a54e8d68e547e976c..fa68cd42bd15d1ce3a1e6c071154ebbd294fbbc2 100644 (file)
 #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;
 }
index 0ceecdbb4658b35ea476bf84620fc1505ac23ec6..08ca26bcca7703c7f74e1531879eea4dd3bf2ac9 100644 (file)
@@ -246,6 +246,32 @@ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
        audit_log_format(ab, "\"");
 }
 
+/**
+ * aa_audit_perms_cb - generic callback fn for auditing perms
+ * @ab: audit buffer (NOT NULL)
+ * @va: audit struct to audit values of (NOT NULL)
+ */
+static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
+{
+       struct common_audit_data *sa = va;
+
+       if (aad(sa)->request) {
+               audit_log_format(ab, " requested_mask=");
+               aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
+                                  PERMS_CHRS_MASK, aa_file_perm_names,
+                                  PERMS_NAMES_MASK);
+       }
+       if (aad(sa)->denied) {
+               audit_log_format(ab, "denied_mask=");
+               aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
+                                  PERMS_CHRS_MASK, aa_file_perm_names,
+                                  PERMS_NAMES_MASK);
+       }
+       audit_log_format(ab, " peer=");
+       aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+                                     FLAGS_NONE, GFP_ATOMIC);
+}
+
 /**
  * aa_apply_modes_to_perms - apply namespace and profile flags to perms
  * @profile: that perms where computed from
@@ -309,6 +335,143 @@ void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
 //     perms->xindex = dfa_user_xindex(dfa, state);
 }
 
+/**
+ * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms
+ * @accum - perms struct to accumulate into
+ * @addend - perms struct to add to @accum
+ */
+void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
+{
+       accum->deny |= addend->deny;
+       accum->allow &= addend->allow & ~addend->deny;
+       accum->audit |= addend->audit & addend->allow;
+       accum->quiet &= addend->quiet & ~addend->allow;
+       accum->kill |= addend->kill & ~addend->allow;
+       accum->stop |= addend->stop & ~addend->allow;
+       accum->complain |= addend->complain & ~addend->allow & ~addend->deny;
+       accum->cond |= addend->cond & ~addend->allow & ~addend->deny;
+       accum->hide &= addend->hide & ~addend->allow;
+       accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny;
+}
+
+/**
+ * aa_perms_accum - accumulate perms, masking off overlapping perms
+ * @accum - perms struct to accumulate into
+ * @addend - perms struct to add to @accum
+ */
+void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
+{
+       accum->deny |= addend->deny;
+       accum->allow &= addend->allow & ~accum->deny;
+       accum->audit |= addend->audit & accum->allow;
+       accum->quiet &= addend->quiet & ~accum->allow;
+       accum->kill |= addend->kill & ~accum->allow;
+       accum->stop |= addend->stop & ~accum->allow;
+       accum->complain |= addend->complain & ~accum->allow & ~accum->deny;
+       accum->cond |= addend->cond & ~accum->allow & ~accum->deny;
+       accum->hide &= addend->hide & ~accum->allow;
+       accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny;
+}
+
+void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
+                           int type, u32 request, struct aa_perms *perms)
+{
+       /* TODO: doesn't yet handle extended types */
+       unsigned int state;
+
+       state = aa_dfa_next(profile->policy.dfa,
+                           profile->policy.start[AA_CLASS_LABEL],
+                           type);
+       aa_label_match(profile, label, state, false, request, perms);
+}
+
+
+/* currently unused */
+int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
+                         u32 request, int type, u32 *deny,
+                         struct common_audit_data *sa)
+{
+       struct aa_perms perms;
+
+       aad(sa)->label = &profile->label;
+       aad(sa)->peer = &target->label;
+       aad(sa)->request = request;
+
+       aa_profile_match_label(profile, &target->label, type, request, &perms);
+       aa_apply_modes_to_perms(profile, &perms);
+       *deny |= request & perms.deny;
+       return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
+}
+
+/**
+ * aa_check_perms - do audit mode selection based on perms set
+ * @profile: profile being checked
+ * @perms: perms computed for the request
+ * @request: requested perms
+ * @deny: Returns: explicit deny set
+ * @sa: initialized audit structure (MAY BE NULL if not auditing)
+ * @cb: callback fn for tpye specific fields (MAY BE NULL)
+ *
+ * Returns: 0 if permission else error code
+ *
+ * Note: profile audit modes need to be set before calling by setting the
+ *       perm masks appropriately.
+ *
+ *       If not auditing then complain mode is not enabled and the
+ *       error code will indicate whether there was an explicit deny
+ *      with a positive value.
+ */
+int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
+                  u32 request, struct common_audit_data *sa,
+                  void (*cb)(struct audit_buffer *, void *))
+{
+       int type, error;
+       bool stop = false;
+       u32 denied = request & (~perms->allow | perms->deny);
+
+       if (likely(!denied)) {
+               /* mask off perms that are not being force audited */
+               request &= perms->audit;
+               if (!request || !sa)
+                       return 0;
+
+               type = AUDIT_APPARMOR_AUDIT;
+               error = 0;
+       } else {
+               error = -EACCES;
+
+               if (denied & perms->kill)
+                       type = AUDIT_APPARMOR_KILL;
+               else if (denied == (denied & perms->complain))
+                       type = AUDIT_APPARMOR_ALLOWED;
+               else
+                       type = AUDIT_APPARMOR_DENIED;
+
+               if (denied & perms->stop)
+                       stop = true;
+               if (denied == (denied & perms->hide))
+                       error = -ENOENT;
+
+               denied &= ~perms->quiet;
+               if (!sa || !denied)
+                       return error;
+       }
+
+       if (sa) {
+               aad(sa)->label = &profile->label;
+               aad(sa)->request = request;
+               aad(sa)->denied = denied;
+               aad(sa)->error = error;
+               aa_audit_msg(type, sa, cb);
+       }
+
+       if (type == AUDIT_APPARMOR_ALLOWED)
+               error = 0;
+
+       return error;
+}
+
+
 /**
  * aa_policy_init - initialize a policy structure
  * @policy: policy to initialize  (NOT NULL)
index 7ba43c18687ad003f8677b13344c6db31fb6386a..3ba08530c92e66e4fb1d3a806ed511b82d2f0eef 100644 (file)
@@ -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;
index 605cb5949c600fd9f3db2abcf7e76388dc5e9ceb..244ea4a4a8f0f73fdfacccd8c49cd55e1f7c695e 100644 (file)
@@ -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);
        }
index c05316809a5ea537b82381f64e294e77b302a50b..351d3bab3a3d2565aa970fe7011453c8fb721ea4 100644 (file)
@@ -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);
 }
index cac69f2cb86d3a37c729e9a6302a4b2df3125abd..f42bb9575cb5381aef344547419ce8c7c2872f20 100644 (file)
@@ -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;
index 2f0cb424927a098c92f37991a62bef85a95f8808..dce970d1f46b19806dcdce1d548657af9f1d717f 100644 (file)
@@ -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
index b26f1dac5106a5f9f03fbd5d0e049013943b62c1..ab8e104c1970a964e63093a32d0c735d84097e88 100644 (file)
@@ -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);
 }