
From: Florian Westphal <fw@strlen.de> mainline inclusion from mainline-v6.8-rc2 commit c9d9eb9c53d37cdebbad56b91e40baf42d5a97aa category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9DNPD CVE: CVE-2024-26668 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Reject bogus configs where internal token counter wraps around. This only occurs with very very large requests, such as 17gbyte/s. Its better to reject this rather than having incorrect ratelimit. Fixes: d2168e849ebf ("netfilter: nft_limit: add per-byte limiting") Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Conflicts: net/netfilter/nft_limit.c Signed-off-by: Zhengchao Shao <shaozhengchao@huawei.com> --- net/netfilter/nft_limit.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/net/netfilter/nft_limit.c b/net/netfilter/nft_limit.c index a7bdc532479a..e9d95112d4dd 100644 --- a/net/netfilter/nft_limit.c +++ b/net/netfilter/nft_limit.c @@ -57,16 +57,18 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost) static int nft_limit_init(struct nft_limit *limit, const struct nlattr * const tb[], bool pkts) { - u64 unit, tokens; + u64 unit, tokens, rate_with_burst; if (tb[NFTA_LIMIT_RATE] == NULL || tb[NFTA_LIMIT_UNIT] == NULL) return -EINVAL; limit->rate = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_RATE])); + if (limit->rate == 0) + return -EINVAL; + unit = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_UNIT])); - limit->nsecs = unit * NSEC_PER_SEC; - if (limit->rate == 0 || limit->nsecs < unit) + if (check_mul_overflow(unit, ((u64)NSEC_PER_SEC), &limit->nsecs)) return -EOVERFLOW; if (tb[NFTA_LIMIT_BURST]) @@ -75,18 +77,25 @@ static int nft_limit_init(struct nft_limit *limit, if (pkts && limit->burst == 0) limit->burst = NFT_LIMIT_PKT_BURST_DEFAULT; - if (limit->rate + limit->burst < limit->rate) + if (check_add_overflow(limit->rate, ((u64)limit->burst), &rate_with_burst)) return -EOVERFLOW; if (pkts) { - tokens = div64_u64(limit->nsecs, limit->rate) * limit->burst; + u64 tmp = div64_u64(limit->nsecs, limit->rate); + + if (check_mul_overflow(tmp, ((u64)limit->burst), &tokens)) + return -EOVERFLOW; } else { + u64 tmp; + /* The token bucket size limits the number of tokens can be * accumulated. tokens_max specifies the bucket size. * tokens_max = unit * (rate + burst) / rate. */ - tokens = div64_u64(limit->nsecs * (limit->rate + limit->burst), - limit->rate); + if (check_mul_overflow(limit->nsecs, rate_with_burst, &tmp)) + return -EOVERFLOW; + + tokens = div64_u64(tmp, limit->rate); } limit->tokens = tokens; -- 2.34.1