Commit d92191aa authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

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: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent aebfa52a
...@@ -1068,6 +1068,8 @@ struct nft_object_ops { ...@@ -1068,6 +1068,8 @@ struct nft_object_ops {
int nft_register_obj(struct nft_object_type *obj_type); int nft_register_obj(struct nft_object_type *obj_type);
void nft_unregister_obj(struct nft_object_type *obj_type); void nft_unregister_obj(struct nft_object_type *obj_type);
#define NFT_FLOWTABLE_DEVICE_MAX 8
/** /**
* struct nft_flowtable - nf_tables flow table * struct nft_flowtable - nf_tables flow table
* *
...@@ -1080,6 +1082,7 @@ void nft_unregister_obj(struct nft_object_type *obj_type); ...@@ -1080,6 +1082,7 @@ void nft_unregister_obj(struct nft_object_type *obj_type);
* @genmask: generation mask * @genmask: generation mask
* @use: number of references to this flow table * @use: number of references to this flow table
* @handle: unique object handle * @handle: unique object handle
* @dev_name: array of device names
* @data: rhashtable and garbage collector * @data: rhashtable and garbage collector
* @ops: array of hooks * @ops: array of hooks
*/ */
...@@ -1093,6 +1096,7 @@ struct nft_flowtable { ...@@ -1093,6 +1096,7 @@ struct nft_flowtable {
u32 genmask:2, u32 genmask:2,
use:30; use:30;
u64 handle; u64 handle;
char *dev_name[NFT_FLOWTABLE_DEVICE_MAX];
/* runtime data below here */ /* runtime data below here */
struct nf_hook_ops *ops ____cacheline_aligned; struct nf_hook_ops *ops ____cacheline_aligned;
struct nf_flowtable data; struct nf_flowtable data;
......
...@@ -4932,8 +4932,6 @@ nf_tables_flowtable_lookup_byhandle(const struct nft_table *table, ...@@ -4932,8 +4932,6 @@ nf_tables_flowtable_lookup_byhandle(const struct nft_table *table,
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
#define NFT_FLOWTABLE_DEVICE_MAX 8
static int nf_tables_parse_devices(const struct nft_ctx *ctx, static int nf_tables_parse_devices(const struct nft_ctx *ctx,
const struct nlattr *attr, const struct nlattr *attr,
struct net_device *dev_array[], int *len) struct net_device *dev_array[], int *len)
...@@ -5006,7 +5004,7 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx, ...@@ -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], err = nf_tables_parse_devices(ctx, tb[NFTA_FLOWTABLE_HOOK_DEVS],
dev_array, &n); dev_array, &n);
if (err < 0) if (err < 0)
goto err1; return err;
ops = kzalloc(sizeof(struct nf_hook_ops) * n, GFP_KERNEL); ops = kzalloc(sizeof(struct nf_hook_ops) * n, GFP_KERNEL);
if (!ops) { if (!ops) {
...@@ -5026,6 +5024,8 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx, ...@@ -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].priv = &flowtable->data.rhashtable;
flowtable->ops[i].hook = flowtable->data.type->hook; flowtable->ops[i].hook = flowtable->data.type->hook;
flowtable->ops[i].dev = dev_array[i]; flowtable->ops[i].dev = dev_array[i];
flowtable->dev_name[i] = kstrdup(dev_array[i]->name,
GFP_KERNEL);
} }
err = 0; err = 0;
...@@ -5203,8 +5203,10 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk, ...@@ -5203,8 +5203,10 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
err5: err5:
i = flowtable->ops_len; i = flowtable->ops_len;
err4: 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]); nf_unregister_net_hook(net, &flowtable->ops[k]);
}
kfree(flowtable->ops); kfree(flowtable->ops);
err3: err3:
...@@ -5294,9 +5296,9 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net, ...@@ -5294,9 +5296,9 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
goto nla_put_failure; goto nla_put_failure;
for (i = 0; i < flowtable->ops_len; i++) { 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, nla_put_string(skb, NFTA_DEVICE_NAME,
flowtable->ops[i].dev->name)) flowtable->dev_name[i]))
goto nla_put_failure; goto nla_put_failure;
} }
nla_nest_end(skb, nest_devs); nla_nest_end(skb, nest_devs);
...@@ -5538,6 +5540,7 @@ static void nft_flowtable_event(unsigned long event, struct net_device *dev, ...@@ -5538,6 +5540,7 @@ static void nft_flowtable_event(unsigned long event, struct net_device *dev,
continue; continue;
nf_unregister_net_hook(dev_net(dev), &flowtable->ops[i]); nf_unregister_net_hook(dev_net(dev), &flowtable->ops[i]);
flowtable->dev_name[i][0] = '\0';
flowtable->ops[i].dev = NULL; flowtable->ops[i].dev = NULL;
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment