]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.0-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 1 Mar 2013 00:45:08 +0000 (16:45 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 1 Mar 2013 00:45:08 +0000 (16:45 -0800)
added patches:
firewire-add-minor-number-range-check-to-fw_device_init.patch
idr-fix-a-subtle-bug-in-idr_get_next.patch
sysctl-fix-null-checking-in-bin_dn_node_address.patch
xen-blkback-do-not-leak-mode-property.patch

queue-3.0/firewire-add-minor-number-range-check-to-fw_device_init.patch [new file with mode: 0644]
queue-3.0/idr-fix-a-subtle-bug-in-idr_get_next.patch [new file with mode: 0644]
queue-3.0/series
queue-3.0/sysctl-fix-null-checking-in-bin_dn_node_address.patch [new file with mode: 0644]
queue-3.0/xen-blkback-do-not-leak-mode-property.patch [new file with mode: 0644]

diff --git a/queue-3.0/firewire-add-minor-number-range-check-to-fw_device_init.patch b/queue-3.0/firewire-add-minor-number-range-check-to-fw_device_init.patch
new file mode 100644 (file)
index 0000000..75ae8e5
--- /dev/null
@@ -0,0 +1,36 @@
+From 3bec60d511179853138836ae6e1b61fe34d9235f Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Wed, 27 Feb 2013 17:04:04 -0800
+Subject: firewire: add minor number range check to fw_device_init()
+
+From: Tejun Heo <tj@kernel.org>
+
+commit 3bec60d511179853138836ae6e1b61fe34d9235f upstream.
+
+fw_device_init() didn't check whether the allocated minor number isn't
+too large.  Fail if it goes overflows MINORBITS.
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Suggested-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
+Acked-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/firewire/core-device.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/firewire/core-device.c
++++ b/drivers/firewire/core-device.c
+@@ -995,6 +995,10 @@ static void fw_device_init(struct work_s
+       ret = idr_pre_get(&fw_device_idr, GFP_KERNEL) ?
+             idr_get_new(&fw_device_idr, device, &minor) :
+             -ENOMEM;
++      if (minor >= 1 << MINORBITS) {
++              idr_remove(&fw_device_idr, minor);
++              minor = -ENOSPC;
++      }
+       up_write(&fw_device_rwsem);
+       if (ret < 0)
diff --git a/queue-3.0/idr-fix-a-subtle-bug-in-idr_get_next.patch b/queue-3.0/idr-fix-a-subtle-bug-in-idr_get_next.patch
new file mode 100644 (file)
index 0000000..6450b26
--- /dev/null
@@ -0,0 +1,73 @@
+From 6cdae7416a1c45c2ce105a78187d9b7e8feb9e24 Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Wed, 27 Feb 2013 17:03:34 -0800
+Subject: idr: fix a subtle bug in idr_get_next()
+
+From: Tejun Heo <tj@kernel.org>
+
+commit 6cdae7416a1c45c2ce105a78187d9b7e8feb9e24 upstream.
+
+The iteration logic of idr_get_next() is borrowed mostly verbatim from
+idr_for_each().  It walks down the tree looking for the slot matching
+the current ID.  If the matching slot is not found, the ID is
+incremented by the distance of single slot at the given level and
+repeats.
+
+The implementation assumes that during the whole iteration id is aligned
+to the layer boundaries of the level closest to the leaf, which is true
+for all iterations starting from zero or an existing element and thus is
+fine for idr_for_each().
+
+However, idr_get_next() may be given any point and if the starting id
+hits in the middle of a non-existent layer, increment to the next layer
+will end up skipping the same offset into it.  For example, an IDR with
+IDs filled between [64, 127] would look like the following.
+
+          [  0  64 ... ]
+       /----/   |
+       |        |
+      NULL    [ 64 ... 127 ]
+
+If idr_get_next() is called with 63 as the starting point, it will try
+to follow down the pointer from 0.  As it is NULL, it will then try to
+proceed to the next slot in the same level by adding the slot distance
+at that level which is 64 - making the next try 127.  It goes around the
+loop and finds and returns 127 skipping [64, 126].
+
+Note that this bug also triggers in idr_for_each_entry() loop which
+deletes during iteration as deletions can make layers go away leaving
+the iteration with unaligned ID into missing layers.
+
+Fix it by ensuring proceeding to the next slot doesn't carry over the
+unaligned offset - ie.  use round_up(id + 1, slot_distance) instead of
+id += slot_distance.
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reported-by: David Teigland <teigland@redhat.com>
+Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ lib/idr.c |    9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/lib/idr.c
++++ b/lib/idr.c
+@@ -621,7 +621,14 @@ void *idr_get_next(struct idr *idp, int
+                       return p;
+               }
+-              id += 1 << n;
++              /*
++               * Proceed to the next layer at the current level.  Unlike
++               * idr_for_each(), @id isn't guaranteed to be aligned to
++               * layer boundary at this point and adding 1 << n may
++               * incorrectly skip IDs.  Make sure we jump to the
++               * beginning of the next layer using round_up().
++               */
++              id = round_up(id + 1, 1 << n);
+               while (n < fls(id)) {
+                       n += IDR_BITS;
+                       p = *--paa;
index 0e9a4b0876e6f107df0cf27628dc2475d1278115..b1adf0ec8e5b8fd2aa46cb85ab8a593646fe71cb 100644 (file)
@@ -7,3 +7,7 @@ doc-kernel-parameters-document-console-hvc-n.patch
 x86-make-sure-we-can-boot-in-the-case-the-bda-contains-pure-garbage.patch
 target-add-missing-mapped_lun-bounds-checking-during-make_mappedlun-setup.patch
 ocfs2-ac-ac_allow_chain_relink-0-won-t-disable-group-relink.patch
+xen-blkback-do-not-leak-mode-property.patch
+idr-fix-a-subtle-bug-in-idr_get_next.patch
+firewire-add-minor-number-range-check-to-fw_device_init.patch
+sysctl-fix-null-checking-in-bin_dn_node_address.patch
diff --git a/queue-3.0/sysctl-fix-null-checking-in-bin_dn_node_address.patch b/queue-3.0/sysctl-fix-null-checking-in-bin_dn_node_address.patch
new file mode 100644 (file)
index 0000000..d1a58a9
--- /dev/null
@@ -0,0 +1,36 @@
+From df1778be1a33edffa51d094eeda87c858ded6560 Mon Sep 17 00:00:00 2001
+From: Xi Wang <xi.wang@gmail.com>
+Date: Wed, 27 Feb 2013 17:05:21 -0800
+Subject: sysctl: fix null checking in bin_dn_node_address()
+
+From: Xi Wang <xi.wang@gmail.com>
+
+commit df1778be1a33edffa51d094eeda87c858ded6560 upstream.
+
+The null check of `strchr() + 1' is broken, which is always non-null,
+leading to OOB read.  Instead, check the result of strchr().
+
+Signed-off-by: Xi Wang <xi.wang@gmail.com>
+Cc: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/sysctl_binary.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/kernel/sysctl_binary.c
++++ b/kernel/sysctl_binary.c
+@@ -1194,9 +1194,10 @@ static ssize_t bin_dn_node_address(struc
+               /* Convert the decnet address to binary */
+               result = -EIO;
+-              nodep = strchr(buf, '.') + 1;
++              nodep = strchr(buf, '.');
+               if (!nodep)
+                       goto out;
++              ++nodep;
+               area = simple_strtoul(buf, NULL, 10);
+               node = simple_strtoul(nodep, NULL, 10);
diff --git a/queue-3.0/xen-blkback-do-not-leak-mode-property.patch b/queue-3.0/xen-blkback-do-not-leak-mode-property.patch
new file mode 100644 (file)
index 0000000..06479b4
--- /dev/null
@@ -0,0 +1,113 @@
+From 9d092603cc306ee6edfe917bf9ab8beb5f32d7bc Mon Sep 17 00:00:00 2001
+From: Jan Beulich <JBeulich@suse.com>
+Date: Thu, 20 Dec 2012 10:31:11 +0000
+Subject: xen-blkback: do not leak mode property
+
+From: Jan Beulich <JBeulich@suse.com>
+
+commit 9d092603cc306ee6edfe917bf9ab8beb5f32d7bc upstream.
+
+"be->mode" is obtained from xenbus_read(), which does a kmalloc() for
+the message body. The short string is never released, so do it along
+with freeing "be" itself, and make sure the string isn't kept when
+backend_changed() doesn't complete successfully (which made it
+desirable to slightly re-structure that function, so that the error
+cleanup can be done in one place).
+
+Reported-by: Olaf Hering <olaf@aepfle.de>
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/xen-blkback/xenbus.c |   49 ++++++++++++++++++-------------------
+ 1 file changed, 24 insertions(+), 25 deletions(-)
+
+--- a/drivers/block/xen-blkback/xenbus.c
++++ b/drivers/block/xen-blkback/xenbus.c
+@@ -400,6 +400,7 @@ static int xen_blkbk_remove(struct xenbu
+               be->blkif = NULL;
+       }
++      kfree(be->mode);
+       kfree(be);
+       dev_set_drvdata(&dev->dev, NULL);
+       return 0;
+@@ -482,6 +483,7 @@ static void backend_changed(struct xenbu
+               = container_of(watch, struct backend_info, backend_watch);
+       struct xenbus_device *dev = be->dev;
+       int cdrom = 0;
++      unsigned long handle;
+       char *device_type;
+       DPRINTK("");
+@@ -501,10 +503,10 @@ static void backend_changed(struct xenbu
+               return;
+       }
+-      if ((be->major || be->minor) &&
+-          ((be->major != major) || (be->minor != minor))) {
+-              pr_warn(DRV_PFX "changing physical device (from %x:%x to %x:%x) not supported.\n",
+-                      be->major, be->minor, major, minor);
++      if (be->major | be->minor) {
++              if (be->major != major || be->minor != minor)
++                      pr_warn(DRV_PFX "changing physical device (from %x:%x to %x:%x) not supported.\n",
++                              be->major, be->minor, major, minor);
+               return;
+       }
+@@ -522,36 +524,33 @@ static void backend_changed(struct xenbu
+               kfree(device_type);
+       }
+-      if (be->major == 0 && be->minor == 0) {
+-              /* Front end dir is a number, which is used as the handle. */
+-
+-              char *p = strrchr(dev->otherend, '/') + 1;
+-              long handle;
+-              err = strict_strtoul(p, 0, &handle);
+-              if (err)
+-                      return;
++      /* Front end dir is a number, which is used as the handle. */
++      err = strict_strtoul(strrchr(dev->otherend, '/') + 1, 0, &handle);
++      if (err)
++              return;
+-              be->major = major;
+-              be->minor = minor;
++      be->major = major;
++      be->minor = minor;
+-              err = xen_vbd_create(be->blkif, handle, major, minor,
+-                               (NULL == strchr(be->mode, 'w')), cdrom);
+-              if (err) {
+-                      be->major = 0;
+-                      be->minor = 0;
+-                      xenbus_dev_fatal(dev, err, "creating vbd structure");
+-                      return;
+-              }
++      err = xen_vbd_create(be->blkif, handle, major, minor,
++                           !strchr(be->mode, 'w'), cdrom);
++      if (err)
++              xenbus_dev_fatal(dev, err, "creating vbd structure");
++      else {
+               err = xenvbd_sysfs_addif(dev);
+               if (err) {
+                       xen_vbd_free(&be->blkif->vbd);
+-                      be->major = 0;
+-                      be->minor = 0;
+                       xenbus_dev_fatal(dev, err, "creating sysfs entries");
+-                      return;
+               }
++      }
++      if (err) {
++              kfree(be->mode);
++              be->mode = NULL;
++              be->major = 0;
++              be->minor = 0;
++      } else {
+               /* We're potentially connected now */
+               xen_update_blkif_status(be->blkif);
+       }