From: Greg Kroah-Hartman Date: Thu, 3 Feb 2022 18:06:55 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v5.4.177~17 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f93447523b4f7313ba5ca22bba219dcd6f0c4969;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: netfilter-nat-limit-port-clash-resolution-attempts.patch netfilter-nat-remove-l4-protocol-port-rovers.patch --- 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 index 00000000000..fe905eefe56 --- /dev/null +++ b/queue-4.9/netfilter-nat-limit-port-clash-resolution-attempts.patch @@ -0,0 +1,79 @@ +From foo@baz Thu Feb 3 06:43:31 PM CET 2022 +From: Florian Westphal +Date: Thu, 3 Feb 2022 13:32:55 +0100 +Subject: netfilter: nat: limit port clash resolution attempts +To: +Cc: , Florian Westphal , Pablo Neira Ayuso +Message-ID: <20220203123255.18974-3-fw@strlen.de> + +From: Florian Westphal + +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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..7e652c74f17 --- /dev/null +++ b/queue-4.9/netfilter-nat-remove-l4-protocol-port-rovers.patch @@ -0,0 +1,188 @@ +From foo@baz Thu Feb 3 06:43:31 PM CET 2022 +From: Florian Westphal +Date: Thu, 3 Feb 2022 13:32:54 +0100 +Subject: netfilter: nat: remove l4 protocol port rovers +To: +Cc: , Florian Westphal , Pablo Neira Ayuso +Message-ID: <20220203123255.18974-2-fw@strlen.de> + +From: Florian Westphal + +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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + +-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 + +-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 + #include + +-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 + #include + +-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 + #include + +-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 diff --git a/queue-4.9/series b/queue-4.9/series index 15fbd1b2e0b..3e603b281c6 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -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