]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Aug 2022 11:14:34 +0000 (13:14 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Aug 2022 11:14:34 +0000 (13:14 +0200)
added patches:
proc-pass-file-mode-to-proc_pid_make_inode.patch
selinux-clean-up-initialization-of-isec-sclass.patch
selinux-convert-isec-lock-into-a-spinlock.patch
selinux-fix-error-initialization-in-inode_doinit_with_dentry.patch
selinux-fix-inode_doinit_with_dentry-label_invalid-error-handling.patch
selinux-minor-cleanups.patch

queue-4.9/proc-pass-file-mode-to-proc_pid_make_inode.patch [new file with mode: 0644]
queue-4.9/selinux-clean-up-initialization-of-isec-sclass.patch [new file with mode: 0644]
queue-4.9/selinux-convert-isec-lock-into-a-spinlock.patch [new file with mode: 0644]
queue-4.9/selinux-fix-error-initialization-in-inode_doinit_with_dentry.patch [new file with mode: 0644]
queue-4.9/selinux-fix-inode_doinit_with_dentry-label_invalid-error-handling.patch [new file with mode: 0644]
queue-4.9/selinux-minor-cleanups.patch [new file with mode: 0644]
queue-4.9/series

diff --git a/queue-4.9/proc-pass-file-mode-to-proc_pid_make_inode.patch b/queue-4.9/proc-pass-file-mode-to-proc_pid_make_inode.patch
new file mode 100644 (file)
index 0000000..2d94410
--- /dev/null
@@ -0,0 +1,182 @@
+From db978da8fa1d0819b210c137d31a339149b88875 Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruenba@redhat.com>
+Date: Thu, 10 Nov 2016 22:18:28 +0100
+Subject: proc: Pass file mode to proc_pid_make_inode
+
+From: Andreas Gruenbacher <agruenba@redhat.com>
+
+commit db978da8fa1d0819b210c137d31a339149b88875 upstream.
+
+Pass the file mode of the proc inode to be created to
+proc_pid_make_inode.  In proc_pid_make_inode, initialize inode->i_mode
+before calling security_task_to_inode.  This allows selinux to set
+isec->sclass right away without introducing "half-initialized" inode
+security structs.
+
+Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+Signed-off-by: Alexander Grund <theflamefire89@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/proc/base.c           |   23 +++++++++--------------
+ fs/proc/fd.c             |    6 ++----
+ fs/proc/internal.h       |    2 +-
+ fs/proc/namespaces.c     |    3 +--
+ security/selinux/hooks.c |    1 +
+ 5 files changed, 14 insertions(+), 21 deletions(-)
+
+--- a/fs/proc/base.c
++++ b/fs/proc/base.c
+@@ -1676,7 +1676,8 @@ const struct inode_operations proc_pid_l
+ /* building an inode */
+-struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
++struct inode *proc_pid_make_inode(struct super_block * sb,
++                                struct task_struct *task, umode_t mode)
+ {
+       struct inode * inode;
+       struct proc_inode *ei;
+@@ -1690,6 +1691,7 @@ struct inode *proc_pid_make_inode(struct
+       /* Common stuff */
+       ei = PROC_I(inode);
++      inode->i_mode = mode;
+       inode->i_ino = get_next_ino();
+       inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+       inode->i_op = &proc_def_inode_operations;
+@@ -2041,7 +2043,9 @@ proc_map_files_instantiate(struct inode
+       struct proc_inode *ei;
+       struct inode *inode;
+-      inode = proc_pid_make_inode(dir->i_sb, task);
++      inode = proc_pid_make_inode(dir->i_sb, task, S_IFLNK |
++                                  ((mode & FMODE_READ ) ? S_IRUSR : 0) |
++                                  ((mode & FMODE_WRITE) ? S_IWUSR : 0));
+       if (!inode)
+               return -ENOENT;
+@@ -2050,12 +2054,6 @@ proc_map_files_instantiate(struct inode
+       inode->i_op = &proc_map_files_link_inode_operations;
+       inode->i_size = 64;
+-      inode->i_mode = S_IFLNK;
+-
+-      if (mode & FMODE_READ)
+-              inode->i_mode |= S_IRUSR;
+-      if (mode & FMODE_WRITE)
+-              inode->i_mode |= S_IWUSR;
+       d_set_d_op(dentry, &tid_map_files_dentry_operations);
+       d_add(dentry, inode);
+@@ -2409,12 +2407,11 @@ static int proc_pident_instantiate(struc
+       struct inode *inode;
+       struct proc_inode *ei;
+-      inode = proc_pid_make_inode(dir->i_sb, task);
++      inode = proc_pid_make_inode(dir->i_sb, task, p->mode);
+       if (!inode)
+               goto out;
+       ei = PROC_I(inode);
+-      inode->i_mode = p->mode;
+       if (S_ISDIR(inode->i_mode))
+               set_nlink(inode, 2);    /* Use getattr to fix if necessary */
+       if (p->iop)
+@@ -3109,11 +3106,10 @@ static int proc_pid_instantiate(struct i
+ {
+       struct inode *inode;
+-      inode = proc_pid_make_inode(dir->i_sb, task);
++      inode = proc_pid_make_inode(dir->i_sb, task, S_IFDIR | S_IRUGO | S_IXUGO);
+       if (!inode)
+               goto out;
+-      inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+       inode->i_op = &proc_tgid_base_inode_operations;
+       inode->i_fop = &proc_tgid_base_operations;
+       inode->i_flags|=S_IMMUTABLE;
+@@ -3404,11 +3400,10 @@ static int proc_task_instantiate(struct
+       struct dentry *dentry, struct task_struct *task, const void *ptr)
+ {
+       struct inode *inode;
+-      inode = proc_pid_make_inode(dir->i_sb, task);
++      inode = proc_pid_make_inode(dir->i_sb, task, S_IFDIR | S_IRUGO | S_IXUGO);
+       if (!inode)
+               goto out;
+-      inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+       inode->i_op = &proc_tid_base_inode_operations;
+       inode->i_fop = &proc_tid_base_operations;
+       inode->i_flags|=S_IMMUTABLE;
+--- a/fs/proc/fd.c
++++ b/fs/proc/fd.c
+@@ -183,14 +183,13 @@ proc_fd_instantiate(struct inode *dir, s
+       struct proc_inode *ei;
+       struct inode *inode;
+-      inode = proc_pid_make_inode(dir->i_sb, task);
++      inode = proc_pid_make_inode(dir->i_sb, task, S_IFLNK);
+       if (!inode)
+               goto out;
+       ei = PROC_I(inode);
+       ei->fd = fd;
+-      inode->i_mode = S_IFLNK;
+       inode->i_op = &proc_pid_link_inode_operations;
+       inode->i_size = 64;
+@@ -322,14 +321,13 @@ proc_fdinfo_instantiate(struct inode *di
+       struct proc_inode *ei;
+       struct inode *inode;
+-      inode = proc_pid_make_inode(dir->i_sb, task);
++      inode = proc_pid_make_inode(dir->i_sb, task, S_IFREG | S_IRUSR);
+       if (!inode)
+               goto out;
+       ei = PROC_I(inode);
+       ei->fd = fd;
+-      inode->i_mode = S_IFREG | S_IRUSR;
+       inode->i_fop = &proc_fdinfo_file_operations;
+       d_set_d_op(dentry, &tid_fd_dentry_operations);
+--- a/fs/proc/internal.h
++++ b/fs/proc/internal.h
+@@ -163,7 +163,7 @@ extern int proc_pid_statm(struct seq_fil
+ extern const struct dentry_operations pid_dentry_operations;
+ extern int pid_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+ extern int proc_setattr(struct dentry *, struct iattr *);
+-extern struct inode *proc_pid_make_inode(struct super_block *, struct task_struct *);
++extern struct inode *proc_pid_make_inode(struct super_block *, struct task_struct *, umode_t);
+ extern int pid_revalidate(struct dentry *, unsigned int);
+ extern int pid_delete_dentry(const struct dentry *);
+ extern int proc_pid_readdir(struct file *, struct dir_context *);
+--- a/fs/proc/namespaces.c
++++ b/fs/proc/namespaces.c
+@@ -92,12 +92,11 @@ static int proc_ns_instantiate(struct in
+       struct inode *inode;
+       struct proc_inode *ei;
+-      inode = proc_pid_make_inode(dir->i_sb, task);
++      inode = proc_pid_make_inode(dir->i_sb, task, S_IFLNK | S_IRWXUGO);
+       if (!inode)
+               goto out;
+       ei = PROC_I(inode);
+-      inode->i_mode = S_IFLNK|S_IRWXUGO;
+       inode->i_op = &proc_ns_link_inode_operations;
+       ei->ns_ops = ns_ops;
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -3958,6 +3958,7 @@ static void selinux_task_to_inode(struct
+       struct inode_security_struct *isec = inode->i_security;
+       u32 sid = task_sid(p);
++      isec->sclass = inode_mode_to_security_class(inode->i_mode);
+       isec->sid = sid;
+       isec->initialized = LABEL_INITIALIZED;
+ }
diff --git a/queue-4.9/selinux-clean-up-initialization-of-isec-sclass.patch b/queue-4.9/selinux-clean-up-initialization-of-isec-sclass.patch
new file mode 100644 (file)
index 0000000..3d485af
--- /dev/null
@@ -0,0 +1,69 @@
+From 13457d073c29da92001f6ee809075eaa8757fb96 Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruenba@redhat.com>
+Date: Thu, 10 Nov 2016 22:18:29 +0100
+Subject: selinux: Clean up initialization of isec->sclass
+
+From: Andreas Gruenbacher <agruenba@redhat.com>
+
+commit 13457d073c29da92001f6ee809075eaa8757fb96 upstream.
+
+Now that isec->initialized == LABEL_INITIALIZED implies that
+isec->sclass is valid, skip such inodes immediately in
+inode_doinit_with_dentry.
+
+For the remaining inodes, initialize isec->sclass at the beginning of
+inode_doinit_with_dentry to simplify the code.
+
+Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+Signed-off-by: Alexander Grund <theflamefire89@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ security/selinux/hooks.c |   10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -1395,12 +1395,15 @@ static int inode_doinit_with_dentry(stru
+       int rc = 0;
+       if (isec->initialized == LABEL_INITIALIZED)
+-              goto out;
++              return 0;
+       mutex_lock(&isec->lock);
+       if (isec->initialized == LABEL_INITIALIZED)
+               goto out_unlock;
++      if (isec->sclass == SECCLASS_FILE)
++              isec->sclass = inode_mode_to_security_class(inode->i_mode);
++
+       sbsec = inode->i_sb->s_security;
+       if (!(sbsec->flags & SE_SBINITIALIZED)) {
+               /* Defer initialization until selinux_complete_init,
+@@ -1518,7 +1521,6 @@ static int inode_doinit_with_dentry(stru
+               isec->sid = sbsec->sid;
+               /* Try to obtain a transition SID. */
+-              isec->sclass = inode_mode_to_security_class(inode->i_mode);
+               rc = security_transition_sid(isec->task_sid, sbsec->sid,
+                                            isec->sclass, NULL, &sid);
+               if (rc)
+@@ -1554,7 +1556,6 @@ static int inode_doinit_with_dentry(stru
+                        */
+                       if (!dentry)
+                               goto out_unlock;
+-                      isec->sclass = inode_mode_to_security_class(inode->i_mode);
+                       rc = selinux_genfs_get_sid(dentry, isec->sclass,
+                                                  sbsec->flags, &sid);
+                       dput(dentry);
+@@ -1569,9 +1570,6 @@ static int inode_doinit_with_dentry(stru
+ out_unlock:
+       mutex_unlock(&isec->lock);
+-out:
+-      if (isec->sclass == SECCLASS_FILE)
+-              isec->sclass = inode_mode_to_security_class(inode->i_mode);
+       return rc;
+ }
diff --git a/queue-4.9/selinux-convert-isec-lock-into-a-spinlock.patch b/queue-4.9/selinux-convert-isec-lock-into-a-spinlock.patch
new file mode 100644 (file)
index 0000000..393976f
--- /dev/null
@@ -0,0 +1,331 @@
+From 9287aed2ad1ff1bde5eb190bcd6dccd5f1cf47d3 Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruenba@redhat.com>
+Date: Tue, 15 Nov 2016 11:06:40 +0100
+Subject: selinux: Convert isec->lock into a spinlock
+
+From: Andreas Gruenbacher <agruenba@redhat.com>
+
+commit 9287aed2ad1ff1bde5eb190bcd6dccd5f1cf47d3 upstream.
+
+Convert isec->lock from a mutex into a spinlock.  Instead of holding
+the lock while sleeping in inode_doinit_with_dentry, set
+isec->initialized to LABEL_PENDING and release the lock.  Then, when
+the sid has been determined, re-acquire the lock.  If isec->initialized
+is still set to LABEL_PENDING, set isec->sid; otherwise, the sid has
+been set by another task (LABEL_INITIALIZED) or invalidated
+(LABEL_INVALID) in the meantime.
+
+This fixes a deadlock on gfs2 where
+
+ * one task is in inode_doinit_with_dentry -> gfs2_getxattr, holds
+   isec->lock, and tries to acquire the inode's glock, and
+
+ * another task is in do_xmote -> inode_go_inval ->
+   selinux_inode_invalidate_secctx, holds the inode's glock, and
+   tries to acquire isec->lock.
+
+Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
+[PM: minor tweaks to keep checkpatch.pl happy]
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+Signed-off-by: Alexander Grund <theflamefire89@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ security/selinux/hooks.c          |  101 +++++++++++++++++++++++---------------
+ security/selinux/include/objsec.h |    5 +
+ 2 files changed, 66 insertions(+), 40 deletions(-)
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -231,7 +231,7 @@ static int inode_alloc_security(struct i
+       if (!isec)
+               return -ENOMEM;
+-      mutex_init(&isec->lock);
++      spin_lock_init(&isec->lock);
+       INIT_LIST_HEAD(&isec->list);
+       isec->inode = inode;
+       isec->sid = SECINITSID_UNLABELED;
+@@ -1387,7 +1387,8 @@ static int inode_doinit_with_dentry(stru
+ {
+       struct superblock_security_struct *sbsec = NULL;
+       struct inode_security_struct *isec = inode->i_security;
+-      u32 sid;
++      u32 task_sid, sid = 0;
++      u16 sclass;
+       struct dentry *dentry;
+ #define INITCONTEXTLEN 255
+       char *context = NULL;
+@@ -1397,7 +1398,7 @@ static int inode_doinit_with_dentry(stru
+       if (isec->initialized == LABEL_INITIALIZED)
+               return 0;
+-      mutex_lock(&isec->lock);
++      spin_lock(&isec->lock);
+       if (isec->initialized == LABEL_INITIALIZED)
+               goto out_unlock;
+@@ -1416,12 +1417,18 @@ static int inode_doinit_with_dentry(stru
+               goto out_unlock;
+       }
++      sclass = isec->sclass;
++      task_sid = isec->task_sid;
++      sid = isec->sid;
++      isec->initialized = LABEL_PENDING;
++      spin_unlock(&isec->lock);
++
+       switch (sbsec->behavior) {
+       case SECURITY_FS_USE_NATIVE:
+               break;
+       case SECURITY_FS_USE_XATTR:
+               if (!(inode->i_opflags & IOP_XATTR)) {
+-                      isec->sid = sbsec->def_sid;
++                      sid = sbsec->def_sid;
+                       break;
+               }
+               /* Need a dentry, since the xattr API requires one.
+@@ -1443,7 +1450,7 @@ static int inode_doinit_with_dentry(stru
+                        * inode_doinit with a dentry, before these inodes could
+                        * be used again by userspace.
+                        */
+-                      goto out_unlock;
++                      goto out;
+               }
+               len = INITCONTEXTLEN;
+@@ -1451,7 +1458,7 @@ static int inode_doinit_with_dentry(stru
+               if (!context) {
+                       rc = -ENOMEM;
+                       dput(dentry);
+-                      goto out_unlock;
++                      goto out;
+               }
+               context[len] = '\0';
+               rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
+@@ -1462,14 +1469,14 @@ static int inode_doinit_with_dentry(stru
+                       rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0);
+                       if (rc < 0) {
+                               dput(dentry);
+-                              goto out_unlock;
++                              goto out;
+                       }
+                       len = rc;
+                       context = kmalloc(len+1, GFP_NOFS);
+                       if (!context) {
+                               rc = -ENOMEM;
+                               dput(dentry);
+-                              goto out_unlock;
++                              goto out;
+                       }
+                       context[len] = '\0';
+                       rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
+@@ -1481,7 +1488,7 @@ static int inode_doinit_with_dentry(stru
+                                      "%d for dev=%s ino=%ld\n", __func__,
+                                      -rc, inode->i_sb->s_id, inode->i_ino);
+                               kfree(context);
+-                              goto out_unlock;
++                              goto out;
+                       }
+                       /* Map ENODATA to the default file SID */
+                       sid = sbsec->def_sid;
+@@ -1511,28 +1518,25 @@ static int inode_doinit_with_dentry(stru
+                       }
+               }
+               kfree(context);
+-              isec->sid = sid;
+               break;
+       case SECURITY_FS_USE_TASK:
+-              isec->sid = isec->task_sid;
++              sid = task_sid;
+               break;
+       case SECURITY_FS_USE_TRANS:
+               /* Default to the fs SID. */
+-              isec->sid = sbsec->sid;
++              sid = sbsec->sid;
+               /* Try to obtain a transition SID. */
+-              rc = security_transition_sid(isec->task_sid, sbsec->sid,
+-                                           isec->sclass, NULL, &sid);
++              rc = security_transition_sid(task_sid, sid, sclass, NULL, &sid);
+               if (rc)
+-                      goto out_unlock;
+-              isec->sid = sid;
++                      goto out;
+               break;
+       case SECURITY_FS_USE_MNTPOINT:
+-              isec->sid = sbsec->mntpoint_sid;
++              sid = sbsec->mntpoint_sid;
+               break;
+       default:
+               /* Default to the fs superblock SID. */
+-              isec->sid = sbsec->sid;
++              sid = sbsec->sid;
+               if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
+                       /* We must have a dentry to determine the label on
+@@ -1555,21 +1559,30 @@ static int inode_doinit_with_dentry(stru
+                        * could be used again by userspace.
+                        */
+                       if (!dentry)
+-                              goto out_unlock;
+-                      rc = selinux_genfs_get_sid(dentry, isec->sclass,
++                              goto out;
++                      rc = selinux_genfs_get_sid(dentry, sclass,
+                                                  sbsec->flags, &sid);
+                       dput(dentry);
+                       if (rc)
+-                              goto out_unlock;
+-                      isec->sid = sid;
++                              goto out;
+               }
+               break;
+       }
+-      isec->initialized = LABEL_INITIALIZED;
++out:
++      spin_lock(&isec->lock);
++      if (isec->initialized == LABEL_PENDING) {
++              if (!sid || rc) {
++                      isec->initialized = LABEL_INVALID;
++                      goto out_unlock;
++              }
++
++              isec->initialized = LABEL_INITIALIZED;
++              isec->sid = sid;
++      }
+ out_unlock:
+-      mutex_unlock(&isec->lock);
++      spin_unlock(&isec->lock);
+       return rc;
+ }
+@@ -3199,9 +3212,11 @@ static void selinux_inode_post_setxattr(
+       }
+       isec = backing_inode_security(dentry);
++      spin_lock(&isec->lock);
+       isec->sclass = inode_mode_to_security_class(inode->i_mode);
+       isec->sid = newsid;
+       isec->initialized = LABEL_INITIALIZED;
++      spin_unlock(&isec->lock);
+       return;
+ }
+@@ -3298,9 +3313,11 @@ static int selinux_inode_setsecurity(str
+       if (rc)
+               return rc;
++      spin_lock(&isec->lock);
+       isec->sclass = inode_mode_to_security_class(inode->i_mode);
+       isec->sid = newsid;
+       isec->initialized = LABEL_INITIALIZED;
++      spin_unlock(&isec->lock);
+       return 0;
+ }
+@@ -3956,9 +3973,11 @@ static void selinux_task_to_inode(struct
+       struct inode_security_struct *isec = inode->i_security;
+       u32 sid = task_sid(p);
++      spin_lock(&isec->lock);
+       isec->sclass = inode_mode_to_security_class(inode->i_mode);
+       isec->sid = sid;
+       isec->initialized = LABEL_INITIALIZED;
++      spin_unlock(&isec->lock);
+ }
+ /* Returns error only if unable to parse addresses */
+@@ -4277,24 +4296,24 @@ static int selinux_socket_post_create(st
+       const struct task_security_struct *tsec = current_security();
+       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);
++      u32 sid = SECINITSID_KERNEL;
+       int err = 0;
+-      isec->sclass = socket_type_to_security_class(family, type, protocol);
+-
+-      if (kern)
+-              isec->sid = SECINITSID_KERNEL;
+-      else {
+-              err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
++      if (!kern) {
++              err = socket_sockcreate_sid(tsec, sclass, &sid);
+               if (err)
+                       return err;
+       }
++      isec->sclass = sclass;
++      isec->sid = sid;
+       isec->initialized = LABEL_INITIALIZED;
+       if (sock->sk) {
+               sksec = sock->sk->sk_security;
+-              sksec->sid = isec->sid;
+-              sksec->sclass = isec->sclass;
++              sksec->sclass = sclass;
++              sksec->sid = sid;
+               err = selinux_netlbl_socket_post_create(sock->sk, family);
+       }
+@@ -4478,16 +4497,22 @@ static int selinux_socket_accept(struct
+       int err;
+       struct inode_security_struct *isec;
+       struct inode_security_struct *newisec;
++      u16 sclass;
++      u32 sid;
+       err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
+       if (err)
+               return err;
+-      newisec = inode_security_novalidate(SOCK_INODE(newsock));
+-
+       isec = inode_security_novalidate(SOCK_INODE(sock));
+-      newisec->sclass = isec->sclass;
+-      newisec->sid = isec->sid;
++      spin_lock(&isec->lock);
++      sclass = isec->sclass;
++      sid = isec->sid;
++      spin_unlock(&isec->lock);
++
++      newisec = inode_security_novalidate(SOCK_INODE(newsock));
++      newisec->sclass = sclass;
++      newisec->sid = sid;
+       newisec->initialized = LABEL_INITIALIZED;
+       return 0;
+@@ -6010,9 +6035,9 @@ static void selinux_inode_invalidate_sec
+ {
+       struct inode_security_struct *isec = inode->i_security;
+-      mutex_lock(&isec->lock);
++      spin_lock(&isec->lock);
+       isec->initialized = LABEL_INVALID;
+-      mutex_unlock(&isec->lock);
++      spin_unlock(&isec->lock);
+ }
+ /*
+--- a/security/selinux/include/objsec.h
++++ b/security/selinux/include/objsec.h
+@@ -39,7 +39,8 @@ struct task_security_struct {
+ enum label_initialized {
+       LABEL_INVALID,          /* invalid or not initialized */
+-      LABEL_INITIALIZED       /* initialized */
++      LABEL_INITIALIZED,      /* initialized */
++      LABEL_PENDING
+ };
+ struct inode_security_struct {
+@@ -52,7 +53,7 @@ struct inode_security_struct {
+       u32 sid;                /* SID of this object */
+       u16 sclass;             /* security class of this object */
+       unsigned char initialized;      /* initialization flag */
+-      struct mutex lock;
++      spinlock_t lock;
+ };
+ struct file_security_struct {
diff --git a/queue-4.9/selinux-fix-error-initialization-in-inode_doinit_with_dentry.patch b/queue-4.9/selinux-fix-error-initialization-in-inode_doinit_with_dentry.patch
new file mode 100644 (file)
index 0000000..4181843
--- /dev/null
@@ -0,0 +1,58 @@
+From 83370b31a915493231e5b9addc72e4bef69f8d31 Mon Sep 17 00:00:00 2001
+From: Tianyue Ren <rentianyue@kylinos.cn>
+Date: Fri, 9 Oct 2020 09:36:30 +0800
+Subject: selinux: fix error initialization in inode_doinit_with_dentry()
+
+From: Tianyue Ren <rentianyue@kylinos.cn>
+
+commit 83370b31a915493231e5b9addc72e4bef69f8d31 upstream.
+
+Mark the inode security label as invalid if we cannot find
+a dentry so that we will retry later rather than marking it
+initialized with the unlabeled SID.
+
+Fixes: 9287aed2ad1f ("selinux: Convert isec->lock into a spinlock")
+Signed-off-by: Tianyue Ren <rentianyue@kylinos.cn>
+[PM: minor comment tweaks]
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+Signed-off-by: Alexander Grund <theflamefire89@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ security/selinux/hooks.c |   19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -1450,7 +1450,13 @@ static int inode_doinit_with_dentry(stru
+                        * inode_doinit with a dentry, before these inodes could
+                        * be used again by userspace.
+                        */
+-                      goto out;
++                      isec->initialized = LABEL_INVALID;
++                      /*
++                       * There is nothing useful to jump to the "out"
++                       * label, except a needless spin lock/unlock
++                       * cycle.
++                       */
++                      return 0;
+               }
+               len = INITCONTEXTLEN;
+@@ -1558,8 +1564,15 @@ static int inode_doinit_with_dentry(stru
+                        * inode_doinit() with a dentry, before these inodes
+                        * could be used again by userspace.
+                        */
+-                      if (!dentry)
+-                              goto out;
++                      if (!dentry) {
++                              isec->initialized = LABEL_INVALID;
++                              /*
++                               * There is nothing useful to jump to the "out"
++                               * label, except a needless spin lock/unlock
++                               * cycle.
++                               */
++                              return 0;
++                      }
+                       rc = selinux_genfs_get_sid(dentry, sclass,
+                                                  sbsec->flags, &sid);
+                       dput(dentry);
diff --git a/queue-4.9/selinux-fix-inode_doinit_with_dentry-label_invalid-error-handling.patch b/queue-4.9/selinux-fix-inode_doinit_with_dentry-label_invalid-error-handling.patch
new file mode 100644 (file)
index 0000000..03a27d2
--- /dev/null
@@ -0,0 +1,97 @@
+From 200ea5a2292dc444a818b096ae6a32ba3caa51b9 Mon Sep 17 00:00:00 2001
+From: Paul Moore <paul@paul-moore.com>
+Date: Tue, 3 Nov 2020 11:49:38 -0500
+Subject: selinux: fix inode_doinit_with_dentry() LABEL_INVALID error handling
+
+From: Paul Moore <paul@paul-moore.com>
+
+commit 200ea5a2292dc444a818b096ae6a32ba3caa51b9 upstream.
+
+A previous fix, commit 83370b31a915 ("selinux: fix error initialization
+in inode_doinit_with_dentry()"), changed how failures were handled
+before a SELinux policy was loaded.  Unfortunately that patch was
+potentially problematic for two reasons: it set the isec->initialized
+state without holding a lock, and it didn't set the inode's SELinux
+label to the "default" for the particular filesystem.  The later can
+be a problem if/when a later attempt to revalidate the inode fails
+and SELinux reverts to the existing inode label.
+
+This patch should restore the default inode labeling that existed
+before the original fix, without affecting the LABEL_INVALID marking
+such that revalidation will still be attempted in the future.
+
+Fixes: 83370b31a915 ("selinux: fix error initialization in inode_doinit_with_dentry()")
+Reported-by: Sven Schnelle <svens@linux.ibm.com>
+Tested-by: Sven Schnelle <svens@linux.ibm.com>
+Reviewed-by: Ondrej Mosnacek <omosnace@redhat.com>
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+Signed-off-by: Alexander Grund <theflamefire89@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ security/selinux/hooks.c |   31 +++++++++++++------------------
+ 1 file changed, 13 insertions(+), 18 deletions(-)
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -1450,13 +1450,7 @@ static int inode_doinit_with_dentry(stru
+                        * inode_doinit with a dentry, before these inodes could
+                        * be used again by userspace.
+                        */
+-                      isec->initialized = LABEL_INVALID;
+-                      /*
+-                       * There is nothing useful to jump to the "out"
+-                       * label, except a needless spin lock/unlock
+-                       * cycle.
+-                       */
+-                      return 0;
++                      goto out_invalid;
+               }
+               len = INITCONTEXTLEN;
+@@ -1564,15 +1558,8 @@ static int inode_doinit_with_dentry(stru
+                        * inode_doinit() with a dentry, before these inodes
+                        * could be used again by userspace.
+                        */
+-                      if (!dentry) {
+-                              isec->initialized = LABEL_INVALID;
+-                              /*
+-                               * There is nothing useful to jump to the "out"
+-                               * label, except a needless spin lock/unlock
+-                               * cycle.
+-                               */
+-                              return 0;
+-                      }
++                      if (!dentry)
++                              goto out_invalid;
+                       rc = selinux_genfs_get_sid(dentry, sclass,
+                                                  sbsec->flags, &sid);
+                       dput(dentry);
+@@ -1585,11 +1572,10 @@ static int inode_doinit_with_dentry(stru
+ out:
+       spin_lock(&isec->lock);
+       if (isec->initialized == LABEL_PENDING) {
+-              if (!sid || rc) {
++              if (rc) {
+                       isec->initialized = LABEL_INVALID;
+                       goto out_unlock;
+               }
+-
+               isec->initialized = LABEL_INITIALIZED;
+               isec->sid = sid;
+       }
+@@ -1597,6 +1583,15 @@ out:
+ out_unlock:
+       spin_unlock(&isec->lock);
+       return rc;
++
++out_invalid:
++      spin_lock(&isec->lock);
++      if (isec->initialized == LABEL_PENDING) {
++              isec->initialized = LABEL_INVALID;
++              isec->sid = sid;
++      }
++      spin_unlock(&isec->lock);
++      return 0;
+ }
+ /* Convert a Linux signal to an access vector. */
diff --git a/queue-4.9/selinux-minor-cleanups.patch b/queue-4.9/selinux-minor-cleanups.patch
new file mode 100644 (file)
index 0000000..057f76c
--- /dev/null
@@ -0,0 +1,62 @@
+From 420591128cb206201dc444c2d42fb6f299b2ecd0 Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruenba@redhat.com>
+Date: Thu, 10 Nov 2016 22:18:27 +0100
+Subject: selinux: Minor cleanups
+
+From: Andreas Gruenbacher <agruenba@redhat.com>
+
+commit 420591128cb206201dc444c2d42fb6f299b2ecd0 upstream.
+
+Fix the comment for function __inode_security_revalidate, which returns
+an integer.
+
+Use the LABEL_* constants consistently for isec->initialized.
+
+Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+Signed-off-by: Alexander Grund <theflamefire89@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ security/selinux/hooks.c     |    3 ++-
+ security/selinux/selinuxfs.c |    4 ++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -237,6 +237,7 @@ static int inode_alloc_security(struct i
+       isec->sid = SECINITSID_UNLABELED;
+       isec->sclass = SECCLASS_FILE;
+       isec->task_sid = sid;
++      isec->initialized = LABEL_INVALID;
+       inode->i_security = isec;
+       return 0;
+@@ -247,7 +248,7 @@ static int inode_doinit_with_dentry(stru
+ /*
+  * Try reloading inode security labels that have been marked as invalid.  The
+  * @may_sleep parameter indicates when sleeping and thus reloading labels is
+- * allowed; when set to false, returns ERR_PTR(-ECHILD) when the label is
++ * allowed; when set to false, returns -ECHILD when the label is
+  * invalid.  The @opt_dentry parameter should be set to a dentry of the inode;
+  * when no dentry is available, set it to NULL instead.
+  */
+--- a/security/selinux/selinuxfs.c
++++ b/security/selinux/selinuxfs.c
+@@ -1301,7 +1301,7 @@ static int sel_make_bools(void)
+                       goto out;
+               isec->sid = sid;
+-              isec->initialized = 1;
++              isec->initialized = LABEL_INITIALIZED;
+               inode->i_fop = &sel_bool_ops;
+               inode->i_ino = i|SEL_BOOL_INO_OFFSET;
+               d_add(dentry, inode);
+@@ -1835,7 +1835,7 @@ static int sel_fill_super(struct super_b
+       isec = (struct inode_security_struct *)inode->i_security;
+       isec->sid = SECINITSID_DEVNULL;
+       isec->sclass = SECCLASS_CHR_FILE;
+-      isec->initialized = 1;
++      isec->initialized = LABEL_INITIALIZED;
+       init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3));
+       d_add(dentry, inode);
index a34b8520a0b5cfa564d0ae97851b0ac7388bf0ba..ed7fbc11cbe6c0c813f6b763e9d70f307a7bcb2a 100644 (file)
@@ -7,3 +7,9 @@ netfilter-nf_queue-do-not-allow-packet-truncation-be.patch
 arm-crypto-comment-out-gcc-warning-that-breaks-clang-builds.patch
 mt7601u-add-usb-device-id-for-some-versions-of-xiaodu-wifi-dongle.patch
 ion-make-user_ion_handle_put_nolock-a-void-function.patch
+selinux-minor-cleanups.patch
+proc-pass-file-mode-to-proc_pid_make_inode.patch
+selinux-clean-up-initialization-of-isec-sclass.patch
+selinux-convert-isec-lock-into-a-spinlock.patch
+selinux-fix-error-initialization-in-inode_doinit_with_dentry.patch
+selinux-fix-inode_doinit_with_dentry-label_invalid-error-handling.patch