Blame SOURCES/CVE-2022-1012.patch

098754
From 2258117c811aa525ec995c601c5f4649553e9490 Mon Sep 17 00:00:00 2001
098754
From: Joe Lawrence <joe.lawrence@redhat.com>
098754
Date: Mon, 6 Jun 2022 09:30:32 -0400
098754
Subject: [KPATCH CVE-2022-1012] kpatch fixes for CVE-2022-1012
098754
Content-type: text/plain
098754
098754
Changes since last build:
098754
arches: x86_64 ppc64le
098754
inet6_hashtables.o: changed function: inet6_hash_connect
098754
inet_hashtables.o: changed function: inet_hash_connect
098754
inet_hashtables.o: new function: klp__inet_hash_connect
098754
inet_hashtables.o: new function: klp_cve_2022_1012_pre_patch_callback
098754
inet_hashtables.o: new function: klp_table_perturb_ctor
098754
secure_seq.o: new function: klp_secure_ipv4_port_ephemeral
098754
secure_seq.o: new function: klp_secure_ipv6_port_ephemeral
098754
---------------------------
098754
098754
Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-9/-/merge_requests/2
098754
Kernels:
098754
5.14.0-70.13.1.el9_0
098754
098754
Modifications:
098754
- Avoid header file changes, move prototypes into .c files
098754
- secure_ipv4_port_ephemeral() and secure_ipv6_port_ephemeral() are
098754
  exported symbols, create "klp_" variants that change return type
098754
  from u32 -> u64
098754
- inet_sk_port_offset() and inet6_sk_port_offset() have only one caller each,
098754
  which we can kpatch, so it's safe to update their return values from
098754
  u32 -> u64
098754
- __inet_hash_connect() is prototyped in a header file, which we don't want to
098754
  touch, so create a "klp" variant updating the interface for port_offset
098754
  u32 -> u64
098754
- Create larger klp_table_perturb for kpatch functions, leaving
098754
  smaller table_perturb intact for unpatched code
098754
- Use a shadow variable for the larger klp_table_perturb so it may
098754
  persist across kpatch upgrades
098754
- Get or allocate klp_table_perturb shadow variable in prepatch callback
098754
  rather than inet_hashinfo2_init()
098754
- Use a shadow variable constructor to initialize klp_table_perturb with
098754
  net_get_random_once() on its allocation
098754
- Use KLP_INET_TABLE_PERTURB_{SHIFT,SIZE} for larger size so we don't
098754
  modify existing (smaller) table_perturb
098754
- Add -fno-optimize-sibling-calls attribute for inet_hash_connect()
098754
098754
commit 2f0029a0cd4a60d087882790b8f2e4b3b7a34fc9
098754
Author: Guillaume Nault <gnault@redhat.com>
098754
Date:   Tue May 10 21:26:43 2022 +0200
098754
098754
    secure_seq: use the 64 bits of the siphash for port offset calculation
098754
098754
    Bugzilla: https://bugzilla.redhat.com/2087128
098754
    CVE: CVE-2022-1012
098754
    Y-Commit: cca87d73827e2be4da6de677da5fbbf05ee1efe7
098754
098754
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2064868
098754
    Upstream Status: linux.git
098754
    O-CVE: CVE-2022-1012
098754
098754
    commit b2d057560b8107c633b39aabe517ff9d93f285e3
098754
    Author: Willy Tarreau <w@1wt.eu>
098754
    Date:   Mon May 2 10:46:08 2022 +0200
098754
098754
        secure_seq: use the 64 bits of the siphash for port offset calculation
098754
098754
        SipHash replaced MD5 in secure_ipv{4,6}_port_ephemeral() via commit
098754
        7cd23e5300c1 ("secure_seq: use SipHash in place of MD5"), but the output
098754
        remained truncated to 32-bit only. In order to exploit more bits from the
098754
        hash, let's make the functions return the full 64-bit of siphash_3u32().
