Merge tag 'lsm-pr-20230829' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 30 Aug 2023 16:07:09 +0000 (09:07 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 30 Aug 2023 16:07:09 +0000 (09:07 -0700)
Pull LSM updates from Paul Moore:

 - Add proper multi-LSM support for xattrs in the
   security_inode_init_security() hook

   Historically the LSM layer has only allowed a single LSM to add an
   xattr to an inode, with IMA/EVM measuring that and adding its own as
   well. As we work towards promoting IMA/EVM to a "proper LSM" instead
   of the special case that it is now, we need to better support the
   case of multiple LSMs each adding xattrs to an inode and after
   several attempts we now appear to have something that is working
   well. It is worth noting that in the process of making this change we
   uncovered a problem with Smack's SMACK64TRANSMUTE xattr which is also
   fixed in this pull request.

 - Additional LSM hook constification

   Two patches to constify parameters to security_capget() and
   security_binder_transfer_file(). While I generally don't make a
   special note of who submitted these patches, these were the work of
   an Outreachy intern, Khadija Kamran, and that makes me happy;
   hopefully it does the same for all of you reading this.

 - LSM hook comment header fixes

   One patch to add a missing hook comment header, one to fix a minor
   typo.

 - Remove an old, unused credential function declaration

   It wasn't clear to me who should pick this up, but it was trivial,
   obviously correct, and arguably the LSM layer has a vested interest
   in credentials so I merged it. Sadly I'm now noticing that despite my
   subject line cleanup I didn't cleanup the "unsued" misspelling, sigh

* tag 'lsm-pr-20230829' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm:
  lsm: constify the 'file' parameter in security_binder_transfer_file()
  lsm: constify the 'target' parameter in security_capget()
  lsm: add comment block for security_sk_classify_flow LSM hook
  security: Fix ret values doc for security_inode_init_security()
  cred: remove unsued extern declaration change_create_files_as()
  evm: Support multiple LSMs providing an xattr
  evm: Align evm_inode_init_security() definition with LSM infrastructure
  smack: Set the SMACK64TRANSMUTE xattr in smack_inode_init_security()
  security: Allow all LSMs to provide xattrs for inode_init_security hook
  lsm: fix typo in security_file_lock() comment header

1  2 
include/linux/lsm_hook_defs.h
include/linux/security.h
security/security.c
security/selinux/hooks.c
security/smack/smack_lsm.c

@@@ -32,11 -32,11 +32,11 @@@ LSM_HOOK(int, 0, binder_transaction, co
  LSM_HOOK(int, 0, binder_transfer_binder, const struct cred *from,
         const struct cred *to)
  LSM_HOOK(int, 0, binder_transfer_file, const struct cred *from,
-        const struct cred *to, struct file *file)
+        const struct cred *to, const struct file *file)
  LSM_HOOK(int, 0, ptrace_access_check, struct task_struct *child,
         unsigned int mode)
  LSM_HOOK(int, 0, ptrace_traceme, struct task_struct *parent)
- LSM_HOOK(int, 0, capget, struct task_struct *target, kernel_cap_t *effective,
+ LSM_HOOK(int, 0, capget, const struct task_struct *target, kernel_cap_t *effective,
         kernel_cap_t *inheritable, kernel_cap_t *permitted)
  LSM_HOOK(int, 0, capset, struct cred *new, const struct cred *old,
         const kernel_cap_t *effective, const kernel_cap_t *inheritable,
@@@ -54,7 -54,6 +54,7 @@@ LSM_HOOK(int, 0, bprm_creds_from_file, 
  LSM_HOOK(int, 0, bprm_check_security, struct linux_binprm *bprm)
  LSM_HOOK(void, LSM_RET_VOID, bprm_committing_creds, struct linux_binprm *bprm)
  LSM_HOOK(void, LSM_RET_VOID, bprm_committed_creds, struct linux_binprm *bprm)
 +LSM_HOOK(int, 0, fs_context_submount, struct fs_context *fc, struct super_block *reference)
  LSM_HOOK(int, 0, fs_context_dup, struct fs_context *fc,
         struct fs_context *src_sc)
  LSM_HOOK(int, -ENOPARAM, fs_context_parse_param, struct fs_context *fc,
@@@ -112,9 -111,9 +112,9 @@@ LSM_HOOK(int, 0, path_notify, const str
         unsigned int obj_type)
  LSM_HOOK(int, 0, inode_alloc_security, struct inode *inode)
  LSM_HOOK(void, LSM_RET_VOID, inode_free_security, struct inode *inode)
- LSM_HOOK(int, 0, inode_init_security, struct inode *inode,
-        struct inode *dir, const struct qstr *qstr, const char **name,
-        void **value, size_t *len)
+ LSM_HOOK(int, -EOPNOTSUPP, inode_init_security, struct inode *inode,
+        struct inode *dir, const struct qstr *qstr, struct xattr *xattrs,
+        int *xattr_count)
  LSM_HOOK(int, 0, inode_init_security_anon, struct inode *inode,
         const struct qstr *name, const struct inode *context_inode)
  LSM_HOOK(int, 0, inode_create, struct inode *dir, struct dentry *dentry,
@@@ -317,7 -316,7 +317,7 @@@ LSM_HOOK(int, 0, sk_alloc_security, str
  LSM_HOOK(void, LSM_RET_VOID, sk_free_security, struct sock *sk)
  LSM_HOOK(void, LSM_RET_VOID, sk_clone_security, const struct sock *sk,
         struct sock *newsk)
 -LSM_HOOK(void, LSM_RET_VOID, sk_getsecid, struct sock *sk, u32 *secid)
 +LSM_HOOK(void, LSM_RET_VOID, sk_getsecid, const struct sock *sk, u32 *secid)
  LSM_HOOK(void, LSM_RET_VOID, sock_graft, struct sock *sk, struct socket *parent)
  LSM_HOOK(int, 0, inet_conn_request, const struct sock *sk, struct sk_buff *skb,
         struct request_sock *req)
diff --combined include/linux/security.h
@@@ -145,7 -145,8 +145,8 @@@ extern int cap_capable(const struct cre
  extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz);
  extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
  extern int cap_ptrace_traceme(struct task_struct *parent);
- extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
+ extern int cap_capget(const struct task_struct *target, kernel_cap_t *effective,
+                     kernel_cap_t *inheritable, kernel_cap_t *permitted);
  extern int cap_capset(struct cred *new, const struct cred *old,
                      const kernel_cap_t *effective,
                      const kernel_cap_t *inheritable,
@@@ -268,10 -269,10 +269,10 @@@ int security_binder_transaction(const s
  int security_binder_transfer_binder(const struct cred *from,
                                    const struct cred *to);
  int security_binder_transfer_file(const struct cred *from,
-                                 const struct cred *to, struct file *file);
+                                 const struct cred *to, const struct file *file);
  int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
  int security_ptrace_traceme(struct task_struct *parent);
- int security_capget(struct task_struct *target,
+ int security_capget(const struct task_struct *target,
                    kernel_cap_t *effective,
                    kernel_cap_t *inheritable,
                    kernel_cap_t *permitted);
@@@ -293,7 -294,6 +294,7 @@@ int security_bprm_creds_from_file(struc
  int security_bprm_check(struct linux_binprm *bprm);
  void security_bprm_committing_creds(struct linux_binprm *bprm);
  void security_bprm_committed_creds(struct linux_binprm *bprm);
 +int security_fs_context_submount(struct fs_context *fc, struct super_block *reference);
  int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc);
  int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param);
  int security_sb_alloc(struct super_block *sb);
@@@ -538,7 -538,7 +539,7 @@@ static inline int security_binder_trans
  
  static inline int security_binder_transfer_file(const struct cred *from,
                                                const struct cred *to,
-                                               struct file *file)
+                                               const struct file *file)
  {
        return 0;
  }
@@@ -554,7 -554,7 +555,7 @@@ static inline int security_ptrace_trace
        return cap_ptrace_traceme(parent);
  }
  
- static inline int security_capget(struct task_struct *target,
+ static inline int security_capget(const struct task_struct *target,
                                   kernel_cap_t *effective,
                                   kernel_cap_t *inheritable,
                                   kernel_cap_t *permitted)
@@@ -630,11 -630,6 +631,11 @@@ static inline void security_bprm_commit
  {
  }
  
 +static inline int security_fs_context_submount(struct fs_context *fc,
 +                                         struct super_block *reference)
 +{
 +      return 0;
 +}
  static inline int security_fs_context_dup(struct fs_context *fc,
                                          struct fs_context *src_fc)
  {
@@@ -1445,8 -1440,7 +1446,8 @@@ int security_socket_getpeersec_dgram(st
  int security_sk_alloc(struct sock *sk, int family, gfp_t priority);
  void security_sk_free(struct sock *sk);
  void security_sk_clone(const struct sock *sk, struct sock *newsk);
 -void security_sk_classify_flow(struct sock *sk, struct flowi_common *flic);
 +void security_sk_classify_flow(const struct sock *sk,
 +                             struct flowi_common *flic);
  void security_req_classify_flow(const struct request_sock *req,
                                struct flowi_common *flic);
  void security_sock_graft(struct sock*sk, struct socket *parent);
@@@ -1604,7 -1598,7 +1605,7 @@@ static inline void security_sk_clone(co
  {
  }
  
 -static inline void security_sk_classify_flow(struct sock *sk,
 +static inline void security_sk_classify_flow(const struct sock *sk,
                                             struct flowi_common *flic)
  {
  }
diff --combined security/security.c
@@@ -31,8 -31,6 +31,6 @@@
  #include <linux/msg.h>
  #include <net/flow.h>
  
- #define MAX_LSM_EVM_XATTR     2
  /* How many LSMs were built into the kernel? */
  #define LSM_COUNT (__end_lsm_info - __start_lsm_info)
  
@@@ -212,6 -210,8 +210,8 @@@ static void __init lsm_set_blob_sizes(s
        lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
        lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
        lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
+       lsm_set_blob_size(&needed->lbs_xattr_count,
+                         &blob_sizes.lbs_xattr_count);
  }
  
  /* Prepare LSM for initialization. */
@@@ -378,6 -378,7 +378,7 @@@ static void __init ordered_lsm_init(voi
        init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
        init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
        init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
+       init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
  
        /*
         * Create any kmem_caches needed for blobs
@@@ -840,7 -841,7 +841,7 @@@ int security_binder_transfer_binder(con
   * Return: Returns 0 if permission is granted.
   */
  int security_binder_transfer_file(const struct cred *from,
-                                 const struct cred *to, struct file *file)
+                                 const struct cred *to, const struct file *file)
  {
        return call_int_hook(binder_transfer_file, 0, from, to, file);
  }
@@@ -893,7 -894,7 +894,7 @@@ int security_ptrace_traceme(struct task
   *
   * Return: Returns 0 if the capability sets were successfully obtained.
   */
- int security_capget(struct task_struct *target,
+ int security_capget(const struct task_struct *target,
                    kernel_cap_t *effective,
                    kernel_cap_t *inheritable,
                    kernel_cap_t *permitted)
@@@ -1139,20 -1140,6 +1140,20 @@@ void security_bprm_committed_creds(stru
  }
  
  /**
 + * security_fs_context_submount() - Initialise fc->security
 + * @fc: new filesystem context
 + * @reference: dentry reference for submount/remount
 + *
 + * Fill out the ->security field for a new fs_context.
 + *
 + * Return: Returns 0 on success or negative error code on failure.
 + */
 +int security_fs_context_submount(struct fs_context *fc, struct super_block *reference)
 +{
 +      return call_int_hook(fs_context_submount, 0, fc, reference);
 +}
 +
 +/**
   * security_fs_context_dup() - Duplicate a fs_context LSM blob
   * @fc: destination filesystem context
   * @src_fc: source filesystem context
@@@ -1605,46 -1592,70 +1606,70 @@@ EXPORT_SYMBOL(security_dentry_create_fi
   * created inode and set up the incore security field for the new inode.  This
   * hook is called by the fs code as part of the inode creation transaction and
   * provides for atomic labeling of the inode, unlike the post_create/mkdir/...
-  * hooks called by the VFS.  The hook function is expected to allocate the name
-  * and value via kmalloc, with the caller being responsible for calling kfree
-  * after using them.  If the security module does not use security attributes
-  * or does not wish to put a security attribute on this particular inode, then
-  * it should return -EOPNOTSUPP to skip this processing.
+  * hooks called by the VFS.
+  *
+  * The hook function is expected to populate the xattrs array, by calling
+  * lsm_get_xattr_slot() to retrieve the slots reserved by the security module
+  * with the lbs_xattr_count field of the lsm_blob_sizes structure.  For each
+  * slot, the hook function should set ->name to the attribute name suffix
+  * (e.g. selinux), to allocate ->value (will be freed by the caller) and set it
+  * to the attribute value, to set ->value_len to the length of the value.  If
+  * the security module does not use security attributes or does not wish to put
+  * a security attribute on this particular inode, then it should return
+  * -EOPNOTSUPP to skip this processing.
   *
-  * Return: Returns 0 on success, -EOPNOTSUPP if no security attribute is
-  * needed, or -ENOMEM on memory allocation failure.
+  * Return: Returns 0 if the LSM successfully initialized all of the inode
+  *         security attributes that are required, negative values otherwise.
   */
  int security_inode_init_security(struct inode *inode, struct inode *dir,
                                 const struct qstr *qstr,
                                 const initxattrs initxattrs, void *fs_data)
  {
-       struct xattr new_xattrs[MAX_LSM_EVM_XATTR + 1];
-       struct xattr *lsm_xattr, *evm_xattr, *xattr;
-       int ret;
+       struct security_hook_list *hp;
+       struct xattr *new_xattrs = NULL;
+       int ret = -EOPNOTSUPP, xattr_count = 0;
  
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
  
-       if (!initxattrs)
-               return call_int_hook(inode_init_security, -EOPNOTSUPP, inode,
-                                    dir, qstr, NULL, NULL, NULL);
-       memset(new_xattrs, 0, sizeof(new_xattrs));
-       lsm_xattr = new_xattrs;
-       ret = call_int_hook(inode_init_security, -EOPNOTSUPP, inode, dir, qstr,
-                           &lsm_xattr->name,
-                           &lsm_xattr->value,
-                           &lsm_xattr->value_len);
-       if (ret)
+       if (!blob_sizes.lbs_xattr_count)
+               return 0;
+       if (initxattrs) {
+               /* Allocate +1 for EVM and +1 as terminator. */
+               new_xattrs = kcalloc(blob_sizes.lbs_xattr_count + 2,
+                                    sizeof(*new_xattrs), GFP_NOFS);
+               if (!new_xattrs)
+                       return -ENOMEM;
+       }
+       hlist_for_each_entry(hp, &security_hook_heads.inode_init_security,
+                            list) {
+               ret = hp->hook.inode_init_security(inode, dir, qstr, new_xattrs,
+                                                 &xattr_count);
+               if (ret && ret != -EOPNOTSUPP)
+                       goto out;
+               /*
+                * As documented in lsm_hooks.h, -EOPNOTSUPP in this context
+                * means that the LSM is not willing to provide an xattr, not
+                * that it wants to signal an error. Thus, continue to invoke
+                * the remaining LSMs.
+                */
+       }
+       /* If initxattrs() is NULL, xattr_count is zero, skip the call. */
+       if (!xattr_count)
                goto out;
  
-       evm_xattr = lsm_xattr + 1;
-       ret = evm_inode_init_security(inode, lsm_xattr, evm_xattr);
+       ret = evm_inode_init_security(inode, dir, qstr, new_xattrs,
+                                     &xattr_count);
        if (ret)
                goto out;
        ret = initxattrs(inode, new_xattrs, fs_data);
  out:
-       for (xattr = new_xattrs; xattr->value != NULL; xattr++)
-               kfree(xattr->value);
+       for (; xattr_count > 0; xattr_count--)
+               kfree(new_xattrs[xattr_count - 1].value);
+       kfree(new_xattrs);
        return (ret == -EOPNOTSUPP) ? 0 : ret;
  }
  EXPORT_SYMBOL(security_inode_init_security);
@@@ -2731,7 -2742,7 +2756,7 @@@ int security_file_lock(struct file *fil
  /**
   * security_file_fcntl() - Check if fcntl() op is allowed
   * @file: file
-  * @cmd: fnctl command
+  * @cmd: fcntl command
   * @arg: command argument
   *
   * Check permission before allowing the file operation specified by @cmd from
@@@ -4410,7 -4421,14 +4435,14 @@@ void security_sk_clone(const struct soc
  }
  EXPORT_SYMBOL(security_sk_clone);
  
 -void security_sk_classify_flow(struct sock *sk, struct flowi_common *flic)
+ /**
+  * security_sk_classify_flow() - Set a flow's secid based on socket
+  * @sk: original socket
+  * @flic: target flow
+  *
+  * Set the target flow's secid to socket's secid.
+  */
 +void security_sk_classify_flow(const struct sock *sk, struct flowi_common *flic)
  {
        call_void_hook(sk_getsecid, sk, &flic->flowic_secid);
  }
diff --combined security/selinux/hooks.c
@@@ -1,10 -1,10 +1,10 @@@
  // SPDX-License-Identifier: GPL-2.0-only
  /*
 - *  NSA Security-Enhanced Linux (SELinux) security module
 + *  Security-Enhanced Linux (SELinux) security module
   *
   *  This file contains the SELinux hook function implementations.
   *
 - *  Authors:  Stephen Smalley, <sds@tycho.nsa.gov>
 + *  Authors:  Stephen Smalley, <stephen.smalley.work@gmail.com>
   *          Chris Vance, <cvance@nai.com>
   *          Wayne Salamon, <wsalamon@nai.com>
   *          James Morris <jmorris@redhat.com>
  #include "audit.h"
  #include "avc_ss.h"
  
+ #define SELINUX_INODE_INIT_XATTRS 1
  struct selinux_state selinux_state;
  
  /* SECMARK reference count */
@@@ -224,31 -226,6 +226,31 @@@ static inline u32 cred_sid(const struc
        return tsec->sid;
  }
  
 +static void __ad_net_init(struct common_audit_data *ad,
 +                        struct lsm_network_audit *net,
 +                        int ifindex, struct sock *sk, u16 family)
 +{
 +      ad->type = LSM_AUDIT_DATA_NET;
 +      ad->u.net = net;
 +      net->netif = ifindex;
 +      net->sk = sk;
 +      net->family = family;
 +}
 +
 +static void ad_net_init_from_sk(struct common_audit_data *ad,
 +                              struct lsm_network_audit *net,
 +                              struct sock *sk)
 +{
 +      __ad_net_init(ad, net, 0, sk, 0);
 +}
 +
 +static void ad_net_init_from_iif(struct common_audit_data *ad,
 +                               struct lsm_network_audit *net,
 +                               int ifindex, u16 family)
 +{
 +      __ad_net_init(ad, net, ifindex, NULL, family);
 +}
 +
  /*
   * get the objective security ID of a task
   */
@@@ -1150,7 -1127,7 +1152,7 @@@ static inline int default_protocol_dgra
  
  static inline u16 socket_type_to_security_class(int family, int type, int protocol)
  {
 -      int extsockclass = selinux_policycap_extsockclass();
 +      bool extsockclass = selinux_policycap_extsockclass();
  
        switch (family) {
        case PF_UNIX:
@@@ -1714,7 -1691,7 +1716,7 @@@ static inline int file_path_has_perm(co
  }
  
  #ifdef CONFIG_BPF_SYSCALL
- static int bpf_fd_pass(struct file *file, u32 sid);
+ static int bpf_fd_pass(const struct file *file, u32 sid);
  #endif
  
  /* Check whether a task can use an open file descriptor to
@@@ -1975,7 -1952,7 +1977,7 @@@ static inline u32 file_mask_to_av(int m
  }
  
  /* Convert a Linux file to an access vector. */
- static inline u32 file_to_av(struct file *file)
+ static inline u32 file_to_av(const struct file *file)
  {
        u32 av = 0;
  
@@@ -2050,7 -2027,7 +2052,7 @@@ static int selinux_binder_transfer_bind
  
  static int selinux_binder_transfer_file(const struct cred *from,
                                        const struct cred *to,
-                                       struct file *file)
+                                       const struct file *file)
  {
        u32 sid = cred_sid(to);
        struct file_security_struct *fsec = selinux_file(file);
@@@ -2105,7 -2082,7 +2107,7 @@@ static int selinux_ptrace_traceme(struc
                            SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
  }
  
- static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
+ static int selinux_capget(const struct task_struct *target, kernel_cap_t *effective,
                          kernel_cap_t *inheritable, kernel_cap_t *permitted)
  {
        return avc_has_perm(current_sid(), task_sid_obj(target),
@@@ -2770,27 -2747,6 +2772,27 @@@ static int selinux_umount(struct vfsmou
                                   FILESYSTEM__UNMOUNT, NULL);
  }
  
 +static int selinux_fs_context_submount(struct fs_context *fc,
 +                                 struct super_block *reference)
 +{
 +      const struct superblock_security_struct *sbsec;
 +      struct selinux_mnt_opts *opts;
 +
 +      opts = kzalloc(sizeof(*opts), GFP_KERNEL);
 +      if (!opts)
 +              return -ENOMEM;
 +
 +      sbsec = selinux_superblock(reference);
 +      if (sbsec->flags & FSCONTEXT_MNT)
 +              opts->fscontext_sid = sbsec->sid;
 +      if (sbsec->flags & CONTEXT_MNT)
 +              opts->context_sid = sbsec->mntpoint_sid;
 +      if (sbsec->flags & DEFCONTEXT_MNT)
 +              opts->defcontext_sid = sbsec->def_sid;
 +      fc->security = opts;
 +      return 0;
 +}
 +
  static int selinux_fs_context_dup(struct fs_context *fc,
                                  struct fs_context *src_fc)
  {
@@@ -2893,11 -2849,11 +2895,11 @@@ static int selinux_dentry_create_files_
  
  static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                                       const struct qstr *qstr,
-                                      const char **name,
-                                      void **value, size_t *len)
+                                      struct xattr *xattrs, int *xattr_count)
  {
        const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct superblock_security_struct *sbsec;
+       struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);
        u32 newsid, clen;
        int rc;
        char *context;
            !(sbsec->flags & SBLABEL_MNT))
                return -EOPNOTSUPP;
  
-       if (name)
-               *name = XATTR_SELINUX_SUFFIX;
-       if (value && len) {
+       if (xattr) {
                rc = security_sid_to_context_force(newsid,
                                                   &context, &clen);
                if (rc)
                        return rc;
-               *value = context;
-               *len = clen;
+               xattr->value = context;
+               xattr->value_len = clen;
+               xattr->name = XATTR_SELINUX_SUFFIX;
        }
  
        return 0;
@@@ -2963,7 -2917,7 +2963,7 @@@ static int selinux_inode_init_security_
                struct inode_security_struct *context_isec =
                        selinux_inode(context_inode);
                if (context_isec->initialized != LABEL_INITIALIZED) {
 -                      pr_err("SELinux:  context_inode is not initialized");
 +                      pr_err("SELinux:  context_inode is not initialized\n");
                        return -EACCES;
                }
  
@@@ -3808,10 -3762,13 +3808,10 @@@ static int selinux_file_mprotect(struc
        if (default_noexec &&
            (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
                int rc = 0;
 -              if (vma->vm_start >= vma->vm_mm->start_brk &&
 -                  vma->vm_end <= vma->vm_mm->brk) {
 +              if (vma_is_initial_heap(vma)) {
                        rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
                                          PROCESS__EXECHEAP, NULL);
 -              } else if (!vma->vm_file &&
 -                         ((vma->vm_start <= vma->vm_mm->start_stack &&
 -                           vma->vm_end >= vma->vm_mm->start_stack) ||
 +              } else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
                            vma_is_stack_for_current(vma))) {
                        rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
                                          PROCESS__EXECSTACK, NULL);
@@@ -4542,12 -4499,14 +4542,12 @@@ static int sock_has_perm(struct sock *s
  {
        struct sk_security_struct *sksec = sk->sk_security;
        struct common_audit_data ad;
 -      struct lsm_network_audit net = {0,};
 +      struct lsm_network_audit net;
  
        if (sksec->sid == SECINITSID_KERNEL)
                return 0;
  
 -      ad.type = LSM_AUDIT_DATA_NET;
 -      ad.u.net = &net;
 -      ad.u.net->sk = sk;
 +      ad_net_init_from_sk(&ad, &net, sk);
  
        return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms,
                            &ad);
@@@ -4940,10 -4899,12 +4940,10 @@@ static int selinux_socket_unix_stream_c
        struct sk_security_struct *sksec_other = other->sk_security;
        struct sk_security_struct *sksec_new = newsk->sk_security;
        struct common_audit_data ad;
 -      struct lsm_network_audit net = {0,};
 +      struct lsm_network_audit net;
        int err;
  
 -      ad.type = LSM_AUDIT_DATA_NET;
 -      ad.u.net = &net;
 -      ad.u.net->sk = other;
 +      ad_net_init_from_sk(&ad, &net, other);
  
        err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
                           sksec_other->sclass,
@@@ -4970,9 -4931,11 +4970,9 @@@ static int selinux_socket_unix_may_send
        struct sk_security_struct *ssec = sock->sk->sk_security;
        struct sk_security_struct *osec = other->sk->sk_security;
        struct common_audit_data ad;
 -      struct lsm_network_audit net = {0,};
 +      struct lsm_network_audit net;
  
 -      ad.type = LSM_AUDIT_DATA_NET;
 -      ad.u.net = &net;
 -      ad.u.net->sk = other->sk;
 +      ad_net_init_from_sk(&ad, &net, other->sk);
  
        return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
                            &ad);
@@@ -5008,10 -4971,13 +5008,10 @@@ static int selinux_sock_rcv_skb_compat(
        struct sk_security_struct *sksec = sk->sk_security;
        u32 sk_sid = sksec->sid;
        struct common_audit_data ad;
 -      struct lsm_network_audit net = {0,};
 +      struct lsm_network_audit net;
        char *addrp;
  
 -      ad.type = LSM_AUDIT_DATA_NET;
 -      ad.u.net = &net;
 -      ad.u.net->netif = skb->skb_iif;
 -      ad.u.net->family = family;
 +      ad_net_init_from_iif(&ad, &net, skb->skb_iif, family);
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
        if (err)
                return err;
  
  static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
  {
 -      int err;
 +      int err, peerlbl_active, secmark_active;
        struct sk_security_struct *sksec = sk->sk_security;
        u16 family = sk->sk_family;
        u32 sk_sid = sksec->sid;
        struct common_audit_data ad;
 -      struct lsm_network_audit net = {0,};
 +      struct lsm_network_audit net;
        char *addrp;
 -      u8 secmark_active;
 -      u8 peerlbl_active;
  
        if (family != PF_INET && family != PF_INET6)
                return 0;
        if (!secmark_active && !peerlbl_active)
                return 0;
  
 -      ad.type = LSM_AUDIT_DATA_NET;
 -      ad.u.net = &net;
 -      ad.u.net->netif = skb->skb_iif;
 -      ad.u.net->family = family;
 +      ad_net_init_from_iif(&ad, &net, skb->skb_iif, family);
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
        if (err)
                return err;
@@@ -5196,12 -5167,12 +5196,12 @@@ static void selinux_sk_clone_security(c
        selinux_netlbl_sk_security_reset(newsksec);
  }
  
 -static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
 +static void selinux_sk_getsecid(const struct sock *sk, u32 *secid)
  {
        if (!sk)
                *secid = SECINITSID_ANY_SOCKET;
        else {
 -              struct sk_security_struct *sksec = sk->sk_security;
 +              const struct sk_security_struct *sksec = sk->sk_security;
  
                *secid = sksec->sid;
        }
@@@ -5230,7 -5201,7 +5230,7 @@@ static int selinux_sctp_process_new_ass
        u16 family = sk->sk_family;
        struct sk_security_struct *sksec = sk->sk_security;
        struct common_audit_data ad;
 -      struct lsm_network_audit net = {0,};
 +      struct lsm_network_audit net;
        int err;
  
        /* handle mapped IPv4 packets arriving via IPv6 sockets */
                /* Other association peer SIDs are checked to enforce
                 * consistency among the peer SIDs.
                 */
 -              ad.type = LSM_AUDIT_DATA_NET;
 -              ad.u.net = &net;
 -              ad.u.net->sk = asoc->base.sk;
 +              ad_net_init_from_sk(&ad, &net, asoc->base.sk);
                err = avc_has_perm(sksec->peer_sid, asoc->peer_secid,
                                   sksec->sclass, SCTP_SOCKET__ASSOCIATION,
                                   &ad);
@@@ -5497,11 -5470,11 +5497,11 @@@ static void selinux_inet_conn_establish
  
  static int selinux_secmark_relabel_packet(u32 sid)
  {
 -      const struct task_security_struct *__tsec;
 +      const struct task_security_struct *tsec;
        u32 tsid;
  
 -      __tsec = selinux_cred(current_cred());
 -      tsid = __tsec->sid;
 +      tsec = selinux_cred(current_cred());
 +      tsid = tsec->sid;
  
        return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
                            NULL);
@@@ -5611,7 -5584,7 +5611,7 @@@ static unsigned int selinux_ip_forward(
        char *addrp;
        u32 peer_sid;
        struct common_audit_data ad;
 -      struct lsm_network_audit net = {0,};
 +      struct lsm_network_audit net;
        int secmark_active, peerlbl_active;
  
        if (!selinux_policycap_netpeer())
                return NF_DROP;
  
        ifindex = state->in->ifindex;
 -      ad.type = LSM_AUDIT_DATA_NET;
 -      ad.u.net = &net;
 -      ad.u.net->netif = ifindex;
 -      ad.u.net->family = family;
 +      ad_net_init_from_iif(&ad, &net, ifindex, family);
        if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
                return NF_DROP;
  
@@@ -5707,7 -5683,7 +5707,7 @@@ static unsigned int selinux_ip_postrout
        struct sock *sk;
        struct sk_security_struct *sksec;
        struct common_audit_data ad;
 -      struct lsm_network_audit net = {0,};
 +      struct lsm_network_audit net;
        u8 proto = 0;
  
        sk = skb_to_full_sk(skb);
                return NF_ACCEPT;
        sksec = sk->sk_security;
  
 -      ad.type = LSM_AUDIT_DATA_NET;
 -      ad.u.net = &net;
 -      ad.u.net->netif = state->out->ifindex;
 -      ad.u.net->family = state->pf;
 +      ad_net_init_from_iif(&ad, &net, state->out->ifindex, state->pf);
        if (selinux_parse_skb(skb, &ad, NULL, 0, &proto))
                return NF_DROP;
  
@@@ -5740,7 -5719,7 +5740,7 @@@ static unsigned int selinux_ip_postrout
        int ifindex;
        struct sock *sk;
        struct common_audit_data ad;
 -      struct lsm_network_audit net = {0,};
 +      struct lsm_network_audit net;
        char *addrp;
        int secmark_active, peerlbl_active;
  
        }
  
        ifindex = state->out->ifindex;
 -      ad.type = LSM_AUDIT_DATA_NET;
 -      ad.u.net = &net;
 -      ad.u.net->netif = ifindex;
 -      ad.u.net->family = family;
 +      ad_net_init_from_iif(&ad, &net, ifindex, family);
        if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
                return NF_DROP;
  
@@@ -5990,7 -5972,8 +5990,7 @@@ static int selinux_msg_queue_associate(
  
  static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
  {
 -      int err;
 -      int perms;
 +      u32 perms;
  
        switch (cmd) {
        case IPC_INFO:
                return 0;
        }
  
 -      err = ipc_has_perm(msq, perms);
 -      return err;
 +      return ipc_has_perm(msq, perms);
  }
  
  static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg)
@@@ -6118,7 -6102,8 +6118,7 @@@ static int selinux_shm_associate(struc
  /* Note, at this point, shp is locked down */
  static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
  {
 -      int perms;
 -      int err;
 +      u32 perms;
  
        switch (cmd) {
        case IPC_INFO:
                return 0;
        }
  
 -      err = ipc_has_perm(shp, perms);
 -      return err;
 +      return ipc_has_perm(shp, perms);
  }
  
  static int selinux_shm_shmat(struct kern_ipc_perm *shp,
@@@ -6732,7 -6718,7 +6732,7 @@@ static u32 bpf_map_fmode_to_av(fmode_t 
   * access the bpf object and that's why we have to add this additional check in
   * selinux_file_receive and selinux_binder_transfer_files.
   */
- static int bpf_fd_pass(struct file *file, u32 sid)
+ static int bpf_fd_pass(const struct file *file, u32 sid)
  {
        struct bpf_security_struct *bpfsec;
        struct bpf_prog *prog;
@@@ -6829,6 -6815,7 +6829,7 @@@ struct lsm_blob_sizes selinux_blob_size
        .lbs_ipc = sizeof(struct ipc_security_struct),
        .lbs_msg_msg = sizeof(struct msg_security_struct),
        .lbs_superblock = sizeof(struct superblock_security_struct),
+       .lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
  };
  
  #ifdef CONFIG_PERF_EVENTS
@@@ -6914,7 -6901,7 +6915,7 @@@ static int selinux_uring_override_creds
   */
  static int selinux_uring_sqpoll(void)
  {
 -      int sid = current_sid();
 +      u32 sid = current_sid();
  
        return avc_has_perm(sid, sid,
                            SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
@@@ -6953,6 -6940,10 +6954,6 @@@ static int selinux_uring_cmd(struct io_
   *    hooks ("allocating" hooks).
   *
   * Please follow block comment delimiters in the list to keep this order.
 - *
 - * This ordering is needed for SELinux runtime disable to work at least somewhat
 - * safely. Breaking the ordering rules above might lead to NULL pointer derefs
 - * when disabling SELinux at runtime.
   */
  static struct security_hook_list selinux_hooks[] __ro_after_init = {
        LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
        /*
         * PUT "CLONING" (ACCESSING + ALLOCATING) HOOKS HERE
         */
 +      LSM_HOOK_INIT(fs_context_submount, selinux_fs_context_submount),
        LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
        LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param),
        LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
@@@ -7252,8 -7242,6 +7253,8 @@@ static __init int selinux_init(void
        cred_init_security();
  
        default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
 +      if (!default_noexec)
 +              pr_notice("SELinux:  virtual memory is executable by default\n");
  
        avc_init();
  
  #define SMK_RECEIVING 1
  #define SMK_SENDING   2
  
+ /*
+  * Smack uses multiple xattrs.
+  * SMACK64 - for access control,
+  * SMACK64TRANSMUTE - label initialization,
+  * Not saved on files - SMACK64IPIN and SMACK64IPOUT,
+  * Must be set explicitly - SMACK64EXEC and SMACK64MMAP
+  */
+ #define SMACK_INODE_INIT_XATTRS 2
  #ifdef SMACK_IPV6_PORT_LABELING
  static DEFINE_MUTEX(smack_ipv6_lock);
  static LIST_HEAD(smk_ipv6_port_list);
@@@ -615,56 -624,6 +624,56 @@@ out_opt_err
  }
  
  /**
 + * smack_fs_context_submount - Initialise security data for a filesystem context
 + * @fc: The filesystem context.
 + * @reference: reference superblock
 + *
 + * Returns 0 on success or -ENOMEM on error.
 + */
 +static int smack_fs_context_submount(struct fs_context *fc,
 +                               struct super_block *reference)
 +{
 +      struct superblock_smack *sbsp;
 +      struct smack_mnt_opts *ctx;
 +      struct inode_smack *isp;
 +
 +      ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 +      if (!ctx)
 +              return -ENOMEM;
 +      fc->security = ctx;
 +
 +      sbsp = smack_superblock(reference);
 +      isp = smack_inode(reference->s_root->d_inode);
 +
 +      if (sbsp->smk_default) {
 +              ctx->fsdefault = kstrdup(sbsp->smk_default->smk_known, GFP_KERNEL);
 +              if (!ctx->fsdefault)
 +                      return -ENOMEM;
 +      }
 +
 +      if (sbsp->smk_floor) {
 +              ctx->fsfloor = kstrdup(sbsp->smk_floor->smk_known, GFP_KERNEL);
 +              if (!ctx->fsfloor)
 +                      return -ENOMEM;
 +      }
 +
 +      if (sbsp->smk_hat) {
 +              ctx->fshat = kstrdup(sbsp->smk_hat->smk_known, GFP_KERNEL);
 +              if (!ctx->fshat)
 +                      return -ENOMEM;
 +      }
 +
 +      if (isp->smk_flags & SMK_INODE_TRANSMUTE) {
 +              if (sbsp->smk_root) {
 +                      ctx->fstransmute = kstrdup(sbsp->smk_root->smk_known, GFP_KERNEL);
 +                      if (!ctx->fstransmute)
 +                              return -ENOMEM;
 +              }
 +      }
 +      return 0;
 +}
 +
 +/**
   * smack_fs_context_dup - Duplicate the security data on fs_context duplication
   * @fc: The new filesystem context.
   * @src_fc: The source filesystem context being duplicated.
@@@ -973,27 -932,23 +982,23 @@@ static int smack_inode_alloc_security(s
   * @inode: the newly created inode
   * @dir: containing directory object
   * @qstr: unused
-  * @name: where to put the attribute name
-  * @value: where to put the attribute value
-  * @len: where to put the length of the attribute
+  * @xattrs: where to put the attributes
+  * @xattr_count: current number of LSM-provided xattrs (updated)
   *
   * Returns 0 if it all works out, -ENOMEM if there's no memory
   */
  static int smack_inode_init_security(struct inode *inode, struct inode *dir,
-                                    const struct qstr *qstr, const char **name,
-                                    void **value, size_t *len)
+                                    const struct qstr *qstr,
+                                    struct xattr *xattrs, int *xattr_count)
  {
        struct task_smack *tsp = smack_cred(current_cred());
-       struct inode_smack *issp = smack_inode(inode);
        struct smack_known *skp = smk_of_task(tsp);
        struct smack_known *isp = smk_of_inode(inode);
        struct smack_known *dsp = smk_of_inode(dir);
+       struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);
        int may;
  
-       if (name)
-               *name = XATTR_SMACK_SUFFIX;
-       if (value && len) {
+       if (xattr) {
                /*
                 * If equal, transmuting already occurred in
                 * smack_dentry_create_files_as(). No need to check again.
                if ((tsp->smk_task == tsp->smk_transmuted) ||
                    (may > 0 && ((may & MAY_TRANSMUTE) != 0) &&
                     smk_inode_transmutable(dir))) {
+                       struct xattr *xattr_transmute;
                        /*
                         * The caller of smack_dentry_create_files_as()
                         * should have overridden the current cred, so the
                         */
                        if (tsp->smk_task != tsp->smk_transmuted)
                                isp = dsp;
-                       issp->smk_flags |= SMK_INODE_CHANGED;
+                       xattr_transmute = lsm_get_xattr_slot(xattrs,
+                                                            xattr_count);
+                       if (xattr_transmute) {
+                               xattr_transmute->value = kmemdup(TRANS_TRUE,
+                                                                TRANS_TRUE_SIZE,
+                                                                GFP_NOFS);
+                               if (!xattr_transmute->value)
+                                       return -ENOMEM;
+                               xattr_transmute->value_len = TRANS_TRUE_SIZE;
+                               xattr_transmute->name = XATTR_SMACK_TRANSMUTE;
+                       }
                }
  
-               *value = kstrdup(isp->smk_known, GFP_NOFS);
-               if (*value == NULL)
+               xattr->value = kstrdup(isp->smk_known, GFP_NOFS);
+               if (!xattr->value)
                        return -ENOMEM;
  
-               *len = strlen(isp->smk_known);
+               xattr->value_len = strlen(isp->smk_known);
+               xattr->name = XATTR_SMACK_SUFFIX;
        }
  
        return 0;
@@@ -3568,20 -3537,12 +3587,12 @@@ static void smack_d_instantiate(struct 
                         * If there is a transmute attribute on the
                         * directory mark the inode.
                         */
-                       if (isp->smk_flags & SMK_INODE_CHANGED) {
-                               isp->smk_flags &= ~SMK_INODE_CHANGED;
-                               rc = __vfs_setxattr(&nop_mnt_idmap, dp, inode,
-                                       XATTR_NAME_SMACKTRANSMUTE,
-                                       TRANS_TRUE, TRANS_TRUE_SIZE,
-                                       0);
-                       } else {
-                               rc = __vfs_getxattr(dp, inode,
-                                       XATTR_NAME_SMACKTRANSMUTE, trattr,
-                                       TRANS_TRUE_SIZE);
-                               if (rc >= 0 && strncmp(trattr, TRANS_TRUE,
-                                                      TRANS_TRUE_SIZE) != 0)
-                                       rc = -EINVAL;
-                       }
+                       rc = __vfs_getxattr(dp, inode,
+                                           XATTR_NAME_SMACKTRANSMUTE, trattr,
+                                           TRANS_TRUE_SIZE);
+                       if (rc >= 0 && strncmp(trattr, TRANS_TRUE,
+                                              TRANS_TRUE_SIZE) != 0)
+                               rc = -EINVAL;
                        if (rc >= 0)
                                transflag = SMK_INODE_TRANSMUTE;
                }
@@@ -4919,6 -4880,7 +4930,7 @@@ struct lsm_blob_sizes smack_blob_sizes 
        .lbs_ipc = sizeof(struct smack_known *),
        .lbs_msg_msg = sizeof(struct smack_known *),
        .lbs_superblock = sizeof(struct superblock_smack),
+       .lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
  };
  
  static struct security_hook_list smack_hooks[] __ro_after_init = {
        LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
        LSM_HOOK_INIT(syslog, smack_syslog),
  
 +      LSM_HOOK_INIT(fs_context_submount, smack_fs_context_submount),
        LSM_HOOK_INIT(fs_context_dup, smack_fs_context_dup),
        LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param),