]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jan 2022 16:01:33 +0000 (17:01 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jan 2022 16:01:33 +0000 (17:01 +0100)
added patches:
net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch
select-fix-indefinitely-sleeping-task-in-poll_schedule_timeout.patch

queue-4.19/net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch [new file with mode: 0644]
queue-4.19/select-fix-indefinitely-sleeping-task-in-poll_schedule_timeout.patch [new file with mode: 0644]
queue-4.19/series

diff --git a/queue-4.19/net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch b/queue-4.19/net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch
new file mode 100644 (file)
index 0000000..e796041
--- /dev/null
@@ -0,0 +1,37 @@
+From fd65e5a95d08389444e8591a20538b3edece0e15 Mon Sep 17 00:00:00 2001
+From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
+Date: Fri, 31 Jul 2020 19:26:16 +0300
+Subject: net: bridge: clear bridge's private skb space on xmit
+
+From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
+
+commit fd65e5a95d08389444e8591a20538b3edece0e15 upstream.
+
+We need to clear all of the bridge private skb variables as they can be
+stale due to the packet being recirculated through the stack and then
+transmitted through the bridge device. Similar memset is already done on
+bridge's input. We've seen cases where proxyarp_replied was 1 on routed
+multicast packets transmitted through the bridge to ports with neigh
+suppress which were getting dropped. Same thing can in theory happen with
+the port isolation bit as well.
+
+Fixes: 821f1b21cabb ("bridge: add new BR_NEIGH_SUPPRESS port flag to suppress arp and nd flood")
+Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Huang Guobin <huangguobin4@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bridge/br_device.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/net/bridge/br_device.c
++++ b/net/bridge/br_device.c
+@@ -42,6 +42,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
+       struct ethhdr *eth;
+       u16 vid = 0;
++      memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
++
+       rcu_read_lock();
+       nf_ops = rcu_dereference(nf_br_ops);
+       if (nf_ops && nf_ops->br_dev_xmit_hook(skb)) {
diff --git a/queue-4.19/select-fix-indefinitely-sleeping-task-in-poll_schedule_timeout.patch b/queue-4.19/select-fix-indefinitely-sleeping-task-in-poll_schedule_timeout.patch
new file mode 100644 (file)
index 0000000..3d1dacb
--- /dev/null
@@ -0,0 +1,135 @@
+From 68514dacf2715d11b91ca50d88de047c086fea9c Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Mon, 10 Jan 2022 19:19:23 +0100
+Subject: select: Fix indefinitely sleeping task in poll_schedule_timeout()
+
+From: Jan Kara <jack@suse.cz>
+
+commit 68514dacf2715d11b91ca50d88de047c086fea9c upstream.
+
+A task can end up indefinitely sleeping in do_select() ->
+poll_schedule_timeout() when the following race happens:
+
+  TASK1 (thread1)             TASK2                   TASK1 (thread2)
+  do_select()
+    setup poll_wqueues table
+    with 'fd'
+                              write data to 'fd'
+                                pollwake()
+                                  table->triggered = 1
+                                                      closes 'fd' thread1 is
+                                                        waiting for
+    poll_schedule_timeout()
+      - sees table->triggered
+      table->triggered = 0
+      return -EINTR
+    loop back in do_select()
+
+But at this point when TASK1 loops back, the fdget() in the setup of
+poll_wqueues fails.  So now so we never find 'fd' is ready for reading
+and sleep in poll_schedule_timeout() indefinitely.
+
+Treat an fd that got closed as a fd on which some event happened.  This
+makes sure cannot block indefinitely in do_select().
+
+Another option would be to return -EBADF in this case but that has a
+potential of subtly breaking applications that excercise this behavior
+and it happens to work for them.  So returning fd as active seems like a
+safer choice.
+
+Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
+CC: stable@vger.kernel.org
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/select.c |   63 +++++++++++++++++++++++++++++++-----------------------------
+ 1 file changed, 33 insertions(+), 30 deletions(-)
+
+--- a/fs/select.c
++++ b/fs/select.c
+@@ -431,9 +431,11 @@ get_max:
+       return max;
+ }
+-#define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR)
+-#define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR)
+-#define POLLEX_SET (EPOLLPRI)
++#define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR |\
++                      EPOLLNVAL)
++#define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR |\
++                       EPOLLNVAL)
++#define POLLEX_SET (EPOLLPRI | EPOLLNVAL)
+ static inline void wait_key_set(poll_table *wait, unsigned long in,
+                               unsigned long out, unsigned long bit,
+@@ -500,6 +502,7 @@ static int do_select(int n, fd_set_bits
+                                       break;
+                               if (!(bit & all_bits))
+                                       continue;
++                              mask = EPOLLNVAL;
+                               f = fdget(i);
+                               if (f.file) {
+                                       wait_key_set(wait, in, out, bit,
+@@ -507,34 +510,34 @@ static int do_select(int n, fd_set_bits
+                                       mask = vfs_poll(f.file, wait);
+                                       fdput(f);
+-                                      if ((mask & POLLIN_SET) && (in & bit)) {
+-                                              res_in |= bit;
+-                                              retval++;
+-                                              wait->_qproc = NULL;
+-                                      }
+-                                      if ((mask & POLLOUT_SET) && (out & bit)) {
+-                                              res_out |= bit;
+-                                              retval++;
+-                                              wait->_qproc = NULL;
+-                                      }
+-                                      if ((mask & POLLEX_SET) && (ex & bit)) {
+-                                              res_ex |= bit;
+-                                              retval++;
+-                                              wait->_qproc = NULL;
+-                                      }
+-                                      /* got something, stop busy polling */
+-                                      if (retval) {
+-                                              can_busy_loop = false;
+-                                              busy_flag = 0;
+-
+-                                      /*
+-                                       * only remember a returned
+-                                       * POLL_BUSY_LOOP if we asked for it
+-                                       */
+-                                      } else if (busy_flag & mask)
+-                                              can_busy_loop = true;
+-
+                               }
++                              if ((mask & POLLIN_SET) && (in & bit)) {
++                                      res_in |= bit;
++                                      retval++;
++                                      wait->_qproc = NULL;
++                              }
++                              if ((mask & POLLOUT_SET) && (out & bit)) {
++                                      res_out |= bit;
++                                      retval++;
++                                      wait->_qproc = NULL;
++                              }
++                              if ((mask & POLLEX_SET) && (ex & bit)) {
++                                      res_ex |= bit;
++                                      retval++;
++                                      wait->_qproc = NULL;
++                              }
++                              /* got something, stop busy polling */
++                              if (retval) {
++                                      can_busy_loop = false;
++                                      busy_flag = 0;
++
++                              /*
++                               * only remember a returned
++                               * POLL_BUSY_LOOP if we asked for it
++                               */
++                              } else if (busy_flag & mask)
++                                      can_busy_loop = true;
++
+                       }
+                       if (res_in)
+                               *rinp = res_in;
index 4f89d40aca8a2b04061a946fe2817706b7995418..8ee73c156b7f20f6a868a82b8c811c117fe8beea 100644 (file)
@@ -1 +1,3 @@
 drm-i915-flush-tlbs-before-releasing-backing-store.patch
+net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch
+select-fix-indefinitely-sleeping-task-in-poll_schedule_timeout.patch