098754
        We also make sure the port offset calculation in __inet_hash_connect()
098754
        remains done on 32-bit to avoid the need for div_u64_rem() and an extra
098754
        cost on 32-bit systems.
098754
098754
        Cc: Jason A. Donenfeld <Jason@zx2c4.com>
098754
        Cc: Moshe Kol <moshe.kol@mail.huji.ac.il>
098754
        Cc: Yossi Gilad <yossi.gilad@mail.huji.ac.il>
098754
        Cc: Amit Klein <aksecurity@gmail.com>
098754
        Reviewed-by: Eric Dumazet <edumazet@google.com>
098754
        Signed-off-by: Willy Tarreau <w@1wt.eu>
098754
        Signed-off-by: Jakub Kicinski <kuba@kernel.org>
098754
098754
    Signed-off-by: Guillaume Nault <gnault@redhat.com>
098754
    Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
098754
098754
commit 12d013e32960f7de65bf6d48b5d1b34f035db485
098754
Author: Guillaume Nault <gnault@redhat.com>
098754
Date:   Tue May 10 21:29:59 2022 +0200
098754
098754
    tcp: use different parts of the port_offset for index and offset
098754
098754
    Bugzilla: https://bugzilla.redhat.com/2087128
098754
    CVE: CVE-2022-1012
098754
    Y-Commit: cf01c418b12c3f395134654725aee76ba8ead14f
098754
098754
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2064868
098754
    Upstream Status: linux.git
098754
    O-CVE: CVE-2022-1012
098754
098754
    commit 9e9b70ae923baf2b5e8a0ea4fd0c8451801ac526
098754
    Author: Willy Tarreau <w@1wt.eu>
098754
    Date:   Mon May 2 10:46:09 2022 +0200
098754
098754
        tcp: use different parts of the port_offset for index and offset
098754
098754
        Amit Klein suggests that we use different parts of port_offset for the
098754
        table's index and the port offset so that there is no direct relation
098754
        between them.
098754
098754
        Cc: Jason A. Donenfeld <Jason@zx2c4.com>
098754
        Cc: Moshe Kol <moshe.kol@mail.huji.ac.il>
098754
        Cc: Yossi Gilad <yossi.gilad@mail.huji.ac.il>
098754
        Cc: Amit Klein <aksecurity@gmail.com>
098754
        Reviewed-by: Eric Dumazet <edumazet@google.com>
098754
        Signed-off-by: Willy Tarreau <w@1wt.eu>
098754
        Signed-off-by: Jakub Kicinski <kuba@kernel.org>
098754
098754
    Signed-off-by: Guillaume Nault <gnault@redhat.com>
098754
    Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
098754
098754
commit a35aa2ee80eba52053d4857f03aaec487e124938
098754
Author: Guillaume Nault <gnault@redhat.com>
098754
Date:   Tue May 10 21:30:49 2022 +0200
098754
098754
    tcp: resalt the secret every 10 seconds
098754
098754
    Bugzilla: https://bugzilla.redhat.com/2087128
098754
    CVE: CVE-2022-1012
098754
    Y-Commit: 76a5e5ab10aa3a222b10ea44aae87b61de99de76
098754
098754
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2064868
098754
    Upstream Status: linux.git
098754
    O-CVE: CVE-2022-1012
098754
    Conflicts:
