Commit 1689f259 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

netfilter: nf_tables: report use refcount overflow



Overflow use refcount checks are not complete.

Add helper function to deal with object reference counter tracking.
Report -EMFILE in case UINT_MAX is reached.

nft_use_dec() splats in case that reference counter underflows,
which should not ever happen.

Add nft_use_inc_restore() and nft_use_dec_restore() which are used
to restore reference counter from error and abort paths.

Use u32 in nft_flowtable and nft_object since helper functions cannot
work on bitfields.

Remove the few early incomplete checks now that the helper functions
are in place and used to check for refcount overflow.

Fixes: 96518518 ("netfilter: add nftables")
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent c451410c
Loading
Loading
Loading
Loading
+27 −4
Original line number Diff line number Diff line
@@ -1211,6 +1211,29 @@ int __nft_release_basechain(struct nft_ctx *ctx);

unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);

static inline bool nft_use_inc(u32 *use)
{
	if (*use == UINT_MAX)
		return false;

	(*use)++;

	return true;
}

static inline void nft_use_dec(u32 *use)
{
	WARN_ON_ONCE((*use)-- == 0);
}

/* For error and abort path: restore use counter to previous state. */
static inline void nft_use_inc_restore(u32 *use)
{
	WARN_ON_ONCE(!nft_use_inc(use));
}

#define nft_use_dec_restore	nft_use_dec

/**
 *	struct nft_table - nf_tables table
 *
@@ -1296,8 +1319,8 @@ struct nft_object {
	struct list_head		list;
	struct rhlist_head		rhlhead;
	struct nft_object_hash_key	key;
	u32				genmask:2,
					use:30;
	u32				genmask:2;
	u32				use;
	u64				handle;
	u16				udlen;
	u8				*udata;
@@ -1399,8 +1422,8 @@ struct nft_flowtable {
	char				*name;
	int				hooknum;
	int				ops_len;
	u32				genmask:2,
					use:30;
	u32				genmask:2;
	u32				use;
	u64				handle;
	/* runtime data below here */
	struct list_head		hook_list ____cacheline_aligned;
+101 −62
Original line number Diff line number Diff line
@@ -253,8 +253,10 @@ int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
	if (chain->bound)
		return -EBUSY;

	if (!nft_use_inc(&chain->use))
		return -EMFILE;

	chain->bound = true;
	chain->use++;
	nft_chain_trans_bind(ctx, chain);

	return 0;
@@ -437,7 +439,7 @@ static int nft_delchain(struct nft_ctx *ctx)
	if (IS_ERR(trans))
		return PTR_ERR(trans);

	ctx->table->use--;
	nft_use_dec(&ctx->table->use);
	nft_deactivate_next(ctx->net, ctx->chain);

	return 0;
@@ -476,7 +478,7 @@ nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule)
	/* You cannot delete the same rule twice */
	if (nft_is_active_next(ctx->net, rule)) {
		nft_deactivate_next(ctx->net, rule);
		ctx->chain->use--;
		nft_use_dec(&ctx->chain->use);
		return 0;
	}
	return -ENOENT;
@@ -644,7 +646,7 @@ static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set)
		nft_map_deactivate(ctx, set);

	nft_deactivate_next(ctx->net, set);
	ctx->table->use--;
	nft_use_dec(&ctx->table->use);

	return err;
}
@@ -676,7 +678,7 @@ static int nft_delobj(struct nft_ctx *ctx, struct nft_object *obj)
		return err;

	nft_deactivate_next(ctx->net, obj);
	ctx->table->use--;
	nft_use_dec(&ctx->table->use);

	return err;
}
@@ -711,7 +713,7 @@ static int nft_delflowtable(struct nft_ctx *ctx,
		return err;

	nft_deactivate_next(ctx->net, flowtable);
	ctx->table->use--;
	nft_use_dec(&ctx->table->use);

	return err;
}
@@ -2396,9 +2398,6 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
	struct nft_chain *chain;
	int err;

	if (table->use == UINT_MAX)
		return -EOVERFLOW;

	if (nla[NFTA_CHAIN_HOOK]) {
		struct nft_stats __percpu *stats = NULL;
		struct nft_chain_hook hook = {};
@@ -2494,6 +2493,11 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
	if (err < 0)
		goto err_destroy_chain;

	if (!nft_use_inc(&table->use)) {
		err = -EMFILE;
		goto err_use;
	}

	trans = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN);
	if (IS_ERR(trans)) {
		err = PTR_ERR(trans);
@@ -2510,10 +2514,11 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
		goto err_unregister_hook;
	}

	table->use++;

	return 0;

