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 <pablo@netfilter.org>
This commit is contained in:
parent
732a8049f3
commit
bb7b40aecb
@ -170,6 +170,7 @@ struct nft_data_desc {
|
|||||||
int nft_data_init(const struct nft_ctx *ctx,
|
int nft_data_init(const struct nft_ctx *ctx,
|
||||||
struct nft_data *data, unsigned int size,
|
struct nft_data *data, unsigned int size,
|
||||||
struct nft_data_desc *desc, const struct nlattr *nla);
|
struct nft_data_desc *desc, const struct nlattr *nla);
|
||||||
|
void nft_data_hold(const struct nft_data *data, enum nft_data_types type);
|
||||||
void nft_data_release(const struct nft_data *data, enum nft_data_types type);
|
void nft_data_release(const struct nft_data *data, enum nft_data_types type);
|
||||||
int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
|
int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
|
||||||
enum nft_data_types type, unsigned int len);
|
enum nft_data_types type, unsigned int len);
|
||||||
@ -736,6 +737,10 @@ struct nft_expr_ops {
|
|||||||
int (*init)(const struct nft_ctx *ctx,
|
int (*init)(const struct nft_ctx *ctx,
|
||||||
const struct nft_expr *expr,
|
const struct nft_expr *expr,
|
||||||
const struct nlattr * const tb[]);
|
const struct nlattr * const tb[]);
|
||||||
|
void (*activate)(const struct nft_ctx *ctx,
|
||||||
|
const struct nft_expr *expr);
|
||||||
|
void (*deactivate)(const struct nft_ctx *ctx,
|
||||||
|
const struct nft_expr *expr);
|
||||||
void (*destroy)(const struct nft_ctx *ctx,
|
void (*destroy)(const struct nft_ctx *ctx,
|
||||||
const struct nft_expr *expr);
|
const struct nft_expr *expr);
|
||||||
int (*dump)(struct sk_buff *skb,
|
int (*dump)(struct sk_buff *skb,
|
||||||
|
@ -214,6 +214,34 @@ static int nft_delchain(struct nft_ctx *ctx)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nft_rule_expr_activate(const struct nft_ctx *ctx,
|
||||||
|
struct nft_rule *rule)
|
||||||
|
{
|
||||||
|
struct nft_expr *expr;
|
||||||
|
|
||||||
|
expr = nft_expr_first(rule);
|
||||||
|
while (expr != nft_expr_last(rule) && expr->ops) {
|
||||||
|
if (expr->ops->activate)
|
||||||
|
expr->ops->activate(ctx, expr);
|
||||||
|
|
||||||
|
expr = nft_expr_next(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nft_rule_expr_deactivate(const struct nft_ctx *ctx,
|
||||||
|
struct nft_rule *rule)
|
||||||
|
{
|
||||||
|
struct nft_expr *expr;
|
||||||
|
|
||||||
|
expr = nft_expr_first(rule);
|
||||||
|
while (expr != nft_expr_last(rule) && expr->ops) {
|
||||||
|
if (expr->ops->deactivate)
|
||||||
|
expr->ops->deactivate(ctx, expr);
|
||||||
|
|
||||||
|
expr = nft_expr_next(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule)
|
nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule)
|
||||||
{
|
{
|
||||||
@ -259,6 +287,7 @@ static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule)
|
|||||||
nft_trans_destroy(trans);
|
nft_trans_destroy(trans);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
nft_rule_expr_deactivate(ctx, rule);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2238,6 +2267,13 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
|
|||||||
kfree(rule);
|
kfree(rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nf_tables_rule_release(const struct nft_ctx *ctx,
|
||||||
|
struct nft_rule *rule)
|
||||||
|
{
|
||||||
|
nft_rule_expr_deactivate(ctx, rule);
|
||||||
|
nf_tables_rule_destroy(ctx, rule);
|
||||||
|
}
|
||||||
|
|
||||||
#define NFT_RULE_MAXEXPRS 128
|
#define NFT_RULE_MAXEXPRS 128
|
||||||
|
|
||||||
static struct nft_expr_info *info;
|
static struct nft_expr_info *info;
|
||||||
@ -2402,7 +2438,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err2:
|
err2:
|
||||||
nf_tables_rule_destroy(&ctx, rule);
|
nf_tables_rule_release(&ctx, rule);
|
||||||
err1:
|
err1:
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
if (info[i].ops != NULL)
|
if (info[i].ops != NULL)
|
||||||
@ -4130,7 +4166,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
|
|||||||
* NFT_GOTO verdicts. This function must be called on active data objects
|
* NFT_GOTO verdicts. This function must be called on active data objects
|
||||||
* from the second phase of the commit protocol.
|
* from the second phase of the commit protocol.
|
||||||
*/
|
*/
|
||||||
static void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
|
void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
|
||||||
{
|
{
|
||||||
if (type == NFT_DATA_VERDICT) {
|
if (type == NFT_DATA_VERDICT) {
|
||||||
switch (data->verdict.code) {
|
switch (data->verdict.code) {
|
||||||
@ -6015,10 +6051,12 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
|
|||||||
case NFT_MSG_NEWRULE:
|
case NFT_MSG_NEWRULE:
|
||||||
trans->ctx.chain->use--;
|
trans->ctx.chain->use--;
|
||||||
list_del_rcu(&nft_trans_rule(trans)->list);
|
list_del_rcu(&nft_trans_rule(trans)->list);
|
||||||
|
nft_rule_expr_deactivate(&trans->ctx, nft_trans_rule(trans));
|
||||||
break;
|
break;
|
||||||
case NFT_MSG_DELRULE:
|
case NFT_MSG_DELRULE:
|
||||||
trans->ctx.chain->use++;
|
trans->ctx.chain->use++;
|
||||||
nft_clear(trans->ctx.net, nft_trans_rule(trans));
|
nft_clear(trans->ctx.net, nft_trans_rule(trans));
|
||||||
|
nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
|
||||||
nft_trans_destroy(trans);
|
nft_trans_destroy(trans);
|
||||||
break;
|
break;
|
||||||
case NFT_MSG_NEWSET:
|
case NFT_MSG_NEWSET:
|
||||||
@ -6594,7 +6632,7 @@ int __nft_release_basechain(struct nft_ctx *ctx)
|
|||||||
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
|
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
|
||||||
list_del(&rule->list);
|
list_del(&rule->list);
|
||||||
ctx->chain->use--;
|
ctx->chain->use--;
|
||||||
nf_tables_rule_destroy(ctx, rule);
|
nf_tables_rule_release(ctx, rule);
|
||||||
}
|
}
|
||||||
list_del(&ctx->chain->list);
|
list_del(&ctx->chain->list);
|
||||||
ctx->table->use--;
|
ctx->table->use--;
|
||||||
@ -6632,7 +6670,7 @@ static void __nft_release_tables(struct net *net)
|
|||||||
list_for_each_entry_safe(rule, nr, &chain->rules, list) {
|
list_for_each_entry_safe(rule, nr, &chain->rules, list) {
|
||||||
list_del(&rule->list);
|
list_del(&rule->list);
|
||||||
chain->use--;
|
chain->use--;
|
||||||
nf_tables_rule_destroy(&ctx, rule);
|
nf_tables_rule_release(&ctx, rule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) {
|
list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) {
|
||||||
|
@ -69,8 +69,16 @@ err1:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nft_immediate_destroy(const struct nft_ctx *ctx,
|
static void nft_immediate_activate(const struct nft_ctx *ctx,
|
||||||
const struct nft_expr *expr)
|
const struct nft_expr *expr)
|
||||||
|
{
|
||||||
|
const struct nft_immediate_expr *priv = nft_expr_priv(expr);
|
||||||
|
|
||||||
|
return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nft_immediate_deactivate(const struct nft_ctx *ctx,
|
||||||
|
const struct nft_expr *expr)
|
||||||
{
|
{
|
||||||
const struct nft_immediate_expr *priv = nft_expr_priv(expr);
|
const struct nft_immediate_expr *priv = nft_expr_priv(expr);
|
||||||
|
|
||||||
@ -108,7 +116,8 @@ static const struct nft_expr_ops nft_imm_ops = {
|
|||||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
|
.size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
|
||||||
.eval = nft_immediate_eval,
|
.eval = nft_immediate_eval,
|
||||||
.init = nft_immediate_init,
|
.init = nft_immediate_init,
|
||||||
.destroy = nft_immediate_destroy,
|
.activate = nft_immediate_activate,
|
||||||
|
.deactivate = nft_immediate_deactivate,
|
||||||
.dump = nft_immediate_dump,
|
.dump = nft_immediate_dump,
|
||||||
.validate = nft_immediate_validate,
|
.validate = nft_immediate_validate,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user