Skip to content

Commit d92191a

Browse files
committed
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 <[email protected]>
1 parent aebfa52 commit d92191a

File tree

2 files changed

+13
-6
lines changed

2 files changed

+13
-6
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,8 @@ struct nft_object_ops {
10681068
int nft_register_obj(struct nft_object_type *obj_type);
10691069
void nft_unregister_obj(struct nft_object_type *obj_type);
10701070

1071+
#define NFT_FLOWTABLE_DEVICE_MAX 8
1072+
10711073
/**
10721074
* struct nft_flowtable - nf_tables flow table
10731075
*
@@ -1080,6 +1082,7 @@ void nft_unregister_obj(struct nft_object_type *obj_type);
10801082
* @genmask: generation mask
10811083
* @use: number of references to this flow table
10821084
* @handle: unique object handle
1085+
* @dev_name: array of device names
10831086
* @data: rhashtable and garbage collector
10841087
* @ops: array of hooks
10851088
*/
@@ -1093,6 +1096,7 @@ struct nft_flowtable {
10931096
u32 genmask:2,
10941097
use:30;
10951098
u64 handle;
1099+
char *dev_name[NFT_FLOWTABLE_DEVICE_MAX];
10961100
/* runtime data below here */
10971101
struct nf_hook_ops *ops ____cacheline_aligned;
10981102
struct nf_flowtable data;

net/netfilter/nf_tables_api.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4932,8 +4932,6 @@ nf_tables_flowtable_lookup_byhandle(const struct nft_table *table,
49324932
return ERR_PTR(-ENOENT);
49334933
}
49344934

4935-
#define NFT_FLOWTABLE_DEVICE_MAX 8
4936-
49374935
static int nf_tables_parse_devices(const struct nft_ctx *ctx,
49384936
const struct nlattr *attr,
49394937
struct net_device *dev_array[], int *len)
@@ -5006,7 +5004,7 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx,
50065004
err = nf_tables_parse_devices(ctx, tb[NFTA_FLOWTABLE_HOOK_DEVS],
50075005
dev_array, &n);
50085006
if (err < 0)
5009-
goto err1;
5007+
return err;
50105008

50115009
ops = kzalloc(sizeof(struct nf_hook_ops) * n, GFP_KERNEL);
50125010
if (!ops) {
@@ -5026,6 +5024,8 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx,
50265024
flowtable->ops[i].priv = &flowtable->data.rhashtable;
50275025
flowtable->ops[i].hook = flowtable->data.type->hook;
50285026
flowtable->ops[i].dev = dev_array[i];
5027+
flowtable->dev_name[i] = kstrdup(dev_array[i]->name,
5028+
GFP_KERNEL);
50295029
}
50305030

50315031
err = 0;
@@ -5203,8 +5203,10 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
52035203
err5:
52045204
i = flowtable->ops_len;
52055205
err4:
5206-
for (k = i - 1; k >= 0; k--)
5206+
for (k = i - 1; k >= 0; k--) {
5207+
kfree(flowtable->dev_name[k]);
52075208
nf_unregister_net_hook(net, &flowtable->ops[k]);
5209+
}
52085210

52095211
kfree(flowtable->ops);
52105212
err3:
@@ -5294,9 +5296,9 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
52945296
goto nla_put_failure;
52955297

52965298
for (i = 0; i < flowtable->ops_len; i++) {
5297-
if (flowtable->ops[i].dev &&
5299+
if (flowtable->dev_name[i][0] &&
52985300
nla_put_string(skb, NFTA_DEVICE_NAME,
5299-
flowtable->ops[i].dev->name))
5301+
flowtable->dev_name[i]))
53005302
goto nla_put_failure;
53015303
}
53025304
nla_nest_end(skb, nest_devs);
@@ -5538,6 +5540,7 @@ static void nft_flowtable_event(unsigned long event, struct net_device *dev,
55385540
continue;
55395541

55405542
nf_unregister_net_hook(dev_net(dev), &flowtable->ops[i]);
5543+
flowtable->dev_name[i][0] = '\0';
55415544
flowtable->ops[i].dev = NULL;
55425545
break;
55435546
}

0 commit comments

Comments
 (0)