err_unregister_hook:
	nft_use_dec_restore(&table->use);
err_use:
	nf_tables_unregister_hook(net, table, chain);
err_destroy_chain:
	nf_tables_chain_destroy(ctx);
@@ -3840,9 +3845,6 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
			return -EINVAL;
		handle = nf_tables_alloc_handle(table);

		if (chain->use == UINT_MAX)
			return -EOVERFLOW;

		if (nla[NFTA_RULE_POSITION]) {
			pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
			old_rule = __nft_rule_lookup(chain, pos_handle);
@@ -3936,6 +3938,11 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
		}
	}

	if (!nft_use_inc(&chain->use)) {
		err = -EMFILE;
		goto err_release_rule;
	}

	if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
		err = nft_delrule(&ctx, old_rule);
		if (err < 0)
@@ -3967,7 +3974,6 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
		}
	}
	kvfree(expr_info);
	chain->use++;

	if (flow)
		nft_trans_flow_rule(trans) = flow;
@@ -3978,6 +3984,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
	return 0;

err_destroy_flow_rule:
	nft_use_dec_restore(&chain->use);
	if (flow)
		nft_flow_rule_destroy(flow);
err_release_rule:
@@ -5014,9 +5021,15 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
	alloc_size = sizeof(*set) + size + udlen;
	if (alloc_size < size || alloc_size > INT_MAX)
		return -ENOMEM;

	if (!nft_use_inc(&table->use))
		return -EMFILE;

	set = kvzalloc(alloc_size, GFP_KERNEL_ACCOUNT);
	if (!set)
		return -ENOMEM;
	if (!set) {
		err = -ENOMEM;
		goto err_alloc;
	}

	name = nla_strdup(nla[NFTA_SET_NAME], GFP_KERNEL_ACCOUNT);
	if (!name) {
@@ -5074,7 +5087,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
		goto err_set_expr_alloc;

	list_add_tail_rcu(&set->list, &table->sets);
	table->use++;

	return 0;

err_set_expr_alloc:
@@ -5086,6 +5099,9 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
	kfree(set->name);
err_set_name:
	kvfree(set);
err_alloc:
	nft_use_dec_restore(&table->use);

	return err;
}

@@ -5224,9 +5240,6 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
	struct nft_set_binding *i;
	struct nft_set_iter iter;

	if (set->use == UINT_MAX)
		return -EOVERFLOW;

	if (!list_empty(&set->bindings) && nft_set_is_anonymous(set))
		return -EBUSY;

@@ -5254,10 +5267,12 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
			return iter.err;
	}
bind:
	if (!nft_use_inc(&set->use))
		return -EMFILE;

	binding->chain = ctx->chain;
	list_add_tail_rcu(&binding->list, &set->bindings);
	nft_set_trans_bind(ctx, set);
	set->use++;

	return 0;
}
@@ -5331,7 +5346,7 @@ void nf_tables_activate_set(const struct nft_ctx *ctx, struct nft_set *set)
		nft_clear(ctx->net, set);
	}

	set->use++;
	nft_use_inc_restore(&set->use);
}
EXPORT_SYMBOL_GPL(nf_tables_activate_set);

@@ -5347,7 +5362,7 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
		else
			list_del_rcu(&binding->list);

		set->use--;
		nft_use_dec(&set->use);
		break;
	case NFT_TRANS_PREPARE:
		if (nft_set_is_anonymous(set)) {
@@ -5356,7 +5371,7 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,

			nft_deactivate_next(ctx->net, set);
		}
		set->use--;
		nft_use_dec(&set->use);
		return;
	case NFT_TRANS_ABORT:
	case NFT_TRANS_RELEASE:
@@ -5364,7 +5379,7 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
		    set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
			nft_map_deactivate(ctx, set);

		set->use--;
		nft_use_dec(&set->use);
		fallthrough;
	default:
		nf_tables_unbind_set(ctx, set, binding,
@@ -6155,7 +6170,7 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
		nft_set_elem_expr_destroy(&ctx, nft_set_ext_expr(ext));

	if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
		(*nft_set_ext_obj(ext))->use--;
		nft_use_dec(&(*nft_set_ext_obj(ext))->use);
	kfree(elem);
}
EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
@@ -6657,8 +6672,16 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
				     set->objtype, genmask);
		if (IS_ERR(obj)) {
			err = PTR_ERR(obj);
			obj = NULL;
			goto err_parse_key_end;
		}

		if (!nft_use_inc(&obj->use)) {
			err = -EMFILE;
			obj = NULL;
			goto err_parse_key_end;
		}

		err = nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
		if (err < 0)
			goto err_parse_key_end;
