Skip to content

Commit bb7b40a

Browse files
committed
netfilter: nf_tables: bogus EBUSY in chain deletions
When removing a rule that jumps to chain and such chain in the same batch, this bogusly hits EBUSY. Add activate and deactivate operations to expression that can be called from the preparation and the commit/abort phases. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 732a804 commit bb7b40a

File tree

3 files changed

+59
-7
lines changed

3 files changed

+59
-7
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ struct nft_data_desc {
170170
int nft_data_init(const struct nft_ctx *ctx,
171171
struct nft_data *data, unsigned int size,
172172
struct nft_data_desc *desc, const struct nlattr *nla);
173+
void nft_data_hold(const struct nft_data *data, enum nft_data_types type);
173174
void nft_data_release(const struct nft_data *data, enum nft_data_types type);
174175
int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
175176
enum nft_data_types type, unsigned int len);
@@ -736,6 +737,10 @@ struct nft_expr_ops {
736737
int (*init)(const struct nft_ctx *ctx,
737738
const struct nft_expr *expr,
738739
const struct nlattr * const tb[]);
740+
void (*activate)(const struct nft_ctx *ctx,
741+
const struct nft_expr *expr);
742+
void (*deactivate)(const struct nft_ctx *ctx,
743+
const struct nft_expr *expr);
739744
void (*destroy)(const struct nft_ctx *ctx,
740745
const struct nft_expr *expr);
741746
int (*dump)(struct sk_buff *skb,

net/netfilter/nf_tables_api.c

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,34 @@ static int nft_delchain(struct nft_ctx *ctx)
214214
return err;
215215
}
216216

217+
static void nft_rule_expr_activate(const struct nft_ctx *ctx,
218+
struct nft_rule *rule)
219+
{
220+
struct nft_expr *expr;
221+
222+
expr = nft_expr_first(rule);
223+
while (expr != nft_expr_last(rule) && expr->ops) {
224+
if (expr->ops->activate)
225+
expr->ops->activate(ctx, expr);
226+
227+
expr = nft_expr_next(expr);
228+
}
229+
}
230+
231+
static void nft_rule_expr_deactivate(const struct nft_ctx *ctx,
232+
struct nft_rule *rule)
233+
{
234+
struct nft_expr *expr;
235+
236+
expr = nft_expr_first(rule);
237+
while (expr != nft_expr_last(rule) && expr->ops) {
238+
if (expr->ops->deactivate)
239+
expr->ops->deactivate(ctx, expr);
240+
241+
expr = nft_expr_next(expr);
242+
}
243+
}
244+
217245
static int
218246
nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule)
219247
{
@@ -259,6 +287,7 @@ static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule)
259287
nft_trans_destroy(trans);
260288
return err;
261289
}
290+
nft_rule_expr_deactivate(ctx, rule);
262291

263292
return 0;
264293
}
@@ -2238,6 +2267,13 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
22382267
kfree(rule);
22392268
}
22402269

2270+
static void nf_tables_rule_release(const struct nft_ctx *ctx,
2271+
struct nft_rule *rule)
2272+
{
2273+
nft_rule_expr_deactivate(ctx, rule);
2274+
nf_tables_rule_destroy(ctx, rule);
2275+
}
2276+
22412277
#define NFT_RULE_MAXEXPRS 128
22422278

22432279
static struct nft_expr_info *info;
@@ -2402,7 +2438,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
24022438
return 0;
24032439

24042440
err2:
2405-
nf_tables_rule_destroy(&ctx, rule);
2441+
nf_tables_rule_release(&ctx, rule);
24062442
err1:
24072443
for (i = 0; i < n; i++) {
24082444
if (info[i].ops != NULL)
@@ -4130,7 +4166,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
41304166
* NFT_GOTO verdicts. This function must be called on active data objects
41314167
* from the second phase of the commit protocol.
41324168
*/
4133-
static void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
4169+
void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
41344170
{
41354171
if (type == NFT_DATA_VERDICT) {
41364172
switch (data->verdict.code) {
@@ -6015,10 +6051,12 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
60156051
case NFT_MSG_NEWRULE:
60166052
trans->ctx.chain->use--;
60176053
list_del_rcu(&nft_trans_rule(trans)->list);
6054+
nft_rule_expr_deactivate(&trans->ctx, nft_trans_rule(trans));
60186055
break;
60196056
case NFT_MSG_DELRULE:
60206057
trans->ctx.chain->use++;
60216058
nft_clear(trans->ctx.net, nft_trans_rule(trans));
6059+
nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
60226060
nft_trans_destroy(trans);
60236061
break;
60246062
case NFT_MSG_NEWSET:
@@ -6594,7 +6632,7 @@ int __nft_release_basechain(struct nft_ctx *ctx)
65946632
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
65956633
list_del(&rule->list);
65966634
ctx->chain->use--;
6597-
nf_tables_rule_destroy(ctx, rule);
6635+
nf_tables_rule_release(ctx, rule);
65986636
}
65996637
list_del(&ctx->chain->list);
66006638
ctx->table->use--;
@@ -6632,7 +6670,7 @@ static void __nft_release_tables(struct net *net)
66326670
list_for_each_entry_safe(rule, nr, &chain->rules, list) {
66336671
list_del(&rule->list);
66346672
chain->use--;
6635-
nf_tables_rule_destroy(&ctx, rule);
6673+
nf_tables_rule_release(&ctx, rule);
66366674
}
66376675
}
66386676
list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) {

net/netfilter/nft_immediate.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,16 @@ static int nft_immediate_init(const struct nft_ctx *ctx,
6969
return err;
7070
}
7171

72-
static void nft_immediate_destroy(const struct nft_ctx *ctx,
73-
const struct nft_expr *expr)
72+
static void nft_immediate_activate(const struct nft_ctx *ctx,
73+
const struct nft_expr *expr)
74+
{
75+
const struct nft_immediate_expr *priv = nft_expr_priv(expr);
76+
77+
return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg));
78+
}
79+
80+
static void nft_immediate_deactivate(const struct nft_ctx *ctx,
81+
const struct nft_expr *expr)
7482
{
7583
const struct nft_immediate_expr *priv = nft_expr_priv(expr);
7684

@@ -108,7 +116,8 @@ static const struct nft_expr_ops nft_imm_ops = {
108116
.size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
109117
.eval = nft_immediate_eval,
110118
.init = nft_immediate_init,
111-
.destroy = nft_immediate_destroy,
119+
.activate = nft_immediate_activate,
120+
.deactivate = nft_immediate_deactivate,
112121
.dump = nft_immediate_dump,
113122
.validate = nft_immediate_validate,
114123
};

0 commit comments

Comments
 (0)