diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-03-21 13:55:42 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-03-22 12:57:07 +0100 |
commit | d92191aa84e5f187d543867c3d54b38f294833fa (patch) | |
tree | 1f3f76eb4fd2c70a38b0c2f17fc7ef64ee574578 /net | |
parent | aebfa52a925d701114afd6af0def35bab16d4f47 (diff) | |
download | linux-d92191aa84e5f187d543867c3d54b38f294833fa.tar.bz2 |
netfilter: nf_tables: cache device name in flowtable object
Devices going away have to grab the nfnl_lock from the netdev event path
to avoid races with control plane updates.
However, netlink dumps in netfilter do not hold nfnl_lock mutex. Cache
the device name into the objects to avoid an use-after-free situation
for a device that is going away.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_tables_api.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 14777c404071..977d43e00f98 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -4932,8 +4932,6 @@ nf_tables_flowtable_lookup_byhandle(const struct nft_table *table, return ERR_PTR(-ENOENT); } -#define NFT_FLOWTABLE_DEVICE_MAX 8 - static int nf_tables_parse_devices(const struct nft_ctx *ctx, const struct nlattr *attr, struct net_device *dev_array[], int *len) @@ -5006,7 +5004,7 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx, err = nf_tables_parse_devices(ctx, tb[NFTA_FLOWTABLE_HOOK_DEVS], dev_array, &n); if (err < 0) - goto err1; + return err; ops = kzalloc(sizeof(struct nf_hook_ops) * n, GFP_KERNEL); if (!ops) { @@ -5026,6 +5024,8 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx, flowtable->ops[i].priv = &flowtable->data.rhashtable; flowtable->ops[i].hook = flowtable->data.type->hook; flowtable->ops[i].dev = dev_array[i]; + flowtable->dev_name[i] = kstrdup(dev_array[i]->name, + GFP_KERNEL); } err = 0; @@ -5203,8 +5203,10 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk, err5: i = flowtable->ops_len; err4: - for (k = i - 1; k >= 0; k--) + for (k = i - 1; k >= 0; k--) { + kfree(flowtable->dev_name[k]); nf_unregister_net_hook(net, &flowtable->ops[k]); + } kfree(flowtable->ops); err3: @@ -5294,9 +5296,9 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net, goto nla_put_failure; for (i = 0; i < flowtable->ops_len; i++) { - if (flowtable->ops[i].dev && + if (flowtable->dev_name[i][0] && nla_put_string(skb, NFTA_DEVICE_NAME, - flowtable->ops[i].dev->name)) + flowtable->dev_name[i])) goto nla_put_failure; } nla_nest_end(skb, nest_devs); @@ -5538,6 +5540,7 @@ static void nft_flowtable_event(unsigned long event, struct net_device *dev, continue; nf_unregister_net_hook(dev_net(dev), &flowtable->ops[i]); + flowtable->dev_name[i][0] = '\0'; flowtable->ops[i].dev = NULL; break; } |