From: Greg Kroah-Hartman Date: Wed, 12 Nov 2014 00:58:54 +0000 (+0900) Subject: 3.14-stable patches X-Git-Tag: v3.10.60~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=076e9a30b9f5bd005d9feb858aff0b2017295cd7;p=thirdparty%2Fkernel%2Fstable-queue.git 3.14-stable patches added patches: btrfs-fix-kfree-on-list_head-in-btrfs_lookup_csums_range-error-cleanup.patch mm-page_alloc-fix-zone-allocation-fairness-on-up.patch of-fix-overflow-bug-in-string-property-parsing-functions.patch --- diff --git a/queue-3.14/btrfs-fix-kfree-on-list_head-in-btrfs_lookup_csums_range-error-cleanup.patch b/queue-3.14/btrfs-fix-kfree-on-list_head-in-btrfs_lookup_csums_range-error-cleanup.patch new file mode 100644 index 00000000000..d68b1d175e9 --- /dev/null +++ b/queue-3.14/btrfs-fix-kfree-on-list_head-in-btrfs_lookup_csums_range-error-cleanup.patch @@ -0,0 +1,36 @@ +From 6e5aafb27419f32575b27ef9d6a31e5d54661aca Mon Sep 17 00:00:00 2001 +From: Chris Mason +Date: Tue, 4 Nov 2014 06:59:04 -0800 +Subject: Btrfs: fix kfree on list_head in btrfs_lookup_csums_range error cleanup + +From: Chris Mason + +commit 6e5aafb27419f32575b27ef9d6a31e5d54661aca upstream. + +If we hit any errors in btrfs_lookup_csums_range, we'll loop through all +the csums we allocate and free them. But the code was using list_entry +incorrectly, and ended up trying to free the on-stack list_head instead. + +This bug came from commit 0678b6185 + +btrfs: Don't BUG_ON kzalloc error in btrfs_lookup_csums_range() + +Signed-off-by: Chris Mason +Reported-by: Erik Berg +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/file-item.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/btrfs/file-item.c ++++ b/fs/btrfs/file-item.c +@@ -423,7 +423,7 @@ int btrfs_lookup_csums_range(struct btrf + ret = 0; + fail: + while (ret < 0 && !list_empty(&tmplist)) { +- sums = list_entry(&tmplist, struct btrfs_ordered_sum, list); ++ sums = list_entry(tmplist.next, struct btrfs_ordered_sum, list); + list_del(&sums->list); + kfree(sums); + } diff --git a/queue-3.14/mm-page_alloc-fix-zone-allocation-fairness-on-up.patch b/queue-3.14/mm-page_alloc-fix-zone-allocation-fairness-on-up.patch new file mode 100644 index 00000000000..11938faa6e5 --- /dev/null +++ b/queue-3.14/mm-page_alloc-fix-zone-allocation-fairness-on-up.patch @@ -0,0 +1,61 @@ +From abe5f972912d086c080be4bde67750630b6fb38b Mon Sep 17 00:00:00 2001 +From: Johannes Weiner +Date: Thu, 2 Oct 2014 16:21:10 -0700 +Subject: mm: page_alloc: fix zone allocation fairness on UP + +From: Johannes Weiner + +commit abe5f972912d086c080be4bde67750630b6fb38b upstream. + +The zone allocation batches can easily underflow due to higher-order +allocations or spills to remote nodes. On SMP that's fine, because +underflows are expected from concurrency and dealt with by returning 0. +But on UP, zone_page_state will just return a wrapped unsigned long, +which will get past the <= 0 check and then consider the zone eligible +until its watermarks are hit. + +Commit 3a025760fc15 ("mm: page_alloc: spill to remote nodes before +waking kswapd") already made the counter-resetting use +atomic_long_read() to accomodate underflows from remote spills, but it +didn't go all the way with it. + +Make it clear that these batches are expected to go negative regardless +of concurrency, and use atomic_long_read() everywhere. + +Fixes: 81c0a2bb515f ("mm: page_alloc: fair zone allocator policy") +Reported-by: Vlastimil Babka +Reported-by: Leon Romanovsky +Signed-off-by: Johannes Weiner +Acked-by: Mel Gorman +Cc: [3.12+] +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/page_alloc.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -1957,7 +1957,7 @@ zonelist_scan: + if (alloc_flags & ALLOC_FAIR) { + if (!zone_local(preferred_zone, zone)) + continue; +- if (zone_page_state(zone, NR_ALLOC_BATCH) <= 0) ++ if (atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH]) <= 0) + continue; + } + /* +@@ -5670,9 +5670,8 @@ static void __setup_per_zone_wmarks(void + zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1); + + __mod_zone_page_state(zone, NR_ALLOC_BATCH, +- high_wmark_pages(zone) - +- low_wmark_pages(zone) - +- zone_page_state(zone, NR_ALLOC_BATCH)); ++ high_wmark_pages(zone) - low_wmark_pages(zone) - ++ atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH])); + + setup_zone_migrate_reserve(zone); + spin_unlock_irqrestore(&zone->lock, flags); diff --git a/queue-3.14/of-fix-overflow-bug-in-string-property-parsing-functions.patch b/queue-3.14/of-fix-overflow-bug-in-string-property-parsing-functions.patch new file mode 100644 index 00000000000..66a85a80a84 --- /dev/null +++ b/queue-3.14/of-fix-overflow-bug-in-string-property-parsing-functions.patch @@ -0,0 +1,373 @@ +From a87fa1d81a9fb5e9adca9820e16008c40ad09f33 Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Mon, 3 Nov 2014 15:15:35 +0000 +Subject: of: Fix overflow bug in string property parsing functions + +From: Grant Likely + +commit a87fa1d81a9fb5e9adca9820e16008c40ad09f33 upstream. + +The string property read helpers will run off the end of the buffer if +it is handed a malformed string property. Rework the parsers to make +sure that doesn't happen. At the same time add new test cases to make +sure the functions behave themselves. + +The original implementations of of_property_read_string_index() and +of_property_count_strings() both open-coded the same block of parsing +code, each with it's own subtly different bugs. The fix here merges +functions into a single helper and makes the original functions static +inline wrappers around the helper. + +One non-bugfix aspect of this patch is the addition of a new wrapper, +of_property_read_string_array(). The new wrapper is needed by the +device_properties feature that Rafael is working on and planning to +merge for v3.19. The implementation is identical both with and without +the new static inline wrapper, so it just got left in to reduce the +churn on the header file. + +Signed-off-by: Grant Likely +Cc: Rafael J. Wysocki +Cc: Mika Westerberg +Cc: Rob Herring +Cc: Arnd Bergmann +Cc: Darren Hart +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/of/base.c | 88 +++++++--------------------- + drivers/of/selftest.c | 64 ++++++++++++++++++-- + drivers/of/testcase-data/tests-phandle.dtsi | 2 + include/linux/of.h | 84 ++++++++++++++++++++++---- + 4 files changed, 153 insertions(+), 85 deletions(-) + +--- a/drivers/of/base.c ++++ b/drivers/of/base.c +@@ -1117,52 +1117,6 @@ int of_property_read_string(struct devic + EXPORT_SYMBOL_GPL(of_property_read_string); + + /** +- * of_property_read_string_index - Find and read a string from a multiple +- * strings property. +- * @np: device node from which the property value is to be read. +- * @propname: name of the property to be searched. +- * @index: index of the string in the list of strings +- * @out_string: pointer to null terminated return string, modified only if +- * return value is 0. +- * +- * Search for a property in a device tree node and retrieve a null +- * terminated string value (pointer to data, not a copy) in the list of strings +- * contained in that property. +- * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if +- * property does not have a value, and -EILSEQ if the string is not +- * null-terminated within the length of the property data. +- * +- * The out_string pointer is modified only if a valid string can be decoded. +- */ +-int of_property_read_string_index(struct device_node *np, const char *propname, +- int index, const char **output) +-{ +- struct property *prop = of_find_property(np, propname, NULL); +- int i = 0; +- size_t l = 0, total = 0; +- const char *p; +- +- if (!prop) +- return -EINVAL; +- if (!prop->value) +- return -ENODATA; +- if (strnlen(prop->value, prop->length) >= prop->length) +- return -EILSEQ; +- +- p = prop->value; +- +- for (i = 0; total < prop->length; total += l, p += l) { +- l = strlen(p) + 1; +- if (i++ == index) { +- *output = p; +- return 0; +- } +- } +- return -ENODATA; +-} +-EXPORT_SYMBOL_GPL(of_property_read_string_index); +- +-/** + * of_property_match_string() - Find string in a list and return index + * @np: pointer to node containing string list property + * @propname: string list property name +@@ -1188,7 +1142,7 @@ int of_property_match_string(struct devi + end = p + prop->length; + + for (i = 0; p < end; i++, p += l) { +- l = strlen(p) + 1; ++ l = strnlen(p, end - p) + 1; + if (p + l > end) + return -EILSEQ; + pr_debug("comparing %s with %s\n", string, p); +@@ -1200,39 +1154,41 @@ int of_property_match_string(struct devi + EXPORT_SYMBOL_GPL(of_property_match_string); + + /** +- * of_property_count_strings - Find and return the number of strings from a +- * multiple strings property. ++ * of_property_read_string_util() - Utility helper for parsing string properties + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. ++ * @out_strs: output array of string pointers. ++ * @sz: number of array elements to read. ++ * @skip: Number of strings to skip over at beginning of list. + * +- * Search for a property in a device tree node and retrieve the number of null +- * terminated string contain in it. Returns the number of strings on +- * success, -EINVAL if the property does not exist, -ENODATA if property +- * does not have a value, and -EILSEQ if the string is not null-terminated +- * within the length of the property data. ++ * Don't call this function directly. It is a utility helper for the ++ * of_property_read_string*() family of functions. + */ +-int of_property_count_strings(struct device_node *np, const char *propname) ++int of_property_read_string_helper(struct device_node *np, const char *propname, ++ const char **out_strs, size_t sz, int skip) + { + struct property *prop = of_find_property(np, propname, NULL); +- int i = 0; +- size_t l = 0, total = 0; +- const char *p; ++ int l = 0, i = 0; ++ const char *p, *end; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; +- if (strnlen(prop->value, prop->length) >= prop->length) +- return -EILSEQ; +- + p = prop->value; ++ end = p + prop->length; + +- for (i = 0; total < prop->length; total += l, p += l, i++) +- l = strlen(p) + 1; +- +- return i; ++ for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) { ++ l = strnlen(p, end - p) + 1; ++ if (p + l > end) ++ return -EILSEQ; ++ if (out_strs && i >= skip) ++ *out_strs++ = p; ++ } ++ i -= skip; ++ return i <= 0 ? -ENODATA : i; + } +-EXPORT_SYMBOL_GPL(of_property_count_strings); ++EXPORT_SYMBOL_GPL(of_property_read_string_helper); + + void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) + { +--- a/drivers/of/selftest.c ++++ b/drivers/of/selftest.c +@@ -132,8 +132,9 @@ static void __init of_selftest_parse_pha + selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); + } + +-static void __init of_selftest_property_match_string(void) ++static void __init of_selftest_property_string(void) + { ++ const char *strings[4]; + struct device_node *np; + int rc; + +@@ -150,13 +151,66 @@ static void __init of_selftest_property_ + rc = of_property_match_string(np, "phandle-list-names", "third"); + selftest(rc == 2, "third expected:0 got:%i\n", rc); + rc = of_property_match_string(np, "phandle-list-names", "fourth"); +- selftest(rc == -ENODATA, "unmatched string; rc=%i", rc); ++ selftest(rc == -ENODATA, "unmatched string; rc=%i\n", rc); + rc = of_property_match_string(np, "missing-property", "blah"); +- selftest(rc == -EINVAL, "missing property; rc=%i", rc); ++ selftest(rc == -EINVAL, "missing property; rc=%i\n", rc); + rc = of_property_match_string(np, "empty-property", "blah"); +- selftest(rc == -ENODATA, "empty property; rc=%i", rc); ++ selftest(rc == -ENODATA, "empty property; rc=%i\n", rc); + rc = of_property_match_string(np, "unterminated-string", "blah"); +- selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); ++ selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); ++ ++ /* of_property_count_strings() tests */ ++ rc = of_property_count_strings(np, "string-property"); ++ selftest(rc == 1, "Incorrect string count; rc=%i\n", rc); ++ rc = of_property_count_strings(np, "phandle-list-names"); ++ selftest(rc == 3, "Incorrect string count; rc=%i\n", rc); ++ rc = of_property_count_strings(np, "unterminated-string"); ++ selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); ++ rc = of_property_count_strings(np, "unterminated-string-list"); ++ selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); ++ ++ /* of_property_read_string_index() tests */ ++ rc = of_property_read_string_index(np, "string-property", 0, strings); ++ selftest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc); ++ strings[0] = NULL; ++ rc = of_property_read_string_index(np, "string-property", 1, strings); ++ selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); ++ rc = of_property_read_string_index(np, "phandle-list-names", 0, strings); ++ selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); ++ rc = of_property_read_string_index(np, "phandle-list-names", 1, strings); ++ selftest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc); ++ rc = of_property_read_string_index(np, "phandle-list-names", 2, strings); ++ selftest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc); ++ strings[0] = NULL; ++ rc = of_property_read_string_index(np, "phandle-list-names", 3, strings); ++ selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); ++ strings[0] = NULL; ++ rc = of_property_read_string_index(np, "unterminated-string", 0, strings); ++ selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); ++ rc = of_property_read_string_index(np, "unterminated-string-list", 0, strings); ++ selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); ++ strings[0] = NULL; ++ rc = of_property_read_string_index(np, "unterminated-string-list", 2, strings); /* should fail */ ++ selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); ++ strings[1] = NULL; ++ ++ /* of_property_read_string_array() tests */ ++ rc = of_property_read_string_array(np, "string-property", strings, 4); ++ selftest(rc == 1, "Incorrect string count; rc=%i\n", rc); ++ rc = of_property_read_string_array(np, "phandle-list-names", strings, 4); ++ selftest(rc == 3, "Incorrect string count; rc=%i\n", rc); ++ rc = of_property_read_string_array(np, "unterminated-string", strings, 4); ++ selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); ++ /* -- An incorrectly formed string should cause a failure */ ++ rc = of_property_read_string_array(np, "unterminated-string-list", strings, 4); ++ selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); ++ /* -- parsing the correctly formed strings should still work: */ ++ strings[2] = NULL; ++ rc = of_property_read_string_array(np, "unterminated-string-list", strings, 2); ++ selftest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc); ++ strings[1] = NULL; ++ rc = of_property_read_string_array(np, "phandle-list-names", strings, 1); ++ selftest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]); + } + + static void __init of_selftest_parse_interrupts(void) +--- a/drivers/of/testcase-data/tests-phandle.dtsi ++++ b/drivers/of/testcase-data/tests-phandle.dtsi +@@ -32,7 +32,9 @@ + phandle-list-bad-args = <&provider2 1 0>, + <&provider3 0>; + empty-property; ++ string-property = "foobar"; + unterminated-string = [40 41 42 43]; ++ unterminated-string-list = "first", "second", [40 41 42 43]; + }; + }; + }; +--- a/include/linux/of.h ++++ b/include/linux/of.h +@@ -215,14 +215,12 @@ extern int of_property_read_u64(const st + extern int of_property_read_string(struct device_node *np, + const char *propname, + const char **out_string); +-extern int of_property_read_string_index(struct device_node *np, +- const char *propname, +- int index, const char **output); + extern int of_property_match_string(struct device_node *np, + const char *propname, + const char *string); +-extern int of_property_count_strings(struct device_node *np, +- const char *propname); ++extern int of_property_read_string_helper(struct device_node *np, ++ const char *propname, ++ const char **out_strs, size_t sz, int index); + extern int of_device_is_compatible(const struct device_node *device, + const char *); + extern int of_device_is_available(const struct device_node *device); +@@ -422,15 +420,9 @@ static inline int of_property_read_strin + return -ENOSYS; + } + +-static inline int of_property_read_string_index(struct device_node *np, +- const char *propname, int index, +- const char **out_string) +-{ +- return -ENOSYS; +-} +- +-static inline int of_property_count_strings(struct device_node *np, +- const char *propname) ++static inline int of_property_read_string_helper(struct device_node *np, ++ const char *propname, ++ const char **out_strs, size_t sz, int index) + { + return -ENOSYS; + } +@@ -536,6 +528,70 @@ static inline struct device_node *of_fin + } + + /** ++ * of_property_read_string_array() - Read an array of strings from a multiple ++ * strings property. ++ * @np: device node from which the property value is to be read. ++ * @propname: name of the property to be searched. ++ * @out_strs: output array of string pointers. ++ * @sz: number of array elements to read. ++ * ++ * Search for a property in a device tree node and retrieve a list of ++ * terminated string values (pointer to data, not a copy) in that property. ++ * ++ * If @out_strs is NULL, the number of strings in the property is returned. ++ */ ++static inline int of_property_read_string_array(struct device_node *np, ++ const char *propname, const char **out_strs, ++ size_t sz) ++{ ++ return of_property_read_string_helper(np, propname, out_strs, sz, 0); ++} ++ ++/** ++ * of_property_count_strings() - Find and return the number of strings from a ++ * multiple strings property. ++ * @np: device node from which the property value is to be read. ++ * @propname: name of the property to be searched. ++ * ++ * Search for a property in a device tree node and retrieve the number of null ++ * terminated string contain in it. Returns the number of strings on ++ * success, -EINVAL if the property does not exist, -ENODATA if property ++ * does not have a value, and -EILSEQ if the string is not null-terminated ++ * within the length of the property data. ++ */ ++static inline int of_property_count_strings(struct device_node *np, ++ const char *propname) ++{ ++ return of_property_read_string_helper(np, propname, NULL, 0, 0); ++} ++ ++/** ++ * of_property_read_string_index() - Find and read a string from a multiple ++ * strings property. ++ * @np: device node from which the property value is to be read. ++ * @propname: name of the property to be searched. ++ * @index: index of the string in the list of strings ++ * @out_string: pointer to null terminated return string, modified only if ++ * return value is 0. ++ * ++ * Search for a property in a device tree node and retrieve a null ++ * terminated string value (pointer to data, not a copy) in the list of strings ++ * contained in that property. ++ * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if ++ * property does not have a value, and -EILSEQ if the string is not ++ * null-terminated within the length of the property data. ++ * ++ * The out_string pointer is modified only if a valid string can be decoded. ++ */ ++static inline int of_property_read_string_index(struct device_node *np, ++ const char *propname, ++ int index, const char **output) ++{ ++ int rc = of_property_read_string_helper(np, propname, output, 1, index); ++ return rc < 0 ? rc : 0; ++} ++ ++/** + * of_property_read_bool - Findfrom a property + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. diff --git a/queue-3.14/series b/queue-3.14/series index bb2cd770ee5..9a07b50f843 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -198,3 +198,6 @@ powerpc-use-device_online-offline-instead-of-cpu_up-down.patch regulator-max77693-fix-use-of-uninitialized-regulator-config.patch i2c-at91-don-t-account-as-iowait.patch sysfs-driver-core-fix-glue-dir-race-condition-by-gdp_mutex.patch +of-fix-overflow-bug-in-string-property-parsing-functions.patch +btrfs-fix-kfree-on-list_head-in-btrfs_lookup_csums_range-error-cleanup.patch +mm-page_alloc-fix-zone-allocation-fairness-on-up.patch