098754
      (context) Missing upstream commit 49ecc2e9c3ab ("net: align static
098754
      siphash keys"):
098754
        RHEL 9 still declares net_secret and ts_secret as siphash_key_t,
098754
        while upstream uses the new siphash_aligned_key_t.
098754
098754
    commit 4dfa9b438ee34caca4e6a4e5e961641807367f6f
098754
    Author: Eric Dumazet <edumazet@google.com>
098754
    Date:   Mon May 2 10:46:10 2022 +0200
098754
098754
        tcp: resalt the secret every 10 seconds
098754
098754
        In order to limit the ability for an observer to recognize the source
098754
        ports sequence used to contact a set of destinations, we should
098754
        periodically shuffle the secret. 10 seconds looks effective enough
098754
        without causing particular issues.
098754
098754
        Cc: Moshe Kol <moshe.kol@mail.huji.ac.il>
098754
        Cc: Yossi Gilad <yossi.gilad@mail.huji.ac.il>
098754
        Cc: Amit Klein <aksecurity@gmail.com>
098754
        Cc: Jason A. Donenfeld <Jason@zx2c4.com>
098754
        Tested-by: Willy Tarreau <w@1wt.eu>
098754
        Signed-off-by: Eric Dumazet <edumazet@google.com>
098754
        Signed-off-by: Jakub Kicinski <kuba@kernel.org>
098754
098754
    Signed-off-by: Guillaume Nault <gnault@redhat.com>
098754
    Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
098754
098754
commit 2e7decde85e1d99aba7cfc25489136757e5e5e4d
098754
Author: Guillaume Nault <gnault@redhat.com>
098754
Date:   Tue May 10 21:37:42 2022 +0200
098754
098754
    tcp: add small random increments to the source port
098754
098754
    Bugzilla: https://bugzilla.redhat.com/2087128
098754
    CVE: CVE-2022-1012
098754
    Y-Commit: c36cc7ecaeb895c5ec73085d925208ead5a9f285
098754
098754
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2064868
098754
    Upstream Status: linux.git
098754
    O-CVE: CVE-2022-1012
098754
098754
    commit ca7af0402550f9a0b3316d5f1c30904e42ed257d
098754
    Author: Willy Tarreau <w@1wt.eu>
098754
    Date:   Mon May 2 10:46:11 2022 +0200
098754
098754
        tcp: add small random increments to the source port
098754
098754
        Here we're randomly adding between 0 and 7 random increments to the
098754
        selected source port in order to add some noise in the source port
098754
        selection that will make the next port less predictable.
098754
098754
        With the default port range of 32768-60999 this means a worst case
098754
        reuse scenario of 14116/8=1764 connections between two consecutive
098754
        uses of the same port, with an average of 14116/4.5=3137. This code
098754
        was stressed at more than 800000 connections per second to a fixed
098754
        target with all connections closed by the client using RSTs (worst
098754
        condition) and only 2 connections failed among 13 billion, despite
098754
        the hash being reseeded every 10 seconds, indicating a perfectly
098754
        safe situation.
098754
098754
        Cc: Moshe Kol <moshe.kol@mail.huji.ac.il>
098754
        Cc: Yossi Gilad <yossi.gilad@mail.huji.ac.il>
098754
        Cc: Amit Klein <aksecurity@gmail.com>
098754
        Reviewed-by: Eric Dumazet <edumazet@google.com>
098754
        Signed-off-by: Willy Tarreau <w@1wt.eu>
098754
        Signed-off-by: Jakub Kicinski <kuba@kernel.org>
098754
098754
    Signed-off-by: Guillaume Nault <gnault@redhat.com>
098754
    Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
098754
098754
commit 11b7585327e4558856beea1b60c2b56a89109034
098754
Author: Guillaume Nault <gnault@redhat.com>
098754
Date:   Tue May 10 21:38:33 2022 +0200
098754
098754
    tcp: dynamically allocate the perturb table used by source ports
098754
098754
    Bugzilla: https://bugzilla.redhat.com/2087128
098754
    CVE: CVE-2022-1012
098754
    Y-Commit: 2a8821f71c0f00f5169888c9e21df0e033306ae8
098754
098754
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2064868
098754
    Upstream Status: linux.git
098754
    O-CVE: CVE-2022-1012
098754
098754
    commit e9261476184be1abd486c9434164b2acbe0ed6c2
098754
    Author: Willy Tarreau <w@1wt.eu>
098754
    Date:   Mon May 2 10:46:12 2022 +0200
098754
098754
        tcp: dynamically allocate the perturb table used by source ports
098754
098754
        We'll need to further increase the size of this table and it's likely
098754
        that at some point its size will not be suitable anymore for a static
098754
        table. Let's allocate it on boot from inet_hashinfo2_init(), which is
098754
        called from tcp_init().
098754
098754
        Cc: Moshe Kol <moshe.kol@mail.huji.ac.il>
098754
        Cc: Yossi Gilad <yossi.gilad@mail.huji.ac.il>
098754
        Cc: Amit Klein <aksecurity@gmail.com>
098754
        Reviewed-by: Eric Dumazet <edumazet@google.com>
098754
        Signed-off-by: Willy Tarreau <w@1wt.eu>
098754
        Signed-off-by: Jakub Kicinski <kuba@kernel.org>
098754
098754
    Signed-off-by: Guillaume Nault <gnault@redhat.com>
098754
    Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
098754
098754
commit ffec79df2cf078ae8efda94fa1644a2f3d249629
098754
Author: Guillaume Nault <gnault@redhat.com>
098754
Date:   Tue May 10 21:39:49 2022 +0200
098754
098754
    tcp: increase source port perturb table to 2^16
098754
098754
    Bugzilla: https://bugzilla.redhat.com/2087128
098754
    CVE: CVE-2022-1012
098754
    Y-Commit: cb2b7f66f852709725a5fc3798b8cf60eee4cfcd
098754
098754
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2064868
098754
    Upstream Status: linux.git
098754
    O-CVE: CVE-2022-1012
098754
098754
    commit 4c2c8f03a5ab7cb04ec64724d7d176d00bcc91e5
098754
    Author: Willy Tarreau <w@1wt.eu>
098754
    Date:   Mon May 2 10:46:13 2022 +0200
098754
098754
        tcp: increase source port perturb table to 2^16
098754
098754
        Moshe Kol, Amit Klein, and Yossi Gilad reported being able to accurately
098754
        identify a client by forcing it to emit only 40 times more connections
098754
        than there are entries in the table_perturb[] table. The previous two
098754
        improvements consisting in resalting the secret every 10s and adding
098754
        randomness to each port selection only slightly improved the situation,
098754
        and the current value of 2^8 was too small as it's not very difficult
098754
        to make a client emit 10k connections in less than 10 seconds.
098754
098754
        Thus we're increasing the perturb table from 2^8 to 2^16 so that the
098754
        same precision now requires 2.6M connections, which is more difficult in
098754
        this time frame and harder to hide as a background activity. The impact
098754
        is that the table now uses 256 kB instead of 1 kB, which could mostly
098754
        affect devices making frequent outgoing connections. However such
098754
        components usually target a small set of destinations (load balancers,
098754
        database clients, perf assessment tools), and in practice only a few
098754
        entries will be visited, like before.
098754
098754
        A live test at 1 million connections per second showed no performance
098754
        difference from the previous value.
098754
098754
        Reported-by: Moshe Kol <moshe.kol@mail.huji.ac.il>
098754
        Reported-by: Yossi Gilad <yossi.gilad@mail.huji.ac.il>
098754
        Reported-by: Amit Klein <aksecurity@gmail.com>
098754
        Reviewed-by: Eric Dumazet <edumazet@google.com>
098754
        Signed-off-by: Willy Tarreau <w@1wt.eu>
098754
        Signed-off-by: Jakub Kicinski <kuba@kernel.org>
098754
098754
    Signed-off-by: Guillaume Nault <gnault@redhat.com>
098754
    Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
098754
098754
commit 8b63da5c1514e473907b074eae7ce5acc0ea739e
098754
Author: Guillaume Nault <gnault@redhat.com>
098754
Date:   Tue May 10 21:40:34 2022 +0200
098754
098754
    tcp: drop the hash_32() part from the index calculation
098754
098754
    Bugzilla: https://bugzilla.redhat.com/2087128
098754
    CVE: CVE-2022-1012
098754
    Y-Commit: f8b7b8321dd6b55062382fc343422f3926ffa04c
098754
098754
    O-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2064868
098754
    Upstream Status: linux.git
098754
    O-CVE: CVE-2022-1012
098754
098754
    commit e8161345ddbb66e449abde10d2fdce93f867eba9
098754
    Author: Willy Tarreau <w@1wt.eu>
098754
    Date:   Mon May 2 10:46:14 2022 +0200
098754
098754
        tcp: drop the hash_32() part from the index calculation
098754
098754
        In commit 190cc82489f4 ("tcp: change source port randomizarion at
098754
        connect() time"), the table_perturb[] array was introduced and an
098754
        index was taken from the port_offset via hash_32(). But it turns
098754
        out that hash_32() performs a multiplication while the input here
098754
        comes from the output of SipHash in secure_seq, that is well
098754
        distributed enough to avoid the need for yet another hash.
098754
098754
        Suggested-by: Amit Klein <aksecurity@gmail.com>
098754
        Reviewed-by: Eric Dumazet <edumazet@google.com>
098754
        Signed-off-by: Willy Tarreau <w@1wt.eu>
098754
        Signed-off-by: Jakub Kicinski <kuba@kernel.org>
098754
098754
    Signed-off-by: Guillaume Nault <gnault@redhat.com>
098754
    Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
098754
098754
Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
098754
---
098754
 net/core/secure_seq.c       |  30 +++++++
098754
 net/ipv4/inet_hashtables.c  | 175 ++++++++++++++++++++++++++++++++++--
098754
 net/ipv6/inet6_hashtables.c |  20 +++--
098754
 3 files changed, 211 insertions(+), 14 deletions(-)
098754
098754
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
098754
index b5bc680d4755..f18f8176d69e 100644
098754
--- a/net/core/secure_seq.c
098754
+++ b/net/core/secure_seq.c
098754
@@ -22,6 +22,8 @@
098754
 static siphash_key_t net_secret __read_mostly;
098754
 static siphash_key_t ts_secret __read_mostly;
098754
 
098754
+#define EPHEMERAL_PORT_SHUFFLE_PERIOD (10 * HZ)
098754
+
098754
 static __always_inline void net_secret_init(void)
098754
 {
098754
 	net_get_random_once(&net_secret, sizeof(net_secret));
098754
@@ -111,6 +113,25 @@ u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
098754
 		       &net_secret);
098754
 }
098754
 EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
098754
+
098754
+u64 klp_secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
098754
+				   __be16 dport)
098754
+{
098754
+	const struct {
098754
+		struct in6_addr saddr;
098754
+		struct in6_addr daddr;
098754
+		unsigned int timeseed;
098754
+		__be16 dport;
098754
+	} __aligned(SIPHASH_ALIGNMENT) combined = {
098754
+		.saddr = *(struct in6_addr *)saddr,
098754
+		.daddr = *(struct in6_addr *)daddr,
098754
+		.timeseed = jiffies / EPHEMERAL_PORT_SHUFFLE_PERIOD,
098754
+		.dport = dport,
098754
+	};
098754
+	net_secret_init();
098754
+	return siphash(&combined, offsetofend(typeof(combined), dport),
098754
+		       &net_secret);
098754
+}
098754
 #endif
