]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 3 Feb 2022 18:06:55 +0000 (19:06 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 3 Feb 2022 18:06:55 +0000 (19:06 +0100)
added patches:
netfilter-nat-limit-port-clash-resolution-attempts.patch
netfilter-nat-remove-l4-protocol-port-rovers.patch

queue-4.9/netfilter-nat-limit-port-clash-resolution-attempts.patch [new file with mode: 0644]
queue-4.9/netfilter-nat-remove-l4-protocol-port-rovers.patch [new file with mode: 0644]
queue-4.9/series

diff --git a/queue-4.9/netfilter-nat-limit-port-clash-resolution-attempts.patch b/queue-4.9/netfilter-nat-limit-port-clash-resolution-attempts.patch
new file mode 100644 (file)
index 0000000..fe905ee
--- /dev/null
@@ -0,0 +1,79 @@
+From foo@baz Thu Feb  3 06:43:31 PM CET 2022
+From: Florian Westphal <fw@strlen.de>
+Date: Thu,  3 Feb 2022 13:32:55 +0100
+Subject: netfilter: nat: limit port clash resolution attempts
+To: <stable@vger.kernel.org>
+Cc: <netfilter-devel@vger.kernel.org>, Florian Westphal <fw@strlen.de>, Pablo Neira Ayuso <pablo@netfilter.org>
+Message-ID: <20220203123255.18974-3-fw@strlen.de>
+
+From: Florian Westphal <fw@strlen.de>
+
+commit a504b703bb1da526a01593da0e4be2af9d9f5fa8 upstream.
+
+In case almost or all available ports are taken, clash resolution can
+take a very long time, resulting in soft lockup.
+
+This can happen when many to-be-natted hosts connect to same
+destination:port (e.g. a proxy) and all connections pass the same SNAT.
+
+Pick a random offset in the acceptable range, then try ever smaller
+number of adjacent port numbers, until either the limit is reached or a
+useable port was found.  This results in at most 248 attempts
+(128 + 64 + 32 + 16 + 8, i.e. 4 restarts with new search offset)
+instead of 64000+,
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_nat_proto_common.c |   29 +++++++++++++++++++++++------
+ 1 file changed, 23 insertions(+), 6 deletions(-)
+
+--- a/net/netfilter/nf_nat_proto_common.c
++++ b/net/netfilter/nf_nat_proto_common.c
+@@ -40,9 +40,10 @@ void nf_nat_l4proto_unique_tuple(const s
+                                enum nf_nat_manip_type maniptype,
+                                const struct nf_conn *ct)
+ {
+-      unsigned int range_size, min, max, i;
++      unsigned int range_size, min, max, i, attempts;
+       __be16 *portptr;
+-      u_int16_t off;
++      u16 off;
++      static const unsigned int max_attempts = 128;
+       if (maniptype == NF_NAT_MANIP_SRC)
+               portptr = &tuple->src.u.all;
+@@ -86,12 +87,28 @@ void nf_nat_l4proto_unique_tuple(const s
+               off = prandom_u32();
+       }
+-      for (i = 0; ; ++off) {
++      attempts = range_size;
++      if (attempts > max_attempts)
++              attempts = max_attempts;
++
++      /* We are in softirq; doing a search of the entire range risks
++       * soft lockup when all tuples are already used.
++       *
++       * If we can't find any free port from first offset, pick a new
++       * one and try again, with ever smaller search window.
++       */
++another_round:
++      for (i = 0; i < attempts; i++, off++) {
+               *portptr = htons(min + off % range_size);
+-              if (++i != range_size && nf_nat_used_tuple(tuple, ct))
+-                      continue;
+-              return;
++              if (!nf_nat_used_tuple(tuple, ct))
++                      return;
+       }
++
++      if (attempts >= range_size || attempts < 16)
++              return;
++      attempts /= 2;
++      off = prandom_u32();
++      goto another_round;
+ }
+ EXPORT_SYMBOL_GPL(nf_nat_l4proto_unique_tuple);
diff --git a/queue-4.9/netfilter-nat-remove-l4-protocol-port-rovers.patch b/queue-4.9/netfilter-nat-remove-l4-protocol-port-rovers.patch
new file mode 100644 (file)
index 0000000..7e652c7
--- /dev/null
@@ -0,0 +1,188 @@
+From foo@baz Thu Feb  3 06:43:31 PM CET 2022
+From: Florian Westphal <fw@strlen.de>
+Date: Thu,  3 Feb 2022 13:32:54 +0100
+Subject: netfilter: nat: remove l4 protocol port rovers
+To: <stable@vger.kernel.org>
+Cc: <netfilter-devel@vger.kernel.org>, Florian Westphal <fw@strlen.de>, Pablo Neira Ayuso <pablo@netfilter.org>
+Message-ID: <20220203123255.18974-2-fw@strlen.de>
+
+From: Florian Westphal <fw@strlen.de>
+
+commit 6ed5943f8735e2b778d92ea4d9805c0a1d89bc2b upstream.
+
+This is a leftover from days where single-cpu systems were common:
+Store last port used to resolve a clash to use it as a starting point when
+the next conflict needs to be resolved.
+
+When we have parallel attempt to connect to same address:port pair,
+its likely that both cores end up computing the same "available" port,
+as both use same starting port, and newly used ports won't become
+visible to other cores until the conntrack gets confirmed later.
+
+One of the cores then has to drop the packet at insertion time because
+the chosen new tuple turns out to be in use after all.
+
+Lets simplify this: remove port rover and use a pseudo-random starting
+point.
+
+Note that this doesn't make netfilter default to 'fully random' mode;
+the 'rover' was only used if NAT could not reuse source port as-is.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_nat_l4proto.h |    2 +-
+ net/netfilter/nf_nat_proto_common.c    |    7 ++-----
+ net/netfilter/nf_nat_proto_dccp.c      |    5 +----
+ net/netfilter/nf_nat_proto_sctp.c      |    5 +----
+ net/netfilter/nf_nat_proto_tcp.c       |    5 +----
+ net/netfilter/nf_nat_proto_udp.c       |    5 +----
+ net/netfilter/nf_nat_proto_udplite.c   |    5 +----
+ 7 files changed, 8 insertions(+), 26 deletions(-)
+
+--- a/include/net/netfilter/nf_nat_l4proto.h
++++ b/include/net/netfilter/nf_nat_l4proto.h
+@@ -64,7 +64,7 @@ void nf_nat_l4proto_unique_tuple(const s
+                                struct nf_conntrack_tuple *tuple,
+                                const struct nf_nat_range *range,
+                                enum nf_nat_manip_type maniptype,
+-                               const struct nf_conn *ct, u16 *rover);
++                               const struct nf_conn *ct);
+ int nf_nat_l4proto_nlattr_to_range(struct nlattr *tb[],
+                                  struct nf_nat_range *range);
+--- a/net/netfilter/nf_nat_proto_common.c
++++ b/net/netfilter/nf_nat_proto_common.c
+@@ -38,8 +38,7 @@ void nf_nat_l4proto_unique_tuple(const s
+                                struct nf_conntrack_tuple *tuple,
+                                const struct nf_nat_range *range,
+                                enum nf_nat_manip_type maniptype,
+-                               const struct nf_conn *ct,
+-                               u16 *rover)
++                               const struct nf_conn *ct)
+ {
+       unsigned int range_size, min, max, i;
+       __be16 *portptr;
+@@ -84,15 +83,13 @@ void nf_nat_l4proto_unique_tuple(const s
+       } else if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
+               off = prandom_u32();
+       } else {
+-              off = *rover;
++              off = prandom_u32();
+       }
+       for (i = 0; ; ++off) {
+               *portptr = htons(min + off % range_size);
+               if (++i != range_size && nf_nat_used_tuple(tuple, ct))
+                       continue;
+-              if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL))
+-                      *rover = off;
+               return;
+       }
+ }
+--- a/net/netfilter/nf_nat_proto_dccp.c
++++ b/net/netfilter/nf_nat_proto_dccp.c
+@@ -20,8 +20,6 @@
+ #include <net/netfilter/nf_nat_l3proto.h>
+ #include <net/netfilter/nf_nat_l4proto.h>
+-static u_int16_t dccp_port_rover;
+-
+ static void
+ dccp_unique_tuple(const struct nf_nat_l3proto *l3proto,
+                 struct nf_conntrack_tuple *tuple,
+@@ -29,8 +27,7 @@ dccp_unique_tuple(const struct nf_nat_l3
+                 enum nf_nat_manip_type maniptype,
+                 const struct nf_conn *ct)
+ {
+-      nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
+-                                  &dccp_port_rover);
++      nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
+ }
+ static bool
+--- a/net/netfilter/nf_nat_proto_sctp.c
++++ b/net/netfilter/nf_nat_proto_sctp.c
+@@ -14,8 +14,6 @@
+ #include <net/netfilter/nf_nat_l4proto.h>
+-static u_int16_t nf_sctp_port_rover;
+-
+ static void
+ sctp_unique_tuple(const struct nf_nat_l3proto *l3proto,
+                 struct nf_conntrack_tuple *tuple,
+@@ -23,8 +21,7 @@ sctp_unique_tuple(const struct nf_nat_l3
+                 enum nf_nat_manip_type maniptype,
+                 const struct nf_conn *ct)
+ {
+-      nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
+-                                  &nf_sctp_port_rover);
++      nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
+ }
+ static bool
+--- a/net/netfilter/nf_nat_proto_tcp.c
++++ b/net/netfilter/nf_nat_proto_tcp.c
+@@ -18,8 +18,6 @@
+ #include <net/netfilter/nf_nat_l4proto.h>
+ #include <net/netfilter/nf_nat_core.h>
+-static u16 tcp_port_rover;
+-
+ static void
+ tcp_unique_tuple(const struct nf_nat_l3proto *l3proto,
+                struct nf_conntrack_tuple *tuple,
+@@ -27,8 +25,7 @@ tcp_unique_tuple(const struct nf_nat_l3p
+                enum nf_nat_manip_type maniptype,
+                const struct nf_conn *ct)
+ {
+-      nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
+-                                  &tcp_port_rover);
++      nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
+ }
+ static bool
+--- a/net/netfilter/nf_nat_proto_udp.c
++++ b/net/netfilter/nf_nat_proto_udp.c
+@@ -17,8 +17,6 @@
+ #include <net/netfilter/nf_nat_l3proto.h>
+ #include <net/netfilter/nf_nat_l4proto.h>
+-static u16 udp_port_rover;
+-
+ static void
+ udp_unique_tuple(const struct nf_nat_l3proto *l3proto,
+                struct nf_conntrack_tuple *tuple,
+@@ -26,8 +24,7 @@ udp_unique_tuple(const struct nf_nat_l3p
+                enum nf_nat_manip_type maniptype,
+                const struct nf_conn *ct)
+ {
+-      nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
+-                                  &udp_port_rover);
++      nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
+ }
+ static bool
+--- a/net/netfilter/nf_nat_proto_udplite.c
++++ b/net/netfilter/nf_nat_proto_udplite.c
+@@ -17,8 +17,6 @@
+ #include <net/netfilter/nf_nat_l3proto.h>
+ #include <net/netfilter/nf_nat_l4proto.h>
+-static u16 udplite_port_rover;
+-
+ static void
+ udplite_unique_tuple(const struct nf_nat_l3proto *l3proto,
+                    struct nf_conntrack_tuple *tuple,
+@@ -26,8 +24,7 @@ udplite_unique_tuple(const struct nf_nat
+                    enum nf_nat_manip_type maniptype,
+                    const struct nf_conn *ct)
+ {
+-      nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
+-                                  &udplite_port_rover);
++      nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
+ }
+ static bool
index 15fbd1b2e0b17f90162fd7c7cd0ae9251a88ff3a..3e603b281c6e15d9802a519fb6e693c5869b02a2 100644 (file)
@@ -23,3 +23,5 @@ drm-msm-fix-wrong-size-calculation.patch
 hwmon-lm90-reduce-maximum-conversion-rate-for-g781.patch
 ipv4-raw-lock-the-socket-in-raw_bind.patch
 ipv4-tcp-send-zero-ipid-in-synack-messages.patch
+netfilter-nat-remove-l4-protocol-port-rovers.patch
+netfilter-nat-limit-port-clash-resolution-attempts.patch