@@ -6727,10 +6750,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
	if (flags)
		*nft_set_ext_flags(ext) = flags;

	if (obj) {
	if (obj)
		*nft_set_ext_obj(ext) = obj;
		obj->use++;
	}

	if (ulen > 0) {
		if (nft_set_ext_check(&tmpl, NFT_SET_EXT_USERDATA, ulen) < 0) {
			err = -EINVAL;
@@ -6798,12 +6820,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
	kfree(trans);
err_elem_free:
	nf_tables_set_elem_destroy(ctx, set, elem.priv);
	if (obj)
		obj->use--;
err_parse_data:
	if (nla[NFTA_SET_ELEM_DATA] != NULL)
		nft_data_release(&elem.data.val, desc.type);
err_parse_key_end:
	if (obj)
		nft_use_dec_restore(&obj->use);

	nft_data_release(&elem.key_end.val, NFT_DATA_VALUE);
err_parse_key:
	nft_data_release(&elem.key.val, NFT_DATA_VALUE);
@@ -6883,7 +6906,7 @@ void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
		case NFT_JUMP:
		case NFT_GOTO:
			chain = data->verdict.chain;
			chain->use++;
			nft_use_inc_restore(&chain->use);
			break;
		}
	}
@@ -6898,7 +6921,7 @@ static void nft_setelem_data_activate(const struct net *net,
	if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
		nft_data_hold(nft_set_ext_data(ext), set->dtype);
	if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
		(*nft_set_ext_obj(ext))->use++;
		nft_use_inc_restore(&(*nft_set_ext_obj(ext))->use);
}

static void nft_setelem_data_deactivate(const struct net *net,
@@ -6910,7 +6933,7 @@ static void nft_setelem_data_deactivate(const struct net *net,
	if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
		nft_data_release(nft_set_ext_data(ext), set->dtype);
	if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
		(*nft_set_ext_obj(ext))->use--;
		nft_use_dec(&(*nft_set_ext_obj(ext))->use);
}

static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
@@ -7453,9 +7476,14 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,

	nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);

	if (!nft_use_inc(&table->use))
		return -EMFILE;

	type = nft_obj_type_get(net, objtype);
	if (IS_ERR(type))
		return PTR_ERR(type);
	if (IS_ERR(type)) {
		err = PTR_ERR(type);
		goto err_type;
	}

	obj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]);
	if (IS_ERR(obj)) {
@@ -7489,7 +7517,7 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
		goto err_obj_ht;

	list_add_tail_rcu(&obj->list, &table->objects);
	table->use++;

	return 0;
err_obj_ht:
	/* queued in transaction log */
@@ -7505,6 +7533,9 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
	kfree(obj);
err_init:
	module_put(type->owner);
err_type:
	nft_use_dec_restore(&table->use);

	return err;
}

@@ -7906,7 +7937,7 @@ void nf_tables_deactivate_flowtable(const struct nft_ctx *ctx,
	case NFT_TRANS_PREPARE:
	case NFT_TRANS_ABORT:
	case NFT_TRANS_RELEASE:
		flowtable->use--;
		nft_use_dec(&flowtable->use);
		fallthrough;
	default:
		return;
@@ -8260,9 +8291,14 @@ static int nf_tables_newflowtable(struct sk_buff *skb,

	nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);

	if (!nft_use_inc(&table->use))
		return -EMFILE;

	flowtable = kzalloc(sizeof(*flowtable), GFP_KERNEL_ACCOUNT);
	if (!flowtable)
		return -ENOMEM;
	if (!flowtable) {
		err = -ENOMEM;
		goto flowtable_alloc;
	}

	flowtable->table = table;
	flowtable->handle = nf_tables_alloc_handle(table);
@@ -8317,7 +8353,6 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
		goto err5;

	list_add_tail_rcu(&flowtable->list, &table->flowtables);
	table->use++;

	return 0;
err5:
@@ -8334,6 +8369,9 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
	kfree(flowtable->name);
err1:
	kfree(flowtable);
flowtable_alloc:
	nft_use_dec_restore(&table->use);

	return err;
}

@@ -9713,7 +9751,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
				 */
				if (nft_set_is_anonymous(nft_trans_set(trans)) &&
				    !list_empty(&nft_trans_set(trans)->bindings))
					trans->ctx.table->use--;
					nft_use_dec(&trans->ctx.table->use);
			}
			nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
					     NFT_MSG_NEWSET, GFP_KERNEL);
