diff options
-rw-r--r-- | net/netfilter/nf_tables_api.c | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 4fffa3680d42..dbf823634669 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -538,8 +538,7 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb, | |||
538 | return PTR_ERR(table); | 538 | return PTR_ERR(table); |
539 | if (table->flags & NFT_TABLE_INACTIVE) | 539 | if (table->flags & NFT_TABLE_INACTIVE) |
540 | return -ENOENT; | 540 | return -ENOENT; |
541 | 541 | if (table->use > 0) | |
542 | if (!list_empty(&table->chains) || !list_empty(&table->sets)) | ||
543 | return -EBUSY; | 542 | return -EBUSY; |
544 | 543 | ||
545 | nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla); | 544 | nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla); |
@@ -553,6 +552,8 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb, | |||
553 | 552 | ||
554 | static void nf_tables_table_destroy(struct nft_ctx *ctx) | 553 | static void nf_tables_table_destroy(struct nft_ctx *ctx) |
555 | { | 554 | { |
555 | BUG_ON(ctx->table->use > 0); | ||
556 | |||
556 | kfree(ctx->table); | 557 | kfree(ctx->table); |
557 | module_put(ctx->afi->owner); | 558 | module_put(ctx->afi->owner); |
558 | } | 559 | } |
@@ -1128,6 +1129,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
1128 | if (err < 0) | 1129 | if (err < 0) |
1129 | goto err2; | 1130 | goto err2; |
1130 | 1131 | ||
1132 | table->use++; | ||
1131 | list_add_tail(&chain->list, &table->chains); | 1133 | list_add_tail(&chain->list, &table->chains); |
1132 | return 0; | 1134 | return 0; |
1133 | err2: | 1135 | err2: |
@@ -1169,7 +1171,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb, | |||
1169 | return PTR_ERR(chain); | 1171 | return PTR_ERR(chain); |
1170 | if (chain->flags & NFT_CHAIN_INACTIVE) | 1172 | if (chain->flags & NFT_CHAIN_INACTIVE) |
1171 | return -ENOENT; | 1173 | return -ENOENT; |
1172 | if (!list_empty(&chain->rules) || chain->use > 0) | 1174 | if (chain->use > 0) |
1173 | return -EBUSY; | 1175 | return -EBUSY; |
1174 | 1176 | ||
1175 | nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla); | 1177 | nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla); |
@@ -1177,6 +1179,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb, | |||
1177 | if (err < 0) | 1179 | if (err < 0) |
1178 | return err; | 1180 | return err; |
1179 | 1181 | ||
1182 | table->use--; | ||
1180 | list_del(&chain->list); | 1183 | list_del(&chain->list); |
1181 | return 0; | 1184 | return 0; |
1182 | } | 1185 | } |
@@ -1814,6 +1817,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, | |||
1814 | err = -ENOMEM; | 1817 | err = -ENOMEM; |
1815 | goto err3; | 1818 | goto err3; |
1816 | } | 1819 | } |
1820 | chain->use++; | ||
1817 | return 0; | 1821 | return 0; |
1818 | 1822 | ||
1819 | err3: | 1823 | err3: |
@@ -1841,6 +1845,7 @@ nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule) | |||
1841 | if (nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule) == NULL) | 1845 | if (nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule) == NULL) |
1842 | return -ENOMEM; | 1846 | return -ENOMEM; |
1843 | nft_rule_disactivate_next(ctx->net, rule); | 1847 | nft_rule_disactivate_next(ctx->net, rule); |
1848 | ctx->chain->use--; | ||
1844 | return 0; | 1849 | return 0; |
1845 | } | 1850 | } |
1846 | return -ENOENT; | 1851 | return -ENOENT; |
@@ -2588,6 +2593,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb, | |||
2588 | goto err2; | 2593 | goto err2; |
2589 | 2594 | ||
2590 | list_add_tail(&set->list, &table->sets); | 2595 | list_add_tail(&set->list, &table->sets); |
2596 | table->use++; | ||
2591 | return 0; | 2597 | return 0; |
2592 | 2598 | ||
2593 | err2: | 2599 | err2: |
@@ -2642,6 +2648,7 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb, | |||
2642 | return err; | 2648 | return err; |
2643 | 2649 | ||
2644 | list_del(&set->list); | 2650 | list_del(&set->list); |
2651 | ctx.table->use--; | ||
2645 | return 0; | 2652 | return 0; |
2646 | } | 2653 | } |
2647 | 2654 | ||
@@ -3122,6 +3129,8 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb, | |||
3122 | err = nft_add_set_elem(&ctx, set, attr); | 3129 | err = nft_add_set_elem(&ctx, set, attr); |
3123 | if (err < 0) | 3130 | if (err < 0) |
3124 | break; | 3131 | break; |
3132 | |||
3133 | set->nelems++; | ||
3125 | } | 3134 | } |
3126 | return err; | 3135 | return err; |
3127 | } | 3136 | } |
@@ -3196,6 +3205,8 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb, | |||
3196 | err = nft_del_setelem(&ctx, set, attr); | 3205 | err = nft_del_setelem(&ctx, set, attr); |
3197 | if (err < 0) | 3206 | if (err < 0) |
3198 | break; | 3207 | break; |
3208 | |||
3209 | set->nelems--; | ||
3199 | } | 3210 | } |
3200 | return err; | 3211 | return err; |
3201 | } | 3212 | } |
@@ -3361,15 +3372,13 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
3361 | case NFT_MSG_NEWCHAIN: | 3372 | case NFT_MSG_NEWCHAIN: |
3362 | if (nft_trans_chain_update(trans)) | 3373 | if (nft_trans_chain_update(trans)) |
3363 | nft_chain_commit_update(trans); | 3374 | nft_chain_commit_update(trans); |
3364 | else { | 3375 | else |
3365 | trans->ctx.chain->flags &= ~NFT_CHAIN_INACTIVE; | 3376 | trans->ctx.chain->flags &= ~NFT_CHAIN_INACTIVE; |
3366 | trans->ctx.table->use++; | 3377 | |
3367 | } | ||
3368 | nf_tables_chain_notify(&trans->ctx, NFT_MSG_NEWCHAIN); | 3378 | nf_tables_chain_notify(&trans->ctx, NFT_MSG_NEWCHAIN); |
3369 | nft_trans_destroy(trans); | 3379 | nft_trans_destroy(trans); |
3370 | break; | 3380 | break; |
3371 | case NFT_MSG_DELCHAIN: | 3381 | case NFT_MSG_DELCHAIN: |
3372 | trans->ctx.table->use--; | ||
3373 | nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN); | 3382 | nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN); |
3374 | if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && | 3383 | if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && |
3375 | trans->ctx.chain->flags & NFT_BASE_CHAIN) { | 3384 | trans->ctx.chain->flags & NFT_BASE_CHAIN) { |
@@ -3392,6 +3401,13 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
3392 | break; | 3401 | break; |
3393 | case NFT_MSG_NEWSET: | 3402 | case NFT_MSG_NEWSET: |
3394 | nft_trans_set(trans)->flags &= ~NFT_SET_INACTIVE; | 3403 | nft_trans_set(trans)->flags &= ~NFT_SET_INACTIVE; |
3404 | /* This avoids hitting -EBUSY when deleting the table | ||
3405 | * from the transaction. | ||
3406 | */ | ||
3407 | if (nft_trans_set(trans)->flags & NFT_SET_ANONYMOUS && | ||
3408 | !list_empty(&nft_trans_set(trans)->bindings)) | ||
3409 | trans->ctx.table->use--; | ||
3410 | |||
3395 | nf_tables_set_notify(&trans->ctx, nft_trans_set(trans), | 3411 | nf_tables_set_notify(&trans->ctx, nft_trans_set(trans), |
3396 | NFT_MSG_NEWSET); | 3412 | NFT_MSG_NEWSET); |
3397 | nft_trans_destroy(trans); | 3413 | nft_trans_destroy(trans); |
@@ -3401,7 +3417,6 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
3401 | NFT_MSG_DELSET); | 3417 | NFT_MSG_DELSET); |
3402 | break; | 3418 | break; |
3403 | case NFT_MSG_NEWSETELEM: | 3419 | case NFT_MSG_NEWSETELEM: |
3404 | nft_trans_elem_set(trans)->nelems++; | ||
3405 | nf_tables_setelem_notify(&trans->ctx, | 3420 | nf_tables_setelem_notify(&trans->ctx, |
3406 | nft_trans_elem_set(trans), | 3421 | nft_trans_elem_set(trans), |
3407 | &nft_trans_elem(trans), | 3422 | &nft_trans_elem(trans), |
@@ -3409,7 +3424,6 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
3409 | nft_trans_destroy(trans); | 3424 | nft_trans_destroy(trans); |
3410 | break; | 3425 | break; |
3411 | case NFT_MSG_DELSETELEM: | 3426 | case NFT_MSG_DELSETELEM: |
3412 | nft_trans_elem_set(trans)->nelems--; | ||
3413 | nf_tables_setelem_notify(&trans->ctx, | 3427 | nf_tables_setelem_notify(&trans->ctx, |
3414 | nft_trans_elem_set(trans), | 3428 | nft_trans_elem_set(trans), |
3415 | &nft_trans_elem(trans), | 3429 | &nft_trans_elem(trans), |
@@ -3487,6 +3501,7 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
3487 | 3501 | ||
3488 | nft_trans_destroy(trans); | 3502 | nft_trans_destroy(trans); |
3489 | } else { | 3503 | } else { |
3504 | trans->ctx.table->use--; | ||
3490 | list_del(&trans->ctx.chain->list); | 3505 | list_del(&trans->ctx.chain->list); |
3491 | if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && | 3506 | if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && |
3492 | trans->ctx.chain->flags & NFT_BASE_CHAIN) { | 3507 | trans->ctx.chain->flags & NFT_BASE_CHAIN) { |
@@ -3496,32 +3511,39 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
3496 | } | 3511 | } |
3497 | break; | 3512 | break; |
3498 | case NFT_MSG_DELCHAIN: | 3513 | case NFT_MSG_DELCHAIN: |
3514 | trans->ctx.table->use++; | ||
3499 | list_add_tail(&trans->ctx.chain->list, | 3515 | list_add_tail(&trans->ctx.chain->list, |
3500 | &trans->ctx.table->chains); | 3516 | &trans->ctx.table->chains); |
3501 | nft_trans_destroy(trans); | 3517 | nft_trans_destroy(trans); |
3502 | break; | 3518 | break; |
3503 | case NFT_MSG_NEWRULE: | 3519 | case NFT_MSG_NEWRULE: |
3520 | trans->ctx.chain->use--; | ||
3504 | list_del_rcu(&nft_trans_rule(trans)->list); | 3521 | list_del_rcu(&nft_trans_rule(trans)->list); |
3505 | break; | 3522 | break; |
3506 | case NFT_MSG_DELRULE: | 3523 | case NFT_MSG_DELRULE: |
3524 | trans->ctx.chain->use++; | ||
3507 | nft_rule_clear(trans->ctx.net, nft_trans_rule(trans)); | 3525 | nft_rule_clear(trans->ctx.net, nft_trans_rule(trans)); |
3508 | nft_trans_destroy(trans); | 3526 | nft_trans_destroy(trans); |
3509 | break; | 3527 | break; |
3510 | case NFT_MSG_NEWSET: | 3528 | case NFT_MSG_NEWSET: |
3529 | trans->ctx.table->use--; | ||
3511 | list_del(&nft_trans_set(trans)->list); | 3530 | list_del(&nft_trans_set(trans)->list); |
3512 | break; | 3531 | break; |
3513 | case NFT_MSG_DELSET: | 3532 | case NFT_MSG_DELSET: |
3533 | trans->ctx.table->use++; | ||
3514 | list_add_tail(&nft_trans_set(trans)->list, | 3534 | list_add_tail(&nft_trans_set(trans)->list, |
3515 | &trans->ctx.table->sets); | 3535 | &trans->ctx.table->sets); |
3516 | nft_trans_destroy(trans); | 3536 | nft_trans_destroy(trans); |
3517 | break; | 3537 | break; |
3518 | case NFT_MSG_NEWSETELEM: | 3538 | case NFT_MSG_NEWSETELEM: |
3539 | nft_trans_elem_set(trans)->nelems--; | ||
3519 | set = nft_trans_elem_set(trans); | 3540 | set = nft_trans_elem_set(trans); |
3520 | set->ops->get(set, &nft_trans_elem(trans)); | 3541 | set->ops->get(set, &nft_trans_elem(trans)); |
3521 | set->ops->remove(set, &nft_trans_elem(trans)); | 3542 | set->ops->remove(set, &nft_trans_elem(trans)); |
3522 | nft_trans_destroy(trans); | 3543 | nft_trans_destroy(trans); |
3523 | break; | 3544 | break; |
3524 | case NFT_MSG_DELSETELEM: | 3545 | case NFT_MSG_DELSETELEM: |
3546 | nft_trans_elem_set(trans)->nelems++; | ||
3525 | nft_trans_destroy(trans); | 3547 | nft_trans_destroy(trans); |
3526 | break; | 3548 | break; |
3527 | } | 3549 | } |