From nobody Wed Feb 12 10:04:59 2025 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 4YtDSr0DMbz5mVj0; Wed, 12 Feb 2025 10:05:00 +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 "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4YtDSq6mkcz3XWV; Wed, 12 Feb 2025 10:04:59 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1739354699; 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=zAzlDierRjUdjYdq+X082LSuIbOTwLNB01PSiDV2MB8=; b=iFGzd15QSHbU39unVwEKIBkvgR899jKTEKy//cF/Q/myOVXkKeSGmstmt7T0IBGnux39+j KxjJ5mIkkC/S4yFuN5dw3BEBuQVK19gWDrRLE/wmm6z/VjoUpzlPh8T6JF/1CLfxK7e3if /JcUzWoegSvV71HPM1KDy3rlvyO6BvT/Pw2EcssRwq1+7gyZzhtoGwrIny+8QX2V33i2kQ +Mv3lyQ/iEUtnEnY8V/OvbeZxWbZe8Ej6FcwelDQtdC2oLjZEtlftWIAtRJBuncYEEDetq s0aTXoVme4fJgVXtnYdz2vNrZzbO3gS4/XOyW8tAzaP9Dt8OCD/TY6C+grMmoQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1739354699; 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=zAzlDierRjUdjYdq+X082LSuIbOTwLNB01PSiDV2MB8=; b=I9NTe7igA4cxJi7nIob5UNJpk4BS8K+MX6owy/bjWRvMyswY28v46KErMQM8zjBDV0N53a G/P1AX/6j2Tx2d4Xk0ny1mXqTnJqDo9A5jXXGTla/TJuK+et+xCbz6WWvkl1ThfrP1csw6 tD9wb+Q9NXlZa9OueVo91jZwvD7oY43p/Oq5aNBQbG6bSvqvdrsBPkYximLA62sHIeuGB6 nyi8A3b6tEitx+vGO/nljFCS9w8/R4HdrRon16xo8gcoiVWN2EuhKx/jb/CuGkzuQtkrCP vXHj0w9O1ByX1UjLUbcf2VE9FH/WlU3Zx/GLcQwQ2EYI1CmkPNxOpZAUeWVvkA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1739354700; a=rsa-sha256; cv=none; b=wy8l9YbC3HdktsjOuatWKA9pcJjf19rShSEi015vJCgWo9//ULWWlk6BTckYmftaBW/PIv ZEuViec2lQIXbZLNppBUvKUDgLG4pJxDpfFMzml6gaTpr+86q/ig0RPjtr0prvdLbOA583 ePLM1KJrGII2judgjDQpHFvMxWRwl4Bs5y9Gf9DWHJ9RhrlkBUQfJSjgPF5z8Dd+i0fMlA j5KEBv2ROVbMNsqK1H5HjpmB1lUHQ67yqP4WNQ3H1KM+GARKFTnEhdwC4nCm0NVkuIxvn4 ypsQtkkpxiEVE6NHLduu+lveRSImfWPqge9cOGYatfAvlDX0QvLJujEr5ifiOA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none 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 4YtDSq6MGZztZ9; Wed, 12 Feb 2025 10:04:59 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 51CA4xfx093102; Wed, 12 Feb 2025 10:04:59 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 51CA4xgB093099; Wed, 12 Feb 2025 10:04:59 GMT (envelope-from git) Date: Wed, 12 Feb 2025 10:04:59 GMT Message-Id: <202502121004.51CA4xgB093099@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Michael Tuexen Subject: git: ccd9c1ef4e90 - stable/14 - icmp: use per rate limit randomized jitter 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: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: tuexen X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: ccd9c1ef4e9008a3ba264756a2e6fff7dfd3dc86 Auto-Submitted: auto-generated The branch stable/14 has been updated by tuexen: URL: https://cgit.FreeBSD.org/src/commit/?id=ccd9c1ef4e9008a3ba264756a2e6fff7dfd3dc86 commit ccd9c1ef4e9008a3ba264756a2e6fff7dfd3dc86 Author: Michael Tuexen AuthorDate: 2025-02-10 21:16:20 +0000 Commit: Michael Tuexen CommitDate: 2025-02-12 10:04:10 +0000 icmp: use per rate limit randomized jitter Using the same random jitter for multiple rate limits allows an attacker to use one rate limiter to figure out the current jitter and then use this knowledge to de-randomize the other rate limiters. This can be mitigated by using a separate randomized jitter for each rate limiter. This issue was reported as issue number 10 in Keyu Man et al.: SCAD: Towards a Universal and Automated Network Side-Channel Vulnerability Detection Reviewed by: rrs, Peter Lei, glebius Sponsored by: Netflix, Inc. Differential Revision: https://reviews.freebsd.org/D48804 (cherry picked from commit 923c223f27e792e51ca13c476428adbbf6887551) --- sys/netinet/ip_icmp.c | 20 ++++++++++++-------- sys/netinet6/icmp6.c | 50 +++++++++++++++++++++++++++----------------------- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index 24a14c4d4879..26ee6e5c1245 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -90,7 +90,7 @@ SYSCTL_PROC(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLTYPE_UINT | &sysctl_icmplim_and_jitter, "IU", "Maximum number of ICMP responses per second"); -VNET_DEFINE_STATIC(int, icmplim_curr_jitter) = 0; +VNET_DEFINE_STATIC(int, icmplim_curr_jitter[BANDLIM_MAX]) = {0}; #define V_icmplim_curr_jitter VNET(icmplim_curr_jitter) VNET_DEFINE_STATIC(u_int, icmplim_jitter) = 16; #define V_icmplim_jitter VNET(icmplim_jitter) @@ -1110,14 +1110,16 @@ static const char *icmp_rate_descrs[BANDLIM_MAX] = { }; static void -icmplim_new_jitter(void) +icmplim_new_jitter(int which) { /* * Adjust limit +/- to jitter the measurement to deny a side-channel * port scan as in https://dl.acm.org/doi/10.1145/3372297.3417280 */ + KASSERT(which >= 0 && which < BANDLIM_MAX, + ("%s: which %d", __func__, which)); if (V_icmplim_jitter > 0) - V_icmplim_curr_jitter = + V_icmplim_curr_jitter[which] = arc4random_uniform(V_icmplim_jitter * 2 + 1) - V_icmplim_jitter; } @@ -1146,7 +1148,9 @@ sysctl_icmplim_and_jitter(SYSCTL_HANDLER_ARGS) error = EINVAL; else { V_icmplim_jitter = new; - icmplim_new_jitter(); + for (int i = 0; i < BANDLIM_MAX; i++) { + icmplim_new_jitter(i); + } } } } @@ -1162,8 +1166,8 @@ icmp_bandlimit_init(void) for (int i = 0; i < BANDLIM_MAX; i++) { V_icmp_rates[i].cr_rate = counter_u64_alloc(M_WAITOK); V_icmp_rates[i].cr_ticks = ticks; + icmplim_new_jitter(i); } - icmplim_new_jitter(); } VNET_SYSINIT(icmp_bandlimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, icmp_bandlimit_init, NULL); @@ -1192,14 +1196,14 @@ badport_bandlim(int which) ("%s: which %d", __func__, which)); pps = counter_ratecheck(&V_icmp_rates[which], V_icmplim + - V_icmplim_curr_jitter); + V_icmplim_curr_jitter[which]); if (pps > 0) { if (V_icmplim_output) log(LOG_NOTICE, "Limiting %s response from %jd to %d packets/sec\n", icmp_rate_descrs[which], (intmax_t )pps, - V_icmplim + V_icmplim_curr_jitter); - icmplim_new_jitter(); + V_icmplim + V_icmplim_curr_jitter[which]); + icmplim_new_jitter(which); } if (pps == -1) return (-1); diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 138a7ce71bbc..39c252e16b75 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -2741,22 +2741,6 @@ SYSCTL_PROC(_net_inet6_icmp6, ICMPV6CTL_ERRPPSLIMIT, errppslimit, &sysctl_icmp6lim_and_jitter, "IU", "Maximum number of ICMPv6 error/reply messages per second"); -VNET_DEFINE_STATIC(int, icmp6lim_curr_jitter) = 0; -#define V_icmp6lim_curr_jitter VNET(icmp6lim_curr_jitter) - -VNET_DEFINE_STATIC(u_int, icmp6lim_jitter) = 8; -#define V_icmp6lim_jitter VNET(icmp6lim_jitter) -SYSCTL_PROC(_net_inet6_icmp6, OID_AUTO, icmp6lim_jitter, CTLTYPE_UINT | - CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6lim_jitter), 0, - &sysctl_icmp6lim_and_jitter, "IU", - "Random errppslimit jitter adjustment limit"); - -VNET_DEFINE_STATIC(int, icmp6lim_output) = 1; -#define V_icmp6lim_output VNET(icmp6lim_output) -SYSCTL_INT(_net_inet6_icmp6, OID_AUTO, icmp6lim_output, - CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6lim_output), 0, - "Enable logging of ICMPv6 response rate limiting"); - typedef enum { RATELIM_PARAM_PROB = 0, RATELIM_TOO_BIG, @@ -2778,15 +2762,33 @@ static const char *icmp6_rate_descrs[RATELIM_MAX] = { [RATELIM_OTHER] = "(other)", }; +VNET_DEFINE_STATIC(int, icmp6lim_curr_jitter[RATELIM_MAX]) = {0}; +#define V_icmp6lim_curr_jitter VNET(icmp6lim_curr_jitter) + +VNET_DEFINE_STATIC(u_int, icmp6lim_jitter) = 8; +#define V_icmp6lim_jitter VNET(icmp6lim_jitter) +SYSCTL_PROC(_net_inet6_icmp6, OID_AUTO, icmp6lim_jitter, CTLTYPE_UINT | + CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6lim_jitter), 0, + &sysctl_icmp6lim_and_jitter, "IU", + "Random errppslimit jitter adjustment limit"); + +VNET_DEFINE_STATIC(int, icmp6lim_output) = 1; +#define V_icmp6lim_output VNET(icmp6lim_output) +SYSCTL_INT(_net_inet6_icmp6, OID_AUTO, icmp6lim_output, + CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6lim_output), 0, + "Enable logging of ICMPv6 response rate limiting"); + static void -icmp6lim_new_jitter(void) +icmp6lim_new_jitter(int which) { /* * Adjust limit +/- to jitter the measurement to deny a side-channel * port scan as in https://dl.acm.org/doi/10.1145/3372297.3417280 */ + KASSERT(which >= 0 && which < RATELIM_MAX, + ("%s: which %d", __func__, which)); if (V_icmp6lim_jitter > 0) - V_icmp6lim_curr_jitter = + V_icmp6lim_curr_jitter[which] = arc4random_uniform(V_icmp6lim_jitter * 2 + 1) - V_icmp6lim_jitter; } @@ -2815,7 +2817,9 @@ sysctl_icmp6lim_and_jitter(SYSCTL_HANDLER_ARGS) error = EINVAL; else { V_icmp6lim_jitter = new; - icmp6lim_new_jitter(); + for (int i = 0; i < RATELIM_MAX; i++) { + icmp6lim_new_jitter(i); + } } } } @@ -2835,8 +2839,8 @@ icmp6_ratelimit_init(void) for (int i = 0; i < RATELIM_MAX; i++) { V_icmp6_rates[i].cr_rate = counter_u64_alloc(M_WAITOK); V_icmp6_rates[i].cr_ticks = ticks; + icmp6lim_new_jitter(i); } - icmp6lim_new_jitter(); } VNET_SYSINIT(icmp6_ratelimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, icmp6_ratelimit_init, NULL); @@ -2898,14 +2902,14 @@ icmp6_ratelimit(const struct in6_addr *dst, const int type, const int code) }; pps = counter_ratecheck(&V_icmp6_rates[which], V_icmp6errppslim + - V_icmp6lim_curr_jitter); + V_icmp6lim_curr_jitter[which]); if (pps > 0) { if (V_icmp6lim_output) log(LOG_NOTICE, "Limiting ICMPv6 %s output from %jd " "to %d packets/sec\n", icmp6_rate_descrs[which], (intmax_t )pps, V_icmp6errppslim + - V_icmp6lim_curr_jitter); - icmp6lim_new_jitter(); + V_icmp6lim_curr_jitter[which]); + icmp6lim_new_jitter(which); } if (pps == -1) { ICMP6STAT_INC(icp6s_toofreq);