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: 795595f68d
("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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
585c9ed565
commit
5e4519d8cd
@@ -19,10 +19,16 @@ struct nft_quota {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static inline bool nft_overquota(struct nft_quota *priv,
|
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) >=
|
u64 consumed = atomic64_add_return(skb->len, priv->consumed);
|
||||||
atomic64_read(&priv->quota);
|
u64 quota = atomic64_read(&priv->quota);
|
||||||
|
|
||||||
|
if (report)
|
||||||
|
*report = consumed >= quota;
|
||||||
|
|
||||||
|
return consumed > quota;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool nft_quota_invert(struct nft_quota *priv)
|
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,
|
struct nft_regs *regs,
|
||||||
const struct nft_pktinfo *pkt)
|
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;
|
regs->verdict.code = NFT_BREAK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,13 +57,13 @@ static void nft_quota_obj_eval(struct nft_object *obj,
|
|||||||
const struct nft_pktinfo *pkt)
|
const struct nft_pktinfo *pkt)
|
||||||
{
|
{
|
||||||
struct nft_quota *priv = nft_obj_data(obj);
|
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))
|
if (overquota ^ nft_quota_invert(priv))
|
||||||
regs->verdict.code = NFT_BREAK;
|
regs->verdict.code = NFT_BREAK;
|
||||||
|
|
||||||
if (overquota &&
|
if (report &&
|
||||||
!test_and_set_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags))
|
!test_and_set_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags))
|
||||||
nft_obj_notify(nft_net(pkt), obj->key.table, obj, 0, 0,
|
nft_obj_notify(nft_net(pkt), obj->key.table, obj, 0, 0,
|
||||||
NFT_MSG_NEWOBJ, 0, nft_pf(pkt), 0, GFP_ATOMIC);
|
NFT_MSG_NEWOBJ, 0, nft_pf(pkt), 0, GFP_ATOMIC);
|
||||||
|
Reference in New Issue
Block a user