Merge tag 'apparmor-pr-2021-11-10' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Nov 2021 22:47:32 +0000 (14:47 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Nov 2021 22:47:32 +0000 (14:47 -0800)
Pull apparmor updates from John Johansen:
 "Features
   - use per file locks for transactional queries
   - update policy management capability checks to work with LSM stacking

  Bug Fixes:
   - check/put label on apparmor_sk_clone_security()
   - fix error check on update of label hname
   - fix introspection of of task mode for unconfined tasks

  Cleanups:
   - avoid -Wempty-body warning
   - remove duplicated 'Returns:' comments
   - fix doc warning
   - remove unneeded one-line hook wrappers
   - use struct_size() helper in kzalloc()
   - fix zero-length compiler warning in AA_BUG()
   - file.h: delete duplicated word
   - delete repeated words in comments
   - remove repeated declaration"

* tag 'apparmor-pr-2021-11-10' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor:
  apparmor: remove duplicated 'Returns:' comments
  apparmor: remove unneeded one-line hook wrappers
  apparmor: Use struct_size() helper in kzalloc()
  apparmor: fix zero-length compiler warning in AA_BUG()
  apparmor: use per file locks for transactional queries
  apparmor: fix doc warning
  apparmor: Remove the repeated declaration
  apparmor: avoid -Wempty-body warning
  apparmor: Fix internal policy capable check for policy management
  apparmor: fix error check
  security: apparmor: delete repeated words in comments
  security: apparmor: file.h: delete duplicated word
  apparmor: switch to apparmor to internal capable check for policy management
  apparmor: update policy capable checks to use a label
  apparmor: fix introspection of of task mode for unconfined tasks
  apparmor: check/put label on apparmor_sk_clone_security()

1  2 
security/apparmor/apparmorfs.c
security/apparmor/include/file.h
security/apparmor/include/label.h
security/apparmor/label.c
security/apparmor/lsm.c
security/apparmor/policy.c
security/apparmor/policy_unpack.c

@@@ -422,7 -422,7 +422,7 @@@ static ssize_t policy_update(u32 mask, 
         */
        error = aa_may_manage_policy(label, ns, mask);
        if (error)
 -              return error;
 +              goto end_section;
  
        data = aa_simple_write_to_buffer(buf, size, size, pos);
        error = PTR_ERR(data);
                error = aa_replace_profiles(ns, label, mask, data);
                aa_put_loaddata(data);
        }
 +end_section:
        end_current_label_crit_section(label);
  
        return error;
@@@ -812,8 -811,6 +812,6 @@@ struct multi_transaction 
  };
  
  #define MULTI_TRANSACTION_LIMIT (PAGE_SIZE - sizeof(struct multi_transaction))
