]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
netfilter: nft_quota: match correctly when the quota just depleted
authorZhongqiu Duan <dzq.aishenghu0@gmail.com>
Thu, 17 Apr 2025 15:49:30 +0000 (15:49 +0000)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 5 May 2025 11:15:09 +0000 (13:15 +0200)
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>
net/netfilter/nft_quota.c

index 9b2d7463d3d32698069e93fdbc94f4910e1a3d55..df0798da2329b9150db43a236fb5570d40a0a445 100644 (file)
@@ -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);