From: Greg Kroah-Hartman Date: Thu, 21 Nov 2019 17:56:15 +0000 (+0100) Subject: 4.19-stable patches X-Git-Tag: v5.3.13~19 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b0ca9f0c7daaeaa998ceb80834ce027cc297ee04;p=thirdparty%2Fkernel%2Fstable-queue.git 4.19-stable patches added patches: idr-fix-idr_get_next-race-with-idr_remove.patch net-cdc_ncm-signedness-bug-in-cdc_ncm_set_dgram_size.patch --- diff --git a/queue-4.19/idr-fix-idr_get_next-race-with-idr_remove.patch b/queue-4.19/idr-fix-idr_get_next-race-with-idr_remove.patch new file mode 100644 index 00000000000..c2befcd8439 --- /dev/null +++ b/queue-4.19/idr-fix-idr_get_next-race-with-idr_remove.patch @@ -0,0 +1,139 @@ +From 5c089fd0c73411f2170ab795c9ffc16718c7d007 Mon Sep 17 00:00:00 2001 +From: "Matthew Wilcox (Oracle)" +Date: Tue, 14 May 2019 16:05:45 -0400 +Subject: idr: Fix idr_get_next race with idr_remove + +From: Matthew Wilcox (Oracle) + +commit 5c089fd0c73411f2170ab795c9ffc16718c7d007 upstream. + +If the entry is deleted from the IDR between the call to +radix_tree_iter_find() and rcu_dereference_raw(), idr_get_next() +will return NULL, which will end the iteration prematurely. We should +instead continue to the next entry in the IDR. This only happens if the +iteration is protected by the RCU lock. Most IDR users use a spinlock +or semaphore to exclude simultaneous modifications. It was noticed once +the PID allocator was converted to use the IDR, as it uses the RCU lock, +but there may be other users elsewhere in the kernel. + +We can't use the normal pattern of calling radix_tree_deref_retry() +(which catches both a retry entry in a leaf node and a node entry in +the root) as the IDR supports storing entries which are unaligned, +which will trigger an infinite loop if they are encountered. Instead, +we have to explicitly check whether the entry is a retry entry. + +Fixes: 0a835c4f090a ("Reimplement IDR and IDA using the radix tree") +Reported-by: Brendan Gregg +Tested-by: Brendan Gregg +Signed-off-by: Matthew Wilcox (Oracle) +Signed-off-by: Greg Kroah-Hartman + + +--- + lib/idr.c | 15 +++++++++- + tools/testing/radix-tree/idr-test.c | 52 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 65 insertions(+), 2 deletions(-) + +--- a/lib/idr.c ++++ b/lib/idr.c +@@ -231,11 +231,22 @@ void *idr_get_next(struct idr *idr, int + { + struct radix_tree_iter iter; + void __rcu **slot; ++ void *entry = NULL; + unsigned long base = idr->idr_base; + unsigned long id = *nextid; + + id = (id < base) ? 0 : id - base; +- slot = radix_tree_iter_find(&idr->idr_rt, &iter, id); ++ radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, id) { ++ entry = radix_tree_deref_slot(slot); ++ if (!entry) ++ continue; ++ if (!radix_tree_deref_retry(entry)) ++ break; ++ if (slot != (void *)&idr->idr_rt.rnode && ++ entry != (void *)RADIX_TREE_INTERNAL_NODE) ++ break; ++ slot = radix_tree_iter_retry(&iter); ++ } + if (!slot) + return NULL; + id = iter.index + base; +@@ -244,7 +255,7 @@ void *idr_get_next(struct idr *idr, int + return NULL; + + *nextid = id; +- return rcu_dereference_raw(*slot); ++ return entry; + } + EXPORT_SYMBOL(idr_get_next); + +--- a/tools/testing/radix-tree/idr-test.c ++++ b/tools/testing/radix-tree/idr-test.c +@@ -227,6 +227,57 @@ void idr_u32_test(int base) + idr_u32_test1(&idr, 0xffffffff); + } + ++static inline void *idr_mk_value(unsigned long v) ++{ ++ BUG_ON((long)v < 0); ++ return (void *)((v & 1) | 2 | (v << 1)); ++} ++ ++DEFINE_IDR(find_idr); ++ ++static void *idr_throbber(void *arg) ++{ ++ time_t start = time(NULL); ++ int id = *(int *)arg; ++ ++ rcu_register_thread(); ++ do { ++ idr_alloc(&find_idr, idr_mk_value(id), id, id + 1, GFP_KERNEL); ++ idr_remove(&find_idr, id); ++ } while (time(NULL) < start + 10); ++ rcu_unregister_thread(); ++ ++ return NULL; ++} ++ ++void idr_find_test_1(int anchor_id, int throbber_id) ++{ ++ pthread_t throbber; ++ time_t start = time(NULL); ++ ++ pthread_create(&throbber, NULL, idr_throbber, &throbber_id); ++ ++ BUG_ON(idr_alloc(&find_idr, idr_mk_value(anchor_id), anchor_id, ++ anchor_id + 1, GFP_KERNEL) != anchor_id); ++ ++ do { ++ int id = 0; ++ void *entry = idr_get_next(&find_idr, &id); ++ BUG_ON(entry != idr_mk_value(id)); ++ } while (time(NULL) < start + 11); ++ ++ pthread_join(throbber, NULL); ++ ++ idr_remove(&find_idr, anchor_id); ++ BUG_ON(!idr_is_empty(&find_idr)); ++} ++ ++void idr_find_test(void) ++{ ++ idr_find_test_1(100000, 0); ++ idr_find_test_1(0, 100000); ++} ++ + void idr_checks(void) + { + unsigned long i; +@@ -307,6 +358,7 @@ void idr_checks(void) + idr_u32_test(4); + idr_u32_test(1); + idr_u32_test(0); ++ idr_find_test(); + } + + #define module_init(x) diff --git a/queue-4.19/net-cdc_ncm-signedness-bug-in-cdc_ncm_set_dgram_size.patch b/queue-4.19/net-cdc_ncm-signedness-bug-in-cdc_ncm_set_dgram_size.patch new file mode 100644 index 00000000000..1b776f53825 --- /dev/null +++ b/queue-4.19/net-cdc_ncm-signedness-bug-in-cdc_ncm_set_dgram_size.patch @@ -0,0 +1,35 @@ +From a56dcc6b455830776899ce3686735f1172e12243 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 13 Nov 2019 21:28:31 +0300 +Subject: net: cdc_ncm: Signedness bug in cdc_ncm_set_dgram_size() + +From: Dan Carpenter + +commit a56dcc6b455830776899ce3686735f1172e12243 upstream. + +This code is supposed to test for negative error codes and partial +reads, but because sizeof() is size_t (unsigned) type then negative +error codes are type promoted to high positive values and the condition +doesn't work as expected. + +Fixes: 332f989a3b00 ("CDC-NCM: handle incomplete transfer of MTU") +Signed-off-by: Dan Carpenter +Signed-off-by: David S. Miller +Signed-off-by: Nobuhiro Iwamatsu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/usb/cdc_ncm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/usb/cdc_ncm.c ++++ b/drivers/net/usb/cdc_ncm.c +@@ -579,7 +579,7 @@ static void cdc_ncm_set_dgram_size(struc + err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE, + USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, + 0, iface_no, &max_datagram_size, sizeof(max_datagram_size)); +- if (err < sizeof(max_datagram_size)) { ++ if (err != sizeof(max_datagram_size)) { + dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed\n"); + goto out; + } diff --git a/queue-4.19/series b/queue-4.19/series index 9f65f63bc37..6042bb7c17f 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -2,3 +2,5 @@ spi-mediatek-use-correct-mata-xfer_len-when-in-fifo-transfer.patch i2c-mediatek-modify-threshold-passed-to-i2c_get_dma_safe_msg_buf.patch tee-optee-add-missing-of_node_put-after-of_device_is_available.patch revert-opp-protect-dev_list-with-opp_table-lock.patch +net-cdc_ncm-signedness-bug-in-cdc_ncm_set_dgram_size.patch +idr-fix-idr_get_next-race-with-idr_remove.patch