- /* TODO: replace with per file lock */
- static DEFINE_SPINLOCK(multi_transaction_lock);
  
  static void multi_transaction_kref(struct kref *kref)
  {
@@@ -847,10 -844,10 +845,10 @@@ static void multi_transaction_set(struc
        AA_BUG(n > MULTI_TRANSACTION_LIMIT);
  
        new->size = n;
-       spin_lock(&multi_transaction_lock);
+       spin_lock(&file->f_lock);
        old = (struct multi_transaction *) file->private_data;
        file->private_data = new;
-       spin_unlock(&multi_transaction_lock);
+       spin_unlock(&file->f_lock);
        put_multi_transaction(old);
  }
  
@@@ -879,9 -876,10 +877,10 @@@ static ssize_t multi_transaction_read(s
        struct multi_transaction *t;
        ssize_t ret;
  
-       spin_lock(&multi_transaction_lock);
+       spin_lock(&file->f_lock);
        t = get_multi_transaction(file->private_data);
-       spin_unlock(&multi_transaction_lock);
+       spin_unlock(&file->f_lock);
        if (!t)
                return 0;
  
@@@ -1358,7 -1356,7 +1357,7 @@@ static int rawdata_open(struct inode *i
        struct aa_loaddata *loaddata;
        struct rawdata_f_data *private;
  
-       if (!policy_view_capable(NULL))
+       if (!aa_current_policy_view_capable(NULL))
                return -EACCES;
  
        loaddata = __aa_get_loaddata(inode->i_private);
@@@ -1773,8 -1771,7 +1772,8 @@@ fail2
        return error;
  }
  
 -static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode)
 +static int ns_mkdir_op(struct user_namespace *mnt_userns, struct inode *dir,
 +                     struct dentry *dentry, umode_t mode)
  {
        struct aa_ns *ns, *parent;
        /* TODO: improve permission check */
@@@ -2047,6 -2044,9 +2046,6 @@@ fail2
        return error;
  }
  
 -
 -#define list_entry_is_head(pos, head, member) (&pos->member == (head))
 -
  /**
   * __next_ns - find the next namespace to list
   * @root: root namespace to stop search at (NOT NULL)
@@@ -2114,7 -2114,7 +2113,7 @@@ static struct aa_profile *__first_profi
  
  /**
   * __next_profile - step to the next profile in a profile tree
-  * @profile: current profile in tree (NOT NULL)
+  * @p: current profile in tree (NOT NULL)
   *
   * Perform a depth first traversal on the profile tree in a namespace
   *
@@@ -2265,7 -2265,7 +2264,7 @@@ static const struct seq_operations aa_s
  
  static int profiles_open(struct inode *inode, struct file *file)
  {
-       if (!policy_view_capable(NULL))
+       if (!aa_current_policy_view_capable(NULL))
                return -EACCES;
  
        return seq_open(file, &aa_sfs_profiles_op);
@@@ -2542,18 -2542,16 +2541,18 @@@ static const char *policy_get_link(stru
  {
        struct aa_ns *ns;
        struct path path;
 +      int error;
  
        if (!dentry)
                return ERR_PTR(-ECHILD);
 +
        ns = aa_get_current_ns();
        path.mnt = mntget(aafs_mnt);
        path.dentry = dget(ns_dir(ns));
 -      nd_jump_link(&path);
 +      error = nd_jump_link(&path);
        aa_put_ns(ns);
  
 -      return NULL;
 +      return ERR_PTR(error);
  }
  
  static int policy_readlink(struct dentry *dentry, char __user *buffer,
@@@ -72,7 -72,7 +72,7 @@@ static inline void aa_free_file_ctx(str
  {
        if (ctx) {
                aa_put_label(rcu_access_pointer(ctx->label));
 -              kzfree(ctx);
 +              kfree_sensitive(ctx);
        }
  }
  
@@@ -167,7 -167,7 +167,7 @@@ int aa_audit_file(struct aa_profile *pr
   * @perms: permission table indexed by the matched state accept entry of @dfa
   * @trans: transition table for indexed by named x transitions
   *
-  * File permission are determined by matching a path against @dfa and then
+  * File permission are determined by matching a path against @dfa and
   * then using the value of the accept entry for the matching state as
   * an index into @perms.  If a named exec transition is required it is
   * looked up in the transition table.
@@@ -77,10 -77,6 +77,6 @@@ struct aa_labelset 
  #define __labelset_for_each(LS, N) \
        for ((N) = rb_first(&(LS)->root); (N); (N) = rb_next(N))
  
- void aa_labelset_destroy(struct aa_labelset *ls);
- void aa_labelset_init(struct aa_labelset *ls);
  enum label_flags {
        FLAG_HAT = 1,                   /* profile is a hat */
        FLAG_UNCONFINED = 2,            /* label unconfined only if all */
@@@ -148,6 -144,7 +144,7 @@@ do {                                                       
  #define __label_make_stale(X) ((X)->flags |= FLAG_STALE)
  #define labels_ns(X) (vec_ns(&((X)->vec[0]), (X)->size))
  #define labels_set(X) (&labels_ns(X)->labels)
+ #define labels_view(X) labels_ns(X)
  #define labels_profile(X) ((X)->vec[(X)->size - 1])
  
  
@@@ -275,7 -272,6 +272,7 @@@ void aa_labelset_destroy(struct aa_labe
  void aa_labelset_init(struct aa_labelset *ls);
  void __aa_labelset_update_subtree(struct aa_ns *ns);
  
 +void aa_label_destroy(struct aa_label *label);
  void aa_label_free(struct aa_label *label);
  void aa_label_kref(struct kref *kref);
  bool aa_label_init(struct aa_label *label, int size, gfp_t gfp);
@@@ -309,7 -309,7 +309,7 @@@ out
  }
  
  
 -static void label_destroy(struct aa_label *label)
 +void aa_label_destroy(struct aa_label *label)
  {
        AA_BUG(!label);
  
                }
        }
  
 -      if (rcu_dereference_protected(label->proxy->label, true) == label)
 -              rcu_assign_pointer(label->proxy->label, NULL);
 -
 +      if (label->proxy) {
 +              if (rcu_dereference_protected(label->proxy->label, true) == label)
 +                      rcu_assign_pointer(label->proxy->label, NULL);
 +              aa_put_proxy(label->proxy);
 +      }
        aa_free_secid(label->secid);
  
 -      aa_put_proxy(label->proxy);
        label->proxy = (struct aa_proxy *) PROXY_POISON + 1;
  }
  
