.. | .. |
---|
21 | 21 | #include <net/netfilter/nf_tables.h> |
---|
22 | 22 | #include <net/netfilter/nf_tables_offload.h> |
---|
23 | 23 | #include <net/net_namespace.h> |
---|
| 24 | +#include <net/netns/generic.h> |
---|
24 | 25 | #include <net/sock.h> |
---|
25 | 26 | |
---|
26 | 27 | #define NFT_MODULE_AUTOLOAD_LIMIT (MODULE_NAME_LEN - sizeof("nft-expr-255-")) |
---|
| 28 | + |
---|
| 29 | +unsigned int nf_tables_net_id __read_mostly; |
---|
27 | 30 | |
---|
28 | 31 | static LIST_HEAD(nf_tables_expressions); |
---|
29 | 32 | static LIST_HEAD(nf_tables_objects); |
---|
30 | 33 | static LIST_HEAD(nf_tables_flowtables); |
---|
31 | 34 | static LIST_HEAD(nf_tables_destroy_list); |
---|
| 35 | +static LIST_HEAD(nf_tables_gc_list); |
---|
32 | 36 | static DEFINE_SPINLOCK(nf_tables_destroy_list_lock); |
---|
| 37 | +static DEFINE_SPINLOCK(nf_tables_gc_list_lock); |
---|
33 | 38 | static u64 table_handle; |
---|
34 | 39 | |
---|
35 | 40 | enum { |
---|
.. | .. |
---|
103 | 108 | |
---|
104 | 109 | static void nft_validate_state_update(struct net *net, u8 new_validate_state) |
---|
105 | 110 | { |
---|
106 | | - switch (net->nft.validate_state) { |
---|
| 111 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
| 112 | + |
---|
| 113 | + switch (nft_net->validate_state) { |
---|
107 | 114 | case NFT_VALIDATE_SKIP: |
---|
108 | 115 | WARN_ON_ONCE(new_validate_state == NFT_VALIDATE_DO); |
---|
109 | 116 | break; |
---|
.. | .. |
---|
114 | 121 | return; |
---|
115 | 122 | } |
---|
116 | 123 | |
---|
117 | | - net->nft.validate_state = new_validate_state; |
---|
| 124 | + nft_net->validate_state = new_validate_state; |
---|
118 | 125 | } |
---|
119 | 126 | static void nf_tables_trans_destroy_work(struct work_struct *w); |
---|
120 | 127 | static DECLARE_WORK(trans_destroy_work, nf_tables_trans_destroy_work); |
---|
| 128 | + |
---|
| 129 | +static void nft_trans_gc_work(struct work_struct *work); |
---|
| 130 | +static DECLARE_WORK(trans_gc_work, nft_trans_gc_work); |
---|
121 | 131 | |
---|
122 | 132 | static void nft_ctx_init(struct nft_ctx *ctx, |
---|
123 | 133 | struct net *net, |
---|
.. | .. |
---|
150 | 160 | return NULL; |
---|
151 | 161 | |
---|
152 | 162 | INIT_LIST_HEAD(&trans->list); |
---|
| 163 | + INIT_LIST_HEAD(&trans->binding_list); |
---|
153 | 164 | trans->msg_type = msg_type; |
---|
154 | 165 | trans->ctx = *ctx; |
---|
155 | 166 | |
---|
.. | .. |
---|
162 | 173 | return nft_trans_alloc_gfp(ctx, msg_type, size, GFP_KERNEL); |
---|
163 | 174 | } |
---|
164 | 175 | |
---|
165 | | -static void nft_trans_destroy(struct nft_trans *trans) |
---|
| 176 | +static void nft_trans_list_del(struct nft_trans *trans) |
---|
166 | 177 | { |
---|
167 | 178 | list_del(&trans->list); |
---|
| 179 | + list_del(&trans->binding_list); |
---|
| 180 | +} |
---|
| 181 | + |
---|
| 182 | +static void nft_trans_destroy(struct nft_trans *trans) |
---|
| 183 | +{ |
---|
| 184 | + nft_trans_list_del(trans); |
---|
168 | 185 | kfree(trans); |
---|
169 | 186 | } |
---|
170 | 187 | |
---|
171 | | -static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set) |
---|
| 188 | +static void __nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set, |
---|
| 189 | + bool bind) |
---|
172 | 190 | { |
---|
| 191 | + struct nftables_pernet *nft_net; |
---|
173 | 192 | struct net *net = ctx->net; |
---|
174 | 193 | struct nft_trans *trans; |
---|
175 | 194 | |
---|
176 | 195 | if (!nft_set_is_anonymous(set)) |
---|
177 | 196 | return; |
---|
178 | 197 | |
---|
179 | | - list_for_each_entry_reverse(trans, &net->nft.commit_list, list) { |
---|
| 198 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 199 | + list_for_each_entry_reverse(trans, &nft_net->commit_list, list) { |
---|
180 | 200 | switch (trans->msg_type) { |
---|
181 | 201 | case NFT_MSG_NEWSET: |
---|
182 | 202 | if (nft_trans_set(trans) == set) |
---|
183 | | - nft_trans_set_bound(trans) = true; |
---|
| 203 | + nft_trans_set_bound(trans) = bind; |
---|
184 | 204 | break; |
---|
185 | 205 | case NFT_MSG_NEWSETELEM: |
---|
186 | 206 | if (nft_trans_elem_set(trans) == set) |
---|
187 | | - nft_trans_elem_set_bound(trans) = true; |
---|
| 207 | + nft_trans_elem_set_bound(trans) = bind; |
---|
188 | 208 | break; |
---|
189 | 209 | } |
---|
190 | 210 | } |
---|
| 211 | +} |
---|
| 212 | + |
---|
| 213 | +static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set) |
---|
| 214 | +{ |
---|
| 215 | + return __nft_set_trans_bind(ctx, set, true); |
---|
| 216 | +} |
---|
| 217 | + |
---|
| 218 | +static void nft_set_trans_unbind(const struct nft_ctx *ctx, struct nft_set *set) |
---|
| 219 | +{ |
---|
| 220 | + return __nft_set_trans_bind(ctx, set, false); |
---|
| 221 | +} |
---|
| 222 | + |
---|
| 223 | +static void __nft_chain_trans_bind(const struct nft_ctx *ctx, |
---|
| 224 | + struct nft_chain *chain, bool bind) |
---|
| 225 | +{ |
---|
| 226 | + struct nftables_pernet *nft_net; |
---|
| 227 | + struct net *net = ctx->net; |
---|
| 228 | + struct nft_trans *trans; |
---|
| 229 | + |
---|
| 230 | + if (!nft_chain_binding(chain)) |
---|
| 231 | + return; |
---|
| 232 | + |
---|
| 233 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 234 | + list_for_each_entry_reverse(trans, &nft_net->commit_list, list) { |
---|
| 235 | + switch (trans->msg_type) { |
---|
| 236 | + case NFT_MSG_NEWCHAIN: |
---|
| 237 | + if (nft_trans_chain(trans) == chain) |
---|
| 238 | + nft_trans_chain_bound(trans) = bind; |
---|
| 239 | + break; |
---|
| 240 | + case NFT_MSG_NEWRULE: |
---|
| 241 | + if (trans->ctx.chain == chain) |
---|
| 242 | + nft_trans_rule_bound(trans) = bind; |
---|
| 243 | + break; |
---|
| 244 | + } |
---|
| 245 | + } |
---|
| 246 | +} |
---|
| 247 | + |
---|
| 248 | +static void nft_chain_trans_bind(const struct nft_ctx *ctx, |
---|
| 249 | + struct nft_chain *chain) |
---|
| 250 | +{ |
---|
| 251 | + __nft_chain_trans_bind(ctx, chain, true); |
---|
| 252 | +} |
---|
| 253 | + |
---|
| 254 | +int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain) |
---|
| 255 | +{ |
---|
| 256 | + if (!nft_chain_binding(chain)) |
---|
| 257 | + return 0; |
---|
| 258 | + |
---|
| 259 | + if (nft_chain_binding(ctx->chain)) |
---|
| 260 | + return -EOPNOTSUPP; |
---|
| 261 | + |
---|
| 262 | + if (chain->bound) |
---|
| 263 | + return -EBUSY; |
---|
| 264 | + |
---|
| 265 | + if (!nft_use_inc(&chain->use)) |
---|
| 266 | + return -EMFILE; |
---|
| 267 | + |
---|
| 268 | + chain->bound = true; |
---|
| 269 | + nft_chain_trans_bind(ctx, chain); |
---|
| 270 | + |
---|
| 271 | + return 0; |
---|
| 272 | +} |
---|
| 273 | + |
---|
| 274 | +void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain) |
---|
| 275 | +{ |
---|
| 276 | + __nft_chain_trans_bind(ctx, chain, false); |
---|
191 | 277 | } |
---|
192 | 278 | |
---|
193 | 279 | static int nft_netdev_register_hooks(struct net *net, |
---|
.. | .. |
---|
217 | 303 | } |
---|
218 | 304 | |
---|
219 | 305 | static void nft_netdev_unregister_hooks(struct net *net, |
---|
220 | | - struct list_head *hook_list) |
---|
| 306 | + struct list_head *hook_list, |
---|
| 307 | + bool release_netdev) |
---|
221 | 308 | { |
---|
222 | | - struct nft_hook *hook; |
---|
| 309 | + struct nft_hook *hook, *next; |
---|
223 | 310 | |
---|
224 | | - list_for_each_entry(hook, hook_list, list) |
---|
| 311 | + list_for_each_entry_safe(hook, next, hook_list, list) { |
---|
225 | 312 | nf_unregister_net_hook(net, &hook->ops); |
---|
| 313 | + if (release_netdev) { |
---|
| 314 | + list_del(&hook->list); |
---|
| 315 | + kfree_rcu(hook, rcu); |
---|
| 316 | + } |
---|
| 317 | + } |
---|
226 | 318 | } |
---|
227 | 319 | |
---|
228 | 320 | static int nf_tables_register_hook(struct net *net, |
---|
.. | .. |
---|
248 | 340 | return nf_register_net_hook(net, &basechain->ops); |
---|
249 | 341 | } |
---|
250 | 342 | |
---|
251 | | -static void nf_tables_unregister_hook(struct net *net, |
---|
252 | | - const struct nft_table *table, |
---|
253 | | - struct nft_chain *chain) |
---|
| 343 | +static void __nf_tables_unregister_hook(struct net *net, |
---|
| 344 | + const struct nft_table *table, |
---|
| 345 | + struct nft_chain *chain, |
---|
| 346 | + bool release_netdev) |
---|
254 | 347 | { |
---|
255 | 348 | struct nft_base_chain *basechain; |
---|
256 | 349 | const struct nf_hook_ops *ops; |
---|
.. | .. |
---|
265 | 358 | return basechain->type->ops_unregister(net, ops); |
---|
266 | 359 | |
---|
267 | 360 | if (nft_base_chain_netdev(table->family, basechain->ops.hooknum)) |
---|
268 | | - nft_netdev_unregister_hooks(net, &basechain->hook_list); |
---|
| 361 | + nft_netdev_unregister_hooks(net, &basechain->hook_list, |
---|
| 362 | + release_netdev); |
---|
269 | 363 | else |
---|
270 | 364 | nf_unregister_net_hook(net, &basechain->ops); |
---|
| 365 | +} |
---|
| 366 | + |
---|
| 367 | +static void nf_tables_unregister_hook(struct net *net, |
---|
| 368 | + const struct nft_table *table, |
---|
| 369 | + struct nft_chain *chain) |
---|
| 370 | +{ |
---|
| 371 | + return __nf_tables_unregister_hook(net, table, chain, false); |
---|
| 372 | +} |
---|
| 373 | + |
---|
| 374 | +static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *trans) |
---|
| 375 | +{ |
---|
| 376 | + struct nftables_pernet *nft_net; |
---|
| 377 | + |
---|
| 378 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 379 | + |
---|
| 380 | + switch (trans->msg_type) { |
---|
| 381 | + case NFT_MSG_NEWSET: |
---|
| 382 | + if (nft_set_is_anonymous(nft_trans_set(trans))) |
---|
| 383 | + list_add_tail(&trans->binding_list, &nft_net->binding_list); |
---|
| 384 | + break; |
---|
| 385 | + case NFT_MSG_NEWCHAIN: |
---|
| 386 | + if (!nft_trans_chain_update(trans) && |
---|
| 387 | + nft_chain_binding(nft_trans_chain(trans))) |
---|
| 388 | + list_add_tail(&trans->binding_list, &nft_net->binding_list); |
---|
| 389 | + break; |
---|
| 390 | + } |
---|
| 391 | + |
---|
| 392 | + list_add_tail(&trans->list, &nft_net->commit_list); |
---|
271 | 393 | } |
---|
272 | 394 | |
---|
273 | 395 | static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type) |
---|
.. | .. |
---|
281 | 403 | if (msg_type == NFT_MSG_NEWTABLE) |
---|
282 | 404 | nft_activate_next(ctx->net, ctx->table); |
---|
283 | 405 | |
---|
284 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 406 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
285 | 407 | return 0; |
---|
286 | 408 | } |
---|
287 | 409 | |
---|
.. | .. |
---|
313 | 435 | ntohl(nla_get_be32(ctx->nla[NFTA_CHAIN_ID])); |
---|
314 | 436 | } |
---|
315 | 437 | } |
---|
| 438 | + nft_trans_chain(trans) = ctx->chain; |
---|
| 439 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
316 | 440 | |
---|
317 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
318 | 441 | return trans; |
---|
319 | 442 | } |
---|
320 | 443 | |
---|
.. | .. |
---|
326 | 449 | if (IS_ERR(trans)) |
---|
327 | 450 | return PTR_ERR(trans); |
---|
328 | 451 | |
---|
329 | | - ctx->table->use--; |
---|
| 452 | + nft_use_dec(&ctx->table->use); |
---|
330 | 453 | nft_deactivate_next(ctx->net, ctx->chain); |
---|
331 | 454 | |
---|
332 | 455 | return 0; |
---|
333 | 456 | } |
---|
334 | 457 | |
---|
335 | | -static void nft_rule_expr_activate(const struct nft_ctx *ctx, |
---|
336 | | - struct nft_rule *rule) |
---|
| 458 | +void nft_rule_expr_activate(const struct nft_ctx *ctx, struct nft_rule *rule) |
---|
337 | 459 | { |
---|
338 | 460 | struct nft_expr *expr; |
---|
339 | 461 | |
---|
.. | .. |
---|
346 | 468 | } |
---|
347 | 469 | } |
---|
348 | 470 | |
---|
349 | | -static void nft_rule_expr_deactivate(const struct nft_ctx *ctx, |
---|
350 | | - struct nft_rule *rule, |
---|
351 | | - enum nft_trans_phase phase) |
---|
| 471 | +void nft_rule_expr_deactivate(const struct nft_ctx *ctx, struct nft_rule *rule, |
---|
| 472 | + enum nft_trans_phase phase) |
---|
352 | 473 | { |
---|
353 | 474 | struct nft_expr *expr; |
---|
354 | 475 | |
---|
.. | .. |
---|
367 | 488 | /* You cannot delete the same rule twice */ |
---|
368 | 489 | if (nft_is_active_next(ctx->net, rule)) { |
---|
369 | 490 | nft_deactivate_next(ctx->net, rule); |
---|
370 | | - ctx->chain->use--; |
---|
| 491 | + nft_use_dec(&ctx->chain->use); |
---|
371 | 492 | return 0; |
---|
372 | 493 | } |
---|
373 | 494 | return -ENOENT; |
---|
.. | .. |
---|
387 | 508 | ntohl(nla_get_be32(ctx->nla[NFTA_RULE_ID])); |
---|
388 | 509 | } |
---|
389 | 510 | nft_trans_rule(trans) = rule; |
---|
390 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 511 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
391 | 512 | |
---|
392 | 513 | return trans; |
---|
393 | 514 | } |
---|
.. | .. |
---|
453 | 574 | nft_activate_next(ctx->net, set); |
---|
454 | 575 | } |
---|
455 | 576 | nft_trans_set(trans) = set; |
---|
456 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 577 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
457 | 578 | |
---|
458 | 579 | return 0; |
---|
| 580 | +} |
---|
| 581 | + |
---|
| 582 | +static int nft_mapelem_deactivate(const struct nft_ctx *ctx, |
---|
| 583 | + struct nft_set *set, |
---|
| 584 | + const struct nft_set_iter *iter, |
---|
| 585 | + struct nft_set_elem *elem) |
---|
| 586 | +{ |
---|
| 587 | + nft_setelem_data_deactivate(ctx->net, set, elem); |
---|
| 588 | + |
---|
| 589 | + return 0; |
---|
| 590 | +} |
---|
| 591 | + |
---|
| 592 | +static void nft_map_deactivate(const struct nft_ctx *ctx, struct nft_set *set) |
---|
| 593 | +{ |
---|
| 594 | + struct nft_set_iter iter = { |
---|
| 595 | + .genmask = nft_genmask_next(ctx->net), |
---|
| 596 | + .fn = nft_mapelem_deactivate, |
---|
| 597 | + }; |
---|
| 598 | + |
---|
| 599 | + set->ops->walk(ctx, set, &iter); |
---|
| 600 | + WARN_ON_ONCE(iter.err); |
---|
459 | 601 | } |
---|
460 | 602 | |
---|
461 | 603 | static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set) |
---|
.. | .. |
---|
466 | 608 | if (err < 0) |
---|
467 | 609 | return err; |
---|
468 | 610 | |
---|
| 611 | + if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT)) |
---|
| 612 | + nft_map_deactivate(ctx, set); |
---|
| 613 | + |
---|
469 | 614 | nft_deactivate_next(ctx->net, set); |
---|
470 | | - ctx->table->use--; |
---|
| 615 | + nft_use_dec(&ctx->table->use); |
---|
471 | 616 | |
---|
472 | 617 | return err; |
---|
473 | 618 | } |
---|
.. | .. |
---|
485 | 630 | nft_activate_next(ctx->net, obj); |
---|
486 | 631 | |
---|
487 | 632 | nft_trans_obj(trans) = obj; |
---|
488 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 633 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
489 | 634 | |
---|
490 | 635 | return 0; |
---|
491 | 636 | } |
---|
.. | .. |
---|
499 | 644 | return err; |
---|
500 | 645 | |
---|
501 | 646 | nft_deactivate_next(ctx->net, obj); |
---|
502 | | - ctx->table->use--; |
---|
| 647 | + nft_use_dec(&ctx->table->use); |
---|
503 | 648 | |
---|
504 | 649 | return err; |
---|
505 | 650 | } |
---|
.. | .. |
---|
519 | 664 | |
---|
520 | 665 | INIT_LIST_HEAD(&nft_trans_flowtable_hooks(trans)); |
---|
521 | 666 | nft_trans_flowtable(trans) = flowtable; |
---|
522 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 667 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
523 | 668 | |
---|
524 | 669 | return 0; |
---|
525 | 670 | } |
---|
.. | .. |
---|
534 | 679 | return err; |
---|
535 | 680 | |
---|
536 | 681 | nft_deactivate_next(ctx->net, flowtable); |
---|
537 | | - ctx->table->use--; |
---|
| 682 | + nft_use_dec(&ctx->table->use); |
---|
538 | 683 | |
---|
539 | 684 | return err; |
---|
540 | 685 | } |
---|
.. | .. |
---|
547 | 692 | const struct nlattr *nla, |
---|
548 | 693 | u8 family, u8 genmask) |
---|
549 | 694 | { |
---|
| 695 | + struct nftables_pernet *nft_net; |
---|
550 | 696 | struct nft_table *table; |
---|
551 | 697 | |
---|
552 | 698 | if (nla == NULL) |
---|
553 | 699 | return ERR_PTR(-EINVAL); |
---|
554 | 700 | |
---|
555 | | - list_for_each_entry_rcu(table, &net->nft.tables, list, |
---|
556 | | - lockdep_is_held(&net->nft.commit_mutex)) { |
---|
| 701 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 702 | + list_for_each_entry_rcu(table, &nft_net->tables, list, |
---|
| 703 | + lockdep_is_held(&nft_net->commit_mutex)) { |
---|
557 | 704 | if (!nla_strcmp(nla, table->name) && |
---|
558 | 705 | table->family == family && |
---|
559 | 706 | nft_active_genmask(table, genmask)) |
---|
.. | .. |
---|
567 | 714 | const struct nlattr *nla, |
---|
568 | 715 | u8 genmask) |
---|
569 | 716 | { |
---|
| 717 | + struct nftables_pernet *nft_net; |
---|
570 | 718 | struct nft_table *table; |
---|
571 | 719 | |
---|
572 | | - list_for_each_entry(table, &net->nft.tables, list) { |
---|
| 720 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 721 | + list_for_each_entry(table, &nft_net->tables, list) { |
---|
573 | 722 | if (be64_to_cpu(nla_get_be64(nla)) == table->handle && |
---|
574 | 723 | nft_active_genmask(table, genmask)) |
---|
575 | 724 | return table; |
---|
.. | .. |
---|
621 | 770 | static int nft_request_module(struct net *net, const char *fmt, ...) |
---|
622 | 771 | { |
---|
623 | 772 | char module_name[MODULE_NAME_LEN]; |
---|
| 773 | + struct nftables_pernet *nft_net; |
---|
624 | 774 | struct nft_module_request *req; |
---|
625 | 775 | va_list args; |
---|
626 | 776 | int ret; |
---|
.. | .. |
---|
631 | 781 | if (ret >= MODULE_NAME_LEN) |
---|
632 | 782 | return 0; |
---|
633 | 783 | |
---|
634 | | - list_for_each_entry(req, &net->nft.module_list, list) { |
---|
| 784 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 785 | + list_for_each_entry(req, &nft_net->module_list, list) { |
---|
635 | 786 | if (!strcmp(req->module, module_name)) { |
---|
636 | 787 | if (req->done) |
---|
637 | 788 | return 0; |
---|
.. | .. |
---|
647 | 798 | |
---|
648 | 799 | req->done = false; |
---|
649 | 800 | strlcpy(req->module, module_name, MODULE_NAME_LEN); |
---|
650 | | - list_add_tail(&req->list, &net->nft.module_list); |
---|
| 801 | + list_add_tail(&req->list, &nft_net->module_list); |
---|
651 | 802 | |
---|
652 | 803 | return -EAGAIN; |
---|
653 | 804 | } |
---|
.. | .. |
---|
685 | 836 | |
---|
686 | 837 | static __be16 nft_base_seq(const struct net *net) |
---|
687 | 838 | { |
---|
688 | | - return htons(net->nft.base_seq & 0xffff); |
---|
| 839 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
| 840 | + |
---|
| 841 | + return htons(nft_net->base_seq & 0xffff); |
---|
689 | 842 | } |
---|
690 | 843 | |
---|
691 | 844 | static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = { |
---|
.. | .. |
---|
743 | 896 | |
---|
744 | 897 | static void nf_tables_table_notify(const struct nft_ctx *ctx, int event) |
---|
745 | 898 | { |
---|
| 899 | + struct nftables_pernet *nft_net; |
---|
746 | 900 | struct sk_buff *skb; |
---|
747 | 901 | int err; |
---|
748 | 902 | |
---|
.. | .. |
---|
761 | 915 | goto err; |
---|
762 | 916 | } |
---|
763 | 917 | |
---|
764 | | - nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list); |
---|
| 918 | + nft_net = net_generic(ctx->net, nf_tables_net_id); |
---|
| 919 | + nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list); |
---|
765 | 920 | return; |
---|
766 | 921 | err: |
---|
767 | 922 | nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS); |
---|
.. | .. |
---|
771 | 926 | struct netlink_callback *cb) |
---|
772 | 927 | { |
---|
773 | 928 | const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); |
---|
| 929 | + struct nftables_pernet *nft_net; |
---|
774 | 930 | const struct nft_table *table; |
---|
775 | 931 | unsigned int idx = 0, s_idx = cb->args[0]; |
---|
776 | 932 | struct net *net = sock_net(skb->sk); |
---|
777 | 933 | int family = nfmsg->nfgen_family; |
---|
778 | 934 | |
---|
779 | 935 | rcu_read_lock(); |
---|
780 | | - cb->seq = net->nft.base_seq; |
---|
| 936 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 937 | + cb->seq = nft_net->base_seq; |
---|
781 | 938 | |
---|
782 | | - list_for_each_entry_rcu(table, &net->nft.tables, list) { |
---|
| 939 | + list_for_each_entry_rcu(table, &nft_net->tables, list) { |
---|
783 | 940 | if (family != NFPROTO_UNSPEC && family != table->family) |
---|
784 | 941 | continue; |
---|
785 | 942 | |
---|
.. | .. |
---|
954 | 1111 | goto err; |
---|
955 | 1112 | |
---|
956 | 1113 | nft_trans_table_update(trans) = true; |
---|
957 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 1114 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
958 | 1115 | return 0; |
---|
959 | 1116 | err: |
---|
960 | 1117 | nft_trans_destroy(trans); |
---|
.. | .. |
---|
1017 | 1174 | const struct nlattr * const nla[], |
---|
1018 | 1175 | struct netlink_ext_ack *extack) |
---|
1019 | 1176 | { |
---|
| 1177 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
1020 | 1178 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
---|
1021 | 1179 | u8 genmask = nft_genmask_next(net); |
---|
1022 | 1180 | int family = nfmsg->nfgen_family; |
---|
.. | .. |
---|
1026 | 1184 | u32 flags = 0; |
---|
1027 | 1185 | int err; |
---|
1028 | 1186 | |
---|
1029 | | - lockdep_assert_held(&net->nft.commit_mutex); |
---|
| 1187 | + lockdep_assert_held(&nft_net->commit_mutex); |
---|
1030 | 1188 | attr = nla[NFTA_TABLE_NAME]; |
---|
1031 | 1189 | table = nft_table_lookup(net, attr, family, genmask); |
---|
1032 | 1190 | if (IS_ERR(table)) { |
---|
.. | .. |
---|
1084 | 1242 | if (err < 0) |
---|
1085 | 1243 | goto err_trans; |
---|
1086 | 1244 | |
---|
1087 | | - list_add_tail_rcu(&table->list, &net->nft.tables); |
---|
| 1245 | + list_add_tail_rcu(&table->list, &nft_net->tables); |
---|
1088 | 1246 | return 0; |
---|
1089 | 1247 | err_trans: |
---|
1090 | 1248 | rhltable_destroy(&table->chains_ht); |
---|
.. | .. |
---|
1110 | 1268 | if (!nft_is_active_next(ctx->net, chain)) |
---|
1111 | 1269 | continue; |
---|
1112 | 1270 | |
---|
1113 | | - if (nft_chain_is_bound(chain)) |
---|
| 1271 | + if (nft_chain_binding(chain)) |
---|
1114 | 1272 | continue; |
---|
1115 | 1273 | |
---|
1116 | 1274 | ctx->chain = chain; |
---|
.. | .. |
---|
1124 | 1282 | if (!nft_is_active_next(ctx->net, set)) |
---|
1125 | 1283 | continue; |
---|
1126 | 1284 | |
---|
1127 | | - if (nft_set_is_anonymous(set) && |
---|
1128 | | - !list_empty(&set->bindings)) |
---|
| 1285 | + if (nft_set_is_anonymous(set)) |
---|
1129 | 1286 | continue; |
---|
1130 | 1287 | |
---|
1131 | 1288 | err = nft_delset(ctx, set); |
---|
.. | .. |
---|
1155 | 1312 | if (!nft_is_active_next(ctx->net, chain)) |
---|
1156 | 1313 | continue; |
---|
1157 | 1314 | |
---|
1158 | | - if (nft_chain_is_bound(chain)) |
---|
| 1315 | + if (nft_chain_binding(chain)) |
---|
1159 | 1316 | continue; |
---|
1160 | 1317 | |
---|
1161 | 1318 | ctx->chain = chain; |
---|
.. | .. |
---|
1172 | 1329 | |
---|
1173 | 1330 | static int nft_flush(struct nft_ctx *ctx, int family) |
---|
1174 | 1331 | { |
---|
| 1332 | + struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id); |
---|
1175 | 1333 | struct nft_table *table, *nt; |
---|
1176 | 1334 | const struct nlattr * const *nla = ctx->nla; |
---|
1177 | 1335 | int err = 0; |
---|
1178 | 1336 | |
---|
1179 | | - list_for_each_entry_safe(table, nt, &ctx->net->nft.tables, list) { |
---|
| 1337 | + list_for_each_entry_safe(table, nt, &nft_net->tables, list) { |
---|
1180 | 1338 | if (family != AF_UNSPEC && table->family != family) |
---|
1181 | 1339 | continue; |
---|
1182 | 1340 | |
---|
.. | .. |
---|
1291 | 1449 | static bool lockdep_commit_lock_is_held(const struct net *net) |
---|
1292 | 1450 | { |
---|
1293 | 1451 | #ifdef CONFIG_PROVE_LOCKING |
---|
1294 | | - return lockdep_is_held(&net->nft.commit_mutex); |
---|
| 1452 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
| 1453 | + |
---|
| 1454 | + return lockdep_is_held(&nft_net->commit_mutex); |
---|
1295 | 1455 | #else |
---|
1296 | 1456 | return true; |
---|
1297 | 1457 | #endif |
---|
.. | .. |
---|
1494 | 1654 | |
---|
1495 | 1655 | static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event) |
---|
1496 | 1656 | { |
---|
| 1657 | + struct nftables_pernet *nft_net; |
---|
1497 | 1658 | struct sk_buff *skb; |
---|
1498 | 1659 | int err; |
---|
1499 | 1660 | |
---|
.. | .. |
---|
1513 | 1674 | goto err; |
---|
1514 | 1675 | } |
---|
1515 | 1676 | |
---|
1516 | | - nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list); |
---|
| 1677 | + nft_net = net_generic(ctx->net, nf_tables_net_id); |
---|
| 1678 | + nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list); |
---|
1517 | 1679 | return; |
---|
1518 | 1680 | err: |
---|
1519 | 1681 | nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS); |
---|
.. | .. |
---|
1528 | 1690 | unsigned int idx = 0, s_idx = cb->args[0]; |
---|
1529 | 1691 | struct net *net = sock_net(skb->sk); |
---|
1530 | 1692 | int family = nfmsg->nfgen_family; |
---|
| 1693 | + struct nftables_pernet *nft_net; |
---|
1531 | 1694 | |
---|
1532 | 1695 | rcu_read_lock(); |
---|
1533 | | - cb->seq = net->nft.base_seq; |
---|
| 1696 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 1697 | + cb->seq = nft_net->base_seq; |
---|
1534 | 1698 | |
---|
1535 | | - list_for_each_entry_rcu(table, &net->nft.tables, list) { |
---|
| 1699 | + list_for_each_entry_rcu(table, &nft_net->tables, list) { |
---|
1536 | 1700 | if (family != NFPROTO_UNSPEC && family != table->family) |
---|
1537 | 1701 | continue; |
---|
1538 | 1702 | |
---|
.. | .. |
---|
1847 | 2011 | struct nft_chain_hook *hook, u8 family, |
---|
1848 | 2012 | bool autoload) |
---|
1849 | 2013 | { |
---|
| 2014 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
1850 | 2015 | struct nlattr *ha[NFTA_HOOK_MAX + 1]; |
---|
1851 | 2016 | const struct nft_chain_type *type; |
---|
1852 | 2017 | int err; |
---|
1853 | 2018 | |
---|
1854 | | - lockdep_assert_held(&net->nft.commit_mutex); |
---|
| 2019 | + lockdep_assert_held(&nft_net->commit_mutex); |
---|
1855 | 2020 | lockdep_nfnl_nft_mutex_not_held(); |
---|
1856 | 2021 | |
---|
1857 | 2022 | err = nla_parse_nested_deprecated(ha, NFTA_HOOK_MAX, |
---|
.. | .. |
---|
1981 | 2146 | return 0; |
---|
1982 | 2147 | } |
---|
1983 | 2148 | |
---|
1984 | | -static int nft_chain_add(struct nft_table *table, struct nft_chain *chain) |
---|
| 2149 | +int nft_chain_add(struct nft_table *table, struct nft_chain *chain) |
---|
1985 | 2150 | { |
---|
1986 | 2151 | int err; |
---|
1987 | 2152 | |
---|
.. | .. |
---|
2009 | 2174 | struct nft_chain *chain; |
---|
2010 | 2175 | struct nft_rule **rules; |
---|
2011 | 2176 | int err; |
---|
2012 | | - |
---|
2013 | | - if (table->use == UINT_MAX) |
---|
2014 | | - return -EOVERFLOW; |
---|
2015 | 2177 | |
---|
2016 | 2178 | if (nla[NFTA_CHAIN_HOOK]) { |
---|
2017 | 2179 | struct nft_stats __percpu *stats = NULL; |
---|
.. | .. |
---|
2108 | 2270 | if (err < 0) |
---|
2109 | 2271 | goto err_destroy_chain; |
---|
2110 | 2272 | |
---|
| 2273 | + if (!nft_use_inc(&table->use)) { |
---|
| 2274 | + err = -EMFILE; |
---|
| 2275 | + goto err_use; |
---|
| 2276 | + } |
---|
| 2277 | + |
---|
2111 | 2278 | trans = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN); |
---|
2112 | 2279 | if (IS_ERR(trans)) { |
---|
2113 | 2280 | err = PTR_ERR(trans); |
---|
.. | .. |
---|
2124 | 2291 | goto err_unregister_hook; |
---|
2125 | 2292 | } |
---|
2126 | 2293 | |
---|
2127 | | - table->use++; |
---|
2128 | | - |
---|
2129 | 2294 | return 0; |
---|
| 2295 | + |
---|
2130 | 2296 | err_unregister_hook: |
---|
| 2297 | + nft_use_dec_restore(&table->use); |
---|
| 2298 | +err_use: |
---|
2131 | 2299 | nf_tables_unregister_hook(net, table, chain); |
---|
2132 | 2300 | err_destroy_chain: |
---|
2133 | 2301 | nf_tables_chain_destroy(ctx); |
---|
.. | .. |
---|
2244 | 2412 | |
---|
2245 | 2413 | if (nla[NFTA_CHAIN_HANDLE] && |
---|
2246 | 2414 | nla[NFTA_CHAIN_NAME]) { |
---|
| 2415 | + struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id); |
---|
2247 | 2416 | struct nft_trans *tmp; |
---|
2248 | 2417 | char *name; |
---|
2249 | 2418 | |
---|
.. | .. |
---|
2253 | 2422 | goto err; |
---|
2254 | 2423 | |
---|
2255 | 2424 | err = -EEXIST; |
---|
2256 | | - list_for_each_entry(tmp, &ctx->net->nft.commit_list, list) { |
---|
| 2425 | + list_for_each_entry(tmp, &nft_net->commit_list, list) { |
---|
2257 | 2426 | if (tmp->msg_type == NFT_MSG_NEWCHAIN && |
---|
2258 | 2427 | tmp->ctx.table == table && |
---|
2259 | 2428 | nft_trans_chain_update(tmp) && |
---|
.. | .. |
---|
2267 | 2436 | |
---|
2268 | 2437 | nft_trans_chain_name(trans) = name; |
---|
2269 | 2438 | } |
---|
2270 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 2439 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
2271 | 2440 | |
---|
2272 | 2441 | return 0; |
---|
2273 | 2442 | err: |
---|
.. | .. |
---|
2278 | 2447 | |
---|
2279 | 2448 | static struct nft_chain *nft_chain_lookup_byid(const struct net *net, |
---|
2280 | 2449 | const struct nft_table *table, |
---|
2281 | | - const struct nlattr *nla) |
---|
| 2450 | + const struct nlattr *nla, u8 genmask) |
---|
2282 | 2451 | { |
---|
| 2452 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
2283 | 2453 | u32 id = ntohl(nla_get_be32(nla)); |
---|
2284 | 2454 | struct nft_trans *trans; |
---|
2285 | 2455 | |
---|
2286 | | - list_for_each_entry(trans, &net->nft.commit_list, list) { |
---|
| 2456 | + list_for_each_entry(trans, &nft_net->commit_list, list) { |
---|
2287 | 2457 | struct nft_chain *chain = trans->ctx.chain; |
---|
2288 | 2458 | |
---|
2289 | 2459 | if (trans->msg_type == NFT_MSG_NEWCHAIN && |
---|
2290 | 2460 | chain->table == table && |
---|
2291 | | - id == nft_trans_chain_id(trans)) |
---|
| 2461 | + id == nft_trans_chain_id(trans) && |
---|
| 2462 | + nft_active_genmask(chain, genmask)) |
---|
2292 | 2463 | return chain; |
---|
2293 | 2464 | } |
---|
2294 | 2465 | return ERR_PTR(-ENOENT); |
---|
.. | .. |
---|
2299 | 2470 | const struct nlattr * const nla[], |
---|
2300 | 2471 | struct netlink_ext_ack *extack) |
---|
2301 | 2472 | { |
---|
| 2473 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
2302 | 2474 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
---|
2303 | 2475 | u8 genmask = nft_genmask_next(net); |
---|
2304 | 2476 | int family = nfmsg->nfgen_family; |
---|
.. | .. |
---|
2310 | 2482 | u64 handle = 0; |
---|
2311 | 2483 | u32 flags = 0; |
---|
2312 | 2484 | |
---|
2313 | | - lockdep_assert_held(&net->nft.commit_mutex); |
---|
| 2485 | + lockdep_assert_held(&nft_net->commit_mutex); |
---|
2314 | 2486 | |
---|
2315 | 2487 | table = nft_table_lookup(net, nla[NFTA_CHAIN_TABLE], family, genmask); |
---|
2316 | 2488 | if (IS_ERR(table)) { |
---|
.. | .. |
---|
2426 | 2598 | NL_SET_BAD_ATTR(extack, attr); |
---|
2427 | 2599 | return PTR_ERR(chain); |
---|
2428 | 2600 | } |
---|
| 2601 | + |
---|
| 2602 | + if (nft_chain_binding(chain)) |
---|
| 2603 | + return -EOPNOTSUPP; |
---|
2429 | 2604 | |
---|
2430 | 2605 | if (nlh->nlmsg_flags & NLM_F_NONREC && |
---|
2431 | 2606 | chain->use > 0) |
---|
.. | .. |
---|
2848 | 3023 | static void nf_tables_rule_notify(const struct nft_ctx *ctx, |
---|
2849 | 3024 | const struct nft_rule *rule, int event) |
---|
2850 | 3025 | { |
---|
| 3026 | + struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id); |
---|
2851 | 3027 | struct sk_buff *skb; |
---|
2852 | 3028 | int err; |
---|
2853 | 3029 | |
---|
.. | .. |
---|
2867 | 3043 | goto err; |
---|
2868 | 3044 | } |
---|
2869 | 3045 | |
---|
2870 | | - nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list); |
---|
| 3046 | + nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list); |
---|
2871 | 3047 | return; |
---|
2872 | 3048 | err: |
---|
2873 | 3049 | nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS); |
---|
.. | .. |
---|
2925 | 3101 | unsigned int idx = 0; |
---|
2926 | 3102 | struct net *net = sock_net(skb->sk); |
---|
2927 | 3103 | int family = nfmsg->nfgen_family; |
---|
| 3104 | + struct nftables_pernet *nft_net; |
---|
2928 | 3105 | |
---|
2929 | 3106 | rcu_read_lock(); |
---|
2930 | | - cb->seq = net->nft.base_seq; |
---|
| 3107 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 3108 | + cb->seq = nft_net->base_seq; |
---|
2931 | 3109 | |
---|
2932 | | - list_for_each_entry_rcu(table, &net->nft.tables, list) { |
---|
| 3110 | + list_for_each_entry_rcu(table, &nft_net->tables, list) { |
---|
2933 | 3111 | if (family != NFPROTO_UNSPEC && family != table->family) |
---|
2934 | 3112 | continue; |
---|
2935 | 3113 | |
---|
.. | .. |
---|
3076 | 3254 | return err; |
---|
3077 | 3255 | } |
---|
3078 | 3256 | |
---|
3079 | | -static void nf_tables_rule_destroy(const struct nft_ctx *ctx, |
---|
3080 | | - struct nft_rule *rule) |
---|
| 3257 | +void nf_tables_rule_destroy(const struct nft_ctx *ctx, struct nft_rule *rule) |
---|
3081 | 3258 | { |
---|
3082 | 3259 | struct nft_expr *expr, *next; |
---|
3083 | 3260 | |
---|
.. | .. |
---|
3094 | 3271 | kfree(rule); |
---|
3095 | 3272 | } |
---|
3096 | 3273 | |
---|
3097 | | -void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule) |
---|
| 3274 | +static void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule) |
---|
3098 | 3275 | { |
---|
3099 | 3276 | nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_RELEASE); |
---|
3100 | 3277 | nf_tables_rule_destroy(ctx, rule); |
---|
.. | .. |
---|
3145 | 3322 | err = nft_chain_validate(&ctx, chain); |
---|
3146 | 3323 | if (err < 0) |
---|
3147 | 3324 | return err; |
---|
| 3325 | + |
---|
| 3326 | + cond_resched(); |
---|
3148 | 3327 | } |
---|
3149 | 3328 | |
---|
3150 | 3329 | return 0; |
---|
.. | .. |
---|
3161 | 3340 | const struct nlattr * const nla[], |
---|
3162 | 3341 | struct netlink_ext_ack *extack) |
---|
3163 | 3342 | { |
---|
| 3343 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
3164 | 3344 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
---|
3165 | 3345 | u8 genmask = nft_genmask_next(net); |
---|
3166 | 3346 | struct nft_expr_info *info = NULL; |
---|
.. | .. |
---|
3178 | 3358 | int err, rem; |
---|
3179 | 3359 | u64 handle, pos_handle; |
---|
3180 | 3360 | |
---|
3181 | | - lockdep_assert_held(&net->nft.commit_mutex); |
---|
| 3361 | + lockdep_assert_held(&nft_net->commit_mutex); |
---|
3182 | 3362 | |
---|
3183 | 3363 | table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask); |
---|
3184 | 3364 | if (IS_ERR(table)) { |
---|
.. | .. |
---|
3193 | 3373 | NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]); |
---|
3194 | 3374 | return PTR_ERR(chain); |
---|
3195 | 3375 | } |
---|
3196 | | - if (nft_chain_is_bound(chain)) |
---|
3197 | | - return -EOPNOTSUPP; |
---|
3198 | 3376 | |
---|
3199 | 3377 | } else if (nla[NFTA_RULE_CHAIN_ID]) { |
---|
3200 | | - chain = nft_chain_lookup_byid(net, table, nla[NFTA_RULE_CHAIN_ID]); |
---|
| 3378 | + chain = nft_chain_lookup_byid(net, table, nla[NFTA_RULE_CHAIN_ID], |
---|
| 3379 | + genmask); |
---|
3201 | 3380 | if (IS_ERR(chain)) { |
---|
3202 | 3381 | NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN_ID]); |
---|
3203 | 3382 | return PTR_ERR(chain); |
---|
.. | .. |
---|
3205 | 3384 | } else { |
---|
3206 | 3385 | return -EINVAL; |
---|
3207 | 3386 | } |
---|
| 3387 | + |
---|
| 3388 | + if (nft_chain_is_bound(chain)) |
---|
| 3389 | + return -EOPNOTSUPP; |
---|
3208 | 3390 | |
---|
3209 | 3391 | if (nla[NFTA_RULE_HANDLE]) { |
---|
3210 | 3392 | handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE])); |
---|
.. | .. |
---|
3227 | 3409 | nlh->nlmsg_flags & NLM_F_REPLACE) |
---|
3228 | 3410 | return -EINVAL; |
---|
3229 | 3411 | handle = nf_tables_alloc_handle(table); |
---|
3230 | | - |
---|
3231 | | - if (chain->use == UINT_MAX) |
---|
3232 | | - return -EOVERFLOW; |
---|
3233 | 3412 | |
---|
3234 | 3413 | if (nla[NFTA_RULE_POSITION]) { |
---|
3235 | 3414 | pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION])); |
---|
.. | .. |
---|
3316 | 3495 | expr = nft_expr_next(expr); |
---|
3317 | 3496 | } |
---|
3318 | 3497 | |
---|
| 3498 | + if (!nft_use_inc(&chain->use)) { |
---|
| 3499 | + err = -EMFILE; |
---|
| 3500 | + goto err2; |
---|
| 3501 | + } |
---|
| 3502 | + |
---|
3319 | 3503 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { |
---|
| 3504 | + if (nft_chain_binding(chain)) { |
---|
| 3505 | + err = -EOPNOTSUPP; |
---|
| 3506 | + goto err_destroy_flow_rule; |
---|
| 3507 | + } |
---|
| 3508 | + |
---|
3320 | 3509 | trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule); |
---|
3321 | 3510 | if (trans == NULL) { |
---|
3322 | 3511 | err = -ENOMEM; |
---|
3323 | | - goto err2; |
---|
| 3512 | + goto err_destroy_flow_rule; |
---|
3324 | 3513 | } |
---|
3325 | 3514 | err = nft_delrule(&ctx, old_rule); |
---|
3326 | 3515 | if (err < 0) { |
---|
3327 | 3516 | nft_trans_destroy(trans); |
---|
3328 | | - goto err2; |
---|
| 3517 | + goto err_destroy_flow_rule; |
---|
3329 | 3518 | } |
---|
3330 | 3519 | |
---|
3331 | 3520 | list_add_tail_rcu(&rule->list, &old_rule->list); |
---|
.. | .. |
---|
3333 | 3522 | trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule); |
---|
3334 | 3523 | if (!trans) { |
---|
3335 | 3524 | err = -ENOMEM; |
---|
3336 | | - goto err2; |
---|
| 3525 | + goto err_destroy_flow_rule; |
---|
3337 | 3526 | } |
---|
3338 | 3527 | |
---|
3339 | 3528 | if (nlh->nlmsg_flags & NLM_F_APPEND) { |
---|
.. | .. |
---|
3349 | 3538 | } |
---|
3350 | 3539 | } |
---|
3351 | 3540 | kvfree(info); |
---|
3352 | | - chain->use++; |
---|
3353 | 3541 | |
---|
3354 | | - if (net->nft.validate_state == NFT_VALIDATE_DO) |
---|
| 3542 | + if (nft_net->validate_state == NFT_VALIDATE_DO) |
---|
3355 | 3543 | return nft_table_validate(net, table); |
---|
3356 | 3544 | |
---|
3357 | 3545 | if (chain->flags & NFT_CHAIN_HW_OFFLOAD) { |
---|
.. | .. |
---|
3363 | 3551 | } |
---|
3364 | 3552 | |
---|
3365 | 3553 | return 0; |
---|
| 3554 | + |
---|
| 3555 | +err_destroy_flow_rule: |
---|
| 3556 | + nft_use_dec_restore(&chain->use); |
---|
3366 | 3557 | err2: |
---|
3367 | | - nf_tables_rule_release(&ctx, rule); |
---|
| 3558 | + nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE_ERROR); |
---|
| 3559 | + nf_tables_rule_destroy(&ctx, rule); |
---|
3368 | 3560 | err1: |
---|
3369 | 3561 | for (i = 0; i < n; i++) { |
---|
3370 | 3562 | if (info[i].ops) { |
---|
.. | .. |
---|
3381 | 3573 | const struct nft_chain *chain, |
---|
3382 | 3574 | const struct nlattr *nla) |
---|
3383 | 3575 | { |
---|
| 3576 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
3384 | 3577 | u32 id = ntohl(nla_get_be32(nla)); |
---|
3385 | 3578 | struct nft_trans *trans; |
---|
3386 | 3579 | |
---|
3387 | | - list_for_each_entry(trans, &net->nft.commit_list, list) { |
---|
| 3580 | + list_for_each_entry(trans, &nft_net->commit_list, list) { |
---|
3388 | 3581 | struct nft_rule *rule = nft_trans_rule(trans); |
---|
3389 | 3582 | |
---|
3390 | 3583 | if (trans->msg_type == NFT_MSG_NEWRULE && |
---|
.. | .. |
---|
3421 | 3614 | NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]); |
---|
3422 | 3615 | return PTR_ERR(chain); |
---|
3423 | 3616 | } |
---|
3424 | | - if (nft_chain_is_bound(chain)) |
---|
| 3617 | + if (nft_chain_binding(chain)) |
---|
3425 | 3618 | return -EOPNOTSUPP; |
---|
3426 | 3619 | } |
---|
3427 | 3620 | |
---|
.. | .. |
---|
3450 | 3643 | } else { |
---|
3451 | 3644 | list_for_each_entry(chain, &table->chains, list) { |
---|
3452 | 3645 | if (!nft_is_active_next(net, chain)) |
---|
| 3646 | + continue; |
---|
| 3647 | + if (nft_chain_binding(chain)) |
---|
3453 | 3648 | continue; |
---|
3454 | 3649 | |
---|
3455 | 3650 | ctx.chain = chain; |
---|
.. | .. |
---|
3497 | 3692 | const struct nft_set_desc *desc, |
---|
3498 | 3693 | enum nft_set_policies policy) |
---|
3499 | 3694 | { |
---|
| 3695 | + struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id); |
---|
3500 | 3696 | const struct nft_set_ops *ops, *bops; |
---|
3501 | 3697 | struct nft_set_estimate est, best; |
---|
3502 | 3698 | const struct nft_set_type *type; |
---|
3503 | 3699 | u32 flags = 0; |
---|
3504 | 3700 | int i; |
---|
3505 | 3701 | |
---|
3506 | | - lockdep_assert_held(&ctx->net->nft.commit_mutex); |
---|
| 3702 | + lockdep_assert_held(&nft_net->commit_mutex); |
---|
3507 | 3703 | lockdep_nfnl_nft_mutex_not_held(); |
---|
3508 | 3704 | |
---|
3509 | 3705 | if (nla[NFTA_SET_FLAGS] != NULL) |
---|
.. | .. |
---|
3641 | 3837 | const struct nft_table *table, |
---|
3642 | 3838 | const struct nlattr *nla, u8 genmask) |
---|
3643 | 3839 | { |
---|
| 3840 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
3644 | 3841 | struct nft_trans *trans; |
---|
3645 | 3842 | u32 id = ntohl(nla_get_be32(nla)); |
---|
3646 | 3843 | |
---|
3647 | | - list_for_each_entry(trans, &net->nft.commit_list, list) { |
---|
| 3844 | + list_for_each_entry(trans, &nft_net->commit_list, list) { |
---|
3648 | 3845 | if (trans->msg_type == NFT_MSG_NEWSET) { |
---|
3649 | 3846 | struct nft_set *set = nft_trans_set(trans); |
---|
3650 | 3847 | |
---|
.. | .. |
---|
3867 | 4064 | const struct nft_set *set, int event, |
---|
3868 | 4065 | gfp_t gfp_flags) |
---|
3869 | 4066 | { |
---|
| 4067 | + struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id); |
---|
3870 | 4068 | struct sk_buff *skb; |
---|
3871 | 4069 | u32 portid = ctx->portid; |
---|
3872 | 4070 | int err; |
---|
.. | .. |
---|
3885 | 4083 | goto err; |
---|
3886 | 4084 | } |
---|
3887 | 4085 | |
---|
3888 | | - nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list); |
---|
| 4086 | + nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list); |
---|
3889 | 4087 | return; |
---|
3890 | 4088 | err: |
---|
3891 | 4089 | nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, -ENOBUFS); |
---|
.. | .. |
---|
3898 | 4096 | struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2]; |
---|
3899 | 4097 | struct net *net = sock_net(skb->sk); |
---|
3900 | 4098 | struct nft_ctx *ctx = cb->data, ctx_set; |
---|
| 4099 | + struct nftables_pernet *nft_net; |
---|
3901 | 4100 | |
---|
3902 | 4101 | if (cb->args[1]) |
---|
3903 | 4102 | return skb->len; |
---|
3904 | 4103 | |
---|
3905 | 4104 | rcu_read_lock(); |
---|
3906 | | - cb->seq = net->nft.base_seq; |
---|
| 4105 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 4106 | + cb->seq = nft_net->base_seq; |
---|
3907 | 4107 | |
---|
3908 | | - list_for_each_entry_rcu(table, &net->nft.tables, list) { |
---|
| 4108 | + list_for_each_entry_rcu(table, &nft_net->tables, list) { |
---|
3909 | 4109 | if (ctx->family != NFPROTO_UNSPEC && |
---|
3910 | 4110 | ctx->family != table->family) |
---|
3911 | 4111 | continue; |
---|
.. | .. |
---|
4269 | 4469 | alloc_size = sizeof(*set) + size + udlen; |
---|
4270 | 4470 | if (alloc_size < size || alloc_size > INT_MAX) |
---|
4271 | 4471 | return -ENOMEM; |
---|
| 4472 | + |
---|
| 4473 | + if (!nft_use_inc(&table->use)) |
---|
| 4474 | + return -EMFILE; |
---|
| 4475 | + |
---|
4272 | 4476 | set = kvzalloc(alloc_size, GFP_KERNEL); |
---|
4273 | | - if (!set) |
---|
4274 | | - return -ENOMEM; |
---|
| 4477 | + if (!set) { |
---|
| 4478 | + err = -ENOMEM; |
---|
| 4479 | + goto err_alloc; |
---|
| 4480 | + } |
---|
4275 | 4481 | |
---|
4276 | 4482 | name = nla_strdup(nla[NFTA_SET_NAME], GFP_KERNEL); |
---|
4277 | 4483 | if (!name) { |
---|
.. | .. |
---|
4291 | 4497 | } |
---|
4292 | 4498 | |
---|
4293 | 4499 | INIT_LIST_HEAD(&set->bindings); |
---|
| 4500 | + refcount_set(&set->refs, 1); |
---|
4294 | 4501 | set->table = table; |
---|
4295 | 4502 | write_pnet(&set->net, net); |
---|
4296 | 4503 | set->ops = ops; |
---|
.. | .. |
---|
4326 | 4533 | } |
---|
4327 | 4534 | |
---|
4328 | 4535 | set->handle = nf_tables_alloc_handle(table); |
---|
| 4536 | + INIT_LIST_HEAD(&set->pending_update); |
---|
4329 | 4537 | |
---|
4330 | 4538 | err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set); |
---|
4331 | 4539 | if (err < 0) |
---|
4332 | 4540 | goto err_set_expr_alloc; |
---|
4333 | 4541 | |
---|
4334 | 4542 | list_add_tail_rcu(&set->list, &table->sets); |
---|
4335 | | - table->use++; |
---|
| 4543 | + |
---|
4336 | 4544 | return 0; |
---|
4337 | 4545 | |
---|
4338 | 4546 | err_set_expr_alloc: |
---|
4339 | 4547 | if (set->expr) |
---|
4340 | 4548 | nft_expr_destroy(&ctx, set->expr); |
---|
4341 | 4549 | |
---|
4342 | | - ops->destroy(set); |
---|
| 4550 | + ops->destroy(&ctx, set); |
---|
4343 | 4551 | err_set_init: |
---|
4344 | 4552 | kfree(set->name); |
---|
4345 | 4553 | err_set_name: |
---|
4346 | 4554 | kvfree(set); |
---|
| 4555 | +err_alloc: |
---|
| 4556 | + nft_use_dec_restore(&table->use); |
---|
| 4557 | + |
---|
4347 | 4558 | return err; |
---|
| 4559 | +} |
---|
| 4560 | + |
---|
| 4561 | +static void nft_set_put(struct nft_set *set) |
---|
| 4562 | +{ |
---|
| 4563 | + if (refcount_dec_and_test(&set->refs)) { |
---|
| 4564 | + kfree(set->name); |
---|
| 4565 | + kvfree(set); |
---|
| 4566 | + } |
---|
4348 | 4567 | } |
---|
4349 | 4568 | |
---|
4350 | 4569 | static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set) |
---|
.. | .. |
---|
4355 | 4574 | if (set->expr) |
---|
4356 | 4575 | nft_expr_destroy(ctx, set->expr); |
---|
4357 | 4576 | |
---|
4358 | | - set->ops->destroy(set); |
---|
4359 | | - kfree(set->name); |
---|
4360 | | - kvfree(set); |
---|
| 4577 | + set->ops->destroy(ctx, set); |
---|
| 4578 | + nft_set_put(set); |
---|
4361 | 4579 | } |
---|
4362 | 4580 | |
---|
4363 | 4581 | static int nf_tables_delset(struct net *net, struct sock *nlsk, |
---|
.. | .. |
---|
4409 | 4627 | enum nft_data_types type, |
---|
4410 | 4628 | unsigned int len); |
---|
4411 | 4629 | |
---|
4412 | | -static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx, |
---|
4413 | | - struct nft_set *set, |
---|
4414 | | - const struct nft_set_iter *iter, |
---|
4415 | | - struct nft_set_elem *elem) |
---|
| 4630 | +static int nft_setelem_data_validate(const struct nft_ctx *ctx, |
---|
| 4631 | + struct nft_set *set, |
---|
| 4632 | + struct nft_set_elem *elem) |
---|
4416 | 4633 | { |
---|
4417 | 4634 | const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); |
---|
4418 | 4635 | enum nft_registers dreg; |
---|
.. | .. |
---|
4424 | 4641 | set->dlen); |
---|
4425 | 4642 | } |
---|
4426 | 4643 | |
---|
| 4644 | +static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx, |
---|
| 4645 | + struct nft_set *set, |
---|
| 4646 | + const struct nft_set_iter *iter, |
---|
| 4647 | + struct nft_set_elem *elem) |
---|
| 4648 | +{ |
---|
| 4649 | + return nft_setelem_data_validate(ctx, set, elem); |
---|
| 4650 | +} |
---|
| 4651 | + |
---|
4427 | 4652 | int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, |
---|
4428 | 4653 | struct nft_set_binding *binding) |
---|
4429 | 4654 | { |
---|
4430 | 4655 | struct nft_set_binding *i; |
---|
4431 | 4656 | struct nft_set_iter iter; |
---|
4432 | | - |
---|
4433 | | - if (set->use == UINT_MAX) |
---|
4434 | | - return -EOVERFLOW; |
---|
4435 | 4657 | |
---|
4436 | 4658 | if (!list_empty(&set->bindings) && nft_set_is_anonymous(set)) |
---|
4437 | 4659 | return -EBUSY; |
---|
.. | .. |
---|
4457 | 4679 | return iter.err; |
---|
4458 | 4680 | } |
---|
4459 | 4681 | bind: |
---|
| 4682 | + if (!nft_use_inc(&set->use)) |
---|
| 4683 | + return -EMFILE; |
---|
| 4684 | + |
---|
4460 | 4685 | binding->chain = ctx->chain; |
---|
4461 | 4686 | list_add_tail_rcu(&binding->list, &set->bindings); |
---|
4462 | 4687 | nft_set_trans_bind(ctx, set); |
---|
4463 | | - set->use++; |
---|
4464 | 4688 | |
---|
4465 | 4689 | return 0; |
---|
4466 | 4690 | } |
---|
.. | .. |
---|
4479 | 4703 | } |
---|
4480 | 4704 | } |
---|
4481 | 4705 | |
---|
| 4706 | +static void nft_setelem_data_activate(const struct net *net, |
---|
| 4707 | + const struct nft_set *set, |
---|
| 4708 | + struct nft_set_elem *elem); |
---|
| 4709 | + |
---|
| 4710 | +static int nft_mapelem_activate(const struct nft_ctx *ctx, |
---|
| 4711 | + struct nft_set *set, |
---|
| 4712 | + const struct nft_set_iter *iter, |
---|
| 4713 | + struct nft_set_elem *elem) |
---|
| 4714 | +{ |
---|
| 4715 | + nft_setelem_data_activate(ctx->net, set, elem); |
---|
| 4716 | + |
---|
| 4717 | + return 0; |
---|
| 4718 | +} |
---|
| 4719 | + |
---|
| 4720 | +static void nft_map_activate(const struct nft_ctx *ctx, struct nft_set *set) |
---|
| 4721 | +{ |
---|
| 4722 | + struct nft_set_iter iter = { |
---|
| 4723 | + .genmask = nft_genmask_next(ctx->net), |
---|
| 4724 | + .fn = nft_mapelem_activate, |
---|
| 4725 | + }; |
---|
| 4726 | + |
---|
| 4727 | + set->ops->walk(ctx, set, &iter); |
---|
| 4728 | + WARN_ON_ONCE(iter.err); |
---|
| 4729 | +} |
---|
| 4730 | + |
---|
| 4731 | +void nf_tables_activate_set(const struct nft_ctx *ctx, struct nft_set *set) |
---|
| 4732 | +{ |
---|
| 4733 | + if (nft_set_is_anonymous(set)) { |
---|
| 4734 | + if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT)) |
---|
| 4735 | + nft_map_activate(ctx, set); |
---|
| 4736 | + |
---|
| 4737 | + nft_clear(ctx->net, set); |
---|
| 4738 | + } |
---|
| 4739 | + |
---|
| 4740 | + nft_use_inc_restore(&set->use); |
---|
| 4741 | +} |
---|
| 4742 | +EXPORT_SYMBOL_GPL(nf_tables_activate_set); |
---|
| 4743 | + |
---|
4482 | 4744 | void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set, |
---|
4483 | 4745 | struct nft_set_binding *binding, |
---|
4484 | 4746 | enum nft_trans_phase phase) |
---|
4485 | 4747 | { |
---|
4486 | 4748 | switch (phase) { |
---|
| 4749 | + case NFT_TRANS_PREPARE_ERROR: |
---|
| 4750 | + nft_set_trans_unbind(ctx, set); |
---|
| 4751 | + if (nft_set_is_anonymous(set)) |
---|
| 4752 | + nft_deactivate_next(ctx->net, set); |
---|
| 4753 | + else |
---|
| 4754 | + list_del_rcu(&binding->list); |
---|
| 4755 | + |
---|
| 4756 | + nft_use_dec(&set->use); |
---|
| 4757 | + break; |
---|
4487 | 4758 | case NFT_TRANS_PREPARE: |
---|
4488 | | - set->use--; |
---|
| 4759 | + if (nft_set_is_anonymous(set)) { |
---|
| 4760 | + if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT)) |
---|
| 4761 | + nft_map_deactivate(ctx, set); |
---|
| 4762 | + |
---|
| 4763 | + nft_deactivate_next(ctx->net, set); |
---|
| 4764 | + } |
---|
| 4765 | + nft_use_dec(&set->use); |
---|
4489 | 4766 | return; |
---|
4490 | 4767 | case NFT_TRANS_ABORT: |
---|
4491 | 4768 | case NFT_TRANS_RELEASE: |
---|
4492 | | - set->use--; |
---|
| 4769 | + if (nft_set_is_anonymous(set) && |
---|
| 4770 | + set->flags & (NFT_SET_MAP | NFT_SET_OBJECT)) |
---|
| 4771 | + nft_map_deactivate(ctx, set); |
---|
| 4772 | + |
---|
| 4773 | + nft_use_dec(&set->use); |
---|
4493 | 4774 | fallthrough; |
---|
4494 | 4775 | default: |
---|
4495 | 4776 | nf_tables_unbind_set(ctx, set, binding, |
---|
.. | .. |
---|
4679 | 4960 | const struct nft_set_iter *iter, |
---|
4680 | 4961 | struct nft_set_elem *elem) |
---|
4681 | 4962 | { |
---|
| 4963 | + const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); |
---|
4682 | 4964 | struct nft_set_dump_args *args; |
---|
| 4965 | + |
---|
| 4966 | + if (nft_set_elem_expired(ext)) |
---|
| 4967 | + return 0; |
---|
4683 | 4968 | |
---|
4684 | 4969 | args = container_of(iter, struct nft_set_dump_args, iter); |
---|
4685 | 4970 | return nf_tables_fill_setelem(args->skb, set, elem); |
---|
.. | .. |
---|
4694 | 4979 | { |
---|
4695 | 4980 | struct nft_set_dump_ctx *dump_ctx = cb->data; |
---|
4696 | 4981 | struct net *net = sock_net(skb->sk); |
---|
| 4982 | + struct nftables_pernet *nft_net; |
---|
4697 | 4983 | struct nft_table *table; |
---|
4698 | 4984 | struct nft_set *set; |
---|
4699 | 4985 | struct nft_set_dump_args args; |
---|
.. | .. |
---|
4704 | 4990 | int event; |
---|
4705 | 4991 | |
---|
4706 | 4992 | rcu_read_lock(); |
---|
4707 | | - list_for_each_entry_rcu(table, &net->nft.tables, list) { |
---|
| 4993 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 4994 | + list_for_each_entry_rcu(table, &nft_net->tables, list) { |
---|
4708 | 4995 | if (dump_ctx->ctx.family != NFPROTO_UNSPEC && |
---|
4709 | 4996 | dump_ctx->ctx.family != table->family) |
---|
4710 | 4997 | continue; |
---|
.. | .. |
---|
4983 | 5270 | const struct nft_set_elem *elem, |
---|
4984 | 5271 | int event, u16 flags) |
---|
4985 | 5272 | { |
---|
| 5273 | + struct nftables_pernet *nft_net; |
---|
4986 | 5274 | struct net *net = ctx->net; |
---|
4987 | 5275 | u32 portid = ctx->portid; |
---|
4988 | 5276 | struct sk_buff *skb; |
---|
.. | .. |
---|
5002 | 5290 | goto err; |
---|
5003 | 5291 | } |
---|
5004 | 5292 | |
---|
5005 | | - nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list); |
---|
| 5293 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 5294 | + nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list); |
---|
5006 | 5295 | return; |
---|
5007 | 5296 | err: |
---|
5008 | 5297 | nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS); |
---|
.. | .. |
---|
5091 | 5380 | } |
---|
5092 | 5381 | } |
---|
5093 | 5382 | |
---|
| 5383 | +/* Drop references and destroy. Called from gc, dynset and abort path. */ |
---|
5094 | 5384 | void nft_set_elem_destroy(const struct nft_set *set, void *elem, |
---|
5095 | 5385 | bool destroy_expr) |
---|
5096 | 5386 | { |
---|
.. | .. |
---|
5107 | 5397 | nft_set_elem_expr_destroy(&ctx, nft_set_ext_expr(ext)); |
---|
5108 | 5398 | |
---|
5109 | 5399 | if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF)) |
---|
5110 | | - (*nft_set_ext_obj(ext))->use--; |
---|
| 5400 | + nft_use_dec(&(*nft_set_ext_obj(ext))->use); |
---|
5111 | 5401 | kfree(elem); |
---|
5112 | 5402 | } |
---|
5113 | 5403 | EXPORT_SYMBOL_GPL(nft_set_elem_destroy); |
---|
5114 | 5404 | |
---|
5115 | | -/* Only called from commit path, nft_set_elem_deactivate() already deals with |
---|
5116 | | - * the refcounting from the preparation phase. |
---|
| 5405 | +/* Destroy element. References have been already dropped in the preparation |
---|
| 5406 | + * path via nft_setelem_data_deactivate(). |
---|
5117 | 5407 | */ |
---|
5118 | | -static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx, |
---|
5119 | | - const struct nft_set *set, void *elem) |
---|
| 5408 | +void nf_tables_set_elem_destroy(const struct nft_ctx *ctx, |
---|
| 5409 | + const struct nft_set *set, void *elem) |
---|
5120 | 5410 | { |
---|
5121 | 5411 | struct nft_set_ext *ext = nft_set_elem_ext(set, elem); |
---|
5122 | 5412 | |
---|
.. | .. |
---|
5281 | 5571 | set->objtype, genmask); |
---|
5282 | 5572 | if (IS_ERR(obj)) { |
---|
5283 | 5573 | err = PTR_ERR(obj); |
---|
| 5574 | + obj = NULL; |
---|
5284 | 5575 | goto err_parse_key_end; |
---|
5285 | 5576 | } |
---|
| 5577 | + |
---|
| 5578 | + if (!nft_use_inc(&obj->use)) { |
---|
| 5579 | + err = -EMFILE; |
---|
| 5580 | + obj = NULL; |
---|
| 5581 | + goto err_parse_key_end; |
---|
| 5582 | + } |
---|
| 5583 | + |
---|
5286 | 5584 | nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF); |
---|
5287 | 5585 | } |
---|
5288 | 5586 | |
---|
.. | .. |
---|
5347 | 5645 | udata->len = ulen - 1; |
---|
5348 | 5646 | nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen); |
---|
5349 | 5647 | } |
---|
5350 | | - if (obj) { |
---|
| 5648 | + if (obj) |
---|
5351 | 5649 | *nft_set_ext_obj(ext) = obj; |
---|
5352 | | - obj->use++; |
---|
5353 | | - } |
---|
5354 | 5650 | |
---|
5355 | 5651 | err = nft_set_elem_expr_setup(ctx, ext, expr); |
---|
5356 | 5652 | if (err < 0) |
---|
.. | .. |
---|
5363 | 5659 | goto err_elem_expr; |
---|
5364 | 5660 | } |
---|
5365 | 5661 | |
---|
5366 | | - ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK; |
---|
| 5662 | + ext->genmask = nft_genmask_cur(ctx->net); |
---|
| 5663 | + |
---|
5367 | 5664 | err = set->ops->insert(ctx->net, set, &elem, &ext2); |
---|
5368 | 5665 | if (err) { |
---|
5369 | 5666 | if (err == -EEXIST) { |
---|
.. | .. |
---|
5398 | 5695 | } |
---|
5399 | 5696 | |
---|
5400 | 5697 | nft_trans_elem(trans) = elem; |
---|
5401 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 5698 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
5402 | 5699 | return 0; |
---|
5403 | 5700 | |
---|
5404 | 5701 | err_set_full: |
---|
.. | .. |
---|
5406 | 5703 | err_element_clash: |
---|
5407 | 5704 | kfree(trans); |
---|
5408 | 5705 | err_elem_expr: |
---|
5409 | | - if (obj) |
---|
5410 | | - obj->use--; |
---|
5411 | | - |
---|
5412 | 5706 | nf_tables_set_elem_destroy(ctx, set, elem.priv); |
---|
5413 | 5707 | err_parse_data: |
---|
5414 | 5708 | if (nla[NFTA_SET_ELEM_DATA] != NULL) |
---|
5415 | 5709 | nft_data_release(&elem.data.val, desc.type); |
---|
5416 | 5710 | err_parse_key_end: |
---|
| 5711 | + if (obj) |
---|
| 5712 | + nft_use_dec_restore(&obj->use); |
---|
| 5713 | + |
---|
5417 | 5714 | nft_data_release(&elem.key_end.val, NFT_DATA_VALUE); |
---|
5418 | 5715 | err_parse_key: |
---|
5419 | 5716 | nft_data_release(&elem.key.val, NFT_DATA_VALUE); |
---|
.. | .. |
---|
5429 | 5726 | const struct nlattr * const nla[], |
---|
5430 | 5727 | struct netlink_ext_ack *extack) |
---|
5431 | 5728 | { |
---|
| 5729 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
5432 | 5730 | u8 genmask = nft_genmask_next(net); |
---|
5433 | 5731 | const struct nlattr *attr; |
---|
5434 | 5732 | struct nft_set *set; |
---|
.. | .. |
---|
5448 | 5746 | if (IS_ERR(set)) |
---|
5449 | 5747 | return PTR_ERR(set); |
---|
5450 | 5748 | |
---|
5451 | | - if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT) |
---|
| 5749 | + if (!list_empty(&set->bindings) && |
---|
| 5750 | + (set->flags & (NFT_SET_CONSTANT | NFT_SET_ANONYMOUS))) |
---|
5452 | 5751 | return -EBUSY; |
---|
5453 | 5752 | |
---|
5454 | 5753 | nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { |
---|
.. | .. |
---|
5457 | 5756 | return err; |
---|
5458 | 5757 | } |
---|
5459 | 5758 | |
---|
5460 | | - if (net->nft.validate_state == NFT_VALIDATE_DO) |
---|
| 5759 | + if (nft_net->validate_state == NFT_VALIDATE_DO) |
---|
5461 | 5760 | return nft_table_validate(net, ctx.table); |
---|
5462 | 5761 | |
---|
5463 | 5762 | return 0; |
---|
.. | .. |
---|
5477 | 5776 | void nft_data_hold(const struct nft_data *data, enum nft_data_types type) |
---|
5478 | 5777 | { |
---|
5479 | 5778 | struct nft_chain *chain; |
---|
5480 | | - struct nft_rule *rule; |
---|
5481 | 5779 | |
---|
5482 | 5780 | if (type == NFT_DATA_VERDICT) { |
---|
5483 | 5781 | switch (data->verdict.code) { |
---|
5484 | 5782 | case NFT_JUMP: |
---|
5485 | 5783 | case NFT_GOTO: |
---|
5486 | 5784 | chain = data->verdict.chain; |
---|
5487 | | - chain->use++; |
---|
5488 | | - |
---|
5489 | | - if (!nft_chain_is_bound(chain)) |
---|
5490 | | - break; |
---|
5491 | | - |
---|
5492 | | - chain->table->use++; |
---|
5493 | | - list_for_each_entry(rule, &chain->rules, list) |
---|
5494 | | - chain->use++; |
---|
5495 | | - |
---|
5496 | | - nft_chain_add(chain->table, chain); |
---|
| 5785 | + nft_use_inc_restore(&chain->use); |
---|
5497 | 5786 | break; |
---|
5498 | 5787 | } |
---|
5499 | 5788 | } |
---|
5500 | 5789 | } |
---|
5501 | 5790 | |
---|
5502 | | -static void nft_set_elem_activate(const struct net *net, |
---|
5503 | | - const struct nft_set *set, |
---|
5504 | | - struct nft_set_elem *elem) |
---|
| 5791 | +static void nft_setelem_data_activate(const struct net *net, |
---|
| 5792 | + const struct nft_set *set, |
---|
| 5793 | + struct nft_set_elem *elem) |
---|
5505 | 5794 | { |
---|
5506 | 5795 | const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); |
---|
5507 | 5796 | |
---|
5508 | 5797 | if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA)) |
---|
5509 | 5798 | nft_data_hold(nft_set_ext_data(ext), set->dtype); |
---|
5510 | 5799 | if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF)) |
---|
5511 | | - (*nft_set_ext_obj(ext))->use++; |
---|
| 5800 | + nft_use_inc_restore(&(*nft_set_ext_obj(ext))->use); |
---|
5512 | 5801 | } |
---|
5513 | 5802 | |
---|
5514 | | -static void nft_set_elem_deactivate(const struct net *net, |
---|
5515 | | - const struct nft_set *set, |
---|
5516 | | - struct nft_set_elem *elem) |
---|
| 5803 | +void nft_setelem_data_deactivate(const struct net *net, |
---|
| 5804 | + const struct nft_set *set, |
---|
| 5805 | + struct nft_set_elem *elem) |
---|
5517 | 5806 | { |
---|
5518 | 5807 | const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); |
---|
5519 | 5808 | |
---|
5520 | 5809 | if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA)) |
---|
5521 | 5810 | nft_data_release(nft_set_ext_data(ext), set->dtype); |
---|
5522 | 5811 | if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF)) |
---|
5523 | | - (*nft_set_ext_obj(ext))->use--; |
---|
| 5812 | + nft_use_dec(&(*nft_set_ext_obj(ext))->use); |
---|
5524 | 5813 | } |
---|
5525 | 5814 | |
---|
5526 | 5815 | static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, |
---|
.. | .. |
---|
5590 | 5879 | kfree(elem.priv); |
---|
5591 | 5880 | elem.priv = priv; |
---|
5592 | 5881 | |
---|
5593 | | - nft_set_elem_deactivate(ctx->net, set, &elem); |
---|
| 5882 | + nft_setelem_data_deactivate(ctx->net, set, &elem); |
---|
5594 | 5883 | |
---|
5595 | 5884 | nft_trans_elem(trans) = elem; |
---|
5596 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 5885 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
5597 | 5886 | return 0; |
---|
5598 | 5887 | |
---|
5599 | 5888 | fail_ops: |
---|
.. | .. |
---|
5624 | 5913 | } |
---|
5625 | 5914 | set->ndeact++; |
---|
5626 | 5915 | |
---|
5627 | | - nft_set_elem_deactivate(ctx->net, set, elem); |
---|
| 5916 | + nft_setelem_data_deactivate(ctx->net, set, elem); |
---|
5628 | 5917 | nft_trans_elem_set(trans) = set; |
---|
5629 | 5918 | nft_trans_elem(trans) = *elem; |
---|
5630 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 5919 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
5631 | 5920 | |
---|
5632 | 5921 | return 0; |
---|
5633 | 5922 | err1: |
---|
.. | .. |
---|
5654 | 5943 | set = nft_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET], genmask); |
---|
5655 | 5944 | if (IS_ERR(set)) |
---|
5656 | 5945 | return PTR_ERR(set); |
---|
5657 | | - if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT) |
---|
| 5946 | + |
---|
| 5947 | + if (nft_set_is_anonymous(set)) |
---|
| 5948 | + return -EOPNOTSUPP; |
---|
| 5949 | + |
---|
| 5950 | + if (!list_empty(&set->bindings) && (set->flags & NFT_SET_CONSTANT)) |
---|
5658 | 5951 | return -EBUSY; |
---|
5659 | 5952 | |
---|
5660 | 5953 | if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) { |
---|
.. | .. |
---|
5675 | 5968 | set->ndeact++; |
---|
5676 | 5969 | } |
---|
5677 | 5970 | return err; |
---|
5678 | | -} |
---|
5679 | | - |
---|
5680 | | -void nft_set_gc_batch_release(struct rcu_head *rcu) |
---|
5681 | | -{ |
---|
5682 | | - struct nft_set_gc_batch *gcb; |
---|
5683 | | - unsigned int i; |
---|
5684 | | - |
---|
5685 | | - gcb = container_of(rcu, struct nft_set_gc_batch, head.rcu); |
---|
5686 | | - for (i = 0; i < gcb->head.cnt; i++) |
---|
5687 | | - nft_set_elem_destroy(gcb->head.set, gcb->elems[i], true); |
---|
5688 | | - kfree(gcb); |
---|
5689 | | -} |
---|
5690 | | - |
---|
5691 | | -struct nft_set_gc_batch *nft_set_gc_batch_alloc(const struct nft_set *set, |
---|
5692 | | - gfp_t gfp) |
---|
5693 | | -{ |
---|
5694 | | - struct nft_set_gc_batch *gcb; |
---|
5695 | | - |
---|
5696 | | - gcb = kzalloc(sizeof(*gcb), gfp); |
---|
5697 | | - if (gcb == NULL) |
---|
5698 | | - return gcb; |
---|
5699 | | - gcb->head.set = set; |
---|
5700 | | - return gcb; |
---|
5701 | 5971 | } |
---|
5702 | 5972 | |
---|
5703 | 5973 | /* |
---|
.. | .. |
---|
5924 | 6194 | nft_trans_obj(trans) = obj; |
---|
5925 | 6195 | nft_trans_obj_update(trans) = true; |
---|
5926 | 6196 | nft_trans_obj_newobj(trans) = newobj; |
---|
5927 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 6197 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
5928 | 6198 | |
---|
5929 | 6199 | return 0; |
---|
5930 | 6200 | |
---|
.. | .. |
---|
5985 | 6255 | |
---|
5986 | 6256 | nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla); |
---|
5987 | 6257 | |
---|
| 6258 | + if (!nft_use_inc(&table->use)) |
---|
| 6259 | + return -EMFILE; |
---|
| 6260 | + |
---|
5988 | 6261 | type = nft_obj_type_get(net, objtype); |
---|
5989 | | - if (IS_ERR(type)) |
---|
5990 | | - return PTR_ERR(type); |
---|
| 6262 | + if (IS_ERR(type)) { |
---|
| 6263 | + err = PTR_ERR(type); |
---|
| 6264 | + goto err_type; |
---|
| 6265 | + } |
---|
5991 | 6266 | |
---|
5992 | 6267 | obj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]); |
---|
5993 | 6268 | if (IS_ERR(obj)) { |
---|
.. | .. |
---|
6021 | 6296 | goto err_obj_ht; |
---|
6022 | 6297 | |
---|
6023 | 6298 | list_add_tail_rcu(&obj->list, &table->objects); |
---|
6024 | | - table->use++; |
---|
| 6299 | + |
---|
6025 | 6300 | return 0; |
---|
6026 | 6301 | err_obj_ht: |
---|
6027 | 6302 | /* queued in transaction log */ |
---|
.. | .. |
---|
6037 | 6312 | kfree(obj); |
---|
6038 | 6313 | err_init: |
---|
6039 | 6314 | module_put(type->owner); |
---|
| 6315 | +err_type: |
---|
| 6316 | + nft_use_dec_restore(&table->use); |
---|
| 6317 | + |
---|
6040 | 6318 | return err; |
---|
6041 | 6319 | } |
---|
6042 | 6320 | |
---|
.. | .. |
---|
6087 | 6365 | struct nft_obj_filter *filter = cb->data; |
---|
6088 | 6366 | struct net *net = sock_net(skb->sk); |
---|
6089 | 6367 | int family = nfmsg->nfgen_family; |
---|
| 6368 | + struct nftables_pernet *nft_net; |
---|
6090 | 6369 | struct nft_object *obj; |
---|
6091 | 6370 | bool reset = false; |
---|
6092 | 6371 | |
---|
.. | .. |
---|
6094 | 6373 | reset = true; |
---|
6095 | 6374 | |
---|
6096 | 6375 | rcu_read_lock(); |
---|
6097 | | - cb->seq = net->nft.base_seq; |
---|
| 6376 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 6377 | + cb->seq = nft_net->base_seq; |
---|
6098 | 6378 | |
---|
6099 | | - list_for_each_entry_rcu(table, &net->nft.tables, list) { |
---|
| 6379 | + list_for_each_entry_rcu(table, &nft_net->tables, list) { |
---|
6100 | 6380 | if (family != NFPROTO_UNSPEC && family != table->family) |
---|
6101 | 6381 | continue; |
---|
6102 | 6382 | |
---|
.. | .. |
---|
6119 | 6399 | char *buf = kasprintf(GFP_ATOMIC, |
---|
6120 | 6400 | "%s:%u", |
---|
6121 | 6401 | table->name, |
---|
6122 | | - net->nft.base_seq); |
---|
| 6402 | + nft_net->base_seq); |
---|
6123 | 6403 | |
---|
6124 | 6404 | audit_log_nfcfg(buf, |
---|
6125 | 6405 | family, |
---|
.. | .. |
---|
6240 | 6520 | reset = true; |
---|
6241 | 6521 | |
---|
6242 | 6522 | if (reset) { |
---|
6243 | | - char *buf = kasprintf(GFP_ATOMIC, "%s:%u", |
---|
6244 | | - table->name, net->nft.base_seq); |
---|
| 6523 | + const struct nftables_pernet *nft_net; |
---|
| 6524 | + char *buf; |
---|
| 6525 | + |
---|
| 6526 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 6527 | + buf = kasprintf(GFP_ATOMIC, "%s:%u", table->name, nft_net->base_seq); |
---|
6245 | 6528 | |
---|
6246 | 6529 | audit_log_nfcfg(buf, |
---|
6247 | 6530 | family, |
---|
.. | .. |
---|
6326 | 6609 | struct nft_object *obj, u32 portid, u32 seq, int event, |
---|
6327 | 6610 | int family, int report, gfp_t gfp) |
---|
6328 | 6611 | { |
---|
| 6612 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
6329 | 6613 | struct sk_buff *skb; |
---|
6330 | 6614 | int err; |
---|
6331 | 6615 | char *buf = kasprintf(gfp, "%s:%u", |
---|
6332 | | - table->name, net->nft.base_seq); |
---|
| 6616 | + table->name, nft_net->base_seq); |
---|
6333 | 6617 | |
---|
6334 | 6618 | audit_log_nfcfg(buf, |
---|
6335 | 6619 | family, |
---|
.. | .. |
---|
6355 | 6639 | goto err; |
---|
6356 | 6640 | } |
---|
6357 | 6641 | |
---|
6358 | | - nft_notify_enqueue(skb, report, &net->nft.notify_list); |
---|
| 6642 | + nft_notify_enqueue(skb, report, &nft_net->notify_list); |
---|
6359 | 6643 | return; |
---|
6360 | 6644 | err: |
---|
6361 | 6645 | nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS); |
---|
.. | .. |
---|
6417 | 6701 | enum nft_trans_phase phase) |
---|
6418 | 6702 | { |
---|
6419 | 6703 | switch (phase) { |
---|
| 6704 | + case NFT_TRANS_PREPARE_ERROR: |
---|
6420 | 6705 | case NFT_TRANS_PREPARE: |
---|
6421 | 6706 | case NFT_TRANS_ABORT: |
---|
6422 | 6707 | case NFT_TRANS_RELEASE: |
---|
6423 | | - flowtable->use--; |
---|
| 6708 | + nft_use_dec(&flowtable->use); |
---|
6424 | 6709 | fallthrough; |
---|
6425 | 6710 | default: |
---|
6426 | 6711 | return; |
---|
.. | .. |
---|
6560 | 6845 | FLOW_BLOCK_UNBIND); |
---|
6561 | 6846 | } |
---|
6562 | 6847 | |
---|
| 6848 | +static void __nft_unregister_flowtable_net_hooks(struct net *net, |
---|
| 6849 | + struct list_head *hook_list, |
---|
| 6850 | + bool release_netdev) |
---|
| 6851 | +{ |
---|
| 6852 | + struct nft_hook *hook, *next; |
---|
| 6853 | + |
---|
| 6854 | + list_for_each_entry_safe(hook, next, hook_list, list) { |
---|
| 6855 | + nf_unregister_net_hook(net, &hook->ops); |
---|
| 6856 | + if (release_netdev) { |
---|
| 6857 | + list_del(&hook->list); |
---|
| 6858 | + kfree_rcu(hook, rcu); |
---|
| 6859 | + } |
---|
| 6860 | + } |
---|
| 6861 | +} |
---|
| 6862 | + |
---|
6563 | 6863 | static void nft_unregister_flowtable_net_hooks(struct net *net, |
---|
6564 | 6864 | struct list_head *hook_list) |
---|
6565 | 6865 | { |
---|
6566 | | - struct nft_hook *hook; |
---|
6567 | | - |
---|
6568 | | - list_for_each_entry(hook, hook_list, list) |
---|
6569 | | - nf_unregister_net_hook(net, &hook->ops); |
---|
| 6866 | + __nft_unregister_flowtable_net_hooks(net, hook_list, false); |
---|
6570 | 6867 | } |
---|
6571 | 6868 | |
---|
6572 | 6869 | static int nft_register_flowtable_net_hooks(struct net *net, |
---|
.. | .. |
---|
6691 | 6988 | INIT_LIST_HEAD(&nft_trans_flowtable_hooks(trans)); |
---|
6692 | 6989 | list_splice(&flowtable_hook.list, &nft_trans_flowtable_hooks(trans)); |
---|
6693 | 6990 | |
---|
6694 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 6991 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
6695 | 6992 | |
---|
6696 | 6993 | return 0; |
---|
6697 | 6994 | |
---|
.. | .. |
---|
6757 | 7054 | |
---|
6758 | 7055 | nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla); |
---|
6759 | 7056 | |
---|
| 7057 | + if (!nft_use_inc(&table->use)) |
---|
| 7058 | + return -EMFILE; |
---|
| 7059 | + |
---|
6760 | 7060 | flowtable = kzalloc(sizeof(*flowtable), GFP_KERNEL); |
---|
6761 | | - if (!flowtable) |
---|
6762 | | - return -ENOMEM; |
---|
| 7061 | + if (!flowtable) { |
---|
| 7062 | + err = -ENOMEM; |
---|
| 7063 | + goto flowtable_alloc; |
---|
| 7064 | + } |
---|
6763 | 7065 | |
---|
6764 | 7066 | flowtable->table = table; |
---|
6765 | 7067 | flowtable->handle = nf_tables_alloc_handle(table); |
---|
.. | .. |
---|
6814 | 7116 | goto err5; |
---|
6815 | 7117 | |
---|
6816 | 7118 | list_add_tail_rcu(&flowtable->list, &table->flowtables); |
---|
6817 | | - table->use++; |
---|
6818 | 7119 | |
---|
6819 | 7120 | return 0; |
---|
6820 | 7121 | err5: |
---|
.. | .. |
---|
6831 | 7132 | kfree(flowtable->name); |
---|
6832 | 7133 | err1: |
---|
6833 | 7134 | kfree(flowtable); |
---|
| 7135 | +flowtable_alloc: |
---|
| 7136 | + nft_use_dec_restore(&table->use); |
---|
| 7137 | + |
---|
6834 | 7138 | return err; |
---|
6835 | 7139 | } |
---|
6836 | 7140 | |
---|
.. | .. |
---|
6881 | 7185 | list_splice(&flowtable_del_list, &nft_trans_flowtable_hooks(trans)); |
---|
6882 | 7186 | nft_flowtable_hook_release(&flowtable_hook); |
---|
6883 | 7187 | |
---|
6884 | | - list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
---|
| 7188 | + nft_trans_commit_list_add_tail(ctx->net, trans); |
---|
6885 | 7189 | |
---|
6886 | 7190 | return 0; |
---|
6887 | 7191 | |
---|
.. | .. |
---|
7007 | 7311 | struct net *net = sock_net(skb->sk); |
---|
7008 | 7312 | int family = nfmsg->nfgen_family; |
---|
7009 | 7313 | struct nft_flowtable *flowtable; |
---|
| 7314 | + struct nftables_pernet *nft_net; |
---|
7010 | 7315 | const struct nft_table *table; |
---|
7011 | 7316 | |
---|
7012 | 7317 | rcu_read_lock(); |
---|
7013 | | - cb->seq = net->nft.base_seq; |
---|
| 7318 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 7319 | + cb->seq = nft_net->base_seq; |
---|
7014 | 7320 | |
---|
7015 | | - list_for_each_entry_rcu(table, &net->nft.tables, list) { |
---|
| 7321 | + list_for_each_entry_rcu(table, &nft_net->tables, list) { |
---|
7016 | 7322 | if (family != NFPROTO_UNSPEC && family != table->family) |
---|
7017 | 7323 | continue; |
---|
7018 | 7324 | |
---|
.. | .. |
---|
7147 | 7453 | struct list_head *hook_list, |
---|
7148 | 7454 | int event) |
---|
7149 | 7455 | { |
---|
| 7456 | + struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id); |
---|
7150 | 7457 | struct sk_buff *skb; |
---|
7151 | 7458 | int err; |
---|
7152 | 7459 | |
---|
.. | .. |
---|
7166 | 7473 | goto err; |
---|
7167 | 7474 | } |
---|
7168 | 7475 | |
---|
7169 | | - nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list); |
---|
| 7476 | + nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list); |
---|
7170 | 7477 | return; |
---|
7171 | 7478 | err: |
---|
7172 | 7479 | nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS); |
---|
.. | .. |
---|
7191 | 7498 | static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net, |
---|
7192 | 7499 | u32 portid, u32 seq) |
---|
7193 | 7500 | { |
---|
| 7501 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
7194 | 7502 | struct nlmsghdr *nlh; |
---|
7195 | 7503 | char buf[TASK_COMM_LEN]; |
---|
7196 | 7504 | int event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWGEN); |
---|
.. | .. |
---|
7200 | 7508 | if (!nlh) |
---|
7201 | 7509 | goto nla_put_failure; |
---|
7202 | 7510 | |
---|
7203 | | - if (nla_put_be32(skb, NFTA_GEN_ID, htonl(net->nft.base_seq)) || |
---|
| 7511 | + if (nla_put_be32(skb, NFTA_GEN_ID, htonl(nft_net->base_seq)) || |
---|
7204 | 7512 | nla_put_be32(skb, NFTA_GEN_PROC_PID, htonl(task_pid_nr(current))) || |
---|
7205 | 7513 | nla_put_string(skb, NFTA_GEN_PROC_NAME, get_task_comm(buf, current))) |
---|
7206 | 7514 | goto nla_put_failure; |
---|
.. | .. |
---|
7235 | 7543 | { |
---|
7236 | 7544 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
---|
7237 | 7545 | struct nft_flowtable *flowtable; |
---|
| 7546 | + struct nftables_pernet *nft_net; |
---|
7238 | 7547 | struct nft_table *table; |
---|
7239 | 7548 | struct net *net; |
---|
7240 | 7549 | |
---|
.. | .. |
---|
7242 | 7551 | return 0; |
---|
7243 | 7552 | |
---|
7244 | 7553 | net = dev_net(dev); |
---|
7245 | | - mutex_lock(&net->nft.commit_mutex); |
---|
7246 | | - list_for_each_entry(table, &net->nft.tables, list) { |
---|
| 7554 | + nft_net = net_generic(net, nf_tables_net_id); |
---|
| 7555 | + mutex_lock(&nft_net->commit_mutex); |
---|
| 7556 | + list_for_each_entry(table, &nft_net->tables, list) { |
---|
7247 | 7557 | list_for_each_entry(flowtable, &table->flowtables, list) { |
---|
7248 | 7558 | nft_flowtable_event(event, dev, flowtable); |
---|
7249 | 7559 | } |
---|
7250 | 7560 | } |
---|
7251 | | - mutex_unlock(&net->nft.commit_mutex); |
---|
| 7561 | + mutex_unlock(&nft_net->commit_mutex); |
---|
7252 | 7562 | |
---|
7253 | 7563 | return NOTIFY_DONE; |
---|
7254 | 7564 | } |
---|
.. | .. |
---|
7429 | 7739 | |
---|
7430 | 7740 | static int nf_tables_validate(struct net *net) |
---|
7431 | 7741 | { |
---|
| 7742 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
7432 | 7743 | struct nft_table *table; |
---|
7433 | 7744 | |
---|
7434 | | - switch (net->nft.validate_state) { |
---|
| 7745 | + switch (nft_net->validate_state) { |
---|
7435 | 7746 | case NFT_VALIDATE_SKIP: |
---|
7436 | 7747 | break; |
---|
7437 | 7748 | case NFT_VALIDATE_NEED: |
---|
7438 | 7749 | nft_validate_state_update(net, NFT_VALIDATE_DO); |
---|
7439 | 7750 | fallthrough; |
---|
7440 | 7751 | case NFT_VALIDATE_DO: |
---|
7441 | | - list_for_each_entry(table, &net->nft.tables, list) { |
---|
| 7752 | + list_for_each_entry(table, &nft_net->tables, list) { |
---|
7442 | 7753 | if (nft_table_validate(net, table) < 0) |
---|
7443 | 7754 | return -EAGAIN; |
---|
7444 | 7755 | } |
---|
| 7756 | + |
---|
| 7757 | + nft_validate_state_update(net, NFT_VALIDATE_SKIP); |
---|
7445 | 7758 | break; |
---|
7446 | 7759 | } |
---|
7447 | 7760 | |
---|
.. | .. |
---|
7569 | 7882 | synchronize_rcu(); |
---|
7570 | 7883 | |
---|
7571 | 7884 | list_for_each_entry_safe(trans, next, &head, list) { |
---|
7572 | | - list_del(&trans->list); |
---|
| 7885 | + nft_trans_list_del(trans); |
---|
7573 | 7886 | nft_commit_release(trans); |
---|
7574 | 7887 | } |
---|
7575 | 7888 | } |
---|
.. | .. |
---|
7613 | 7926 | |
---|
7614 | 7927 | static void nf_tables_commit_chain_prepare_cancel(struct net *net) |
---|
7615 | 7928 | { |
---|
| 7929 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
7616 | 7930 | struct nft_trans *trans, *next; |
---|
7617 | 7931 | |
---|
7618 | | - list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { |
---|
| 7932 | + list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) { |
---|
7619 | 7933 | struct nft_chain *chain = trans->ctx.chain; |
---|
7620 | 7934 | |
---|
7621 | 7935 | if (trans->msg_type == NFT_MSG_NEWRULE || |
---|
.. | .. |
---|
7711 | 8025 | list_del_rcu(&chain->list); |
---|
7712 | 8026 | } |
---|
7713 | 8027 | |
---|
| 8028 | +static void nft_trans_gc_setelem_remove(struct nft_ctx *ctx, |
---|
| 8029 | + struct nft_trans_gc *trans) |
---|
| 8030 | +{ |
---|
| 8031 | + void **priv = trans->priv; |
---|
| 8032 | + unsigned int i; |
---|
| 8033 | + |
---|
| 8034 | + for (i = 0; i < trans->count; i++) { |
---|
| 8035 | + struct nft_set_elem elem = { |
---|
| 8036 | + .priv = priv[i], |
---|
| 8037 | + }; |
---|
| 8038 | + |
---|
| 8039 | + nft_setelem_data_deactivate(ctx->net, trans->set, &elem); |
---|
| 8040 | + trans->set->ops->remove(trans->net, trans->set, &elem); |
---|
| 8041 | + } |
---|
| 8042 | +} |
---|
| 8043 | + |
---|
| 8044 | +void nft_trans_gc_destroy(struct nft_trans_gc *trans) |
---|
| 8045 | +{ |
---|
| 8046 | + nft_set_put(trans->set); |
---|
| 8047 | + put_net(trans->net); |
---|
| 8048 | + kfree(trans); |
---|
| 8049 | +} |
---|
| 8050 | + |
---|
| 8051 | +static void nft_trans_gc_trans_free(struct rcu_head *rcu) |
---|
| 8052 | +{ |
---|
| 8053 | + struct nft_set_elem elem = {}; |
---|
| 8054 | + struct nft_trans_gc *trans; |
---|
| 8055 | + struct nft_ctx ctx = {}; |
---|
| 8056 | + unsigned int i; |
---|
| 8057 | + |
---|
| 8058 | + trans = container_of(rcu, struct nft_trans_gc, rcu); |
---|
| 8059 | + ctx.net = read_pnet(&trans->set->net); |
---|
| 8060 | + |
---|
| 8061 | + for (i = 0; i < trans->count; i++) { |
---|
| 8062 | + elem.priv = trans->priv[i]; |
---|
| 8063 | + atomic_dec(&trans->set->nelems); |
---|
| 8064 | + |
---|
| 8065 | + nf_tables_set_elem_destroy(&ctx, trans->set, elem.priv); |
---|
| 8066 | + } |
---|
| 8067 | + |
---|
| 8068 | + nft_trans_gc_destroy(trans); |
---|
| 8069 | +} |
---|
| 8070 | + |
---|
| 8071 | +static bool nft_trans_gc_work_done(struct nft_trans_gc *trans) |
---|
| 8072 | +{ |
---|
| 8073 | + struct nftables_pernet *nft_net; |
---|
| 8074 | + struct nft_ctx ctx = {}; |
---|
| 8075 | + |
---|
| 8076 | + nft_net = net_generic(trans->net, nf_tables_net_id); |
---|
| 8077 | + |
---|
| 8078 | + mutex_lock(&nft_net->commit_mutex); |
---|
| 8079 | + |
---|
| 8080 | + /* Check for race with transaction, otherwise this batch refers to |
---|
| 8081 | + * stale objects that might not be there anymore. Skip transaction if |
---|
| 8082 | + * set has been destroyed from control plane transaction in case gc |
---|
| 8083 | + * worker loses race. |
---|
| 8084 | + */ |
---|
| 8085 | + if (READ_ONCE(nft_net->gc_seq) != trans->seq || trans->set->dead) { |
---|
| 8086 | + mutex_unlock(&nft_net->commit_mutex); |
---|
| 8087 | + return false; |
---|
| 8088 | + } |
---|
| 8089 | + |
---|
| 8090 | + ctx.net = trans->net; |
---|
| 8091 | + ctx.table = trans->set->table; |
---|
| 8092 | + |
---|
| 8093 | + nft_trans_gc_setelem_remove(&ctx, trans); |
---|
| 8094 | + mutex_unlock(&nft_net->commit_mutex); |
---|
| 8095 | + |
---|
| 8096 | + return true; |
---|
| 8097 | +} |
---|
| 8098 | + |
---|
| 8099 | +static void nft_trans_gc_work(struct work_struct *work) |
---|
| 8100 | +{ |
---|
| 8101 | + struct nft_trans_gc *trans, *next; |
---|
| 8102 | + LIST_HEAD(trans_gc_list); |
---|
| 8103 | + |
---|
| 8104 | + spin_lock(&nf_tables_gc_list_lock); |
---|
| 8105 | + list_splice_init(&nf_tables_gc_list, &trans_gc_list); |
---|
| 8106 | + spin_unlock(&nf_tables_gc_list_lock); |
---|
| 8107 | + |
---|
| 8108 | + list_for_each_entry_safe(trans, next, &trans_gc_list, list) { |
---|
| 8109 | + list_del(&trans->list); |
---|
| 8110 | + if (!nft_trans_gc_work_done(trans)) { |
---|
| 8111 | + nft_trans_gc_destroy(trans); |
---|
| 8112 | + continue; |
---|
| 8113 | + } |
---|
| 8114 | + call_rcu(&trans->rcu, nft_trans_gc_trans_free); |
---|
| 8115 | + } |
---|
| 8116 | +} |
---|
| 8117 | + |
---|
| 8118 | +struct nft_trans_gc *nft_trans_gc_alloc(struct nft_set *set, |
---|
| 8119 | + unsigned int gc_seq, gfp_t gfp) |
---|
| 8120 | +{ |
---|
| 8121 | + struct net *net = read_pnet(&set->net); |
---|
| 8122 | + struct nft_trans_gc *trans; |
---|
| 8123 | + |
---|
| 8124 | + trans = kzalloc(sizeof(*trans), gfp); |
---|
| 8125 | + if (!trans) |
---|
| 8126 | + return NULL; |
---|
| 8127 | + |
---|
| 8128 | + trans->net = maybe_get_net(net); |
---|
| 8129 | + if (!trans->net) { |
---|
| 8130 | + kfree(trans); |
---|
| 8131 | + return NULL; |
---|
| 8132 | + } |
---|
| 8133 | + |
---|
| 8134 | + refcount_inc(&set->refs); |
---|
| 8135 | + trans->set = set; |
---|
| 8136 | + trans->seq = gc_seq; |
---|
| 8137 | + |
---|
| 8138 | + return trans; |
---|
| 8139 | +} |
---|
| 8140 | + |
---|
| 8141 | +void nft_trans_gc_elem_add(struct nft_trans_gc *trans, void *priv) |
---|
| 8142 | +{ |
---|
| 8143 | + trans->priv[trans->count++] = priv; |
---|
| 8144 | +} |
---|
| 8145 | + |
---|
| 8146 | +static void nft_trans_gc_queue_work(struct nft_trans_gc *trans) |
---|
| 8147 | +{ |
---|
| 8148 | + spin_lock(&nf_tables_gc_list_lock); |
---|
| 8149 | + list_add_tail(&trans->list, &nf_tables_gc_list); |
---|
| 8150 | + spin_unlock(&nf_tables_gc_list_lock); |
---|
| 8151 | + |
---|
| 8152 | + schedule_work(&trans_gc_work); |
---|
| 8153 | +} |
---|
| 8154 | + |
---|
| 8155 | +static int nft_trans_gc_space(struct nft_trans_gc *trans) |
---|
| 8156 | +{ |
---|
| 8157 | + return NFT_TRANS_GC_BATCHCOUNT - trans->count; |
---|
| 8158 | +} |
---|
| 8159 | + |
---|
| 8160 | +struct nft_trans_gc *nft_trans_gc_queue_async(struct nft_trans_gc *gc, |
---|
| 8161 | + unsigned int gc_seq, gfp_t gfp) |
---|
| 8162 | +{ |
---|
| 8163 | + struct nft_set *set; |
---|
| 8164 | + |
---|
| 8165 | + if (nft_trans_gc_space(gc)) |
---|
| 8166 | + return gc; |
---|
| 8167 | + |
---|
| 8168 | + set = gc->set; |
---|
| 8169 | + nft_trans_gc_queue_work(gc); |
---|
| 8170 | + |
---|
| 8171 | + return nft_trans_gc_alloc(set, gc_seq, gfp); |
---|
| 8172 | +} |
---|
| 8173 | + |
---|
| 8174 | +void nft_trans_gc_queue_async_done(struct nft_trans_gc *trans) |
---|
| 8175 | +{ |
---|
| 8176 | + if (trans->count == 0) { |
---|
| 8177 | + nft_trans_gc_destroy(trans); |
---|
| 8178 | + return; |
---|
| 8179 | + } |
---|
| 8180 | + |
---|
| 8181 | + nft_trans_gc_queue_work(trans); |
---|
| 8182 | +} |
---|
| 8183 | + |
---|
| 8184 | +struct nft_trans_gc *nft_trans_gc_queue_sync(struct nft_trans_gc *gc, gfp_t gfp) |
---|
| 8185 | +{ |
---|
| 8186 | + struct nft_set *set; |
---|
| 8187 | + |
---|
| 8188 | + if (WARN_ON_ONCE(!lockdep_commit_lock_is_held(gc->net))) |
---|
| 8189 | + return NULL; |
---|
| 8190 | + |
---|
| 8191 | + if (nft_trans_gc_space(gc)) |
---|
| 8192 | + return gc; |
---|
| 8193 | + |
---|
| 8194 | + set = gc->set; |
---|
| 8195 | + call_rcu(&gc->rcu, nft_trans_gc_trans_free); |
---|
| 8196 | + |
---|
| 8197 | + return nft_trans_gc_alloc(set, 0, gfp); |
---|
| 8198 | +} |
---|
| 8199 | + |
---|
| 8200 | +void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans) |
---|
| 8201 | +{ |
---|
| 8202 | + WARN_ON_ONCE(!lockdep_commit_lock_is_held(trans->net)); |
---|
| 8203 | + |
---|
| 8204 | + if (trans->count == 0) { |
---|
| 8205 | + nft_trans_gc_destroy(trans); |
---|
| 8206 | + return; |
---|
| 8207 | + } |
---|
| 8208 | + |
---|
| 8209 | + call_rcu(&trans->rcu, nft_trans_gc_trans_free); |
---|
| 8210 | +} |
---|
| 8211 | + |
---|
7714 | 8212 | static void nf_tables_module_autoload_cleanup(struct net *net) |
---|
7715 | 8213 | { |
---|
| 8214 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
7716 | 8215 | struct nft_module_request *req, *next; |
---|
7717 | 8216 | |
---|
7718 | | - WARN_ON_ONCE(!list_empty(&net->nft.commit_list)); |
---|
7719 | | - list_for_each_entry_safe(req, next, &net->nft.module_list, list) { |
---|
| 8217 | + WARN_ON_ONCE(!list_empty(&nft_net->commit_list)); |
---|
| 8218 | + list_for_each_entry_safe(req, next, &nft_net->module_list, list) { |
---|
7720 | 8219 | WARN_ON_ONCE(!req->done); |
---|
7721 | 8220 | list_del(&req->list); |
---|
7722 | 8221 | kfree(req); |
---|
.. | .. |
---|
7725 | 8224 | |
---|
7726 | 8225 | static void nf_tables_commit_release(struct net *net) |
---|
7727 | 8226 | { |
---|
| 8227 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
7728 | 8228 | struct nft_trans *trans; |
---|
7729 | 8229 | |
---|
7730 | 8230 | /* all side effects have to be made visible. |
---|
.. | .. |
---|
7734 | 8234 | * Memory reclaim happens asynchronously from work queue |
---|
7735 | 8235 | * to prevent expensive synchronize_rcu() in commit phase. |
---|
7736 | 8236 | */ |
---|
7737 | | - if (list_empty(&net->nft.commit_list)) { |
---|
| 8237 | + if (list_empty(&nft_net->commit_list)) { |
---|
7738 | 8238 | nf_tables_module_autoload_cleanup(net); |
---|
7739 | | - mutex_unlock(&net->nft.commit_mutex); |
---|
| 8239 | + mutex_unlock(&nft_net->commit_mutex); |
---|
7740 | 8240 | return; |
---|
7741 | 8241 | } |
---|
7742 | 8242 | |
---|
7743 | | - trans = list_last_entry(&net->nft.commit_list, |
---|
| 8243 | + trans = list_last_entry(&nft_net->commit_list, |
---|
7744 | 8244 | struct nft_trans, list); |
---|
7745 | 8245 | get_net(trans->ctx.net); |
---|
7746 | 8246 | WARN_ON_ONCE(trans->put_net); |
---|
7747 | 8247 | |
---|
7748 | 8248 | trans->put_net = true; |
---|
7749 | 8249 | spin_lock(&nf_tables_destroy_list_lock); |
---|
7750 | | - list_splice_tail_init(&net->nft.commit_list, &nf_tables_destroy_list); |
---|
| 8250 | + list_splice_tail_init(&nft_net->commit_list, &nf_tables_destroy_list); |
---|
7751 | 8251 | spin_unlock(&nf_tables_destroy_list_lock); |
---|
7752 | 8252 | |
---|
7753 | 8253 | nf_tables_module_autoload_cleanup(net); |
---|
7754 | 8254 | schedule_work(&trans_destroy_work); |
---|
7755 | 8255 | |
---|
7756 | | - mutex_unlock(&net->nft.commit_mutex); |
---|
| 8256 | + mutex_unlock(&nft_net->commit_mutex); |
---|
7757 | 8257 | } |
---|
7758 | 8258 | |
---|
7759 | 8259 | static void nft_commit_notify(struct net *net, u32 portid) |
---|
7760 | 8260 | { |
---|
| 8261 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
7761 | 8262 | struct sk_buff *batch_skb = NULL, *nskb, *skb; |
---|
7762 | 8263 | unsigned char *data; |
---|
7763 | 8264 | int len; |
---|
7764 | 8265 | |
---|
7765 | | - list_for_each_entry_safe(skb, nskb, &net->nft.notify_list, list) { |
---|
| 8266 | + list_for_each_entry_safe(skb, nskb, &nft_net->notify_list, list) { |
---|
7766 | 8267 | if (!batch_skb) { |
---|
7767 | 8268 | new_batch: |
---|
7768 | 8269 | batch_skb = skb; |
---|
.. | .. |
---|
7788 | 8289 | NFT_CB(batch_skb).report, GFP_KERNEL); |
---|
7789 | 8290 | } |
---|
7790 | 8291 | |
---|
7791 | | - WARN_ON_ONCE(!list_empty(&net->nft.notify_list)); |
---|
| 8292 | + WARN_ON_ONCE(!list_empty(&nft_net->notify_list)); |
---|
7792 | 8293 | } |
---|
7793 | 8294 | |
---|
7794 | 8295 | static int nf_tables_commit_audit_alloc(struct list_head *adl, |
---|
.. | .. |
---|
7852 | 8353 | } |
---|
7853 | 8354 | } |
---|
7854 | 8355 | |
---|
| 8356 | +static void nft_set_commit_update(struct list_head *set_update_list) |
---|
| 8357 | +{ |
---|
| 8358 | + struct nft_set *set, *next; |
---|
| 8359 | + |
---|
| 8360 | + list_for_each_entry_safe(set, next, set_update_list, pending_update) { |
---|
| 8361 | + list_del_init(&set->pending_update); |
---|
| 8362 | + |
---|
| 8363 | + if (!set->ops->commit) |
---|
| 8364 | + continue; |
---|
| 8365 | + |
---|
| 8366 | + set->ops->commit(set); |
---|
| 8367 | + } |
---|
| 8368 | +} |
---|
| 8369 | + |
---|
| 8370 | +static unsigned int nft_gc_seq_begin(struct nftables_pernet *nft_net) |
---|
| 8371 | +{ |
---|
| 8372 | + unsigned int gc_seq; |
---|
| 8373 | + |
---|
| 8374 | + /* Bump gc counter, it becomes odd, this is the busy mark. */ |
---|
| 8375 | + gc_seq = READ_ONCE(nft_net->gc_seq); |
---|
| 8376 | + WRITE_ONCE(nft_net->gc_seq, ++gc_seq); |
---|
| 8377 | + |
---|
| 8378 | + return gc_seq; |
---|
| 8379 | +} |
---|
| 8380 | + |
---|
| 8381 | +static void nft_gc_seq_end(struct nftables_pernet *nft_net, unsigned int gc_seq) |
---|
| 8382 | +{ |
---|
| 8383 | + WRITE_ONCE(nft_net->gc_seq, ++gc_seq); |
---|
| 8384 | +} |
---|
| 8385 | + |
---|
7855 | 8386 | static int nf_tables_commit(struct net *net, struct sk_buff *skb) |
---|
7856 | 8387 | { |
---|
| 8388 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
7857 | 8389 | struct nft_trans *trans, *next; |
---|
| 8390 | + LIST_HEAD(set_update_list); |
---|
7858 | 8391 | struct nft_trans_elem *te; |
---|
7859 | 8392 | struct nft_chain *chain; |
---|
7860 | 8393 | struct nft_table *table; |
---|
| 8394 | + unsigned int gc_seq; |
---|
7861 | 8395 | LIST_HEAD(adl); |
---|
7862 | 8396 | int err; |
---|
7863 | 8397 | |
---|
7864 | | - if (list_empty(&net->nft.commit_list)) { |
---|
7865 | | - mutex_unlock(&net->nft.commit_mutex); |
---|
| 8398 | + if (list_empty(&nft_net->commit_list)) { |
---|
| 8399 | + mutex_unlock(&nft_net->commit_mutex); |
---|
7866 | 8400 | return 0; |
---|
| 8401 | + } |
---|
| 8402 | + |
---|
| 8403 | + list_for_each_entry(trans, &nft_net->binding_list, binding_list) { |
---|
| 8404 | + switch (trans->msg_type) { |
---|
| 8405 | + case NFT_MSG_NEWSET: |
---|
| 8406 | + if (nft_set_is_anonymous(nft_trans_set(trans)) && |
---|
| 8407 | + !nft_trans_set_bound(trans)) { |
---|
| 8408 | + pr_warn_once("nftables ruleset with unbound set\n"); |
---|
| 8409 | + return -EINVAL; |
---|
| 8410 | + } |
---|
| 8411 | + break; |
---|
| 8412 | + case NFT_MSG_NEWCHAIN: |
---|
| 8413 | + if (!nft_trans_chain_update(trans) && |
---|
| 8414 | + nft_chain_binding(nft_trans_chain(trans)) && |
---|
| 8415 | + !nft_trans_chain_bound(trans)) { |
---|
| 8416 | + pr_warn_once("nftables ruleset with unbound chain\n"); |
---|
| 8417 | + return -EINVAL; |
---|
| 8418 | + } |
---|
| 8419 | + break; |
---|
| 8420 | + } |
---|
7867 | 8421 | } |
---|
7868 | 8422 | |
---|
7869 | 8423 | /* 0. Validate ruleset, otherwise roll back for error reporting. */ |
---|
.. | .. |
---|
7875 | 8429 | return err; |
---|
7876 | 8430 | |
---|
7877 | 8431 | /* 1. Allocate space for next generation rules_gen_X[] */ |
---|
7878 | | - list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { |
---|
| 8432 | + list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) { |
---|
7879 | 8433 | int ret; |
---|
7880 | 8434 | |
---|
7881 | 8435 | ret = nf_tables_commit_audit_alloc(&adl, trans->ctx.table); |
---|
.. | .. |
---|
7898 | 8452 | } |
---|
7899 | 8453 | |
---|
7900 | 8454 | /* step 2. Make rules_gen_X visible to packet path */ |
---|
7901 | | - list_for_each_entry(table, &net->nft.tables, list) { |
---|
| 8455 | + list_for_each_entry(table, &nft_net->tables, list) { |
---|
7902 | 8456 | list_for_each_entry(chain, &table->chains, list) |
---|
7903 | 8457 | nf_tables_commit_chain(net, chain); |
---|
7904 | 8458 | } |
---|
.. | .. |
---|
7907 | 8461 | * Bump generation counter, invalidate any dump in progress. |
---|
7908 | 8462 | * Cannot fail after this point. |
---|
7909 | 8463 | */ |
---|
7910 | | - while (++net->nft.base_seq == 0); |
---|
| 8464 | + while (++nft_net->base_seq == 0) |
---|
| 8465 | + ; |
---|
| 8466 | + |
---|
| 8467 | + gc_seq = nft_gc_seq_begin(nft_net); |
---|
7911 | 8468 | |
---|
7912 | 8469 | /* step 3. Start new generation, rules_gen_X now in use. */ |
---|
7913 | 8470 | net->nft.gencursor = nft_gencursor_next(net); |
---|
7914 | 8471 | |
---|
7915 | | - list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { |
---|
| 8472 | + list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) { |
---|
7916 | 8473 | nf_tables_commit_audit_collect(&adl, trans->ctx.table, |
---|
7917 | 8474 | trans->msg_type); |
---|
7918 | 8475 | switch (trans->msg_type) { |
---|
.. | .. |
---|
7981 | 8538 | */ |
---|
7982 | 8539 | if (nft_set_is_anonymous(nft_trans_set(trans)) && |
---|
7983 | 8540 | !list_empty(&nft_trans_set(trans)->bindings)) |
---|
7984 | | - trans->ctx.table->use--; |
---|
| 8541 | + nft_use_dec(&trans->ctx.table->use); |
---|
7985 | 8542 | |
---|
7986 | 8543 | nf_tables_set_notify(&trans->ctx, nft_trans_set(trans), |
---|
7987 | 8544 | NFT_MSG_NEWSET, GFP_KERNEL); |
---|
7988 | 8545 | nft_trans_destroy(trans); |
---|
7989 | 8546 | break; |
---|
7990 | 8547 | case NFT_MSG_DELSET: |
---|
| 8548 | + nft_trans_set(trans)->dead = 1; |
---|
7991 | 8549 | list_del_rcu(&nft_trans_set(trans)->list); |
---|
7992 | 8550 | nf_tables_set_notify(&trans->ctx, nft_trans_set(trans), |
---|
7993 | 8551 | NFT_MSG_DELSET, GFP_KERNEL); |
---|
.. | .. |
---|
7999 | 8557 | nf_tables_setelem_notify(&trans->ctx, te->set, |
---|
8000 | 8558 | &te->elem, |
---|
8001 | 8559 | NFT_MSG_NEWSETELEM, 0); |
---|
| 8560 | + if (te->set->ops->commit && |
---|
| 8561 | + list_empty(&te->set->pending_update)) { |
---|
| 8562 | + list_add_tail(&te->set->pending_update, |
---|
| 8563 | + &set_update_list); |
---|
| 8564 | + } |
---|
8002 | 8565 | nft_trans_destroy(trans); |
---|
8003 | 8566 | break; |
---|
8004 | 8567 | case NFT_MSG_DELSETELEM: |
---|
.. | .. |
---|
8010 | 8573 | te->set->ops->remove(net, te->set, &te->elem); |
---|
8011 | 8574 | atomic_dec(&te->set->nelems); |
---|
8012 | 8575 | te->set->ndeact--; |
---|
| 8576 | + if (te->set->ops->commit && |
---|
| 8577 | + list_empty(&te->set->pending_update)) { |
---|
| 8578 | + list_add_tail(&te->set->pending_update, |
---|
| 8579 | + &set_update_list); |
---|
| 8580 | + } |
---|
8013 | 8581 | break; |
---|
8014 | 8582 | case NFT_MSG_NEWOBJ: |
---|
8015 | 8583 | if (nft_trans_obj_update(trans)) { |
---|
.. | .. |
---|
8070 | 8638 | } |
---|
8071 | 8639 | } |
---|
8072 | 8640 | |
---|
| 8641 | + nft_set_commit_update(&set_update_list); |
---|
| 8642 | + |
---|
8073 | 8643 | nft_commit_notify(net, NETLINK_CB(skb).portid); |
---|
8074 | 8644 | nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN); |
---|
8075 | | - nf_tables_commit_audit_log(&adl, net->nft.base_seq); |
---|
| 8645 | + nf_tables_commit_audit_log(&adl, nft_net->base_seq); |
---|
| 8646 | + |
---|
| 8647 | + nft_gc_seq_end(nft_net, gc_seq); |
---|
8076 | 8648 | nf_tables_commit_release(net); |
---|
8077 | 8649 | |
---|
8078 | 8650 | return 0; |
---|
.. | .. |
---|
8080 | 8652 | |
---|
8081 | 8653 | static void nf_tables_module_autoload(struct net *net) |
---|
8082 | 8654 | { |
---|
| 8655 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
8083 | 8656 | struct nft_module_request *req, *next; |
---|
8084 | 8657 | LIST_HEAD(module_list); |
---|
8085 | 8658 | |
---|
8086 | | - list_splice_init(&net->nft.module_list, &module_list); |
---|
8087 | | - mutex_unlock(&net->nft.commit_mutex); |
---|
| 8659 | + list_splice_init(&nft_net->module_list, &module_list); |
---|
| 8660 | + mutex_unlock(&nft_net->commit_mutex); |
---|
8088 | 8661 | list_for_each_entry_safe(req, next, &module_list, list) { |
---|
8089 | 8662 | request_module("%s", req->module); |
---|
8090 | 8663 | req->done = true; |
---|
8091 | 8664 | } |
---|
8092 | | - mutex_lock(&net->nft.commit_mutex); |
---|
8093 | | - list_splice(&module_list, &net->nft.module_list); |
---|
| 8665 | + mutex_lock(&nft_net->commit_mutex); |
---|
| 8666 | + list_splice(&module_list, &nft_net->module_list); |
---|
8094 | 8667 | } |
---|
8095 | 8668 | |
---|
8096 | 8669 | static void nf_tables_abort_release(struct nft_trans *trans) |
---|
.. | .. |
---|
8125 | 8698 | kfree(trans); |
---|
8126 | 8699 | } |
---|
8127 | 8700 | |
---|
| 8701 | +static void nft_set_abort_update(struct list_head *set_update_list) |
---|
| 8702 | +{ |
---|
| 8703 | + struct nft_set *set, *next; |
---|
| 8704 | + |
---|
| 8705 | + list_for_each_entry_safe(set, next, set_update_list, pending_update) { |
---|
| 8706 | + list_del_init(&set->pending_update); |
---|
| 8707 | + |
---|
| 8708 | + if (!set->ops->abort) |
---|
| 8709 | + continue; |
---|
| 8710 | + |
---|
| 8711 | + set->ops->abort(set); |
---|
| 8712 | + } |
---|
| 8713 | +} |
---|
| 8714 | + |
---|
8128 | 8715 | static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action) |
---|
8129 | 8716 | { |
---|
| 8717 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
8130 | 8718 | struct nft_trans *trans, *next; |
---|
| 8719 | + LIST_HEAD(set_update_list); |
---|
8131 | 8720 | struct nft_trans_elem *te; |
---|
8132 | 8721 | |
---|
8133 | 8722 | if (action == NFNL_ABORT_VALIDATE && |
---|
8134 | 8723 | nf_tables_validate(net) < 0) |
---|
8135 | 8724 | return -EAGAIN; |
---|
8136 | 8725 | |
---|
8137 | | - list_for_each_entry_safe_reverse(trans, next, &net->nft.commit_list, |
---|
| 8726 | + list_for_each_entry_safe_reverse(trans, next, &nft_net->commit_list, |
---|
8138 | 8727 | list) { |
---|
8139 | 8728 | switch (trans->msg_type) { |
---|
8140 | 8729 | case NFT_MSG_NEWTABLE: |
---|
.. | .. |
---|
8159 | 8748 | kfree(nft_trans_chain_name(trans)); |
---|
8160 | 8749 | nft_trans_destroy(trans); |
---|
8161 | 8750 | } else { |
---|
8162 | | - if (nft_chain_is_bound(trans->ctx.chain)) { |
---|
| 8751 | + if (nft_trans_chain_bound(trans)) { |
---|
8163 | 8752 | nft_trans_destroy(trans); |
---|
8164 | 8753 | break; |
---|
8165 | 8754 | } |
---|
8166 | | - trans->ctx.table->use--; |
---|
| 8755 | + nft_use_dec_restore(&trans->ctx.table->use); |
---|
8167 | 8756 | nft_chain_del(trans->ctx.chain); |
---|
8168 | 8757 | nf_tables_unregister_hook(trans->ctx.net, |
---|
8169 | 8758 | trans->ctx.table, |
---|
.. | .. |
---|
8171 | 8760 | } |
---|
8172 | 8761 | break; |
---|
8173 | 8762 | case NFT_MSG_DELCHAIN: |
---|
8174 | | - trans->ctx.table->use++; |
---|
| 8763 | + nft_use_inc_restore(&trans->ctx.table->use); |
---|
8175 | 8764 | nft_clear(trans->ctx.net, trans->ctx.chain); |
---|
8176 | 8765 | nft_trans_destroy(trans); |
---|
8177 | 8766 | break; |
---|
8178 | 8767 | case NFT_MSG_NEWRULE: |
---|
8179 | | - trans->ctx.chain->use--; |
---|
| 8768 | + if (nft_trans_rule_bound(trans)) { |
---|
| 8769 | + nft_trans_destroy(trans); |
---|
| 8770 | + break; |
---|
| 8771 | + } |
---|
| 8772 | + nft_use_dec_restore(&trans->ctx.chain->use); |
---|
8180 | 8773 | list_del_rcu(&nft_trans_rule(trans)->list); |
---|
8181 | 8774 | nft_rule_expr_deactivate(&trans->ctx, |
---|
8182 | 8775 | nft_trans_rule(trans), |
---|
8183 | 8776 | NFT_TRANS_ABORT); |
---|
8184 | 8777 | break; |
---|
8185 | 8778 | case NFT_MSG_DELRULE: |
---|
8186 | | - trans->ctx.chain->use++; |
---|
| 8779 | + nft_use_inc_restore(&trans->ctx.chain->use); |
---|
8187 | 8780 | nft_clear(trans->ctx.net, nft_trans_rule(trans)); |
---|
8188 | 8781 | nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans)); |
---|
8189 | 8782 | nft_trans_destroy(trans); |
---|
8190 | 8783 | break; |
---|
8191 | 8784 | case NFT_MSG_NEWSET: |
---|
8192 | | - trans->ctx.table->use--; |
---|
| 8785 | + nft_use_dec_restore(&trans->ctx.table->use); |
---|
8193 | 8786 | if (nft_trans_set_bound(trans)) { |
---|
8194 | 8787 | nft_trans_destroy(trans); |
---|
8195 | 8788 | break; |
---|
.. | .. |
---|
8197 | 8790 | list_del_rcu(&nft_trans_set(trans)->list); |
---|
8198 | 8791 | break; |
---|
8199 | 8792 | case NFT_MSG_DELSET: |
---|
8200 | | - trans->ctx.table->use++; |
---|
| 8793 | + nft_use_inc_restore(&trans->ctx.table->use); |
---|
8201 | 8794 | nft_clear(trans->ctx.net, nft_trans_set(trans)); |
---|
| 8795 | + if (nft_trans_set(trans)->flags & (NFT_SET_MAP | NFT_SET_OBJECT)) |
---|
| 8796 | + nft_map_activate(&trans->ctx, nft_trans_set(trans)); |
---|
| 8797 | + |
---|
8202 | 8798 | nft_trans_destroy(trans); |
---|
8203 | 8799 | break; |
---|
8204 | 8800 | case NFT_MSG_NEWSETELEM: |
---|
.. | .. |
---|
8209 | 8805 | te = (struct nft_trans_elem *)trans->data; |
---|
8210 | 8806 | te->set->ops->remove(net, te->set, &te->elem); |
---|
8211 | 8807 | atomic_dec(&te->set->nelems); |
---|
| 8808 | + |
---|
| 8809 | + if (te->set->ops->abort && |
---|
| 8810 | + list_empty(&te->set->pending_update)) { |
---|
| 8811 | + list_add_tail(&te->set->pending_update, |
---|
| 8812 | + &set_update_list); |
---|
| 8813 | + } |
---|
8212 | 8814 | break; |
---|
8213 | 8815 | case NFT_MSG_DELSETELEM: |
---|
8214 | 8816 | te = (struct nft_trans_elem *)trans->data; |
---|
8215 | 8817 | |
---|
8216 | | - nft_set_elem_activate(net, te->set, &te->elem); |
---|
| 8818 | + nft_setelem_data_activate(net, te->set, &te->elem); |
---|
8217 | 8819 | te->set->ops->activate(net, te->set, &te->elem); |
---|
8218 | 8820 | te->set->ndeact--; |
---|
8219 | 8821 | |
---|
| 8822 | + if (te->set->ops->abort && |
---|
| 8823 | + list_empty(&te->set->pending_update)) { |
---|
| 8824 | + list_add_tail(&te->set->pending_update, |
---|
| 8825 | + &set_update_list); |
---|
| 8826 | + } |
---|
8220 | 8827 | nft_trans_destroy(trans); |
---|
8221 | 8828 | break; |
---|
8222 | 8829 | case NFT_MSG_NEWOBJ: |
---|
.. | .. |
---|
8224 | 8831 | nft_obj_destroy(&trans->ctx, nft_trans_obj_newobj(trans)); |
---|
8225 | 8832 | nft_trans_destroy(trans); |
---|
8226 | 8833 | } else { |
---|
8227 | | - trans->ctx.table->use--; |
---|
| 8834 | + nft_use_dec_restore(&trans->ctx.table->use); |
---|
8228 | 8835 | nft_obj_del(nft_trans_obj(trans)); |
---|
8229 | 8836 | } |
---|
8230 | 8837 | break; |
---|
8231 | 8838 | case NFT_MSG_DELOBJ: |
---|
8232 | | - trans->ctx.table->use++; |
---|
| 8839 | + nft_use_inc_restore(&trans->ctx.table->use); |
---|
8233 | 8840 | nft_clear(trans->ctx.net, nft_trans_obj(trans)); |
---|
8234 | 8841 | nft_trans_destroy(trans); |
---|
8235 | 8842 | break; |
---|
.. | .. |
---|
8238 | 8845 | nft_unregister_flowtable_net_hooks(net, |
---|
8239 | 8846 | &nft_trans_flowtable_hooks(trans)); |
---|
8240 | 8847 | } else { |
---|
8241 | | - trans->ctx.table->use--; |
---|
| 8848 | + nft_use_dec_restore(&trans->ctx.table->use); |
---|
8242 | 8849 | list_del_rcu(&nft_trans_flowtable(trans)->list); |
---|
8243 | 8850 | nft_unregister_flowtable_net_hooks(net, |
---|
8244 | 8851 | &nft_trans_flowtable(trans)->hook_list); |
---|
.. | .. |
---|
8249 | 8856 | list_splice(&nft_trans_flowtable_hooks(trans), |
---|
8250 | 8857 | &nft_trans_flowtable(trans)->hook_list); |
---|
8251 | 8858 | } else { |
---|
8252 | | - trans->ctx.table->use++; |
---|
| 8859 | + nft_use_inc_restore(&trans->ctx.table->use); |
---|
8253 | 8860 | nft_clear(trans->ctx.net, nft_trans_flowtable(trans)); |
---|
8254 | 8861 | } |
---|
8255 | 8862 | nft_trans_destroy(trans); |
---|
.. | .. |
---|
8257 | 8864 | } |
---|
8258 | 8865 | } |
---|
8259 | 8866 | |
---|
| 8867 | + nft_set_abort_update(&set_update_list); |
---|
| 8868 | + |
---|
8260 | 8869 | synchronize_rcu(); |
---|
8261 | 8870 | |
---|
8262 | 8871 | list_for_each_entry_safe_reverse(trans, next, |
---|
8263 | | - &net->nft.commit_list, list) { |
---|
8264 | | - list_del(&trans->list); |
---|
| 8872 | + &nft_net->commit_list, list) { |
---|
| 8873 | + nft_trans_list_del(trans); |
---|
8265 | 8874 | nf_tables_abort_release(trans); |
---|
8266 | 8875 | } |
---|
8267 | 8876 | |
---|
.. | .. |
---|
8273 | 8882 | return 0; |
---|
8274 | 8883 | } |
---|
8275 | 8884 | |
---|
8276 | | -static void nf_tables_cleanup(struct net *net) |
---|
8277 | | -{ |
---|
8278 | | - nft_validate_state_update(net, NFT_VALIDATE_SKIP); |
---|
8279 | | -} |
---|
8280 | | - |
---|
8281 | 8885 | static int nf_tables_abort(struct net *net, struct sk_buff *skb, |
---|
8282 | 8886 | enum nfnl_abort_action action) |
---|
8283 | 8887 | { |
---|
8284 | | - int ret = __nf_tables_abort(net, action); |
---|
| 8888 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
| 8889 | + unsigned int gc_seq; |
---|
| 8890 | + int ret; |
---|
8285 | 8891 | |
---|
8286 | | - mutex_unlock(&net->nft.commit_mutex); |
---|
| 8892 | + gc_seq = nft_gc_seq_begin(nft_net); |
---|
| 8893 | + ret = __nf_tables_abort(net, action); |
---|
| 8894 | + nft_gc_seq_end(nft_net, gc_seq); |
---|
| 8895 | + |
---|
| 8896 | + mutex_unlock(&nft_net->commit_mutex); |
---|
8287 | 8897 | |
---|
8288 | 8898 | return ret; |
---|
8289 | 8899 | } |
---|
8290 | 8900 | |
---|
8291 | 8901 | static bool nf_tables_valid_genid(struct net *net, u32 genid) |
---|
8292 | 8902 | { |
---|
| 8903 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
8293 | 8904 | bool genid_ok; |
---|
8294 | 8905 | |
---|
8295 | | - mutex_lock(&net->nft.commit_mutex); |
---|
| 8906 | + mutex_lock(&nft_net->commit_mutex); |
---|
8296 | 8907 | |
---|
8297 | | - genid_ok = genid == 0 || net->nft.base_seq == genid; |
---|
| 8908 | + genid_ok = genid == 0 || nft_net->base_seq == genid; |
---|
8298 | 8909 | if (!genid_ok) |
---|
8299 | | - mutex_unlock(&net->nft.commit_mutex); |
---|
| 8910 | + mutex_unlock(&nft_net->commit_mutex); |
---|
8300 | 8911 | |
---|
8301 | 8912 | /* else, commit mutex has to be released by commit or abort function */ |
---|
8302 | 8913 | return genid_ok; |
---|
.. | .. |
---|
8309 | 8920 | .cb = nf_tables_cb, |
---|
8310 | 8921 | .commit = nf_tables_commit, |
---|
8311 | 8922 | .abort = nf_tables_abort, |
---|
8312 | | - .cleanup = nf_tables_cleanup, |
---|
8313 | 8923 | .valid_genid = nf_tables_valid_genid, |
---|
8314 | 8924 | .owner = THIS_MODULE, |
---|
8315 | 8925 | }; |
---|
.. | .. |
---|
8472 | 9082 | } |
---|
8473 | 9083 | EXPORT_SYMBOL_GPL(nft_parse_u32_check); |
---|
8474 | 9084 | |
---|
8475 | | -/** |
---|
8476 | | - * nft_parse_register - parse a register value from a netlink attribute |
---|
8477 | | - * |
---|
8478 | | - * @attr: netlink attribute |
---|
8479 | | - * |
---|
8480 | | - * Parse and translate a register value from a netlink attribute. |
---|
8481 | | - * Registers used to be 128 bit wide, these register numbers will be |
---|
8482 | | - * mapped to the corresponding 32 bit register numbers. |
---|
8483 | | - */ |
---|
8484 | | -unsigned int nft_parse_register(const struct nlattr *attr) |
---|
| 9085 | +static int nft_parse_register(const struct nlattr *attr, u32 *preg) |
---|
8485 | 9086 | { |
---|
8486 | 9087 | unsigned int reg; |
---|
8487 | 9088 | |
---|
8488 | 9089 | reg = ntohl(nla_get_be32(attr)); |
---|
8489 | 9090 | switch (reg) { |
---|
8490 | 9091 | case NFT_REG_VERDICT...NFT_REG_4: |
---|
8491 | | - return reg * NFT_REG_SIZE / NFT_REG32_SIZE; |
---|
| 9092 | + *preg = reg * NFT_REG_SIZE / NFT_REG32_SIZE; |
---|
| 9093 | + break; |
---|
| 9094 | + case NFT_REG32_00...NFT_REG32_15: |
---|
| 9095 | + *preg = reg + NFT_REG_SIZE / NFT_REG32_SIZE - NFT_REG32_00; |
---|
| 9096 | + break; |
---|
8492 | 9097 | default: |
---|
8493 | | - return reg + NFT_REG_SIZE / NFT_REG32_SIZE - NFT_REG32_00; |
---|
| 9098 | + return -ERANGE; |
---|
8494 | 9099 | } |
---|
| 9100 | + |
---|
| 9101 | + return 0; |
---|
8495 | 9102 | } |
---|
8496 | | -EXPORT_SYMBOL_GPL(nft_parse_register); |
---|
8497 | 9103 | |
---|
8498 | 9104 | /** |
---|
8499 | 9105 | * nft_dump_register - dump a register value to a netlink attribute |
---|
.. | .. |
---|
8543 | 9149 | u32 reg; |
---|
8544 | 9150 | int err; |
---|
8545 | 9151 | |
---|
8546 | | - reg = nft_parse_register(attr); |
---|
| 9152 | + err = nft_parse_register(attr, ®); |
---|
| 9153 | + if (err < 0) |
---|
| 9154 | + return err; |
---|
| 9155 | + |
---|
8547 | 9156 | err = nft_validate_register_load(reg, len); |
---|
8548 | 9157 | if (err < 0) |
---|
8549 | 9158 | return err; |
---|
.. | .. |
---|
8612 | 9221 | int err; |
---|
8613 | 9222 | u32 reg; |
---|
8614 | 9223 | |
---|
8615 | | - reg = nft_parse_register(attr); |
---|
| 9224 | + err = nft_parse_register(attr, ®); |
---|
| 9225 | + if (err < 0) |
---|
| 9226 | + return err; |
---|
| 9227 | + |
---|
8616 | 9228 | err = nft_validate_register_store(ctx, reg, data, type, len); |
---|
8617 | 9229 | if (err < 0) |
---|
8618 | 9230 | return err; |
---|
.. | .. |
---|
8644 | 9256 | |
---|
8645 | 9257 | if (!tb[NFTA_VERDICT_CODE]) |
---|
8646 | 9258 | return -EINVAL; |
---|
| 9259 | + |
---|
| 9260 | + /* zero padding hole for memcmp */ |
---|
| 9261 | + memset(data, 0, sizeof(*data)); |
---|
8647 | 9262 | data->verdict.code = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE])); |
---|
8648 | 9263 | |
---|
8649 | 9264 | switch (data->verdict.code) { |
---|
.. | .. |
---|
8669 | 9284 | genmask); |
---|
8670 | 9285 | } else if (tb[NFTA_VERDICT_CHAIN_ID]) { |
---|
8671 | 9286 | chain = nft_chain_lookup_byid(ctx->net, ctx->table, |
---|
8672 | | - tb[NFTA_VERDICT_CHAIN_ID]); |
---|
| 9287 | + tb[NFTA_VERDICT_CHAIN_ID], |
---|
| 9288 | + genmask); |
---|
8673 | 9289 | if (IS_ERR(chain)) |
---|
8674 | 9290 | return PTR_ERR(chain); |
---|
8675 | 9291 | } else { |
---|
.. | .. |
---|
8685 | 9301 | if (desc->flags & NFT_DATA_DESC_SETELEM && |
---|
8686 | 9302 | chain->flags & NFT_CHAIN_BINDING) |
---|
8687 | 9303 | return -EINVAL; |
---|
| 9304 | + if (!nft_use_inc(&chain->use)) |
---|
| 9305 | + return -EMFILE; |
---|
8688 | 9306 | |
---|
8689 | | - chain->use++; |
---|
8690 | 9307 | data->verdict.chain = chain; |
---|
8691 | 9308 | break; |
---|
8692 | 9309 | } |
---|
.. | .. |
---|
8699 | 9316 | static void nft_verdict_uninit(const struct nft_data *data) |
---|
8700 | 9317 | { |
---|
8701 | 9318 | struct nft_chain *chain; |
---|
8702 | | - struct nft_rule *rule; |
---|
8703 | 9319 | |
---|
8704 | 9320 | switch (data->verdict.code) { |
---|
8705 | 9321 | case NFT_JUMP: |
---|
8706 | 9322 | case NFT_GOTO: |
---|
8707 | 9323 | chain = data->verdict.chain; |
---|
8708 | | - chain->use--; |
---|
8709 | | - |
---|
8710 | | - if (!nft_chain_is_bound(chain)) |
---|
8711 | | - break; |
---|
8712 | | - |
---|
8713 | | - chain->table->use--; |
---|
8714 | | - list_for_each_entry(rule, &chain->rules, list) |
---|
8715 | | - chain->use--; |
---|
8716 | | - |
---|
8717 | | - nft_chain_del(chain); |
---|
| 9324 | + nft_use_dec(&chain->use); |
---|
8718 | 9325 | break; |
---|
8719 | 9326 | } |
---|
8720 | 9327 | } |
---|
.. | .. |
---|
8883 | 9490 | nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain); |
---|
8884 | 9491 | list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) { |
---|
8885 | 9492 | list_del(&rule->list); |
---|
8886 | | - ctx->chain->use--; |
---|
| 9493 | + nft_use_dec(&ctx->chain->use); |
---|
8887 | 9494 | nf_tables_rule_release(ctx, rule); |
---|
8888 | 9495 | } |
---|
8889 | 9496 | nft_chain_del(ctx->chain); |
---|
8890 | | - ctx->table->use--; |
---|
| 9497 | + nft_use_dec(&ctx->table->use); |
---|
8891 | 9498 | nf_tables_chain_destroy(ctx); |
---|
8892 | 9499 | |
---|
8893 | 9500 | return 0; |
---|
8894 | 9501 | } |
---|
8895 | 9502 | EXPORT_SYMBOL_GPL(__nft_release_basechain); |
---|
8896 | 9503 | |
---|
8897 | | -static void __nft_release_hooks(struct net *net) |
---|
| 9504 | +static void __nft_release_hook(struct net *net, struct nft_table *table) |
---|
8898 | 9505 | { |
---|
8899 | | - struct nft_table *table; |
---|
| 9506 | + struct nft_flowtable *flowtable; |
---|
8900 | 9507 | struct nft_chain *chain; |
---|
8901 | 9508 | |
---|
8902 | | - list_for_each_entry(table, &net->nft.tables, list) { |
---|
8903 | | - list_for_each_entry(chain, &table->chains, list) |
---|
8904 | | - nf_tables_unregister_hook(net, table, chain); |
---|
8905 | | - } |
---|
| 9509 | + list_for_each_entry(chain, &table->chains, list) |
---|
| 9510 | + __nf_tables_unregister_hook(net, table, chain, true); |
---|
| 9511 | + list_for_each_entry(flowtable, &table->flowtables, list) |
---|
| 9512 | + __nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list, |
---|
| 9513 | + true); |
---|
8906 | 9514 | } |
---|
8907 | 9515 | |
---|
8908 | | -static void __nft_release_tables(struct net *net) |
---|
| 9516 | +static void __nft_release_hooks(struct net *net) |
---|
| 9517 | +{ |
---|
| 9518 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
| 9519 | + struct nft_table *table; |
---|
| 9520 | + |
---|
| 9521 | + list_for_each_entry(table, &nft_net->tables, list) |
---|
| 9522 | + __nft_release_hook(net, table); |
---|
| 9523 | +} |
---|
| 9524 | + |
---|
| 9525 | +static void __nft_release_table(struct net *net, struct nft_table *table) |
---|
8909 | 9526 | { |
---|
8910 | 9527 | struct nft_flowtable *flowtable, *nf; |
---|
8911 | | - struct nft_table *table, *nt; |
---|
8912 | 9528 | struct nft_chain *chain, *nc; |
---|
8913 | 9529 | struct nft_object *obj, *ne; |
---|
8914 | 9530 | struct nft_rule *rule, *nr; |
---|
.. | .. |
---|
8918 | 9534 | .family = NFPROTO_NETDEV, |
---|
8919 | 9535 | }; |
---|
8920 | 9536 | |
---|
8921 | | - list_for_each_entry_safe(table, nt, &net->nft.tables, list) { |
---|
8922 | | - ctx.family = table->family; |
---|
8923 | | - ctx.table = table; |
---|
8924 | | - list_for_each_entry(chain, &table->chains, list) { |
---|
8925 | | - ctx.chain = chain; |
---|
8926 | | - list_for_each_entry_safe(rule, nr, &chain->rules, list) { |
---|
8927 | | - list_del(&rule->list); |
---|
8928 | | - chain->use--; |
---|
8929 | | - nf_tables_rule_release(&ctx, rule); |
---|
8930 | | - } |
---|
| 9537 | + ctx.family = table->family; |
---|
| 9538 | + ctx.table = table; |
---|
| 9539 | + list_for_each_entry(chain, &table->chains, list) { |
---|
| 9540 | + if (nft_chain_binding(chain)) |
---|
| 9541 | + continue; |
---|
| 9542 | + |
---|
| 9543 | + ctx.chain = chain; |
---|
| 9544 | + list_for_each_entry_safe(rule, nr, &chain->rules, list) { |
---|
| 9545 | + list_del(&rule->list); |
---|
| 9546 | + nft_use_dec(&chain->use); |
---|
| 9547 | + nf_tables_rule_release(&ctx, rule); |
---|
8931 | 9548 | } |
---|
8932 | | - list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) { |
---|
8933 | | - list_del(&flowtable->list); |
---|
8934 | | - table->use--; |
---|
8935 | | - nf_tables_flowtable_destroy(flowtable); |
---|
8936 | | - } |
---|
8937 | | - list_for_each_entry_safe(set, ns, &table->sets, list) { |
---|
8938 | | - list_del(&set->list); |
---|
8939 | | - table->use--; |
---|
8940 | | - nft_set_destroy(&ctx, set); |
---|
8941 | | - } |
---|
8942 | | - list_for_each_entry_safe(obj, ne, &table->objects, list) { |
---|
8943 | | - nft_obj_del(obj); |
---|
8944 | | - table->use--; |
---|
8945 | | - nft_obj_destroy(&ctx, obj); |
---|
8946 | | - } |
---|
8947 | | - list_for_each_entry_safe(chain, nc, &table->chains, list) { |
---|
8948 | | - ctx.chain = chain; |
---|
8949 | | - nft_chain_del(chain); |
---|
8950 | | - table->use--; |
---|
8951 | | - nf_tables_chain_destroy(&ctx); |
---|
8952 | | - } |
---|
8953 | | - list_del(&table->list); |
---|
8954 | | - nf_tables_table_destroy(&ctx); |
---|
8955 | 9549 | } |
---|
| 9550 | + list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) { |
---|
| 9551 | + list_del(&flowtable->list); |
---|
| 9552 | + nft_use_dec(&table->use); |
---|
| 9553 | + nf_tables_flowtable_destroy(flowtable); |
---|
| 9554 | + } |
---|
| 9555 | + list_for_each_entry_safe(set, ns, &table->sets, list) { |
---|
| 9556 | + list_del(&set->list); |
---|
| 9557 | + nft_use_dec(&table->use); |
---|
| 9558 | + if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT)) |
---|
| 9559 | + nft_map_deactivate(&ctx, set); |
---|
| 9560 | + |
---|
| 9561 | + nft_set_destroy(&ctx, set); |
---|
| 9562 | + } |
---|
| 9563 | + list_for_each_entry_safe(obj, ne, &table->objects, list) { |
---|
| 9564 | + nft_obj_del(obj); |
---|
| 9565 | + nft_use_dec(&table->use); |
---|
| 9566 | + nft_obj_destroy(&ctx, obj); |
---|
| 9567 | + } |
---|
| 9568 | + list_for_each_entry_safe(chain, nc, &table->chains, list) { |
---|
| 9569 | + ctx.chain = chain; |
---|
| 9570 | + nft_chain_del(chain); |
---|
| 9571 | + nft_use_dec(&table->use); |
---|
| 9572 | + nf_tables_chain_destroy(&ctx); |
---|
| 9573 | + } |
---|
| 9574 | + list_del(&table->list); |
---|
| 9575 | + nf_tables_table_destroy(&ctx); |
---|
| 9576 | +} |
---|
| 9577 | + |
---|
| 9578 | +static void __nft_release_tables(struct net *net) |
---|
| 9579 | +{ |
---|
| 9580 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
| 9581 | + struct nft_table *table, *nt; |
---|
| 9582 | + |
---|
| 9583 | + list_for_each_entry_safe(table, nt, &nft_net->tables, list) |
---|
| 9584 | + __nft_release_table(net, table); |
---|
8956 | 9585 | } |
---|
8957 | 9586 | |
---|
8958 | 9587 | static int __net_init nf_tables_init_net(struct net *net) |
---|
8959 | 9588 | { |
---|
8960 | | - INIT_LIST_HEAD(&net->nft.tables); |
---|
8961 | | - INIT_LIST_HEAD(&net->nft.commit_list); |
---|
8962 | | - INIT_LIST_HEAD(&net->nft.module_list); |
---|
8963 | | - INIT_LIST_HEAD(&net->nft.notify_list); |
---|
8964 | | - mutex_init(&net->nft.commit_mutex); |
---|
8965 | | - net->nft.base_seq = 1; |
---|
8966 | | - net->nft.validate_state = NFT_VALIDATE_SKIP; |
---|
| 9589 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
| 9590 | + |
---|
| 9591 | + INIT_LIST_HEAD(&nft_net->tables); |
---|
| 9592 | + INIT_LIST_HEAD(&nft_net->commit_list); |
---|
| 9593 | + INIT_LIST_HEAD(&nft_net->binding_list); |
---|
| 9594 | + INIT_LIST_HEAD(&nft_net->module_list); |
---|
| 9595 | + INIT_LIST_HEAD(&nft_net->notify_list); |
---|
| 9596 | + mutex_init(&nft_net->commit_mutex); |
---|
| 9597 | + nft_net->base_seq = 1; |
---|
| 9598 | + nft_net->validate_state = NFT_VALIDATE_SKIP; |
---|
| 9599 | + nft_net->gc_seq = 0; |
---|
8967 | 9600 | |
---|
8968 | 9601 | return 0; |
---|
8969 | 9602 | } |
---|
8970 | 9603 | |
---|
8971 | 9604 | static void __net_exit nf_tables_pre_exit_net(struct net *net) |
---|
8972 | 9605 | { |
---|
| 9606 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
| 9607 | + |
---|
| 9608 | + mutex_lock(&nft_net->commit_mutex); |
---|
8973 | 9609 | __nft_release_hooks(net); |
---|
| 9610 | + mutex_unlock(&nft_net->commit_mutex); |
---|
8974 | 9611 | } |
---|
8975 | 9612 | |
---|
8976 | 9613 | static void __net_exit nf_tables_exit_net(struct net *net) |
---|
8977 | 9614 | { |
---|
8978 | | - mutex_lock(&net->nft.commit_mutex); |
---|
8979 | | - if (!list_empty(&net->nft.commit_list)) |
---|
| 9615 | + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); |
---|
| 9616 | + unsigned int gc_seq; |
---|
| 9617 | + |
---|
| 9618 | + mutex_lock(&nft_net->commit_mutex); |
---|
| 9619 | + |
---|
| 9620 | + gc_seq = nft_gc_seq_begin(nft_net); |
---|
| 9621 | + |
---|
| 9622 | + if (!list_empty(&nft_net->commit_list)) |
---|
8980 | 9623 | __nf_tables_abort(net, NFNL_ABORT_NONE); |
---|
8981 | 9624 | __nft_release_tables(net); |
---|
8982 | | - mutex_unlock(&net->nft.commit_mutex); |
---|
8983 | | - WARN_ON_ONCE(!list_empty(&net->nft.tables)); |
---|
8984 | | - WARN_ON_ONCE(!list_empty(&net->nft.module_list)); |
---|
8985 | | - WARN_ON_ONCE(!list_empty(&net->nft.notify_list)); |
---|
| 9625 | + |
---|
| 9626 | + nft_gc_seq_end(nft_net, gc_seq); |
---|
| 9627 | + |
---|
| 9628 | + mutex_unlock(&nft_net->commit_mutex); |
---|
| 9629 | + WARN_ON_ONCE(!list_empty(&nft_net->tables)); |
---|
| 9630 | + WARN_ON_ONCE(!list_empty(&nft_net->module_list)); |
---|
| 9631 | + WARN_ON_ONCE(!list_empty(&nft_net->notify_list)); |
---|
| 9632 | +} |
---|
| 9633 | + |
---|
| 9634 | +static void nf_tables_exit_batch(struct list_head *net_exit_list) |
---|
| 9635 | +{ |
---|
| 9636 | + flush_work(&trans_gc_work); |
---|
8986 | 9637 | } |
---|
8987 | 9638 | |
---|
8988 | 9639 | static struct pernet_operations nf_tables_net_ops = { |
---|
8989 | 9640 | .init = nf_tables_init_net, |
---|
8990 | 9641 | .pre_exit = nf_tables_pre_exit_net, |
---|
8991 | 9642 | .exit = nf_tables_exit_net, |
---|
| 9643 | + .exit_batch = nf_tables_exit_batch, |
---|
| 9644 | + .id = &nf_tables_net_id, |
---|
| 9645 | + .size = sizeof(struct nftables_pernet), |
---|
8992 | 9646 | }; |
---|
8993 | 9647 | |
---|
8994 | 9648 | static int __init nf_tables_module_init(void) |
---|
.. | .. |
---|
9051 | 9705 | nft_chain_filter_fini(); |
---|
9052 | 9706 | nft_chain_route_fini(); |
---|
9053 | 9707 | unregister_pernet_subsys(&nf_tables_net_ops); |
---|
| 9708 | + cancel_work_sync(&trans_gc_work); |
---|
9054 | 9709 | cancel_work_sync(&trans_destroy_work); |
---|
9055 | 9710 | rcu_barrier(); |
---|
9056 | 9711 | rhltable_destroy(&nft_objname_ht); |
---|