]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 21 Nov 2019 17:55:51 +0000 (18:55 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 21 Nov 2019 17:55:51 +0000 (18:55 +0100)
added patches:
idr-fix-idr_get_next-race-with-idr_remove.patch
net-cdc_ncm-signedness-bug-in-cdc_ncm_set_dgram_size.patch

queue-4.14/idr-fix-idr_get_next-race-with-idr_remove.patch [new file with mode: 0644]
queue-4.14/net-cdc_ncm-signedness-bug-in-cdc_ncm_set_dgram_size.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/idr-fix-idr_get_next-race-with-idr_remove.patch b/queue-4.14/idr-fix-idr_get_next-race-with-idr_remove.patch
new file mode 100644 (file)
index 0000000..542955c
--- /dev/null
@@ -0,0 +1,136 @@
+From 5c089fd0c73411f2170ab795c9ffc16718c7d007 Mon Sep 17 00:00:00 2001
+From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
+Date: Tue, 14 May 2019 16:05:45 -0400
+Subject: idr: Fix idr_get_next race with idr_remove
+
+From: Matthew Wilcox (Oracle) <willy@infradead.org>
+
+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 <bgregg@netflix.com>
+Tested-by: Brendan Gregg <bgregg@netflix.com>
+Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ lib/idr.c                           |   18 +++++++++++-
+ tools/testing/radix-tree/idr-test.c |   52 ++++++++++++++++++++++++++++++++++++
+ 2 files changed, 68 insertions(+), 2 deletions(-)
+
+--- a/lib/idr.c
++++ b/lib/idr.c
+@@ -111,13 +111,27 @@ void *idr_get_next(struct idr *idr, int
+ {
+       struct radix_tree_iter iter;
+       void __rcu **slot;
++      void *entry = NULL;
+-      slot = radix_tree_iter_find(&idr->idr_rt, &iter, *nextid);
++      radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, *nextid) {
++              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;
++      if (WARN_ON_ONCE(iter.index > INT_MAX))
++              return NULL;
++
+       *nextid = iter.index;
+-      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
+@@ -177,6 +177,57 @@ void idr_get_next_test(void)
+       idr_destroy(&idr);
+ }
++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;
+@@ -234,6 +285,7 @@ void idr_checks(void)
+       idr_null_test();
+       idr_nowait_test();
+       idr_get_next_test();
++      idr_find_test();
+ }
+ /*
diff --git a/queue-4.14/net-cdc_ncm-signedness-bug-in-cdc_ncm_set_dgram_size.patch b/queue-4.14/net-cdc_ncm-signedness-bug-in-cdc_ncm_set_dgram_size.patch
new file mode 100644 (file)
index 0000000..1b776f5
--- /dev/null
@@ -0,0 +1,35 @@
+From a56dcc6b455830776899ce3686735f1172e12243 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Wed, 13 Nov 2019 21:28:31 +0300
+Subject: net: cdc_ncm: Signedness bug in cdc_ncm_set_dgram_size()
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+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 <dan.carpenter@oracle.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
+       }
index 5b61ba75811a7dd31ba1aa3cc99531f518e5da20..3514ebdbc0c0228bef59259ec2214453f85134e2 100644 (file)
@@ -1,3 +1,5 @@
 spi-mediatek-use-correct-mata-xfer_len-when-in-fifo-transfer.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