098754
 
098754
 #ifdef CONFIG_INET
098754
@@ -149,6 +170,15 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
098754
 			    (__force u16)dport, &net_secret);
098754
 }
098754
 EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
098754
+
098754
+u64 klp_secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
098754
+{
098754
+	net_secret_init();
098754
+	return siphash_4u32((__force u32)saddr, (__force u32)daddr,
098754
+			    (__force u16)dport,
098754
+			    jiffies / EPHEMERAL_PORT_SHUFFLE_PERIOD,
098754
+			    &net_secret);
098754
+}
098754
 #endif
098754
 
098754
 #if IS_ENABLED(CONFIG_IP_DCCP)
098754
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
098754
index bfb522e51346..7f982eb04e3f 100644
098754
--- a/net/ipv4/inet_hashtables.c
098754
+++ b/net/ipv4/inet_hashtables.c
098754
@@ -504,13 +504,14 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
098754
 	return -EADDRNOTAVAIL;
098754
 }
098754
 
098754
-static u32 inet_sk_port_offset(const struct sock *sk)
098754
+u64 klp_secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
098754
+static u64 inet_sk_port_offset(const struct sock *sk)
098754
 {
098754
 	const struct inet_sock *inet = inet_sk(sk);
098754
 
098754
-	return secure_ipv4_port_ephemeral(inet->inet_rcv_saddr,
098754
-					  inet->inet_daddr,
098754
-					  inet->inet_dport);
098754
+	return klp_secure_ipv4_port_ephemeral(inet->inet_rcv_saddr,
098754
+					      inet->inet_daddr,
098754
+					      inet->inet_dport);
098754
 }
