summaryrefslogtreecommitdiff
path: root/net/netfilter
diff options
context:
space:
mode:
authorZhongqiu Duan <dzq.aishenghu0@gmail.com>2025-04-17 15:49:30 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-06-27 11:07:10 +0100
commite1db95b19a5d75766241b7a68ec29bd71dfc940c (patch)
tree413fb7d3d5e0f2ec8b7892305cd56720e6b7b8a6 /net/netfilter
parent260cbb00910f96f83874ca846285f71ae1dff097 (diff)
downloadlinux-e1db95b19a5d75766241b7a68ec29bd71dfc940c.tar.gz
linux-e1db95b19a5d75766241b7a68ec29bd71dfc940c.tar.bz2
linux-e1db95b19a5d75766241b7a68ec29bd71dfc940c.zip
netfilter: nft_quota: match correctly when the quota just depleted
[ Upstream commit bfe7cfb65c753952735c3eed703eba9a8b96a18d ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nft_quota.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/net/netfilter/nft_quota.c b/net/netfilter/nft_quota.c
index ef8e7cdbd0e6..60e6d0c5f04e 100644
--- a/net/netfilter/nft_quota.c
+++ b/net/netfilter/nft_quota.c
@@ -19,10 +19,16 @@ struct nft_quota {
};
static inline bool nft_overquota(struct nft_quota *priv,
- const struct sk_buff *skb)
+ const struct sk_buff *skb,
+ bool *report)
{
- return atomic64_add_return(skb->len, priv->consumed) >=
- atomic64_read(&priv->quota);
+ u64 consumed = atomic64_add_return(skb->len, priv->consumed);
+ u64 quota = atomic64_read(&priv->quota);
+
+ if (report)
+ *report = consumed >= quota;
+
+ return consumed > quota;
}
static inline bool nft_quota_invert(struct nft_quota *priv)
@@ -34,7 +40,7 @@ static inline void nft_quota_do_eval(struct nft_quota *priv,
struct nft_regs *regs,
const struct nft_pktinfo *pkt)
{
- if (nft_overquota(priv, pkt->skb) ^ nft_quota_invert(priv))
+ if (nft_overquota(priv, pkt->skb, NULL) ^ nft_quota_invert(priv))
regs->verdict.code = NFT_BREAK;
}
@@ -51,13 +57,13 @@ static void nft_quota_obj_eval(struct nft_object *obj,
const struct nft_pktinfo *pkt)
{
struct nft_quota *priv = nft_obj_data(obj);
- bool overquota;
+ bool overquota, report;
- overquota = nft_overquota(priv, pkt->skb);
+ overquota = nft_overquota(priv, pkt->skb, &report);
if (overquota ^ nft_quota_invert(priv))
regs->verdict.code = NFT_BREAK;
- if (overquota &&
+ if (report &&
!test_and_set_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags))
nft_obj_notify(nft_net(pkt), obj->key.table, obj, 0, 0,
NFT_MSG_NEWOBJ, 0, nft_pf(pkt), 0, GFP_ATOMIC);