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

netfilter: nf_tables: do not allow RULE_ID to refer to another chain

When doing lookups for rules on the same batch by using its ID, a rule from
a different chain can be used. If a rule is added to a chain but tries to
be positioned next to a rule from a different chain, it will be linked to
chain2, but the use counter on chain1 would be the one to be incremented.

When looking for rules by ID, use the chain that was used for the lookup by
name. The chain used in the context copied to the transaction needs to
match that same chain. That way, struct nft_rule does not need to get
enlarged with another member.

Fixes: 1a94e38d254b ("netfilter: nf_tables: add NFTA_RULE_ID attribute")
Fixes: 75dd48e2e420 ("netfilter: nf_tables: Support RULE_ID reference in new rule")
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Thadeu Lima de Souza Cascardo and committed by
Pablo Neira Ayuso
36d5b291 95f466d2

+5 -2
+5 -2
net/netfilter/nf_tables_api.c
··· 3373 3373 } 3374 3374 3375 3375 static struct nft_rule *nft_rule_lookup_byid(const struct net *net, 3376 + const struct nft_chain *chain, 3376 3377 const struct nlattr *nla); 3377 3378 3378 3379 #define NFT_RULE_MAXEXPRS 128 ··· 3462 3461 return PTR_ERR(old_rule); 3463 3462 } 3464 3463 } else if (nla[NFTA_RULE_POSITION_ID]) { 3465 - old_rule = nft_rule_lookup_byid(net, nla[NFTA_RULE_POSITION_ID]); 3464 + old_rule = nft_rule_lookup_byid(net, chain, nla[NFTA_RULE_POSITION_ID]); 3466 3465 if (IS_ERR(old_rule)) { 3467 3466 NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_POSITION_ID]); 3468 3467 return PTR_ERR(old_rule); ··· 3607 3606 } 3608 3607 3609 3608 static struct nft_rule *nft_rule_lookup_byid(const struct net *net, 3609 + const struct nft_chain *chain, 3610 3610 const struct nlattr *nla) 3611 3611 { 3612 3612 struct nftables_pernet *nft_net = nft_pernet(net); ··· 3618 3616 struct nft_rule *rule = nft_trans_rule(trans); 3619 3617 3620 3618 if (trans->msg_type == NFT_MSG_NEWRULE && 3619 + trans->ctx.chain == chain && 3621 3620 id == nft_trans_rule_id(trans)) 3622 3621 return rule; 3623 3622 } ··· 3668 3665 3669 3666 err = nft_delrule(&ctx, rule); 3670 3667 } else if (nla[NFTA_RULE_ID]) { 3671 - rule = nft_rule_lookup_byid(net, nla[NFTA_RULE_ID]); 3668 + rule = nft_rule_lookup_byid(net, chain, nla[NFTA_RULE_ID]); 3672 3669 if (IS_ERR(rule)) { 3673 3670 NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_ID]); 3674 3671 return PTR_ERR(rule);