@@@ -341,7 -340,7 +341,7 @@@ void aa_label_free(struct aa_label *lab
        if (!label)
                return;
  
 -      label_destroy(label);
 +      aa_label_destroy(label);
        kfree(label);
  }
  
@@@ -425,8 -424,7 +425,7 @@@ struct aa_label *aa_label_alloc(int siz
        AA_BUG(size < 1);
  
        /*  + 1 for null terminator entry on vec */
-       new = kzalloc(sizeof(*new) + sizeof(struct aa_profile *) * (size + 1),
-                       gfp);
+       new = kzalloc(struct_size(new, vec, size + 1), gfp);
        AA_DEBUG("%s (%p)\n", __func__, new);
        if (!new)
                goto fail;
@@@ -1454,7 -1452,7 +1453,7 @@@ bool aa_update_label_name(struct aa_ns 
        if (label->hname || labels_ns(label) != ns)
                return res;
  
-       if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) == -1)
+       if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) < 0)
                return res;
  
        ls = labels_set(label);
@@@ -1704,7 -1702,7 +1703,7 @@@ int aa_label_asxprint(char **strp, stru
  
  /**
   * aa_label_acntsxprint - allocate a __counted string buffer and print label
-  * @strp: buffer to write to. (MAY BE NULL if @size == 0)
+  * @strp: buffer to write to.
   * @ns: namespace profile is being viewed from
   * @label: label to view (NOT NULL)
   * @flags: flags controlling what label info is printed
diff --combined security/apparmor/lsm.c
@@@ -224,10 -224,8 +224,10 @@@ static int common_perm(const char *op, 
   */
  static int common_perm_cond(const char *op, const struct path *path, u32 mask)
  {
 -      struct path_cond cond = { d_backing_inode(path->dentry)->i_uid,
 -                                d_backing_inode(path->dentry)->i_mode
 +      struct user_namespace *mnt_userns = mnt_user_ns(path->mnt);
 +      struct path_cond cond = {
 +              i_uid_into_mnt(mnt_userns, d_backing_inode(path->dentry)),
 +              d_backing_inode(path->dentry)->i_mode
        };
  
        if (!path_mediated_fs(path->dentry))
@@@ -268,13 -266,12 +268,13 @@@ static int common_perm_rm(const char *o
                          struct dentry *dentry, u32 mask)
  {
        struct inode *inode = d_backing_inode(dentry);
 +      struct user_namespace *mnt_userns = mnt_user_ns(dir->mnt);
        struct path_cond cond = { };
  
        if (!inode || !path_mediated_fs(dentry))
                return 0;
  
 -      cond.uid = inode->i_uid;
 +      cond.uid = i_uid_into_mnt(mnt_userns, inode);
        cond.mode = inode->i_mode;
  
        return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
@@@ -364,14 -361,12 +364,14 @@@ static int apparmor_path_rename(const s
  
        label = begin_current_label_crit_section();
        if (!unconfined(label)) {
 +              struct user_namespace *mnt_userns = mnt_user_ns(old_dir->mnt);
                struct path old_path = { .mnt = old_dir->mnt,
                                         .dentry = old_dentry };
                struct path new_path = { .mnt = new_dir->mnt,
                                         .dentry = new_dentry };
 -              struct path_cond cond = { d_backing_inode(old_dentry)->i_uid,
 -                                        d_backing_inode(old_dentry)->i_mode
 +              struct path_cond cond = {
 +                      i_uid_into_mnt(mnt_userns, d_backing_inode(old_dentry)),
 +                      d_backing_inode(old_dentry)->i_mode
                };
  
                error = aa_path_perm(OP_RENAME_SRC, label, &old_path, 0,
@@@ -425,12 -420,8 +425,12 @@@ static int apparmor_file_open(struct fi
  
        label = aa_get_newest_cred_label(file->f_cred);
        if (!unconfined(label)) {
 +              struct user_namespace *mnt_userns = file_mnt_user_ns(file);
                struct inode *inode = file_inode(file);
 -              struct path_cond cond = { inode->i_uid, inode->i_mode };
 +              struct path_cond cond = {
 +                      i_uid_into_mnt(mnt_userns, inode),
 +                      inode->i_mode
 +              };
  
                error = aa_path_perm(OP_OPEN, label, &file->f_path, 0,
                                     aa_map_file_to_perms(file), &cond);
@@@ -1156,7 -1147,7 +1156,7 @@@ static void apparmor_sock_graft(struct 
  }
  
  #ifdef CONFIG_NETWORK_SECMARK
 -static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
 +static int apparmor_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
                                      struct request_sock *req)
  {
        struct aa_sk_ctx *ctx = SK_CTX(sk);
@@@ -1246,14 -1237,13 +1246,14 @@@ static struct security_hook_list apparm
        LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
        LSM_HOOK_INIT(cred_transfer, apparmor_cred_transfer),
  
 -      LSM_HOOK_INIT(bprm_set_creds, apparmor_bprm_set_creds),
 +      LSM_HOOK_INIT(bprm_creds_for_exec, apparmor_bprm_creds_for_exec),
        LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds),
        LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds),
  
        LSM_HOOK_INIT(task_free, apparmor_task_free),
        LSM_HOOK_INIT(task_alloc, apparmor_task_alloc),
 -      LSM_HOOK_INIT(task_getsecid, apparmor_task_getsecid),
 +      LSM_HOOK_INIT(task_getsecid_subj, apparmor_task_getsecid),
 +      LSM_HOOK_INIT(task_getsecid_obj, apparmor_task_getsecid),
        LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
        LSM_HOOK_INIT(task_kill, apparmor_task_kill),
  
@@@ -1402,7 -1392,7 +1402,7 @@@ static int param_set_aalockpolicy(cons
  {
        if (!apparmor_enabled)
                return -EINVAL;
-       if (apparmor_initialized && !policy_admin_capable(NULL))
+       if (apparmor_initialized && !aa_current_policy_admin_capable(NULL))
                return -EPERM;
        return param_set_bool(val, kp);
  }
@@@ -1411,7 -1401,7 +1411,7 @@@ static int param_get_aalockpolicy(char 
  {
        if (!apparmor_enabled)
                return -EINVAL;
-       if (apparmor_initialized && !policy_view_capable(NULL))
+       if (apparmor_initialized && !aa_current_policy_view_capable(NULL))
                return -EPERM;
        return param_get_bool(buffer, kp);
  }
@@@ -1420,7 -1410,7 +1420,7 @@@ static int param_set_aabool(const char 
  {
        if (!apparmor_enabled)
                return -EINVAL;
-       if (apparmor_initialized && !policy_admin_capable(NULL))
+       if (apparmor_initialized && !aa_current_policy_admin_capable(NULL))
                return -EPERM;
        return param_set_bool(val, kp);
  }
@@@ -1429,7 -1419,7 +1429,7 @@@ static int param_get_aabool(char *buffe
  {
        if (!apparmor_enabled)
                return -EINVAL;
-       if (apparmor_initialized && !policy_view_capable(NULL))
+       if (apparmor_initialized && !aa_current_policy_view_capable(NULL))
                return -EPERM;
        return param_get_bool(buffer, kp);
  }
@@@ -1455,7 -1445,7 +1455,7 @@@ static int param_get_aauint(char *buffe
  {
        if (!apparmor_enabled)
                return -EINVAL;
-       if (apparmor_initialized && !policy_view_capable(NULL))
+       if (apparmor_initialized && !aa_current_policy_view_capable(NULL))
                return -EPERM;
        return param_get_uint(buffer, kp);
  }
@@@ -1526,7 -1516,7 +1526,7 @@@ static int param_get_aacompressionlevel
  {
        if (!apparmor_enabled)
                return -EINVAL;
-       if (apparmor_initialized && !policy_view_capable(NULL))
+       if (apparmor_initialized && !aa_current_policy_view_capable(NULL))
                return -EPERM;
        return param_get_int(buffer, kp);
  }
@@@ -1535,7 -1525,7 +1535,7 @@@ static int param_get_audit(char *buffer
  {
        if (!apparmor_enabled)
                return -EINVAL;
-       if (apparmor_initialized && !policy_view_capable(NULL))
+       if (apparmor_initialized && !aa_current_policy_view_capable(NULL))
                return -EPERM;
        return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]);
  }
@@@ -1548,7 -1538,7 +1548,7 @@@ static int param_set_audit(const char *
                return -EINVAL;
        if (!val)
                return -EINVAL;
-       if (apparmor_initialized && !policy_admin_capable(NULL))
+       if (apparmor_initialized && !aa_current_policy_admin_capable(NULL))
                return -EPERM;
  
        i = match_string(audit_mode_names, AUDIT_MAX_INDEX, val);
@@@ -1563,7 -1553,7 +1563,7 @@@ static int param_get_mode(char *buffer
  {
        if (!apparmor_enabled)
                return -EINVAL;
-       if (apparmor_initialized && !policy_view_capable(NULL))
+       if (apparmor_initialized && !aa_current_policy_view_capable(NULL))
                return -EPERM;
  
        return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]);
@@@ -1577,7 -1567,7 +1577,7 @@@ static int param_set_mode(const char *v
                return -EINVAL;
        if (!val)
                return -EINVAL;
-       if (apparmor_initialized && !policy_admin_capable(NULL))
+       if (apparmor_initialized && !aa_current_policy_admin_capable(NULL))
                return -EPERM;
  
        i = match_string(aa_profile_mode_names, APPARMOR_MODE_NAMES_MAX_INDEX,
@@@ -1711,9 -1701,9 +1711,9 @@@ static int __init alloc_buffers(void
  
  #ifdef CONFIG_SYSCTL
  static int apparmor_dointvec(struct ctl_table *table, int write,
 -                           void __user *buffer, size_t *lenp, loff_t *ppos)
 +                           void *buffer, size_t *lenp, loff_t *ppos)
  {
-       if (!policy_admin_capable(NULL))
+       if (!aa_current_policy_admin_capable(NULL))
                return -EPERM;
        if (!apparmor_enabled)
                return -EINVAL;
@@@ -1773,32 -1763,16 +1773,16 @@@ static unsigned int apparmor_ip_postrou
  
  }
  
- static unsigned int apparmor_ipv4_postroute(void *priv,
-                                           struct sk_buff *skb,
-                                           const struct nf_hook_state *state)
- {
-       return apparmor_ip_postroute(priv, skb, state);
- }
- #if IS_ENABLED(CONFIG_IPV6)
- static unsigned int apparmor_ipv6_postroute(void *priv,
-                                           struct sk_buff *skb,
-                                           const struct nf_hook_state *state)
- {
-       return apparmor_ip_postroute(priv, skb, state);
- }
- #endif
  static const struct nf_hook_ops apparmor_nf_ops[] = {
        {
-               .hook =         apparmor_ipv4_postroute,
+               .hook =         apparmor_ip_postroute,
                .pf =           NFPROTO_IPV4,
                .hooknum =      NF_INET_POST_ROUTING,
                .priority =     NF_IP_PRI_SELINUX_FIRST,
        },
  #if IS_ENABLED(CONFIG_IPV6)
        {
-               .hook =         apparmor_ipv6_postroute,
+               .hook =         apparmor_ip_postroute,
                .pf =           NFPROTO_IPV6,
                .hooknum =      NF_INET_POST_ROUTING,
                .priority =     NF_IP6_PRI_SELINUX_FIRST,
@@@ -187,9 -187,9 +187,9 @@@ static void aa_free_data(void *ptr, voi
  {
        struct aa_data *data = ptr;
  
 -      kzfree(data->data);
 -      kzfree(data->key);
 -      kzfree(data);
 +      kfree_sensitive(data->data);
 +      kfree_sensitive(data->key);
 +      kfree_sensitive(data);
  }
  
  /**
@@@ -217,19 -217,19 +217,19 @@@ void aa_free_profile(struct aa_profile 
        aa_put_profile(rcu_access_pointer(profile->parent));
  
        aa_put_ns(profile->ns);
 -      kzfree(profile->rename);
 +      kfree_sensitive(profile->rename);
  
        aa_free_file_rules(&profile->file);
        aa_free_cap_rules(&profile->caps);
        aa_free_rlimit_rules(&profile->rlimits);
  
        for (i = 0; i < profile->xattr_count; i++)
 -              kzfree(profile->xattrs[i]);
 -      kzfree(profile->xattrs);
 +              kfree_sensitive(profile->xattrs[i]);
 +      kfree_sensitive(profile->xattrs);
        for (i = 0; i < profile->secmark_count; i++)
 -              kzfree(profile->secmark[i].label);
 -      kzfree(profile->secmark);
 -      kzfree(profile->dirname);
 +              kfree_sensitive(profile->secmark[i].label);
 +      kfree_sensitive(profile->secmark);
 +      kfree_sensitive(profile->dirname);
        aa_put_dfa(profile->xmatch);
        aa_put_dfa(profile->policy.dfa);
  
                rht = profile->data;
                profile->data = NULL;
                rhashtable_free_and_destroy(rht, aa_free_data, NULL);
 -              kzfree(rht);
 +              kfree_sensitive(rht);
        }
  
 -      kzfree(profile->hash);
 +      kfree_sensitive(profile->hash);
        aa_put_loaddata(profile->rawdata);
 +      aa_label_destroy(&profile->label);
  
 -      kzfree(profile);
 +      kfree_sensitive(profile);
  }
  
  /**
@@@ -260,8 -259,7 +260,7 @@@ struct aa_profile *aa_alloc_profile(con
        struct aa_profile *profile;
  
        /* freed by free_profile - usually through aa_put_profile */
-       profile = kzalloc(sizeof(*profile) + sizeof(struct aa_profile *) * 2,
-                         gfp);
+       profile = kzalloc(struct_size(profile, label.vec, 2), gfp);
        if (!profile)
                return NULL;
  
@@@ -632,18 -630,35 +631,35 @@@ static int audit_policy(struct aa_labe
        return error;
  }
  
+ /* don't call out to other LSMs in the stack for apparmor policy admin
+  * permissions
+  */
+ static int policy_ns_capable(struct aa_label *label,
+                            struct user_namespace *userns, int cap)
+ {
+       int err;
+       /* check for MAC_ADMIN cap in cred */
+       err = cap_capable(current_cred(), userns, cap, CAP_OPT_NONE);
+       if (!err)
+               err = aa_capable(label, cap, CAP_OPT_NONE);
+       return err;
+ }
  /**
-  * policy_view_capable - check if viewing policy in at @ns is allowed
-  * ns: namespace being viewed by current task (may be NULL)
+  * aa_policy_view_capable - check if viewing policy in at @ns is allowed
+  * label: label that is trying to view policy in ns
+  * ns: namespace being viewed by @label (may be NULL if @label's ns)
   * Returns: true if viewing policy is allowed
   *
   * If @ns is NULL then the namespace being viewed is assumed to be the
   * tasks current namespace.
   */
- bool policy_view_capable(struct aa_ns *ns)
+ bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns)
  {
        struct user_namespace *user_ns = current_user_ns();
-       struct aa_ns *view_ns = aa_get_current_ns();
+       struct aa_ns *view_ns = labels_view(label);
        bool root_in_user_ns = uid_eq(current_euid(), make_kuid(user_ns, 0)) ||
                               in_egroup_p(make_kgid(user_ns, 0));
        bool response = false;
             (unprivileged_userns_apparmor_policy != 0 &&
              user_ns->level == view_ns->level)))
                response = true;
-       aa_put_ns(view_ns);
  
        return response;
  }
  
- bool policy_admin_capable(struct aa_ns *ns)
+ bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns)
  {
        struct user_namespace *user_ns = current_user_ns();
-       bool capable = ns_capable(user_ns, CAP_MAC_ADMIN);
+       bool capable = policy_ns_capable(label, user_ns, CAP_MAC_ADMIN) == 0;
  
        AA_DEBUG("cap_mac_admin? %d\n", capable);
        AA_DEBUG("policy locked? %d\n", aa_g_lock_policy);
  
-       return policy_view_capable(ns) && capable && !aa_g_lock_policy;
+       return aa_policy_view_capable(label, ns) && capable &&
+               !aa_g_lock_policy;
+ }
+ bool aa_current_policy_view_capable(struct aa_ns *ns)
+ {
+       struct aa_label *label;
+       bool res;
+       label = __begin_current_label_crit_section();
+       res = aa_policy_view_capable(label, ns);
+       __end_current_label_crit_section(label);
+       return res;
+ }
+ bool aa_current_policy_admin_capable(struct aa_ns *ns)
+ {
+       struct aa_label *label;
+       bool res;
+       label = __begin_current_label_crit_section();
+       res = aa_policy_admin_capable(label, ns);
+       __end_current_label_crit_section(label);
+       return res;
  }
  
  /**
@@@ -694,7 -733,7 +734,7 @@@ int aa_may_manage_policy(struct aa_labe
                return audit_policy(label, op, NULL, NULL, "policy_locked",
                                    -EACCES);
  
-       if (!policy_admin_capable(ns))
+       if (!aa_policy_admin_capable(label, ns))
                return audit_policy(label, op, NULL, NULL, "not policy admin",
                                    -EACCES);
  
@@@ -39,7 -39,7 +39,7 @@@
  
  /*
   * The AppArmor interface treats data as a type byte followed by the
-  * actual data.  The interface has the notion of a named entry
+  * actual data.  The interface has the notion of a named entry
   * which has a name (AA_NAME typecode followed by name string) followed by
   * the entries typecode and data.  Named types allow for optional
   * elements and extensions to be added and tested for without breaking
@@@ -163,10 -163,10 +163,10 @@@ static void do_loaddata_free(struct wor
                aa_put_ns(ns);
        }
  
 -      kzfree(d->hash);
 -      kzfree(d->name);
 +      kfree_sensitive(d->hash);
 +      kfree_sensitive(d->name);
        kvfree(d->data);
 -      kzfree(d);
 +      kfree_sensitive(d);
  }
  
  void aa_loaddata_kref(struct kref *kref)
@@@ -304,7 -304,7 +304,7 @@@ static bool unpack_u8(struct aa_ext *e
                if (!inbounds(e, sizeof(u8)))
                        goto fail;
                if (data)
 -                      *data = get_unaligned((u8 *)e->pos);
 +                      *data = *((u8 *)e->pos);
                e->pos += sizeof(u8);
                return true;
        }
@@@ -894,7 -894,7 +894,7 @@@ static struct aa_profile *unpack_profil
                while (unpack_strdup(e, &key, NULL)) {
                        data = kzalloc(sizeof(*data), GFP_KERNEL);
                        if (!data) {
 -                              kzfree(key);
 +                              kfree_sensitive(key);
                                goto fail;
                        }
  
                        data->size = unpack_blob(e, &data->data, NULL);
                        data->data = kvmemdup(data->data, data->size);
                        if (data->size && !data->data) {
 -                              kzfree(data->key);
 -                              kzfree(data);
 +                              kfree_sensitive(data->key);
 +                              kfree_sensitive(data);
                                goto fail;
                        }
  
@@@ -1037,7 -1037,7 +1037,7 @@@ void aa_load_ent_free(struct aa_load_en
                aa_put_profile(ent->old);
                aa_put_profile(ent->new);
                kfree(ent->ns_name);
 -              kzfree(ent);
 +              kfree_sensitive(ent);
        }
  }
  
@@@ -1232,7 -1232,3 +1232,7 @@@ fail
  
        return error;
  }
 +
 +#ifdef CONFIG_SECURITY_APPARMOR_KUNIT_TEST
 +#include "policy_unpack_test.c"
 +#endif /* CONFIG_SECURITY_APPARMOR_KUNIT_TEST */