]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.0-stable patches
authorGreg Kroah-Hartman <greg@kroah.com>
Mon, 1 Jul 2013 18:09:48 +0000 (11:09 -0700)
committerGreg Kroah-Hartman <greg@kroah.com>
Mon, 1 Jul 2013 18:09:48 +0000 (11:09 -0700)
added patches:
perf-disable-monitoring-on-setuid-processes-for-regular-users.patch
ubifs-fix-a-horrid-bug.patch
ubifs-prepare-to-fix-a-horrid-bug.patch

queue-3.0/perf-disable-monitoring-on-setuid-processes-for-regular-users.patch [new file with mode: 0644]
queue-3.0/series
queue-3.0/ubifs-fix-a-horrid-bug.patch [new file with mode: 0644]
queue-3.0/ubifs-prepare-to-fix-a-horrid-bug.patch [new file with mode: 0644]

diff --git a/queue-3.0/perf-disable-monitoring-on-setuid-processes-for-regular-users.patch b/queue-3.0/perf-disable-monitoring-on-setuid-processes-for-regular-users.patch
new file mode 100644 (file)
index 0000000..8c839f2
--- /dev/null
@@ -0,0 +1,61 @@
+From 2976b10f05bd7f6dab9f9e7524451ddfed656a89 Mon Sep 17 00:00:00 2001
+From: Stephane Eranian <eranian@google.com>
+Date: Thu, 20 Jun 2013 11:36:28 +0200
+Subject: perf: Disable monitoring on setuid processes for regular users
+
+From: Stephane Eranian <eranian@google.com>
+
+commit 2976b10f05bd7f6dab9f9e7524451ddfed656a89 upstream.
+
+There was a a bug in setup_new_exec(), whereby
+the test to disabled perf monitoring was not
+correct because the new credentials for the
+process were not yet committed and therefore
+the get_dumpable() test was never firing.
+
+The patch fixes the problem by moving the
+perf_event test until after the credentials
+are committed.
+
+Signed-off-by: Stephane Eranian <eranian@google.com>
+Tested-by: Jiri Olsa <jolsa@redhat.com>
+Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/exec.c |   16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -1149,13 +1149,6 @@ void setup_new_exec(struct linux_binprm
+               set_dumpable(current->mm, suid_dumpable);
+       }
+-      /*
+-       * Flush performance counters when crossing a
+-       * security domain:
+-       */
+-      if (!get_dumpable(current->mm))
+-              perf_event_exit_task(current);
+-
+       /* An exec changes our domain. We are no longer part of the thread
+          group */
+@@ -1219,6 +1212,15 @@ void install_exec_creds(struct linux_bin
+       commit_creds(bprm->cred);
+       bprm->cred = NULL;
++
++      /*
++       * Disable monitoring for regular users
++       * when executing setuid binaries. Must
++       * wait until new credentials are committed
++       * by commit_creds() above
++       */
++      if (get_dumpable(current->mm) != SUID_DUMP_USER)
++              perf_event_exit_task(current);
+       /*
+        * cred_guard_mutex must be held at least to this point to prevent
+        * ptrace_attach() from altering our determination of the task's
index 097f912c2b5df3b8f6ac77de2df042c3590e1707..608723c1820b6ae8902d9f9413628db37e49bda5 100644 (file)
@@ -2,3 +2,6 @@ bluetooth-fix-crash-in-l2cap_build_cmd-with-small-mtu.patch
 hw_breakpoint-use-cpu_possible_mask-in-reserve-release-_bp_slot.patch
 dlci-acquire-rtnl_lock-before-calling-__dev_get_by_name.patch
 dlci-validate-the-net-device-in-dlci_del.patch
+perf-disable-monitoring-on-setuid-processes-for-regular-users.patch
+ubifs-prepare-to-fix-a-horrid-bug.patch
+ubifs-fix-a-horrid-bug.patch
diff --git a/queue-3.0/ubifs-fix-a-horrid-bug.patch b/queue-3.0/ubifs-fix-a-horrid-bug.patch
new file mode 100644 (file)
index 0000000..9b979fb
--- /dev/null
@@ -0,0 +1,96 @@
+From 605c912bb843c024b1ed173dc427cd5c08e5d54d Mon Sep 17 00:00:00 2001
+From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Date: Fri, 28 Jun 2013 14:15:15 +0300
+Subject: UBIFS: fix a horrid bug
+
+From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+
+commit 605c912bb843c024b1ed173dc427cd5c08e5d54d upstream.
+
+Al Viro pointed me to the fact that '->readdir()' and '->llseek()' have no
+mutual exclusion, which means the 'ubifs_dir_llseek()' can be run while we are
+in the middle of 'ubifs_readdir()'.
+
+This means that 'file->private_data' can be freed while 'ubifs_readdir()' uses
+it, and this is a very bad bug: not only 'ubifs_readdir()' can return garbage,
+but this may corrupt memory and lead to all kinds of problems like crashes an
+security holes.
+
+This patch fixes the problem by using the 'file->f_version' field, which
+'->llseek()' always unconditionally sets to zero. We set it to 1 in
+'ubifs_readdir()' and whenever we detect that it became 0, we know there was a
+seek and it is time to clear the state saved in 'file->private_data'.
+
+I tested this patch by writing a user-space program which runds readdir and
+seek in parallell. I could easily crash the kernel without these patches, but
+could not crash it with these patches.
+
+Reported-by: Al Viro <viro@zeniv.linux.org.uk>
+Tested-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ubifs/dir.c |   30 +++++++++++++++++++++++++++---
+ 1 file changed, 27 insertions(+), 3 deletions(-)
+
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -371,6 +371,24 @@ static int ubifs_readdir(struct file *fi
+                */
+               return 0;
++      if (file->f_version == 0) {
++              /*
++               * The file was seek'ed, which means that @file->private_data
++               * is now invalid. This may also be just the first
++               * 'ubifs_readdir()' invocation, in which case
++               * @file->private_data is NULL, and the below code is
++               * basically a no-op.
++               */
++              kfree(file->private_data);
++              file->private_data = NULL;
++      }
++
++      /*
++       * 'generic_file_llseek()' unconditionally sets @file->f_version to
++       * zero, and we use this for detecting whether the file was seek'ed.
++       */
++      file->f_version = 1;
++
+       /* File positions 0 and 1 correspond to "." and ".." */
+       if (pos == 0) {
+               ubifs_assert(!file->private_data);
+@@ -444,6 +462,14 @@ static int ubifs_readdir(struct file *fi
+               file->f_pos = pos = key_hash_flash(c, &dent->key);
+               file->private_data = dent;
+               cond_resched();
++
++              if (file->f_version == 0)
++                      /*
++                       * The file was seek'ed meanwhile, lets return and start
++                       * reading direntries from the new position on the next
++                       * invocation.
++                       */
++                      return 0;
+       }
+ out:
+@@ -454,15 +480,13 @@ out:
+       kfree(file->private_data);
+       file->private_data = NULL;
++      /* 2 is a special value indicating that there are no more direntries */
+       file->f_pos = 2;
+       return 0;
+ }
+-/* If a directory is seeked, we have to free saved readdir() state */
+ static loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int origin)
+ {
+-      kfree(file->private_data);
+-      file->private_data = NULL;
+       return generic_file_llseek(file, offset, origin);
+ }
diff --git a/queue-3.0/ubifs-prepare-to-fix-a-horrid-bug.patch b/queue-3.0/ubifs-prepare-to-fix-a-horrid-bug.patch
new file mode 100644 (file)
index 0000000..dcf0e8b
--- /dev/null
@@ -0,0 +1,125 @@
+From 33f1a63ae84dfd9ad298cf275b8f1887043ced36 Mon Sep 17 00:00:00 2001
+From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Date: Fri, 28 Jun 2013 14:15:14 +0300
+Subject: UBIFS: prepare to fix a horrid bug
+
+From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+
+commit 33f1a63ae84dfd9ad298cf275b8f1887043ced36 upstream.
+
+Al Viro pointed me to the fact that '->readdir()' and '->llseek()' have no
+mutual exclusion, which means the 'ubifs_dir_llseek()' can be run while we are
+in the middle of 'ubifs_readdir()'.
+
+First of all, this means that 'file->private_data' can be freed while
+'ubifs_readdir()' uses it.  But this particular patch does not fix the problem.
+This patch is only a preparation, and the fix will follow next.
+
+In this patch we make 'ubifs_readdir()' stop using 'file->f_pos' directly,
+because 'file->f_pos' can be changed by '->llseek()' at any point. This may
+lead 'ubifs_readdir()' to returning inconsistent data: directory entry names
+may correspond to incorrect file positions.
+
+So here we introduce a local variable 'pos', read 'file->f_pose' once at very
+the beginning, and then stick to 'pos'. The result of this is that when
+'ubifs_dir_llseek()' changes 'file->f_pos' while we are in the middle of
+'ubifs_readdir()', the latter "wins".
+
+Reported-by: Al Viro <viro@zeniv.linux.org.uk>
+Tested-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ubifs/dir.c |   24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -355,15 +355,16 @@ static unsigned int vfs_dent_type(uint8_
+ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
+ {
+       int err, over = 0;
++      loff_t pos = file->f_pos;
+       struct qstr nm;
+       union ubifs_key key;
+       struct ubifs_dent_node *dent;
+       struct inode *dir = file->f_path.dentry->d_inode;
+       struct ubifs_info *c = dir->i_sb->s_fs_info;
+-      dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
++      dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, pos);
+-      if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
++      if (pos > UBIFS_S_KEY_HASH_MASK || pos == 2)
+               /*
+                * The directory was seek'ed to a senseless position or there
+                * are no more entries.
+@@ -371,15 +372,15 @@ static int ubifs_readdir(struct file *fi
+               return 0;
+       /* File positions 0 and 1 correspond to "." and ".." */
+-      if (file->f_pos == 0) {
++      if (pos == 0) {
+               ubifs_assert(!file->private_data);
+               over = filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR);
+               if (over)
+                       return 0;
+-              file->f_pos = 1;
++              file->f_pos = pos = 1;
+       }
+-      if (file->f_pos == 1) {
++      if (pos == 1) {
+               ubifs_assert(!file->private_data);
+               over = filldir(dirent, "..", 2, 1,
+                              parent_ino(file->f_path.dentry), DT_DIR);
+@@ -395,7 +396,7 @@ static int ubifs_readdir(struct file *fi
+                       goto out;
+               }
+-              file->f_pos = key_hash_flash(c, &dent->key);
++              file->f_pos = pos = key_hash_flash(c, &dent->key);
+               file->private_data = dent;
+       }
+@@ -403,17 +404,16 @@ static int ubifs_readdir(struct file *fi
+       if (!dent) {
+               /*
+                * The directory was seek'ed to and is now readdir'ed.
+-               * Find the entry corresponding to @file->f_pos or the
+-               * closest one.
++               * Find the entry corresponding to @pos or the closest one.
+                */
+-              dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
++              dent_key_init_hash(c, &key, dir->i_ino, pos);
+               nm.name = NULL;
+               dent = ubifs_tnc_next_ent(c, &key, &nm);
+               if (IS_ERR(dent)) {
+                       err = PTR_ERR(dent);
+                       goto out;
+               }
+-              file->f_pos = key_hash_flash(c, &dent->key);
++              file->f_pos = pos = key_hash_flash(c, &dent->key);
+               file->private_data = dent;
+       }
+@@ -425,7 +425,7 @@ static int ubifs_readdir(struct file *fi
+                            ubifs_inode(dir)->creat_sqnum);
+               nm.len = le16_to_cpu(dent->nlen);
+-              over = filldir(dirent, dent->name, nm.len, file->f_pos,
++              over = filldir(dirent, dent->name, nm.len, pos,
+                              le64_to_cpu(dent->inum),
+                              vfs_dent_type(dent->type));
+               if (over)
+@@ -441,7 +441,7 @@ static int ubifs_readdir(struct file *fi
+               }
+               kfree(file->private_data);
+-              file->f_pos = key_hash_flash(c, &dent->key);
++              file->f_pos = pos = key_hash_flash(c, &dent->key);
+               file->private_data = dent;
+               cond_resched();
+       }