Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nft_quota: match correctly when the quota just depleted

The xt_quota compares skb length with remaining quota, but the nft_quota
compares it with consumed bytes.

The xt_quota can match consumed bytes up to quota at maximum. But the
nft_quota break match when consumed bytes equal to quota.

i.e., nft_quota match consumed bytes in [0, quota - 1], not [0, quota].

Fixes: 795595f68d6c ("netfilter: nft_quota: dump consumed quota")
Signed-off-by: Zhongqiu Duan <dzq.aishenghu0@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Zhongqiu Duan and committed by
Pablo Neira Ayuso
bfe7cfb6 d33f889f

+13 -7
+13 -7
net/netfilter/nft_quota.c
··· 19 19 }; 20 20 21 21 static inline bool nft_overquota(struct nft_quota *priv, 22 - const struct sk_buff *skb) 22 + const struct sk_buff *skb, 23 + bool *report) 23 24 { 24 - return atomic64_add_return(skb->len, priv->consumed) >= 25 - atomic64_read(&priv->quota); 25 + u64 consumed = atomic64_add_return(skb->len, priv->consumed); 26 + u64 quota = atomic64_read(&priv->quota); 27 + 28 + if (report) 29 + *report = consumed >= quota; 30 + 31 + return consumed > quota; 26 32 } 27 33 28 34 static inline bool nft_quota_invert(struct nft_quota *priv) ··· 40 34 struct nft_regs *regs, 41 35 const struct nft_pktinfo *pkt) 42 36 { 43 - if (nft_overquota(priv, pkt->skb) ^ nft_quota_invert(priv)) 37 + if (nft_overquota(priv, pkt->skb, NULL) ^ nft_quota_invert(priv)) 44 38 regs->verdict.code = NFT_BREAK; 45 39 } 46 40 ··· 57 51 const struct nft_pktinfo *pkt) 58 52 { 59 53 struct nft_quota *priv = nft_obj_data(obj); 60 - bool overquota; 54 + bool overquota, report; 61 55 62 - overquota = nft_overquota(priv, pkt->skb); 56 + overquota = nft_overquota(priv, pkt->skb, &report); 63 57 if (overquota ^ nft_quota_invert(priv)) 64 58 regs->verdict.code = NFT_BREAK; 65 59 66 - if (overquota && 60 + if (report && 67 61 !test_and_set_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags)) 68 62 nft_obj_notify(nft_net(pkt), obj->key.table, obj, 0, 0, 69 63 NFT_MSG_NEWOBJ, 0, nft_pf(pkt), 0, GFP_ATOMIC);