diff options
-rw-r--r-- | net/netfilter/nf_tables_api.c | 78 | ||||
-rw-r--r-- | net/netfilter/nft_set_hash.c | 2 |
2 files changed, 57 insertions, 23 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 559225029740..5f4a4d48b871 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -3367,35 +3367,50 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx, | |||
3367 | return nf_tables_fill_setelem(args->skb, set, elem); | 3367 | return nf_tables_fill_setelem(args->skb, set, elem); |
3368 | } | 3368 | } |
3369 | 3369 | ||
3370 | struct nft_set_dump_ctx { | ||
3371 | const struct nft_set *set; | ||
3372 | struct nft_ctx ctx; | ||
3373 | }; | ||
3374 | |||
3370 | static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) | 3375 | static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) |
3371 | { | 3376 | { |
3377 | struct nft_set_dump_ctx *dump_ctx = cb->data; | ||
3372 | struct net *net = sock_net(skb->sk); | 3378 | struct net *net = sock_net(skb->sk); |
3373 | u8 genmask = nft_genmask_cur(net); | 3379 | struct nft_af_info *afi; |
3380 | struct nft_table *table; | ||
3374 | struct nft_set *set; | 3381 | struct nft_set *set; |
3375 | struct nft_set_dump_args args; | 3382 | struct nft_set_dump_args args; |
3376 | struct nft_ctx ctx; | 3383 | bool set_found = false; |
3377 | struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1]; | ||
3378 | struct nfgenmsg *nfmsg; | 3384 | struct nfgenmsg *nfmsg; |
3379 | struct nlmsghdr *nlh; | 3385 | struct nlmsghdr *nlh; |
3380 | struct nlattr *nest; | 3386 | struct nlattr *nest; |
3381 | u32 portid, seq; | 3387 | u32 portid, seq; |
3382 | int event, err; | 3388 | int event; |
3383 | 3389 | ||
3384 | err = nlmsg_parse(cb->nlh, sizeof(struct nfgenmsg), nla, | 3390 | rcu_read_lock(); |
3385 | NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy, | 3391 | list_for_each_entry_rcu(afi, &net->nft.af_info, list) { |
3386 | NULL); | 3392 | if (afi != dump_ctx->ctx.afi) |
3387 | if (err < 0) | 3393 | continue; |
3388 | return err; | ||
3389 | 3394 | ||
3390 | err = nft_ctx_init_from_elemattr(&ctx, net, cb->skb, cb->nlh, | 3395 | list_for_each_entry_rcu(table, &afi->tables, list) { |
3391 | (void *)nla, genmask); | 3396 | if (table != dump_ctx->ctx.table) |
3392 | if (err < 0) | 3397 | continue; |
3393 | return err; | ||
3394 | 3398 | ||
3395 | set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET], | 3399 | list_for_each_entry_rcu(set, &table->sets, list) { |
3396 | genmask); | 3400 | if (set == dump_ctx->set) { |
3397 | if (IS_ERR(set)) | 3401 | set_found = true; |
3398 | return PTR_ERR(set); | 3402 | break; |
3403 | } | ||
3404 | } | ||
3405 | break; | ||
3406 | } | ||
3407 | break; | ||
3408 | } | ||
3409 | |||
3410 | if (!set_found) { | ||
3411 | rcu_read_unlock(); | ||
3412 | return -ENOENT; | ||
3413 | } | ||
3399 | 3414 | ||
3400 | event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWSETELEM); | 3415 | event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWSETELEM); |
3401 | portid = NETLINK_CB(cb->skb).portid; | 3416 | portid = NETLINK_CB(cb->skb).portid; |
@@ -3407,11 +3422,11 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) | |||
3407 | goto nla_put_failure; | 3422 | goto nla_put_failure; |
3408 | 3423 | ||
3409 | nfmsg = nlmsg_data(nlh); | 3424 | nfmsg = nlmsg_data(nlh); |
3410 | nfmsg->nfgen_family = ctx.afi->family; | 3425 | nfmsg->nfgen_family = afi->family; |
3411 | nfmsg->version = NFNETLINK_V0; | 3426 | nfmsg->version = NFNETLINK_V0; |
3412 | nfmsg->res_id = htons(ctx.net->nft.base_seq & 0xffff); | 3427 | nfmsg->res_id = htons(net->nft.base_seq & 0xffff); |
3413 | 3428 | ||
3414 | if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name)) | 3429 | if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, table->name)) |
3415 | goto nla_put_failure; | 3430 | goto nla_put_failure; |
3416 | if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name)) | 3431 | if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name)) |
3417 | goto nla_put_failure; | 3432 | goto nla_put_failure; |
@@ -3422,12 +3437,13 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) | |||
3422 | 3437 | ||
3423 | args.cb = cb; | 3438 | args.cb = cb; |
3424 | args.skb = skb; | 3439 | args.skb = skb; |
3425 | args.iter.genmask = nft_genmask_cur(ctx.net); | 3440 | args.iter.genmask = nft_genmask_cur(net); |
3426 | args.iter.skip = cb->args[0]; | 3441 | args.iter.skip = cb->args[0]; |
3427 | args.iter.count = 0; | 3442 | args.iter.count = 0; |
3428 | args.iter.err = 0; | 3443 | args.iter.err = 0; |
3429 | args.iter.fn = nf_tables_dump_setelem; | 3444 | args.iter.fn = nf_tables_dump_setelem; |
3430 | set->ops->walk(&ctx, set, &args.iter); | 3445 | set->ops->walk(&dump_ctx->ctx, set, &args.iter); |
3446 | rcu_read_unlock(); | ||
3431 | 3447 | ||
3432 | nla_nest_end(skb, nest); | 3448 | nla_nest_end(skb, nest); |
3433 | nlmsg_end(skb, nlh); | 3449 | nlmsg_end(skb, nlh); |
@@ -3441,9 +3457,16 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) | |||
3441 | return skb->len; | 3457 | return skb->len; |
3442 | 3458 | ||
3443 | nla_put_failure: | 3459 | nla_put_failure: |
3460 | rcu_read_unlock(); | ||
3444 | return -ENOSPC; | 3461 | return -ENOSPC; |
3445 | } | 3462 | } |
3446 | 3463 | ||
3464 | static int nf_tables_dump_set_done(struct netlink_callback *cb) | ||
3465 | { | ||
3466 | kfree(cb->data); | ||
3467 | return 0; | ||
3468 | } | ||
3469 | |||
3447 | static int nf_tables_getsetelem(struct net *net, struct sock *nlsk, | 3470 | static int nf_tables_getsetelem(struct net *net, struct sock *nlsk, |
3448 | struct sk_buff *skb, const struct nlmsghdr *nlh, | 3471 | struct sk_buff *skb, const struct nlmsghdr *nlh, |
3449 | const struct nlattr * const nla[]) | 3472 | const struct nlattr * const nla[]) |
@@ -3465,7 +3488,18 @@ static int nf_tables_getsetelem(struct net *net, struct sock *nlsk, | |||
3465 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 3488 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
3466 | struct netlink_dump_control c = { | 3489 | struct netlink_dump_control c = { |
3467 | .dump = nf_tables_dump_set, | 3490 | .dump = nf_tables_dump_set, |
3491 | .done = nf_tables_dump_set_done, | ||
3468 | }; | 3492 | }; |
3493 | struct nft_set_dump_ctx *dump_ctx; | ||
3494 | |||
3495 | dump_ctx = kmalloc(sizeof(*dump_ctx), GFP_KERNEL); | ||
3496 | if (!dump_ctx) | ||
3497 | return -ENOMEM; | ||
3498 | |||
3499 | dump_ctx->set = set; | ||
3500 | dump_ctx->ctx = ctx; | ||
3501 | |||
3502 | c.data = dump_ctx; | ||
3469 | return netlink_dump_start(nlsk, skb, nlh, &c); | 3503 | return netlink_dump_start(nlsk, skb, nlh, &c); |
3470 | } | 3504 | } |
3471 | return -EOPNOTSUPP; | 3505 | return -EOPNOTSUPP; |
diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c index 8ec086b6b56b..3d3a6df4ce70 100644 --- a/net/netfilter/nft_set_hash.c +++ b/net/netfilter/nft_set_hash.c | |||
@@ -222,7 +222,7 @@ static void nft_hash_walk(const struct nft_ctx *ctx, struct nft_set *set, | |||
222 | struct nft_set_elem elem; | 222 | struct nft_set_elem elem; |
223 | int err; | 223 | int err; |
224 | 224 | ||
225 | err = rhashtable_walk_init(&priv->ht, &hti, GFP_KERNEL); | 225 | err = rhashtable_walk_init(&priv->ht, &hti, GFP_ATOMIC); |
226 | iter->err = err; | 226 | iter->err = err; |
227 | if (err) | 227 | if (err) |
228 | return; | 228 | return; |