From f9c211722792a91debf807b732f145bda03c06db Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 28 Feb 2013 16:45:08 -0800 Subject: [PATCH] 3.0-stable patches 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 --- ...number-range-check-to-fw_device_init.patch | 36 ++++++ ...idr-fix-a-subtle-bug-in-idr_get_next.patch | 73 +++++++++++ queue-3.0/series | 4 + ...null-checking-in-bin_dn_node_address.patch | 36 ++++++ ...en-blkback-do-not-leak-mode-property.patch | 113 ++++++++++++++++++ 5 files changed, 262 insertions(+) create mode 100644 queue-3.0/firewire-add-minor-number-range-check-to-fw_device_init.patch create mode 100644 queue-3.0/idr-fix-a-subtle-bug-in-idr_get_next.patch create mode 100644 queue-3.0/sysctl-fix-null-checking-in-bin_dn_node_address.patch create mode 100644 queue-3.0/xen-blkback-do-not-leak-mode-property.patch 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 index 00000000000..75ae8e59625 --- /dev/null +++ b/queue-3.0/firewire-add-minor-number-range-check-to-fw_device_init.patch @@ -0,0 +1,36 @@ +From 3bec60d511179853138836ae6e1b61fe34d9235f Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Wed, 27 Feb 2013 17:04:04 -0800 +Subject: firewire: add minor number range check to fw_device_init() + +From: Tejun Heo + +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 +Suggested-by: Stefan Richter +Acked-by: Stefan Richter +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..6450b26bb69 --- /dev/null +++ b/queue-3.0/idr-fix-a-subtle-bug-in-idr_get_next.patch @@ -0,0 +1,73 @@ +From 6cdae7416a1c45c2ce105a78187d9b7e8feb9e24 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Wed, 27 Feb 2013 17:03:34 -0800 +Subject: idr: fix a subtle bug in idr_get_next() + +From: Tejun Heo + +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 +Reported-by: David Teigland +Cc: KAMEZAWA Hiroyuki +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + 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; diff --git a/queue-3.0/series b/queue-3.0/series index 0e9a4b0876e..b1adf0ec8e5 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -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 index 00000000000..d1a58a954d2 --- /dev/null +++ b/queue-3.0/sysctl-fix-null-checking-in-bin_dn_node_address.patch @@ -0,0 +1,36 @@ +From df1778be1a33edffa51d094eeda87c858ded6560 Mon Sep 17 00:00:00 2001 +From: Xi Wang +Date: Wed, 27 Feb 2013 17:05:21 -0800 +Subject: sysctl: fix null checking in bin_dn_node_address() + +From: Xi Wang + +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 +Cc: "Eric W. Biederman" +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..06479b49d0c --- /dev/null +++ b/queue-3.0/xen-blkback-do-not-leak-mode-property.patch @@ -0,0 +1,113 @@ +From 9d092603cc306ee6edfe917bf9ab8beb5f32d7bc Mon Sep 17 00:00:00 2001 +From: Jan Beulich +Date: Thu, 20 Dec 2012 10:31:11 +0000 +Subject: xen-blkback: do not leak mode property + +From: Jan Beulich + +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 +Signed-off-by: Jan Beulich +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Greg Kroah-Hartman + +--- + 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); + } -- 2.47.3