From nobody Sun Dec 26 18:48:54 2021 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 2EB6F1912327; Sun, 26 Dec 2021 18:48:55 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4JMVFL6TDQz3jwn; Sun, 26 Dec 2021 18:48:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id BAC877947; Sun, 26 Dec 2021 18:48:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 1BQIms98075524; Sun, 26 Dec 2021 18:48:54 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 1BQImsZh075523; Sun, 26 Dec 2021 18:48:54 GMT (envelope-from git) Date: Sun, 26 Dec 2021 18:48:54 GMT Message-Id: <202112261848.1BQImsZh075523@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Gleb Smirnoff Subject: git: a057769205c3 - main - in_pcb: use jenkins hash over the entire IPv6 (or IPv4) address List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: glebius X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: a057769205c3a14e14d4e2a4a3635f6db78c4098 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1640544534; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=pYswWzA18uOggSha2TZ0eY4nQpi9nq57eit0e8mucEw=; b=Bi8qgiduyBGXs2Z+96TMlMLEdwWxb+G2ySP+yqsWE32BBhTKh/iwNemfVeOUK8h/nuMnCX lsWm+9WaUB9S4zhS2tn+PNVPKirMUsT4i4PY14euTpLt8xmXdUO3/H8mPt63sr31pDp8rA WoWgpyoIi4T3oKyXh4jre+Y9TsE+KXO/YKplZVlXb8KxOkag4xnIozJKBguoICRsFVQ8l2 GPQQ7BIJZtMZUnTrXgiinCd9TlkwZB9li0FVveq7sLvAZyEk3cRcHt7CsrKguqfvvtLGps KIZS/5+Oy5T2BfIMd+cPHjKITgpudIYQi/MwX0hIlI+jt+y9gD70RvISXj0BbQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1640544534; a=rsa-sha256; cv=none; b=B+dcSn28rvlxCzteifJXd1TgoVvwfaSTu3PruLQz4wWNGlmVjPDDlQOeRTi2QmrlHZ5lga sdCcAXBNsWYfFlFLlYky+yMMJH6L+GDtwjkmtqI5z288nGLAKyJLY21dPZ4neTgdgk2IGC 3OXYGDRJ/2hkkPIZ35AR+xa9CFBW+VLuesNlSzMLrCZa7XWNz69dIq1YCbTFuaeQ1SrVGR WzCe+pHMUUUirvRgwVgS22vlKq6c9KMgDgMRIsz7RghONrnJE2RnX/POHld18PYkVGMLrl 3QRNTkb62zW5Fd+kjmMshfKocjP5wUeWnxCVrCidbfJxYxIXeESs0aki8wmPYw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=a057769205c3a14e14d4e2a4a3635f6db78c4098 commit a057769205c3a14e14d4e2a4a3635f6db78c4098 Author: Gleb Smirnoff AuthorDate: 2021-12-26 18:47:28 +0000 Commit: Gleb Smirnoff CommitDate: 2021-12-26 18:47:28 +0000 in_pcb: use jenkins hash over the entire IPv6 (or IPv4) address The intent is to provide more entropy than can be provided by just the 32-bits of the IPv6 address which overlaps with 6to4 tunnels. This is needed to mitigate potential algorithmic complexity attacks from attackers who can control large numbers of IPv6 addresses. Together with: gallatin Reviewed by: dwmalone, rscheff Differential revision: https://reviews.freebsd.org/D33254 --- sys/netinet/in_pcb.c | 44 ++++++++++++++++++++++++++------------------ sys/netinet/in_pcb.h | 40 ++++++++++++++++++++++++++++++++-------- sys/netinet/in_pcb_var.h | 3 +++ sys/netinet6/in6_pcb.c | 15 +++++++-------- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index b1cbef537c88..b0ee7aa8f522 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -49,7 +49,9 @@ __FBSDID("$FreeBSD$"); #include "opt_rss.h" #include +#include #include +#include #include #include #include @@ -246,6 +248,16 @@ SYSCTL_COUNTER_U64(_net_inet_ip_rl, OID_AUTO, chgrl, CTLFLAG_RD, #endif /* INET */ +VNET_DEFINE(uint32_t, in_pcbhashseed); +static void +in_pcbhashseed_init(void) +{ + + V_in_pcbhashseed = arc4random(); +} +VNET_SYSINIT(in_pcbhashseed_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, + in_pcbhashseed_init, 0); + /* * in_pcb.c: manage the Protocol Control Blocks. * @@ -2085,8 +2097,8 @@ in_pcblookup_local(struct inpcbinfo *pcbinfo, struct in_addr laddr, * Look for an unconnected (wildcard foreign addr) PCB that * matches the local address and port we're looking for. */ - head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, - 0, pcbinfo->ipi_hashmask)]; + head = &pcbinfo->ipi_hashbase[INP_PCBHASH_WILD(lport, + pcbinfo->ipi_hashmask)]; CK_LIST_FOREACH(inp, head, inp_hash) { #ifdef INET6 /* XXX inp locking */ @@ -2214,7 +2226,7 @@ in_pcblookup_lbgroup(const struct inpcbinfo *pcbinfo, if (grp->il_lport != lport) continue; - idx = INP_PCBLBGROUP_PKTHASH(faddr->s_addr, lport, fport) % + idx = INP_PCBLBGROUP_PKTHASH(faddr, lport, fport) % grp->il_inpcnt; if (grp->il_laddr.s_addr == laddr->s_addr) { if (numa_domain == M_NODOM || @@ -2260,7 +2272,7 @@ in_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in_addr faddr, * First look for an exact match. */ tmpinp = NULL; - head = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, + head = &pcbinfo->ipi_hashbase[INP_PCBHASH(&faddr, lport, fport, pcbinfo->ipi_hashmask)]; CK_LIST_FOREACH(inp, head, inp_hash) { #ifdef INET6 @@ -2315,8 +2327,8 @@ in_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in_addr faddr, * 4. non-jailed, wild. */ - head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, - 0, pcbinfo->ipi_hashmask)]; + head = &pcbinfo->ipi_hashbase[INP_PCBHASH_WILD(lport, + pcbinfo->ipi_hashmask)]; CK_LIST_FOREACH(inp, head, inp_hash) { #ifdef INET6 /* XXX inp locking */ @@ -2439,7 +2451,6 @@ in_pcbinshash(struct inpcb *inp) struct inpcbporthead *pcbporthash; struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; struct inpcbport *phd; - u_int32_t hashkey_faddr; int so_options; INP_WLOCK_ASSERT(inp); @@ -2450,13 +2461,12 @@ in_pcbinshash(struct inpcb *inp) #ifdef INET6 if (inp->inp_vflag & INP_IPV6) - hashkey_faddr = INP6_PCBHASHKEY(&inp->in6p_faddr); + pcbhash = &pcbinfo->ipi_hashbase[INP6_PCBHASH(&inp->in6p_faddr, + inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; else #endif - hashkey_faddr = inp->inp_faddr.s_addr; - - pcbhash = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr, - inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; + pcbhash = &pcbinfo->ipi_hashbase[INP_PCBHASH(&inp->inp_faddr, + inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; pcbporthash = &pcbinfo->ipi_porthashbase[ INP_PCBPORTHASH(inp->inp_lport, pcbinfo->ipi_porthashmask)]; @@ -2516,7 +2526,6 @@ in_pcbrehash(struct inpcb *inp) { struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; struct inpcbhead *head; - u_int32_t hashkey_faddr; INP_WLOCK_ASSERT(inp); INP_HASH_WLOCK_ASSERT(pcbinfo); @@ -2526,13 +2535,12 @@ in_pcbrehash(struct inpcb *inp) #ifdef INET6 if (inp->inp_vflag & INP_IPV6) - hashkey_faddr = INP6_PCBHASHKEY(&inp->in6p_faddr); + head = &pcbinfo->ipi_hashbase[INP6_PCBHASH(&inp->in6p_faddr, + inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; else #endif - hashkey_faddr = inp->inp_faddr.s_addr; - - head = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr, - inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; + head = &pcbinfo->ipi_hashbase[INP_PCBHASH(&inp->inp_faddr, + inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; CK_LIST_REMOVE(inp, inp_hash); CK_LIST_INSERT_HEAD(head, inp, inp_hash); diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index 02e6c7b60e38..0e87a68e81fa 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -73,7 +73,8 @@ typedef uint64_t inp_gen_t; /* * PCB with AF_INET6 null bind'ed laddr can receive AF_INET input packet. * So, AF_INET6 null laddr is also used as AF_INET null laddr, by utilizing - * the following structure. + * the following structure. This requires padding always be zeroed out, + * which is done right after inpcb allocation and stays through its lifetime. */ struct in_addr_4in6 { u_int32_t ia46_pad32[3]; @@ -530,13 +531,36 @@ int inp_so_options(const struct inpcb *inp); #define INP_HASH_WLOCK_ASSERT(ipi) mtx_assert(&(ipi)->ipi_hash_lock, \ MA_OWNED) -#define INP_PCBHASH(faddr, lport, fport, mask) \ - (((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport))) & (mask)) -#define INP_PCBPORTHASH(lport, mask) \ - (ntohs((lport)) & (mask)) -#define INP_PCBLBGROUP_PKTHASH(faddr, lport, fport) \ - ((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport))) -#define INP6_PCBHASHKEY(faddr) ((faddr)->s6_addr32[3]) +/* + * Wildcard matching hash is not just a microoptimisation! The hash for + * wildcard IPv4 and wildcard IPv6 must be the same, otherwise AF_INET6 + * wildcard bound pcb won't be able to receive AF_INET connections, while: + * jenkins_hash(&zeroes, 1, s) != jenkins_hash(&zeroes, 4, s) + * See also comment above struct in_addr_4in6. + */ +#define IN_ADDR_JHASH32(addr) \ + ((addr)->s_addr == INADDR_ANY ? V_in_pcbhashseed : \ + jenkins_hash32((&(addr)->s_addr), 1, V_in_pcbhashseed)) +#define IN6_ADDR_JHASH32(addr) \ + (memcmp((addr), &in6addr_any, sizeof(in6addr_any)) == 0 ? \ + V_in_pcbhashseed : \ + jenkins_hash32((addr)->__u6_addr.__u6_addr32, \ + nitems((addr)->__u6_addr.__u6_addr32), V_in_pcbhashseed)) + +#define INP_PCBHASH(faddr, lport, fport, mask) \ + ((IN_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport))) & (mask)) +#define INP6_PCBHASH(faddr, lport, fport, mask) \ + ((IN6_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport))) & (mask)) + +#define INP_PCBHASH_WILD(lport, mask) \ + ((V_in_pcbhashseed ^ ntohs(lport)) & (mask)) + +#define INP_PCBLBGROUP_PKTHASH(faddr, lport, fport) \ + (IN_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport))) +#define INP6_PCBLBGROUP_PKTHASH(faddr, lport, fport) \ + (IN6_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport))) + +#define INP_PCBPORTHASH(lport, mask) (ntohs((lport)) & (mask)) /* * Flags for inp_vflags -- historically version flags only diff --git a/sys/netinet/in_pcb_var.h b/sys/netinet/in_pcb_var.h index 4db20418708d..31214b6092f3 100644 --- a/sys/netinet/in_pcb_var.h +++ b/sys/netinet/in_pcb_var.h @@ -44,6 +44,9 @@ * Definitions shared between netinet/in_pcb.c and netinet6/in6_pcb.c */ +VNET_DECLARE(uint32_t, in_pcbhashseed); +#define V_in_pcbhashseed VNET(in_pcbhashseed) + bool inp_smr_lock(struct inpcb *, const inp_lookup_t); int in_pcb_lport(struct inpcb *, struct in_addr *, u_short *, struct ucred *, int); diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index f86c72958a9e..2d76a8b3db77 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$"); #include "opt_route.h" #include "opt_rss.h" +#include #include #include #include @@ -787,8 +788,7 @@ in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr, * Look for an unconnected (wildcard foreign addr) PCB that * matches the local address and port we're looking for. */ - head = &pcbinfo->ipi_hashbase[INP_PCBHASH( - INP6_PCBHASHKEY(&in6addr_any), lport, 0, + head = &pcbinfo->ipi_hashbase[INP_PCBHASH_WILD(lport, pcbinfo->ipi_hashmask)]; CK_LIST_FOREACH(inp, head, inp_hash) { /* XXX inp locking */ @@ -972,8 +972,8 @@ in6_pcblookup_lbgroup(const struct inpcbinfo *pcbinfo, if (grp->il_lport != lport) continue; - idx = INP_PCBLBGROUP_PKTHASH(INP6_PCBHASHKEY(faddr), lport, - fport) % grp->il_inpcnt; + idx = INP6_PCBLBGROUP_PKTHASH(faddr, lport, fport) % + grp->il_inpcnt; if (IN6_ARE_ADDR_EQUAL(&grp->il6_laddr, laddr)) { if (numa_domain == M_NODOM || grp->il_numa_domain == numa_domain) { @@ -1015,8 +1015,8 @@ in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in6_addr *faddr, * First look for an exact match. */ tmpinp = NULL; - head = &pcbinfo->ipi_hashbase[INP_PCBHASH( - INP6_PCBHASHKEY(faddr), lport, fport, pcbinfo->ipi_hashmask)]; + head = &pcbinfo->ipi_hashbase[INP6_PCBHASH(faddr, lport, fport, + pcbinfo->ipi_hashmask)]; CK_LIST_FOREACH(inp, head, inp_hash) { /* XXX inp locking */ if ((inp->inp_vflag & INP_IPV6) == 0) @@ -1064,8 +1064,7 @@ in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in6_addr *faddr, * 3. non-jailed, non-wild. * 4. non-jailed, wild. */ - head = &pcbinfo->ipi_hashbase[INP_PCBHASH( - INP6_PCBHASHKEY(&in6addr_any), lport, 0, + head = &pcbinfo->ipi_hashbase[INP_PCBHASH_WILD(lport, pcbinfo->ipi_hashmask)]; CK_LIST_FOREACH(inp, head, inp_hash) { /* XXX inp locking */