098754
 
098754
 /* Searches for an exsiting socket in the ehash bucket list.
098754
@@ -842,18 +843,178 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
098754
 	return 0;
098754
 }
098754
 
098754
+#include "kpatch-macros.h"
098754
+#define KLP_CVE_2022_1012_TABLE_PERTURB 0x2022101200000001
098754
+
098754
+#define KLP_INET_TABLE_PERTURB_SHIFT 16
098754
+#define KLP_INET_TABLE_PERTURB_SIZE (1 << KLP_INET_TABLE_PERTURB_SHIFT)
098754
+static u32 *klp_table_perturb;
098754
+
098754
+static int klp_table_perturb_ctor(void *obj, void *shadow_data, void *ctor_data)
098754
+{
098754
+	u32 *klp_tp = shadow_data;
098754
+	if (!net_get_random_once(klp_tp, KLP_INET_TABLE_PERTURB_SIZE * sizeof(*klp_tp))) {
098754
+		pr_err("kpatch assertion: net_get_random_once() on klp_table_perturb");
098754
+		return -1;
098754
+	}
098754
+
098754
+	return 0;
098754
+}
098754
+
098754
+static int klp_cve_2022_1012_pre_patch_callback(struct klp_object *obj)
098754
+{
098754
+	/* this one is used for source ports of outgoing connections */
098754
+	klp_table_perturb = klp_shadow_get_or_alloc(0, KLP_CVE_2022_1012_TABLE_PERTURB,
098754
+						    KLP_INET_TABLE_PERTURB_SIZE * sizeof(*klp_table_perturb),
098754
+						    GFP_KERNEL, klp_table_perturb_ctor, NULL);
098754
+	if (!klp_table_perturb) {
098754
+		pr_err("TCP: failed to alloc / find klp_table_perturb");
098754
+		return -ENOMEM;
098754
+	}
098754
+
098754
+	return 0;
098754
+}
098754
+KPATCH_PRE_PATCH_CALLBACK(klp_cve_2022_1012_pre_patch_callback);
098754
+
098754
+int klp__inet_hash_connect(struct inet_timewait_death_row *death_row,
098754
+			   struct sock *sk, u64 port_offset,
098754
+			   int (*check_established)(struct inet_timewait_death_row *,
098754
+				   struct sock *, __u16, struct inet_timewait_sock **))
098754
+{
098754
+	struct inet_hashinfo *hinfo = death_row->hashinfo;
098754
+	struct inet_timewait_sock *tw = NULL;
098754
+	struct inet_bind_hashbucket *head;
098754
+	int port = inet_sk(sk)->inet_num;
098754
+	struct net *net = sock_net(sk);
098754
+	struct inet_bind_bucket *tb;
098754
+	u32 remaining, offset;
098754
+	int ret, i, low, high;
098754
+	int l3mdev;
098754
+	u32 index;
098754
+
098754
+	if (port) {
098754
+		head = &hinfo->bhash[inet_bhashfn(net, port,
098754
+						  hinfo->bhash_size)];
098754
+		tb = inet_csk(sk)->icsk_bind_hash;
098754
+		spin_lock_bh(&head->lock);
098754
+		if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) {
098754
+			inet_ehash_nolisten(sk, NULL, NULL);
098754
+			spin_unlock_bh(&head->lock);
098754
+			return 0;
098754
+		}
098754
+		spin_unlock(&head->lock);
098754
+		/* No definite answer... Walk to established hash table */
098754
+		ret = check_established(death_row, sk, port, NULL);
098754
+		local_bh_enable();
098754
+		return ret;
098754
+	}
098754
+
098754
+	l3mdev = inet_sk_bound_l3mdev(sk);
098754
+
098754
+	inet_get_local_port_range(net, &low, &high);
098754
+	high++; /* [32768, 60999] -> [32768, 61000[ */
098754
+	remaining = high - low;
098754
+	if (likely(remaining > 1))
098754
+		remaining &= ~1U;
098754
+
098754
+	/*
098754
+	 * kpatch: klp_table_perturb_ctor() responsible for calling
098754
+	 * net_get_random_once() for klp_table_perturb
098754
+	 */
098754
+	index = port_offset & (KLP_INET_TABLE_PERTURB_SIZE - 1);
098754
+
098754
+	offset = READ_ONCE(klp_table_perturb[index]) + (port_offset >> 32);
098754
+	offset %= remaining;
098754
+
098754
+	/* In first pass we try ports of @low parity.
098754
+	 * inet_csk_get_port() does the opposite choice.
098754
+	 */
098754
+	offset &= ~1U;
098754
+other_parity_scan:
098754
+	port = low + offset;
098754
+	for (i = 0; i < remaining; i += 2, port += 2) {
098754
+		if (unlikely(port >= high))
098754
+			port -= remaining;
098754
+		if (inet_is_local_reserved_port(net, port))
098754
+			continue;
098754
+		head = &hinfo->bhash[inet_bhashfn(net, port,
098754
+						  hinfo->bhash_size)];
098754
+		spin_lock_bh(&head->lock);
098754
+
098754
+		/* Does not bother with rcv_saddr checks, because
098754
+		 * the established check is already unique enough.
098754
+		 */
098754
+		inet_bind_bucket_for_each(tb, &head->chain) {
098754
+			if (net_eq(ib_net(tb), net) && tb->l3mdev == l3mdev &&
098754
+			    tb->port == port) {
098754
+				if (tb->fastreuse >= 0 ||
098754
+				    tb->fastreuseport >= 0)
098754
+					goto next_port;
098754
+				WARN_ON(hlist_empty(&tb->owners));
098754
+				if (!check_established(death_row, sk,
098754
+						       port, &tw))
098754
+					goto ok;
098754
+				goto next_port;
098754
+			}
098754
+		}
098754
+
098754
+		tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep,
098754
+					     net, head, port, l3mdev);
098754
+		if (!tb) {
098754
+			spin_unlock_bh(&head->lock);
098754
+			return -ENOMEM;
098754
+		}
098754
+		tb->fastreuse = -1;
098754
+		tb->fastreuseport = -1;
098754
+		goto ok;
098754
+next_port:
098754
+		spin_unlock_bh(&head->lock);
098754
+		cond_resched();
098754
+	}
098754
+
098754
+	offset++;
098754
+	if ((offset & 1) && remaining > 1)
098754
+		goto other_parity_scan;
098754
+
098754
+	return -EADDRNOTAVAIL;
098754
+
098754
+ok:
098754
+	/* Here we want to add a little bit of randomness to the next source
098754
+	 * port that will be chosen. We use a max() with a random here so that
098754
+	 * on low contention the randomness is maximal and on high contention
098754
+	 * it may be inexistent.
098754
+	 */
098754
+	i = max_t(int, i, (prandom_u32() & 7) * 2);
098754
+	WRITE_ONCE(klp_table_perturb[index], READ_ONCE(klp_table_perturb[index]) + i + 2);
098754
+
098754
+	/* Head lock still held and bh's disabled */
098754
+	inet_bind_hash(sk, tb, port);
098754
+	if (sk_unhashed(sk)) {
098754
+		inet_sk(sk)->inet_sport = htons(port);
098754
+		inet_ehash_nolisten(sk, (struct sock *)tw, NULL);
098754
+	}
098754
+	if (tw)
098754
+		inet_twsk_bind_unhash(tw, hinfo);
098754
+	spin_unlock(&head->lock);
098754
+	if (tw)
098754
+		inet_twsk_deschedule_put(tw);
098754
+	local_bh_enable();
098754
+	return 0;
098754
+}
098754
+
098754
 /*
098754
  * Bind a port for a connect operation and hash it.
098754
  */
