Skip to content

Commit

Permalink
netfilter: nft_limit: reject configurations that cause integer overflow
Browse files Browse the repository at this point in the history
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: d2168e8 ("netfilter: nft_limit: add per-byte limiting")
Signed-off-by: Florian Westphal <[email protected]>
Signed-off-by: Pablo Neira Ayuso <[email protected]>
  • Loading branch information
Florian Westphal authored and ummakynes committed Jan 24, 2024
1 parent 01acb2e commit c9d9eb9
Showing 1 changed file with 16 additions and 7 deletions.
23 changes: 16 additions & 7 deletions net/netfilter/nft_limit.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,19 @@ static inline bool nft_limit_eval(struct nft_limit_priv *priv, u64 cost)
static int nft_limit_init(struct nft_limit_priv *priv,
const struct nlattr * const tb[], bool pkts)
{
u64 unit, tokens, rate_with_burst;
bool invert = false;
u64 unit, tokens;

if (tb[NFTA_LIMIT_RATE] == NULL ||
tb[NFTA_LIMIT_UNIT] == NULL)
return -EINVAL;

priv->rate = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_RATE]));
if (priv->rate == 0)
return -EINVAL;

unit = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_UNIT]));
priv->nsecs = unit * NSEC_PER_SEC;
if (priv->rate == 0 || priv->nsecs < unit)
if (check_mul_overflow(unit, NSEC_PER_SEC, &priv->nsecs))
return -EOVERFLOW;

if (tb[NFTA_LIMIT_BURST])
Expand All @@ -77,18 +79,25 @@ static int nft_limit_init(struct nft_limit_priv *priv,
if (pkts && priv->burst == 0)
priv->burst = NFT_LIMIT_PKT_BURST_DEFAULT;

if (priv->rate + priv->burst < priv->rate)
if (check_add_overflow(priv->rate, priv->burst, &rate_with_burst))
return -EOVERFLOW;

if (pkts) {
tokens = div64_u64(priv->nsecs, priv->rate) * priv->burst;
u64 tmp = div64_u64(priv->nsecs, priv->rate);

if (check_mul_overflow(tmp, priv->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(priv->nsecs * (priv->rate + priv->burst),
priv->rate);
if (check_mul_overflow(priv->nsecs, rate_with_burst, &tmp))
return -EOVERFLOW;

tokens = div64_u64(tmp, priv->rate);
}

if (tb[NFTA_LIMIT_FLAGS]) {
Expand Down

0 comments on commit c9d9eb9

Please sign in to comment.