]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
fdecf07ba49d9a20998fc272a9d2e226f32258a8
[thirdparty/kernel/stable-queue.git] /
1 From d91ef1e1b55f730bee8ce286b02b7bdccbc42973 Mon Sep 17 00:00:00 2001
2 From: Kuniyuki Iwashima <kuniyu@amazon.com>
3 Date: Tue, 26 Mar 2024 13:42:45 -0700
4 Subject: tcp: Fix bind() regression for v6-only wildcard and v4(-mapped-v6) non-wildcard addresses.
5
6 From: Kuniyuki Iwashima <kuniyu@amazon.com>
7
8 commit d91ef1e1b55f730bee8ce286b02b7bdccbc42973 upstream.
9
10 Jianguo Wu reported another bind() regression introduced by bhash2.
11
12 Calling bind() for the following 3 addresses on the same port, the
13 3rd one should fail but now succeeds.
14
15 1. 0.0.0.0 or ::ffff:0.0.0.0
16 2. [::] w/ IPV6_V6ONLY
17 3. IPv4 non-wildcard address or v4-mapped-v6 non-wildcard address
18
19 The first two bind() create tb2 like this:
20
21 bhash2 -> tb2(:: w/ IPV6_V6ONLY) -> tb2(0.0.0.0)
22
23 The 3rd bind() will match with the IPv6 only wildcard address bucket
24 in inet_bind2_bucket_match_addr_any(), however, no conflicting socket
25 exists in the bucket. So, inet_bhash2_conflict() will returns false,
26 and thus, inet_bhash2_addr_any_conflict() returns false consequently.
27
28 As a result, the 3rd bind() bypasses conflict check, which should be
29 done against the IPv4 wildcard address bucket.
30
31 So, in inet_bhash2_addr_any_conflict(), we must iterate over all buckets.
32
33 Note that we cannot add ipv6_only flag for inet_bind2_bucket as it
34 would confuse the following patetrn.
35
36 1. [::] w/ SO_REUSE{ADDR,PORT} and IPV6_V6ONLY
37 2. [::] w/ SO_REUSE{ADDR,PORT}
38 3. IPv4 non-wildcard address or v4-mapped-v6 non-wildcard address
39
40 The first bind() would create a bucket with ipv6_only flag true,
41 the second bind() would add the [::] socket into the same bucket,
42 and the third bind() could succeed based on the wrong assumption
43 that ipv6_only bucket would not conflict with v4(-mapped-v6) address.
44
45 Fixes: 28044fc1d495 ("net: Add a bhash2 table hashed by port and address")
46 Diagnosed-by: Jianguo Wu <wujianguo106@163.com>
47 Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
48 Link: https://lore.kernel.org/r/20240326204251.51301-3-kuniyu@amazon.com
49 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
50 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
51 ---
52 net/ipv4/inet_connection_sock.c | 21 ++++++++++++---------
53 1 file changed, 12 insertions(+), 9 deletions(-)
54
55 --- a/net/ipv4/inet_connection_sock.c
56 +++ b/net/ipv4/inet_connection_sock.c
57 @@ -294,6 +294,7 @@ static bool inet_bhash2_addr_any_conflic
58 struct sock_reuseport *reuseport_cb;
59 struct inet_bind_hashbucket *head2;
60 struct inet_bind2_bucket *tb2;
61 + bool conflict = false;
62 bool reuseport_cb_ok;
63
64 rcu_read_lock();
65 @@ -306,18 +307,20 @@ static bool inet_bhash2_addr_any_conflic
66
67 spin_lock(&head2->lock);
68
69 - inet_bind_bucket_for_each(tb2, &head2->chain)
70 - if (inet_bind2_bucket_match_addr_any(tb2, net, port, l3mdev, sk))
71 - break;
72 -
73 - if (tb2 && inet_bhash2_conflict(sk, tb2, uid, relax, reuseport_cb_ok,
74 - reuseport_ok)) {
75 - spin_unlock(&head2->lock);
76 - return true;
77 + inet_bind_bucket_for_each(tb2, &head2->chain) {
78 + if (!inet_bind2_bucket_match_addr_any(tb2, net, port, l3mdev, sk))
79 + continue;
80 +
81 + if (!inet_bhash2_conflict(sk, tb2, uid, relax, reuseport_cb_ok, reuseport_ok))
82 + continue;
83 +
84 + conflict = true;
85 + break;
86 }
87
88 spin_unlock(&head2->lock);
89 - return false;
90 +
91 + return conflict;
92 }
93
94 /*