098754
+__attribute__((optimize("-fno-optimize-sibling-calls")))
098754
 int inet_hash_connect(struct inet_timewait_death_row *death_row,
098754
 		      struct sock *sk)
098754
 {
098754
-	u32 port_offset = 0;
098754
+	u64 port_offset = 0;
098754
 
098754
 	if (!inet_sk(sk)->inet_num)
098754
 		port_offset = inet_sk_port_offset(sk);
098754
-	return __inet_hash_connect(death_row, sk, port_offset,
098754
-				   __inet_check_established);
098754
+	return klp__inet_hash_connect(death_row, sk, port_offset,
098754
+				      __inet_check_established);
098754
 }
098754
 EXPORT_SYMBOL_GPL(inet_hash_connect);
098754
 
098754
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
098754
index 67c9114835c8..fe0c5e5935e7 100644
098754
--- a/net/ipv6/inet6_hashtables.c
098754
+++ b/net/ipv6/inet6_hashtables.c
098754
@@ -308,24 +308,30 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
098754
 	return -EADDRNOTAVAIL;
098754
 }
098754
 
098754
-static u32 inet6_sk_port_offset(const struct sock *sk)
098754
+u64 klp_secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
098754
+				   __be16 dport);
098754
+static u64 inet6_sk_port_offset(const struct sock *sk)
098754
 {
098754
 	const struct inet_sock *inet = inet_sk(sk);
098754
 
098754
-	return secure_ipv6_port_ephemeral(sk->sk_v6_rcv_saddr.s6_addr32,
098754
-					  sk->sk_v6_daddr.s6_addr32,
098754
-					  inet->inet_dport);
098754
+	return klp_secure_ipv6_port_ephemeral(sk->sk_v6_rcv_saddr.s6_addr32,
098754
+					      sk->sk_v6_daddr.s6_addr32,
098754
+					      inet->inet_dport);
098754
 }
098754
 
098754
+int klp__inet_hash_connect(struct inet_timewait_death_row *death_row,
098754
+			   struct sock *sk, u64 port_offset,
098754
+			   int (*check_established)(struct inet_timewait_death_row *,
098754
+				   struct sock *, __u16, struct inet_timewait_sock **));
098754
 int inet6_hash_connect(struct inet_timewait_death_row *death_row,
098754
 		       struct sock *sk)
098754
 {
098754
-	u32 port_offset = 0;
098754
+	u64 port_offset = 0;
098754
 
098754
 	if (!inet_sk(sk)->inet_num)
098754
 		port_offset = inet6_sk_port_offset(sk);
098754
-	return __inet_hash_connect(death_row, sk, port_offset,
098754
-				   __inet6_check_established);
098754
+	return klp__inet_hash_connect(death_row, sk, port_offset,
098754
+				      __inet6_check_established);
098754
 }
098754
 EXPORT_SYMBOL_GPL(inet6_hash_connect);
098754
 
098754
-- 
098754
2.26.3
098754
098754