From: Greg Kroah-Hartman Date: Thu, 3 Feb 2022 14:47:19 +0000 (+0100) Subject: 4.19-stable patches X-Git-Tag: v5.4.177~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f321a41b0c620fab17d6ab84fefb855e784ac060;p=thirdparty%2Fkernel%2Fstable-queue.git 4.19-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.19/netfilter-nat-limit-port-clash-resolution-attempts.patch b/queue-4.19/netfilter-nat-limit-port-clash-resolution-attempts.patch new file mode 100644 index 00000000000..66a759b8e89 --- /dev/null +++ b/queue-4.19/netfilter-nat-limit-port-clash-resolution-attempts.patch @@ -0,0 +1,76 @@ +From a504b703bb1da526a01593da0e4be2af9d9f5fa8 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Mon, 10 Dec 2018 17:18:46 +0100 +Subject: netfilter: nat: limit port clash resolution attempts + +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; +@@ -88,12 +89,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.19/netfilter-nat-remove-l4-protocol-port-rovers.patch b/queue-4.19/netfilter-nat-remove-l4-protocol-port-rovers.patch new file mode 100644 index 00000000000..115674f75df --- /dev/null +++ b/queue-4.19/netfilter-nat-remove-l4-protocol-port-rovers.patch @@ -0,0 +1,183 @@ +From 6ed5943f8735e2b778d92ea4d9805c0a1d89bc2b Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Thu, 15 Nov 2018 10:22:59 +0100 +Subject: netfilter: nat: remove l4 protocol port rovers + +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 | 8 ++------ + 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 | 10 ++-------- + 6 files changed, 8 insertions(+), 27 deletions(-) + +--- a/include/net/netfilter/nf_nat_l4proto.h ++++ b/include/net/netfilter/nf_nat_l4proto.h +@@ -74,7 +74,7 @@ void nf_nat_l4proto_unique_tuple(const s + struct nf_conntrack_tuple *tuple, + const struct nf_nat_range2 *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_range2 *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_range2 *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; +@@ -86,16 +85,13 @@ void nf_nat_l4proto_unique_tuple(const s + } else if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) { + off = (ntohs(*portptr) - ntohs(range->base_proto.all)); + } 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| +- NF_NAT_RANGE_PROTO_OFFSET))) +- *rover = off; + return; + } + } +--- a/net/netfilter/nf_nat_proto_dccp.c ++++ b/net/netfilter/nf_nat_proto_dccp.c +@@ -18,8 +18,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, +@@ -27,8 +25,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 +@@ -12,8 +12,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, +@@ -21,8 +19,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 void +@@ -78,8 +75,6 @@ static bool udp_manip_pkt(struct sk_buff + } + + #ifdef CONFIG_NF_NAT_PROTO_UDPLITE +-static u16 udplite_port_rover; +- + static bool udplite_manip_pkt(struct sk_buff *skb, + const struct nf_nat_l3proto *l3proto, + unsigned int iphdroff, unsigned int hdroff, +@@ -103,8 +98,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); + } + + const struct nf_nat_l4proto nf_nat_l4proto_udplite = { diff --git a/queue-4.19/series b/queue-4.19/series index ea400239e28..dc2ea36fc40 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -43,3 +43,5 @@ ibmvnic-don-t-spin-in-tasklet.patch yam-fix-a-memory-leak-in-yam_siocdevprivate.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