mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
netfilter: nf_tables: fix device name and prefix match in hook lookup
Currently, a netdev chain or flowtable hooked to a device prefix can be
unintentionally deleted by a control-plane request targeting an exact
device name or even a shorter one due to the usage of min() to calculate
the length to match.
Fix this by making sure an exact device match never matches a prefix and
that both the target and the candidate have the same length during
delete operation. The add and update paths retain the existing overlap
matching to prevent a single device from matching multiple hooks.
Reported-by: Wei Fang <void0red@gmail.com>
Closes: https://lore.kernel.org/netfilter-devel/CANE+tVrDeNCHQVmsqkV2ozeBqyE3GtRDMhZgsg1bhw10yGNTRQ@mail.gmail.com/
Fixes: 6d07a28950 ("netfilter: nf_tables: Support wildcard netdev hook specs")
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
d313499df6
commit
444e4c88c9
|
|
@ -2440,11 +2440,14 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
|
|||
}
|
||||
|
||||
static struct nft_hook *nft_hook_list_find(struct list_head *hook_list,
|
||||
const struct nft_hook *this)
|
||||
const struct nft_hook *this,
|
||||
bool strict)
|
||||
{
|
||||
struct nft_hook *hook;
|
||||
|
||||
list_for_each_entry(hook, hook_list, list) {
|
||||
if (strict && hook->ifnamelen != this->ifnamelen)
|
||||
continue;
|
||||
if (!strncmp(hook->ifname, this->ifname,
|
||||
min(hook->ifnamelen, this->ifnamelen))) {
|
||||
if (hook->flags & NFT_HOOK_REMOVE)
|
||||
|
|
@ -2486,7 +2489,7 @@ static int nf_tables_parse_netdev_hooks(struct net *net,
|
|||
err = PTR_ERR(hook);
|
||||
goto err_hook;
|
||||
}
|
||||
if (nft_hook_list_find(hook_list, hook)) {
|
||||
if (nft_hook_list_find(hook_list, hook, false)) {
|
||||
NL_SET_BAD_ATTR(extack, tmp);
|
||||
nft_netdev_hook_free(hook);
|
||||
err = -EEXIST;
|
||||
|
|
@ -2943,7 +2946,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
|
|||
ops->hook = basechain->ops.hook;
|
||||
}
|
||||
|
||||
if (nft_hook_list_find(&basechain->hook_list, h)) {
|
||||
if (nft_hook_list_find(&basechain->hook_list, h, false)) {
|
||||
list_del(&h->list);
|
||||
nft_netdev_hook_free(h);
|
||||
continue;
|
||||
|
|
@ -2956,7 +2959,8 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
|
|||
!nft_trans_chain_update(trans))
|
||||
continue;
|
||||
|
||||
if (nft_hook_list_find(&nft_trans_chain_hooks(trans), h)) {
|
||||
if (nft_hook_list_find(&nft_trans_chain_hooks(trans),
|
||||
h, false)) {
|
||||
nft_chain_release_hook(&hook);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
|
@ -3257,7 +3261,7 @@ static int nft_delchain_hook(struct nft_ctx *ctx,
|
|||
return err;
|
||||
|
||||
list_for_each_entry(this, &chain_hook.list, list) {
|
||||
hook = nft_hook_list_find(&basechain->hook_list, this);
|
||||
hook = nft_hook_list_find(&basechain->hook_list, this, true);
|
||||
if (!hook) {
|
||||
err = -ENOENT;
|
||||
goto err_chain_del_hook;
|
||||
|
|
@ -9053,7 +9057,7 @@ static int nft_register_flowtable_net_hooks(struct net *net,
|
|||
if (!nft_is_active_next(net, ft))
|
||||
continue;
|
||||
|
||||
if (nft_hook_list_find(&ft->hook_list, hook)) {
|
||||
if (nft_hook_list_find(&ft->hook_list, hook, false)) {
|
||||
err = -EEXIST;
|
||||
goto err_unregister_net_hooks;
|
||||
}
|
||||
|
|
@ -9130,7 +9134,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
|
|||
return err;
|
||||
|
||||
list_for_each_entry_safe(hook, next, &flowtable_hook.list, list) {
|
||||
if (nft_hook_list_find(&flowtable->hook_list, hook)) {
|
||||
if (nft_hook_list_find(&flowtable->hook_list, hook, false)) {
|
||||
list_del(&hook->list);
|
||||
nft_netdev_hook_free(hook);
|
||||
continue;
|
||||
|
|
@ -9143,7 +9147,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
|
|||
!nft_trans_flowtable_update(trans))
|
||||
continue;
|
||||
|
||||
if (nft_hook_list_find(&nft_trans_flowtable_hooks(trans), hook)) {
|
||||
if (nft_hook_list_find(&nft_trans_flowtable_hooks(trans), hook, false)) {
|
||||
err = -EEXIST;
|
||||
goto err_flowtable_update_hook;
|
||||
}
|
||||
|
|
@ -9363,7 +9367,7 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx,
|
|||
return err;
|
||||
|
||||
list_for_each_entry(this, &flowtable_hook.list, list) {
|
||||
hook = nft_hook_list_find(&flowtable->hook_list, this);
|
||||
hook = nft_hook_list_find(&flowtable->hook_list, this, true);
|
||||
if (!hook) {
|
||||
err = -ENOENT;
|
||||
goto err_flowtable_del_hook;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user