@@ -9943,7 +9981,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
					nft_trans_destroy(trans);
					break;
				}
				trans->ctx.table->use--;
				nft_use_dec_restore(&trans->ctx.table->use);
				nft_chain_del(trans->ctx.chain);
				nf_tables_unregister_hook(trans->ctx.net,
							  trans->ctx.table,
@@ -9956,7 +9994,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
				list_splice(&nft_trans_chain_hooks(trans),
					    &nft_trans_basechain(trans)->hook_list);
			} else {
				trans->ctx.table->use++;
				nft_use_inc_restore(&trans->ctx.table->use);
				nft_clear(trans->ctx.net, trans->ctx.chain);
			}
			nft_trans_destroy(trans);
@@ -9966,7 +10004,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
				nft_trans_destroy(trans);
				break;
			}
			trans->ctx.chain->use--;
			nft_use_dec_restore(&trans->ctx.chain->use);
			list_del_rcu(&nft_trans_rule(trans)->list);
			nft_rule_expr_deactivate(&trans->ctx,
						 nft_trans_rule(trans),
@@ -9976,7 +10014,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
			break;
		case NFT_MSG_DELRULE:
		case NFT_MSG_DESTROYRULE:
			trans->ctx.chain->use++;
			nft_use_inc_restore(&trans->ctx.chain->use);
			nft_clear(trans->ctx.net, nft_trans_rule(trans));
			nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
			if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)
@@ -9989,7 +10027,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
				nft_trans_destroy(trans);
				break;
			}
			trans->ctx.table->use--;
			nft_use_dec_restore(&trans->ctx.table->use);
			if (nft_trans_set_bound(trans)) {
				nft_trans_destroy(trans);
				break;
@@ -9998,7 +10036,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
			break;
		case NFT_MSG_DELSET:
		case NFT_MSG_DESTROYSET:
			trans->ctx.table->use++;
			nft_use_inc_restore(&trans->ctx.table->use);
			nft_clear(trans->ctx.net, nft_trans_set(trans));
			if (nft_trans_set(trans)->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
				nft_map_activate(&trans->ctx, nft_trans_set(trans));
@@ -10042,13 +10080,13 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
				nft_obj_destroy(&trans->ctx, nft_trans_obj_newobj(trans));
				nft_trans_destroy(trans);
			} else {
				trans->ctx.table->use--;
				nft_use_dec_restore(&trans->ctx.table->use);
				nft_obj_del(nft_trans_obj(trans));
			}
			break;
		case NFT_MSG_DELOBJ:
		case NFT_MSG_DESTROYOBJ:
			trans->ctx.table->use++;
			nft_use_inc_restore(&trans->ctx.table->use);
			nft_clear(trans->ctx.net, nft_trans_obj(trans));
			nft_trans_destroy(trans);
			break;
@@ -10057,7 +10095,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
				nft_unregister_flowtable_net_hooks(net,
						&nft_trans_flowtable_hooks(trans));
			} else {
				trans->ctx.table->use--;
				nft_use_dec_restore(&trans->ctx.table->use);
				list_del_rcu(&nft_trans_flowtable(trans)->list);
				nft_unregister_flowtable_net_hooks(net,
						&nft_trans_flowtable(trans)->hook_list);
@@ -10069,7 +10107,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
				list_splice(&nft_trans_flowtable_hooks(trans),
					    &nft_trans_flowtable(trans)->hook_list);
			} else {
				trans->ctx.table->use++;
				nft_use_inc_restore(&trans->ctx.table->use);
				nft_clear(trans->ctx.net, nft_trans_flowtable(trans));
			}
			nft_trans_destroy(trans);
@@ -10518,8 +10556,9 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
		if (desc->flags & NFT_DATA_DESC_SETELEM &&
		    chain->flags & NFT_CHAIN_BINDING)
			return -EINVAL;
		if (!nft_use_inc(&chain->use))
			return -EMFILE;

		chain->use++;
		data->verdict.chain = chain;
		break;
	}
