Commit bfe7cfb6 authored by Zhongqiu Duan's avatar Zhongqiu Duan Committed by Pablo Neira Ayuso
Browse files

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: 795595f6 ("netfilter: nft_quota: dump consumed quota")
Signed-off-by: default avatarZhongqiu Duan <dzq.aishenghu0@gmail.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent d33f889f
Loading
Loading
Loading
Loading
+13 −7
Original line number Diff line number Diff line
@@ -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);