Merge tag 'selinux-pr-20190312' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Mar 2019 18:10:42 +0000 (11:10 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Mar 2019 18:10:42 +0000 (11:10 -0700)
Pull selinux fixes from Paul Moore:
 "Two small fixes for SELinux in v5.1: one adds a buffer length check to
  the SELinux SCTP code, the other ensures that the SELinux labeling for
  a NFS mount is not disabled if the filesystem is mounted twice"

* tag 'selinux-pr-20190312' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  security/selinux: fix SECURITY_LSM_NATIVE_LABELS on reused superblock
  selinux: add the missing walk_size + len check in selinux_sctp_bind_connect

1  2 
security/selinux/hooks.c

diff --combined security/selinux/hooks.c
@@@ -48,8 -48,6 +48,8 @@@
  #include <linux/fdtable.h>
  #include <linux/namei.h>
  #include <linux/mount.h>
 +#include <linux/fs_context.h>
 +#include <linux/fs_parser.h>
  #include <linux/netfilter_ipv4.h>
  #include <linux/netfilter_ipv6.h>
  #include <linux/tty.h>
@@@ -81,6 -79,7 +81,6 @@@
  #include <linux/personality.h>
  #include <linux/audit.h>
  #include <linux/string.h>
 -#include <linux/selinux.h>
  #include <linux/mutex.h>
  #include <linux/posix-timers.h>
  #include <linux/syslog.h>
@@@ -122,8 -121,9 +122,8 @@@ __setup("enforcing=", enforcing_setup)
  #define selinux_enforcing_boot 1
  #endif
  
 +int selinux_enabled __lsm_ro_after_init = 1;
  #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
 -int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
 -
  static int __init selinux_enabled_setup(char *str)
  {
        unsigned long enabled;
        return 1;
  }
  __setup("selinux=", selinux_enabled_setup);
 -#else
 -int selinux_enabled = 1;
  #endif
  
  static unsigned int selinux_checkreqprot_boot =
@@@ -147,6 -149,9 +147,6 @@@ static int __init checkreqprot_setup(ch
  }
  __setup("checkreqprot=", checkreqprot_setup);
  
 -static struct kmem_cache *sel_inode_cache;
 -static struct kmem_cache *file_security_cache;
 -
  /**
   * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
   *
@@@ -209,8 -214,12 +209,8 @@@ static void cred_init_security(void
        struct cred *cred = (struct cred *) current->real_cred;
        struct task_security_struct *tsec;
  
 -      tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
 -      if (!tsec)
 -              panic("SELinux:  Failed to initialize initial task.\n");
 -
 +      tsec = selinux_cred(cred);
        tsec->osid = tsec->sid = SECINITSID_KERNEL;
 -      cred->security = tsec;
  }
  
  /*
@@@ -220,7 -229,7 +220,7 @@@ static inline u32 cred_sid(const struc
  {
        const struct task_security_struct *tsec;
  
 -      tsec = cred->security;
 +      tsec = selinux_cred(cred);
        return tsec->sid;
  }
  
@@@ -241,9 -250,13 +241,9 @@@ static inline u32 task_sid(const struc
  
  static int inode_alloc_security(struct inode *inode)
  {
 -      struct inode_security_struct *isec;
 +      struct inode_security_struct *isec = selinux_inode(inode);
        u32 sid = current_sid();
  
 -      isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
 -      if (!isec)
 -              return -ENOMEM;
 -
        spin_lock_init(&isec->lock);
        INIT_LIST_HEAD(&isec->list);
        isec->inode = inode;
        isec->sclass = SECCLASS_FILE;
        isec->task_sid = sid;
        isec->initialized = LABEL_INVALID;
 -      inode->i_security = isec;
  
        return 0;
  }
@@@ -267,7 -281,7 +267,7 @@@ static int __inode_security_revalidate(
                                       struct dentry *dentry,
                                       bool may_sleep)
  {
 -      struct inode_security_struct *isec = inode->i_security;
 +      struct inode_security_struct *isec = selinux_inode(inode);
  
        might_sleep_if(may_sleep);
  
  
  static struct inode_security_struct *inode_security_novalidate(struct inode *inode)
  {
 -      return inode->i_security;
 +      return selinux_inode(inode);
  }
  
  static struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu)
        error = __inode_security_revalidate(inode, NULL, !rcu);
        if (error)
                return ERR_PTR(error);
 -      return inode->i_security;
 +      return selinux_inode(inode);
  }
  
  /*
  static struct inode_security_struct *inode_security(struct inode *inode)
  {
        __inode_security_revalidate(inode, NULL, true);
 -      return inode->i_security;
 +      return selinux_inode(inode);
  }
  
  static struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry)
  {
        struct inode *inode = d_backing_inode(dentry);
  
 -      return inode->i_security;
 +      return selinux_inode(inode);
  }
  
  /*
@@@ -325,17 -339,22 +325,17 @@@ static struct inode_security_struct *ba
        struct inode *inode = d_backing_inode(dentry);
  
        __inode_security_revalidate(inode, dentry, true);
 -      return inode->i_security;
 -}
 -
 -static void inode_free_rcu(struct rcu_head *head)
 -{
 -      struct inode_security_struct *isec;
 -
 -      isec = container_of(head, struct inode_security_struct, rcu);
 -      kmem_cache_free(sel_inode_cache, isec);
 +      return selinux_inode(inode);
  }
  
  static void inode_free_security(struct inode *inode)
  {
 -      struct inode_security_struct *isec = inode->i_security;
 -      struct superblock_security_struct *sbsec = inode->i_sb->s_security;
 +      struct inode_security_struct *isec = selinux_inode(inode);
 +      struct superblock_security_struct *sbsec;
  
 +      if (!isec)
 +              return;
 +      sbsec = inode->i_sb->s_security;
        /*
         * As not all inode security structures are in a list, we check for
         * empty list outside of the lock to make sure that we won't waste
                list_del_init(&isec->list);
                spin_unlock(&sbsec->isec_lock);
        }
 -
 -      /*
 -       * The inode may still be referenced in a path walk and
 -       * a call to selinux_inode_permission() can be made
 -       * after inode_free_security() is called. Ideally, the VFS
 -       * wouldn't do this, but fixing that is a much harder
 -       * job. For now, simply free the i_security via RCU, and
 -       * leave the current inode->i_security pointer intact.
 -       * The inode will be freed after the RCU grace period too.
 -       */
 -      call_rcu(&isec->rcu, inode_free_rcu);
  }
  
  static int file_alloc_security(struct file *file)
  {
 -      struct file_security_struct *fsec;
 +      struct file_security_struct *fsec = selinux_file(file);
        u32 sid = current_sid();
  
 -      fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
 -      if (!fsec)
 -              return -ENOMEM;
 -
        fsec->sid = sid;
        fsec->fown_sid = sid;
 -      file->f_security = fsec;
  
        return 0;
  }
  
 -static void file_free_security(struct file *file)
 -{
 -      struct file_security_struct *fsec = file->f_security;
 -      file->f_security = NULL;
 -      kmem_cache_free(file_security_cache, fsec);
 -}
 -
  static int superblock_alloc_security(struct super_block *sb)
  {
        struct superblock_security_struct *sbsec;
@@@ -412,11 -454,11 +412,11 @@@ static inline int inode_doinit(struct i
  
  enum {
        Opt_error = -1,
 -      Opt_context = 1,
 +      Opt_context = 0,
 +      Opt_defcontext = 1,
        Opt_fscontext = 2,
 -      Opt_defcontext = 3,
 -      Opt_rootcontext = 4,
 -      Opt_seclabel = 5,
 +      Opt_rootcontext = 3,
 +      Opt_seclabel = 4,
  };
  
  #define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg}
@@@ -459,7 -501,7 +459,7 @@@ static int may_context_mount_sb_relabel
                        struct superblock_security_struct *sbsec,
                        const struct cred *cred)
  {
 -      const struct task_security_struct *tsec = cred->security;
 +      const struct task_security_struct *tsec = selinux_cred(cred);
        int rc;
  
        rc = avc_has_perm(&selinux_state,
@@@ -478,7 -520,7 +478,7 @@@ static int may_context_mount_inode_rela
                        struct superblock_security_struct *sbsec,
                        const struct cred *cred)
  {
 -      const struct task_security_struct *tsec = cred->security;
 +      const struct task_security_struct *tsec = selinux_cred(cred);
        int rc;
        rc = avc_has_perm(&selinux_state,
                          tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
@@@ -939,8 -981,11 +939,11 @@@ static int selinux_sb_clone_mnt_opts(co
        BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
  
        /* if fs is reusing a sb, make sure that the contexts match */
-       if (newsbsec->flags & SE_SBINITIALIZED)
+       if (newsbsec->flags & SE_SBINITIALIZED) {
+               if ((kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context)
+                       *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
                return selinux_cmp_sb_context(oldsb, newsb);
+       }
  
        mutex_lock(&newsbsec->lock);
  
@@@ -1069,7 -1114,6 +1072,7 @@@ static int show_sid(struct seq_file *m
        if (!rc) {
                bool has_comma = context && strchr(context, ',');
  
 +              seq_putc(m, '=');
                if (has_comma)
                        seq_putc(m, '\"');
                seq_escape(m, context, "\"\n\\");
@@@ -1123,7 -1167,7 +1126,7 @@@ static int selinux_sb_show_options(stru
        }
        if (sbsec->flags & SBLABEL_MNT) {
                seq_putc(m, ',');
 -              seq_puts(m, LABELSUPP_STR);
 +              seq_puts(m, SECLABEL_STR);
        }
        return 0;
  }
@@@ -1355,7 -1399,7 +1358,7 @@@ static int selinux_genfs_get_sid(struc
  static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
  {
        struct superblock_security_struct *sbsec = NULL;
 -      struct inode_security_struct *isec = inode->i_security;
 +      struct inode_security_struct *isec = selinux_inode(inode);
        u32 task_sid, sid = 0;
        u16 sclass;
        struct dentry *dentry;
@@@ -1602,7 -1646,7 +1605,7 @@@ static inline u32 signal_to_av(int sig
  
  /* Check whether a task is allowed to use a capability. */
  static int cred_has_capability(const struct cred *cred,
 -                             int cap, int audit, bool initns)
 +                             int cap, unsigned int opts, bool initns)
  {
        struct common_audit_data ad;
        struct av_decision avd;
  
        rc = avc_has_perm_noaudit(&selinux_state,
                                  sid, sid, sclass, av, 0, &avd);
 -      if (audit == SECURITY_CAP_AUDIT) {
 +      if (!(opts & CAP_OPT_NOAUDIT)) {
                int rc2 = avc_audit(&selinux_state,
                                    sid, sid, sclass, av, &avd, rc, &ad, 0);
                if (rc2)
@@@ -1655,7 -1699,7 +1658,7 @@@ static int inode_has_perm(const struct 
                return 0;
  
        sid = cred_sid(cred);
 -      isec = inode->i_security;
 +      isec = selinux_inode(inode);
  
        return avc_has_perm(&selinux_state,
                            sid, isec->sid, isec->sclass, perms, adp);
@@@ -1721,7 -1765,7 +1724,7 @@@ static int file_has_perm(const struct c
                         struct file *file,
                         u32 av)
  {
 -      struct file_security_struct *fsec = file->f_security;
 +      struct file_security_struct *fsec = selinux_file(file);
        struct inode *inode = file_inode(file);
        struct common_audit_data ad;
        u32 sid = cred_sid(cred);
@@@ -1787,7 -1831,7 +1790,7 @@@ static int may_create(struct inode *dir
                      struct dentry *dentry,
                      u16 tclass)
  {
 -      const struct task_security_struct *tsec = current_security();
 +      const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid;
        if (rc)
                return rc;
  
 -      rc = selinux_determine_inode_label(current_security(), dir,
 +      rc = selinux_determine_inode_label(selinux_cred(current_cred()), dir,
                                           &dentry->d_name, tclass, &newsid);
        if (rc)
                return rc;
@@@ -2065,7 -2109,7 +2068,7 @@@ static int selinux_binder_transfer_file
                                        struct file *file)
  {
        u32 sid = task_sid(to);
 -      struct file_security_struct *fsec = file->f_security;
 +      struct file_security_struct *fsec = selinux_file(file);
        struct dentry *dentry = file->f_path.dentry;
        struct inode_security_struct *isec;
        struct common_audit_data ad;
@@@ -2149,9 -2193,9 +2152,9 @@@ static int selinux_capset(struct cred *
   */
  
  static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
 -                         int cap, int audit)
 +                         int cap, unsigned int opts)
  {
 -      return cred_has_capability(cred, cap, audit, ns == &init_user_ns);
 +      return cred_has_capability(cred, cap, opts, ns == &init_user_ns);
  }
  
  static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
@@@ -2225,7 -2269,7 +2228,7 @@@ static int selinux_vm_enough_memory(str
        int rc, cap_sys_admin = 0;
  
        rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
 -                               SECURITY_CAP_NOAUDIT, true);
 +                               CAP_OPT_NOAUDIT, true);
        if (rc == 0)
                cap_sys_admin = 1;
  
@@@ -2316,8 -2360,8 +2319,8 @@@ static int selinux_bprm_set_creds(struc
        if (bprm->called_set_creds)
                return 0;
  
 -      old_tsec = current_security();
 -      new_tsec = bprm->cred->security;
 +      old_tsec = selinux_cred(current_cred());
 +      new_tsec = selinux_cred(bprm->cred);
        isec = inode_security(inode);
  
        /* Default to the current task SID. */
@@@ -2481,7 -2525,7 +2484,7 @@@ static void selinux_bprm_committing_cre
        struct rlimit *rlim, *initrlim;
        int rc, i;
  
 -      new_tsec = bprm->cred->security;
 +      new_tsec = selinux_cred(bprm->cred);
        if (new_tsec->sid == new_tsec->osid)
                return;
  
   */
  static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
  {
 -      const struct task_security_struct *tsec = current_security();
 +      const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct itimerval itimer;
        u32 osid, sid;
        int rc, i;
@@@ -2742,76 -2786,6 +2745,76 @@@ static int selinux_umount(struct vfsmou
                                   FILESYSTEM__UNMOUNT, NULL);
  }
  
 +static int selinux_fs_context_dup(struct fs_context *fc,
 +                                struct fs_context *src_fc)
 +{
 +      const struct selinux_mnt_opts *src = src_fc->security;
 +      struct selinux_mnt_opts *opts;
 +
 +      if (!src)
 +              return 0;
 +
 +      fc->security = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
 +      if (!fc->security)
 +              return -ENOMEM;
 +
 +      opts = fc->security;
 +
 +      if (src->fscontext) {
 +              opts->fscontext = kstrdup(src->fscontext, GFP_KERNEL);
 +              if (!opts->fscontext)
 +                      return -ENOMEM;
 +      }
 +      if (src->context) {
 +              opts->context = kstrdup(src->context, GFP_KERNEL);
 +              if (!opts->context)
 +                      return -ENOMEM;
 +      }
 +      if (src->rootcontext) {
 +              opts->rootcontext = kstrdup(src->rootcontext, GFP_KERNEL);
 +              if (!opts->rootcontext)
 +                      return -ENOMEM;
 +      }
 +      if (src->defcontext) {
 +              opts->defcontext = kstrdup(src->defcontext, GFP_KERNEL);
 +              if (!opts->defcontext)
 +                      return -ENOMEM;
 +      }
 +      return 0;
 +}
 +
 +static const struct fs_parameter_spec selinux_param_specs[] = {
 +      fsparam_string(CONTEXT_STR,     Opt_context),
 +      fsparam_string(DEFCONTEXT_STR,  Opt_defcontext),
 +      fsparam_string(FSCONTEXT_STR,   Opt_fscontext),
 +      fsparam_string(ROOTCONTEXT_STR, Opt_rootcontext),
 +      fsparam_flag  (SECLABEL_STR,    Opt_seclabel),
 +      {}
 +};
 +
 +static const struct fs_parameter_description selinux_fs_parameters = {
 +      .name           = "SELinux",
 +      .specs          = selinux_param_specs,
 +};
 +
 +static int selinux_fs_context_parse_param(struct fs_context *fc,
 +                                        struct fs_parameter *param)
 +{
 +      struct fs_parse_result result;
 +      int opt, rc;
 +
 +      opt = fs_parse(fc, &selinux_fs_parameters, param, &result);
 +      if (opt < 0)
 +              return opt;
 +
 +      rc = selinux_add_opt(opt, param->string, &fc->security);
 +      if (!rc) {
 +              param->string = NULL;
 +              rc = 1;
 +      }
 +      return rc;
 +}
 +
  /* inode security operations */
  
  static int selinux_inode_alloc_security(struct inode *inode)
@@@ -2831,7 -2805,7 +2834,7 @@@ static int selinux_dentry_init_security
        u32 newsid;
        int rc;
  
 -      rc = selinux_determine_inode_label(current_security(),
 +      rc = selinux_determine_inode_label(selinux_cred(current_cred()),
                                           d_inode(dentry->d_parent), name,
                                           inode_mode_to_security_class(mode),
                                           &newsid);
@@@ -2851,14 -2825,14 +2854,14 @@@ static int selinux_dentry_create_files_
        int rc;
        struct task_security_struct *tsec;
  
 -      rc = selinux_determine_inode_label(old->security,
 +      rc = selinux_determine_inode_label(selinux_cred(old),
                                           d_inode(dentry->d_parent), name,
                                           inode_mode_to_security_class(mode),
                                           &newsid);
        if (rc)
                return rc;
  
 -      tsec = new->security;
 +      tsec = selinux_cred(new);
        tsec->create_sid = newsid;
        return 0;
  }
@@@ -2868,7 -2842,7 +2871,7 @@@ static int selinux_inode_init_security(
                                       const char **name,
                                       void **value, size_t *len)
  {
 -      const struct task_security_struct *tsec = current_security();
 +      const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct superblock_security_struct *sbsec;
        u32 newsid, clen;
        int rc;
  
        newsid = tsec->create_sid;
  
 -      rc = selinux_determine_inode_label(current_security(),
 +      rc = selinux_determine_inode_label(selinux_cred(current_cred()),
                dir, qstr,
                inode_mode_to_security_class(inode->i_mode),
                &newsid);
  
        /* Possibly defer initialization to selinux_complete_init. */
        if (sbsec->flags & SE_SBINITIALIZED) {
 -              struct inode_security_struct *isec = inode->i_security;
 +              struct inode_security_struct *isec = selinux_inode(inode);
                isec->sclass = inode_mode_to_security_class(inode->i_mode);
                isec->sid = newsid;
                isec->initialized = LABEL_INITIALIZED;
@@@ -2986,7 -2960,7 +2989,7 @@@ static noinline int audit_inode_permiss
                                           unsigned flags)
  {
        struct common_audit_data ad;
 -      struct inode_security_struct *isec = inode->i_security;
 +      struct inode_security_struct *isec = selinux_inode(inode);
        int rc;
  
        ad.type = LSM_AUDIT_DATA_INODE;
@@@ -3083,11 -3057,11 +3086,11 @@@ static int selinux_inode_getattr(const 
  static bool has_cap_mac_admin(bool audit)
  {
        const struct cred *cred = current_cred();
 -      int cap_audit = audit ? SECURITY_CAP_AUDIT : SECURITY_CAP_NOAUDIT;
 +      unsigned int opts = audit ? CAP_OPT_NONE : CAP_OPT_NOAUDIT;
  
 -      if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, cap_audit))
 +      if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts))
                return false;
 -      if (cred_has_capability(cred, CAP_MAC_ADMIN, cap_audit, true))
 +      if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true))
                return false;
        return true;
  }
@@@ -3345,7 -3319,7 +3348,7 @@@ static int selinux_inode_copy_up(struc
                        return -ENOMEM;
        }
  
 -      tsec = new_creds->security;
 +      tsec = selinux_cred(new_creds);
        /* Get label from overlay inode and set it in create_sid */
        selinux_inode_getsecid(d_inode(src), &sid);
        tsec->create_sid = sid;
@@@ -3386,7 -3360,7 +3389,7 @@@ static int selinux_revalidate_file_perm
  static int selinux_file_permission(struct file *file, int mask)
  {
        struct inode *inode = file_inode(file);
 -      struct file_security_struct *fsec = file->f_security;
 +      struct file_security_struct *fsec = selinux_file(file);
        struct inode_security_struct *isec;
        u32 sid = current_sid();
  
@@@ -3408,6 -3382,11 +3411,6 @@@ static int selinux_file_alloc_security(
        return file_alloc_security(file);
  }
  
 -static void selinux_file_free_security(struct file *file)
 -{
 -      file_free_security(file);
 -}
 -
  /*
   * Check whether a task has the ioctl permission and cmd
   * operation to an inode.
@@@ -3416,7 -3395,7 +3419,7 @@@ static int ioctl_has_perm(const struct 
                u32 requested, u16 cmd)
  {
        struct common_audit_data ad;
 -      struct file_security_struct *fsec = file->f_security;
 +      struct file_security_struct *fsec = selinux_file(file);
        struct inode *inode = file_inode(file);
        struct inode_security_struct *isec;
        struct lsm_ioctlop_audit ioctl;
@@@ -3486,7 -3465,7 +3489,7 @@@ static int selinux_file_ioctl(struct fi
        case KDSKBENT:
        case KDSKBSENT:
                error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
 -                                          SECURITY_CAP_AUDIT, true);
 +                                          CAP_OPT_NONE, true);
                break;
  
        /* default case assumes that the command will go
@@@ -3668,7 -3647,7 +3671,7 @@@ static void selinux_file_set_fowner(str
  {
        struct file_security_struct *fsec;
  
 -      fsec = file->f_security;
 +      fsec = selinux_file(file);
        fsec->fown_sid = current_sid();
  }
  
@@@ -3683,7 -3662,7 +3686,7 @@@ static int selinux_file_send_sigiotask(
        /* struct fown_struct is never outside the context of a struct file */
        file = container_of(fown, struct file, f_owner);
  
 -      fsec = file->f_security;
 +      fsec = selinux_file(file);
  
        if (!signum)
                perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
@@@ -3707,7 -3686,7 +3710,7 @@@ static int selinux_file_open(struct fil
        struct file_security_struct *fsec;
        struct inode_security_struct *isec;
  
 -      fsec = file->f_security;
 +      fsec = selinux_file(file);
        isec = inode_security(file_inode(file));
        /*
         * Save inode label and policy sequence number
@@@ -3740,16 -3719,53 +3743,16 @@@ static int selinux_task_alloc(struct ta
                            sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
  }
  
 -/*
 - * allocate the SELinux part of blank credentials
 - */
 -static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 -{
 -      struct task_security_struct *tsec;
 -
 -      tsec = kzalloc(sizeof(struct task_security_struct), gfp);
 -      if (!tsec)
 -              return -ENOMEM;
 -
 -      cred->security = tsec;
 -      return 0;
 -}
 -
 -/*
 - * detach and free the LSM part of a set of credentials
 - */
 -static void selinux_cred_free(struct cred *cred)
 -{
 -      struct task_security_struct *tsec = cred->security;
 -
 -      /*
 -       * cred->security == NULL if security_cred_alloc_blank() or
 -       * security_prepare_creds() returned an error.
 -       */
 -      BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
 -      cred->security = (void *) 0x7UL;
 -      kfree(tsec);
 -}
 -
  /*
   * prepare a new set of credentials for modification
   */
  static int selinux_cred_prepare(struct cred *new, const struct cred *old,
                                gfp_t gfp)
  {
 -      const struct task_security_struct *old_tsec;
 -      struct task_security_struct *tsec;
 -
 -      old_tsec = old->security;
 -
 -      tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
 -      if (!tsec)
 -              return -ENOMEM;
 +      const struct task_security_struct *old_tsec = selinux_cred(old);
 +      struct task_security_struct *tsec = selinux_cred(new);
  
 -      new->security = tsec;
 +      *tsec = *old_tsec;
        return 0;
  }
  
   */
  static void selinux_cred_transfer(struct cred *new, const struct cred *old)
  {
 -      const struct task_security_struct *old_tsec = old->security;
 -      struct task_security_struct *tsec = new->security;
 +      const struct task_security_struct *old_tsec = selinux_cred(old);
 +      struct task_security_struct *tsec = selinux_cred(new);
  
        *tsec = *old_tsec;
  }
@@@ -3775,7 -3791,7 +3778,7 @@@ static void selinux_cred_getsecid(cons
   */
  static int selinux_kernel_act_as(struct cred *new, u32 secid)
  {
 -      struct task_security_struct *tsec = new->security;
 +      struct task_security_struct *tsec = selinux_cred(new);
        u32 sid = current_sid();
        int ret;
  
  static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
  {
        struct inode_security_struct *isec = inode_security(inode);
 -      struct task_security_struct *tsec = new->security;
 +      struct task_security_struct *tsec = selinux_cred(new);
        u32 sid = current_sid();
        int ret;
  
@@@ -3846,7 -3862,7 +3849,7 @@@ static int selinux_kernel_module_from_f
        ad.type = LSM_AUDIT_DATA_FILE;
        ad.u.file = file;
  
 -      fsec = file->f_security;
 +      fsec = selinux_file(file);
        if (sid != fsec->sid) {
                rc = avc_has_perm(&selinux_state,
                                  sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
@@@ -4012,7 -4028,7 +4015,7 @@@ static int selinux_task_kill(struct tas
  static void selinux_task_to_inode(struct task_struct *p,
                                  struct inode *inode)
  {
 -      struct inode_security_struct *isec = inode->i_security;
 +      struct inode_security_struct *isec = selinux_inode(inode);
        u32 sid = task_sid(p);
  
        spin_lock(&isec->lock);
@@@ -4349,7 -4365,7 +4352,7 @@@ static int sock_has_perm(struct sock *s
  static int selinux_socket_create(int family, int type,
                                 int protocol, int kern)
  {
 -      const struct task_security_struct *tsec = current_security();
 +      const struct task_security_struct *tsec = selinux_cred(current_cred());
        u32 newsid;
        u16 secclass;
        int rc;
  static int selinux_socket_post_create(struct socket *sock, int family,
                                      int type, int protocol, int kern)
  {
 -      const struct task_security_struct *tsec = current_security();
 +      const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock));
        struct sk_security_struct *sksec;
        u16 sclass = socket_type_to_security_class(family, type, protocol);
@@@ -4545,7 -4561,7 +4548,7 @@@ err_af
  }
  
  /* This supports connect(2) and SCTP connect services such as sctp_connectx(3)
 - * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.rst
 + * and sctp_sendmsg(3) as described in Documentation/security/SCTP.rst
   */
  static int selinux_socket_connect_helper(struct socket *sock,
                                         struct sockaddr *address, int addrlen)
@@@ -5134,6 -5150,9 +5137,9 @@@ static int selinux_sctp_bind_connect(st
                        return -EINVAL;
                }
  
+               if (walk_size + len > addrlen)
+                       return -EINVAL;
                err = -EINVAL;
                switch (optname) {
                /* Bind checks */
@@@ -5250,7 -5269,7 +5256,7 @@@ static int selinux_secmark_relabel_pack
        const struct task_security_struct *__tsec;
        u32 tsid;
  
 -      __tsec = current_security();
 +      __tsec = selinux_cred(current_cred());
        tsid = __tsec->sid;
  
        return avc_has_perm(&selinux_state,
@@@ -5725,22 -5744,51 +5731,22 @@@ static int selinux_netlink_send(struct 
        return selinux_nlmsg_perm(sk, skb);
  }
  
 -static int ipc_alloc_security(struct kern_ipc_perm *perm,
 -                            u16 sclass)
 +static void ipc_init_security(struct ipc_security_struct *isec, u16 sclass)
  {
 -      struct ipc_security_struct *isec;
 -
 -      isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
 -      if (!isec)
 -              return -ENOMEM;
 -
        isec->sclass = sclass;
        isec->sid = current_sid();
 -      perm->security = isec;
 -
 -      return 0;
 -}
 -
 -static void ipc_free_security(struct kern_ipc_perm *perm)
 -{
 -      struct ipc_security_struct *isec = perm->security;
 -      perm->security = NULL;
 -      kfree(isec);
  }
  
  static int msg_msg_alloc_security(struct msg_msg *msg)
  {
        struct msg_security_struct *msec;
  
 -      msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
 -      if (!msec)
 -              return -ENOMEM;
 -
 +      msec = selinux_msg_msg(msg);
        msec->sid = SECINITSID_UNLABELED;
 -      msg->security = msec;
  
        return 0;
  }
  
 -static void msg_msg_free_security(struct msg_msg *msg)
 -{
 -      struct msg_security_struct *msec = msg->security;
 -
 -      msg->security = NULL;
 -      kfree(msec);
 -}
 -
  static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
                        u32 perms)
  {
        struct common_audit_data ad;
        u32 sid = current_sid();
  
 -      isec = ipc_perms->security;
 +      isec = selinux_ipc(ipc_perms);
  
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = ipc_perms->key;
@@@ -5762,6 -5810,11 +5768,6 @@@ static int selinux_msg_msg_alloc_securi
        return msg_msg_alloc_security(msg);
  }
  
 -static void selinux_msg_msg_free_security(struct msg_msg *msg)
 -{
 -      msg_msg_free_security(msg);
 -}
 -
  /* message queue security operations */
  static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
  {
        u32 sid = current_sid();
        int rc;
  
 -      rc = ipc_alloc_security(msq, SECCLASS_MSGQ);
 -      if (rc)
 -              return rc;
 -
 -      isec = msq->security;
 +      isec = selinux_ipc(msq);
 +      ipc_init_security(isec, SECCLASS_MSGQ);
  
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->key;
        rc = avc_has_perm(&selinux_state,
                          sid, isec->sid, SECCLASS_MSGQ,
                          MSGQ__CREATE, &ad);
 -      if (rc) {
 -              ipc_free_security(msq);
 -              return rc;
 -      }
 -      return 0;
 -}
 -
 -static void selinux_msg_queue_free_security(struct kern_ipc_perm *msq)
 -{
 -      ipc_free_security(msq);
 +      return rc;
  }
  
  static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
        struct common_audit_data ad;
        u32 sid = current_sid();
  
 -      isec = msq->security;
 +      isec = selinux_ipc(msq);
  
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->key;
@@@ -5837,8 -5902,8 +5843,8 @@@ static int selinux_msg_queue_msgsnd(str
        u32 sid = current_sid();
        int rc;
  
 -      isec = msq->security;
 -      msec = msg->security;
 +      isec = selinux_ipc(msq);
 +      msec = selinux_msg_msg(msg);
  
        /*
         * First time through, need to assign label to the message
@@@ -5885,8 -5950,8 +5891,8 @@@ static int selinux_msg_queue_msgrcv(str
        u32 sid = task_sid(target);
        int rc;
  
 -      isec = msq->security;
 -      msec = msg->security;
 +      isec = selinux_ipc(msq);
 +      msec = selinux_msg_msg(msg);
  
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->key;
@@@ -5909,8 -5974,11 +5915,8 @@@ static int selinux_shm_alloc_security(s
        u32 sid = current_sid();
        int rc;
  
 -      rc = ipc_alloc_security(shp, SECCLASS_SHM);
 -      if (rc)
 -              return rc;
 -
 -      isec = shp->security;
 +      isec = selinux_ipc(shp);
 +      ipc_init_security(isec, SECCLASS_SHM);
  
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = shp->key;
        rc = avc_has_perm(&selinux_state,
                          sid, isec->sid, SECCLASS_SHM,
                          SHM__CREATE, &ad);
 -      if (rc) {
 -              ipc_free_security(shp);
 -              return rc;
 -      }
 -      return 0;
 -}
 -
 -static void selinux_shm_free_security(struct kern_ipc_perm *shp)
 -{
 -      ipc_free_security(shp);
 +      return rc;
  }
  
  static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
        struct common_audit_data ad;
        u32 sid = current_sid();
  
 -      isec = shp->security;
 +      isec = selinux_ipc(shp);
  
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = shp->key;
@@@ -5994,8 -6071,11 +6000,8 @@@ static int selinux_sem_alloc_security(s
        u32 sid = current_sid();
        int rc;
  
 -      rc = ipc_alloc_security(sma, SECCLASS_SEM);
 -      if (rc)
 -              return rc;
 -
 -      isec = sma->security;
 +      isec = selinux_ipc(sma);
 +      ipc_init_security(isec, SECCLASS_SEM);
  
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = sma->key;
        rc = avc_has_perm(&selinux_state,
                          sid, isec->sid, SECCLASS_SEM,
                          SEM__CREATE, &ad);
 -      if (rc) {
 -              ipc_free_security(sma);
 -              return rc;
 -      }
 -      return 0;
 -}
 -
 -static void selinux_sem_free_security(struct kern_ipc_perm *sma)
 -{
 -      ipc_free_security(sma);
 +      return rc;
  }
  
  static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
        struct common_audit_data ad;
        u32 sid = current_sid();
  
 -      isec = sma->security;
 +      isec = selinux_ipc(sma);
  
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = sma->key;
@@@ -6098,7 -6187,7 +6104,7 @@@ static int selinux_ipc_permission(struc
  
  static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
  {
 -      struct ipc_security_struct *isec = ipcp->security;
 +      struct ipc_security_struct *isec = selinux_ipc(ipcp);
        *secid = isec->sid;
  }
  
@@@ -6117,7 -6206,7 +6123,7 @@@ static int selinux_getprocattr(struct t
        unsigned len;
  
        rcu_read_lock();
 -      __tsec = __task_cred(p)->security;
 +      __tsec = selinux_cred(__task_cred(p));
  
        if (current != p) {
                error = avc_has_perm(&selinux_state,
@@@ -6240,7 -6329,7 +6246,7 @@@ static int selinux_setprocattr(const ch
           operation.  See selinux_bprm_set_creds for the execve
           checks and may_create for the file creation checks. The
           operation will then fail if the context is not permitted. */
 -      tsec = new->security;
 +      tsec = selinux_cred(new);
        if (!strcmp(name, "exec")) {
                tsec->exec_sid = sid;
        } else if (!strcmp(name, "fscreate")) {
@@@ -6324,7 -6413,7 +6330,7 @@@ static void selinux_release_secctx(cha
  
  static void selinux_inode_invalidate_secctx(struct inode *inode)
  {
 -      struct inode_security_struct *isec = inode->i_security;
 +      struct inode_security_struct *isec = selinux_inode(inode);
  
        spin_lock(&isec->lock);
        isec->initialized = LABEL_INVALID;
@@@ -6372,7 -6461,7 +6378,7 @@@ static int selinux_key_alloc(struct ke
        if (!ksec)
                return -ENOMEM;
  
 -      tsec = cred->security;
 +      tsec = selinux_cred(cred);
        if (tsec->keycreate_sid)
                ksec->sid = tsec->keycreate_sid;
        else
@@@ -6635,14 -6724,6 +6641,14 @@@ static void selinux_bpf_prog_free(struc
  }
  #endif
  
 +struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
 +      .lbs_cred = sizeof(struct task_security_struct),
 +      .lbs_file = sizeof(struct file_security_struct),
 +      .lbs_inode = sizeof(struct inode_security_struct),
 +      .lbs_ipc = sizeof(struct ipc_security_struct),
 +      .lbs_msg_msg = sizeof(struct msg_security_struct),
 +};
 +
  static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
        LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
        LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
        LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
  
 +      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_alloc_security, selinux_sb_alloc_security),
        LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
        LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
  
        LSM_HOOK_INIT(file_permission, selinux_file_permission),
        LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
 -      LSM_HOOK_INIT(file_free_security, selinux_file_free_security),
        LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
        LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
        LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
        LSM_HOOK_INIT(file_open, selinux_file_open),
  
        LSM_HOOK_INIT(task_alloc, selinux_task_alloc),
 -      LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank),
 -      LSM_HOOK_INIT(cred_free, selinux_cred_free),
        LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
        LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
        LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
        LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
  
        LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security),
 -      LSM_HOOK_INIT(msg_msg_free_security, selinux_msg_msg_free_security),
  
        LSM_HOOK_INIT(msg_queue_alloc_security,
                        selinux_msg_queue_alloc_security),
 -      LSM_HOOK_INIT(msg_queue_free_security, selinux_msg_queue_free_security),
        LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
        LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
        LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd),
        LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv),
  
        LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security),
 -      LSM_HOOK_INIT(shm_free_security, selinux_shm_free_security),
        LSM_HOOK_INIT(shm_associate, selinux_shm_associate),
        LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl),
        LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat),
  
        LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
 -      LSM_HOOK_INIT(sem_free_security, selinux_sem_free_security),
        LSM_HOOK_INIT(sem_associate, selinux_sem_associate),
        LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl),
        LSM_HOOK_INIT(sem_semop, selinux_sem_semop),
  
  static __init int selinux_init(void)
  {
 -      if (!security_module_enable("selinux")) {
 -              selinux_enabled = 0;
 -              return 0;
 -      }
 -
 -      if (!selinux_enabled) {
 -              pr_info("SELinux:  Disabled at boot.\n");
 -              return 0;
 -      }
 -
        pr_info("SELinux:  Initializing.\n");
  
        memset(&selinux_state, 0, sizeof(selinux_state));
  
        default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
  
 -      sel_inode_cache = kmem_cache_create("selinux_inode_security",
 -                                          sizeof(struct inode_security_struct),
 -                                          0, SLAB_PANIC, NULL);
 -      file_security_cache = kmem_cache_create("selinux_file_security",
 -                                          sizeof(struct file_security_struct),
 -                                          0, SLAB_PANIC, NULL);
        avc_init();
  
        avtab_cache_init();
        else
                pr_debug("SELinux:  Starting in permissive mode\n");
  
 +      fs_validate_description(&selinux_fs_parameters);
 +
        return 0;
  }
  
@@@ -6936,9 -7035,6 +6942,9 @@@ void selinux_complete_init(void
     all processes and objects when they are created. */
  DEFINE_LSM(selinux) = {
        .name = "selinux",
 +      .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
 +      .enabled = &selinux_enabled,
 +      .blobs = &selinux_blob_sizes,
        .init = selinux_init,
  };