@@ -10537,7 +10576,7 @@ static void nft_verdict_uninit(const struct nft_data *data)
	case NFT_JUMP:
	case NFT_GOTO:
		chain = data->verdict.chain;
		chain->use--;
		nft_use_dec(&chain->use);
		break;
	}
}
@@ -10706,11 +10745,11 @@ int __nft_release_basechain(struct nft_ctx *ctx)
	nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
	list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
		list_del(&rule->list);
		ctx->chain->use--;
		nft_use_dec(&ctx->chain->use);
		nf_tables_rule_release(ctx, rule);
	}
	nft_chain_del(ctx->chain);
	ctx->table->use--;
	nft_use_dec(&ctx->table->use);
	nf_tables_chain_destroy(ctx);

	return 0;
@@ -10760,18 +10799,18 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
		ctx.chain = chain;
		list_for_each_entry_safe(rule, nr, &chain->rules, list) {
			list_del(&rule->list);
			chain->use--;
			nft_use_dec(&chain->use);
			nf_tables_rule_release(&ctx, rule);
		}
	}
	list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) {
		list_del(&flowtable->list);
		table->use--;
		nft_use_dec(&table->use);
		nf_tables_flowtable_destroy(flowtable);
	}
	list_for_each_entry_safe(set, ns, &table->sets, list) {
		list_del(&set->list);
		table->use--;
		nft_use_dec(&table->use);
		if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
			nft_map_deactivate(&ctx, set);

@@ -10779,13 +10818,13 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
	}
	list_for_each_entry_safe(obj, ne, &table->objects, list) {
		nft_obj_del(obj);
		table->use--;
		nft_use_dec(&table->use);
		nft_obj_destroy(&ctx, obj);
	}
	list_for_each_entry_safe(chain, nc, &table->chains, list) {
		ctx.chain = chain;
		nft_chain_del(chain);
		table->use--;
		nft_use_dec(&table->use);
		nf_tables_chain_destroy(&ctx);
	}
	nf_tables_table_destroy(&ctx);
+4 −2
Original line number Diff line number Diff line
@@ -408,8 +408,10 @@ static int nft_flow_offload_init(const struct nft_ctx *ctx,
	if (IS_ERR(flowtable))
		return PTR_ERR(flowtable);

	if (!nft_use_inc(&flowtable->use))
		return -EMFILE;

	priv->flowtable = flowtable;
	flowtable->use++;

	return nf_ct_netns_get(ctx->net, ctx->family);
}
@@ -428,7 +430,7 @@ static void nft_flow_offload_activate(const struct nft_ctx *ctx,
{
	struct nft_flow_offload *priv = nft_expr_priv(expr);

	priv->flowtable->use++;
	nft_use_inc_restore(&priv->flowtable->use);
}

static void nft_flow_offload_destroy(const struct nft_ctx *ctx,
+4 −4
Original line number Diff line number Diff line
@@ -159,7 +159,7 @@ static void nft_immediate_deactivate(const struct nft_ctx *ctx,
			default:
				nft_chain_del(chain);
				chain->bound = false;
				chain->table->use--;
				nft_use_dec(&chain->table->use);
				break;
			}
			break;
@@ -198,7 +198,7 @@ static void nft_immediate_destroy(const struct nft_ctx *ctx,
		 * let the transaction records release this chain and its rules.
		 */
		if (chain->bound) {
			chain->use--;
			nft_use_dec(&chain->use);
			break;
		}

@@ -206,9 +206,9 @@ static void nft_immediate_destroy(const struct nft_ctx *ctx,
		chain_ctx = *ctx;
		chain_ctx.chain = chain;

		chain->use--;
		nft_use_dec(&chain->use);
		list_for_each_entry_safe(rule, n, &chain->rules, list) {
			chain->use--;
			nft_use_dec(&chain->use);
			list_del(&rule->list);
			nf_tables_rule_destroy(&chain_ctx, rule);
		}
+5 −3
Original line number Diff line number Diff line
@@ -41,8 +41,10 @@ static int nft_objref_init(const struct nft_ctx *ctx,
	if (IS_ERR(obj))
		return -ENOENT;

	if (!nft_use_inc(&obj->use))
		return -EMFILE;

	nft_objref_priv(expr) = obj;
	obj->use++;

	return 0;
}
@@ -72,7 +74,7 @@ static void nft_objref_deactivate(const struct nft_ctx *ctx,
	if (phase == NFT_TRANS_COMMIT)
		return;

	obj->use--;
	nft_use_dec(&obj->use);
}

static void nft_objref_activate(const struct nft_ctx *ctx,
@@ -80,7 +82,7 @@ static void nft_objref_activate(const struct nft_ctx *ctx,
{
	struct nft_object *obj = nft_objref_priv(expr);

	obj->use++;
	nft_use_inc_restore(&obj->use);
}

static const struct nft_expr_ops nft_objref_ops = {