]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 2 May 2015 18:39:19 +0000 (20:39 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 2 May 2015 18:39:19 +0000 (20:39 +0200)
added patches:
fs-take-i_mutex-during-prepare_binprm-for-setid-executables.patch

queue-3.14/fs-take-i_mutex-during-prepare_binprm-for-setid-executables.patch [new file with mode: 0644]
queue-3.14/series

diff --git a/queue-3.14/fs-take-i_mutex-during-prepare_binprm-for-setid-executables.patch b/queue-3.14/fs-take-i_mutex-during-prepare_binprm-for-setid-executables.patch
new file mode 100644 (file)
index 0000000..94a7c26
--- /dev/null
@@ -0,0 +1,118 @@
+From 8b01fc86b9f425899f8a3a8fc1c47d73c2c20543 Mon Sep 17 00:00:00 2001
+From: Jann Horn <jann@thejh.net>
+Date: Sun, 19 Apr 2015 02:48:39 +0200
+Subject: fs: take i_mutex during prepare_binprm for set[ug]id executables
+
+From: Jann Horn <jann@thejh.net>
+
+commit 8b01fc86b9f425899f8a3a8fc1c47d73c2c20543 upstream.
+
+This prevents a race between chown() and execve(), where chowning a
+setuid-user binary to root would momentarily make the binary setuid
+root.
+
+This patch was mostly written by Linus Torvalds.
+
+Signed-off-by: Jann Horn <jann@thejh.net>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Charles Williams <ciwillia@brocade.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/exec.c |   76 +++++++++++++++++++++++++++++++++++++++-----------------------
+ 1 file changed, 48 insertions(+), 28 deletions(-)
+
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -1268,6 +1268,53 @@ static void check_unsafe_exec(struct lin
+       spin_unlock(&p->fs->lock);
+ }
++static void bprm_fill_uid(struct linux_binprm *bprm)
++{
++      struct inode *inode;
++      unsigned int mode;
++      kuid_t uid;
++      kgid_t gid;
++
++      /* clear any previous set[ug]id data from a previous binary */
++      bprm->cred->euid = current_euid();
++      bprm->cred->egid = current_egid();
++
++      if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
++              return;
++
++      if (current->no_new_privs)
++              return;
++
++      inode = file_inode(bprm->file);
++      mode = ACCESS_ONCE(inode->i_mode);
++      if (!(mode & (S_ISUID|S_ISGID)))
++              return;
++
++      /* Be careful if suid/sgid is set */
++      mutex_lock(&inode->i_mutex);
++
++      /* reload atomically mode/uid/gid now that lock held */
++      mode = inode->i_mode;
++      uid = inode->i_uid;
++      gid = inode->i_gid;
++      mutex_unlock(&inode->i_mutex);
++
++      /* We ignore suid/sgid if there are no mappings for them in the ns */
++      if (!kuid_has_mapping(bprm->cred->user_ns, uid) ||
++               !kgid_has_mapping(bprm->cred->user_ns, gid))
++              return;
++
++      if (mode & S_ISUID) {
++              bprm->per_clear |= PER_CLEAR_ON_SETID;
++              bprm->cred->euid = uid;
++      }
++
++      if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
++              bprm->per_clear |= PER_CLEAR_ON_SETID;
++              bprm->cred->egid = gid;
++      }
++}
++
+ /*
+  * Fill the binprm structure from the inode.
+  * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
+@@ -1276,36 +1323,9 @@ static void check_unsafe_exec(struct lin
+  */
+ int prepare_binprm(struct linux_binprm *bprm)
+ {
+-      struct inode *inode = file_inode(bprm->file);
+-      umode_t mode = inode->i_mode;
+       int retval;
+-
+-      /* clear any previous set[ug]id data from a previous binary */
+-      bprm->cred->euid = current_euid();
+-      bprm->cred->egid = current_egid();
+-
+-      if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
+-          !current->no_new_privs &&
+-          kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) &&
+-          kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) {
+-              /* Set-uid? */
+-              if (mode & S_ISUID) {
+-                      bprm->per_clear |= PER_CLEAR_ON_SETID;
+-                      bprm->cred->euid = inode->i_uid;
+-              }
+-
+-              /* Set-gid? */
+-              /*
+-               * If setgid is set but no group execute bit then this
+-               * is a candidate for mandatory locking, not a setgid
+-               * executable.
+-               */
+-              if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+-                      bprm->per_clear |= PER_CLEAR_ON_SETID;
+-                      bprm->cred->egid = inode->i_gid;
+-              }
+-      }
++      bprm_fill_uid(bprm);
+       /* fill in binprm security blob */
+       retval = security_bprm_set_creds(bprm);
index 19fd2e81b7ee649d3e336946182d4333c4ce404f..38b6f6f95176f82670edcda9167dc915754d2c67 100644 (file)
@@ -89,3 +89,4 @@ crypto-omap-aes-fix-support-for-unequal-lengths.patch
 c6x-time-ensure-consistency-in-__init.patch
 memstick-mspro_block-add-missing-curly-braces.patch
 driver-core-bus-goto-appropriate-labels-on-failure-in-bus_add_device.patch
+fs-take-i_mutex-during-prepare_binprm-for-setid-executables.patch