Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR for completion of LE-2004 #8

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 62 additions & 21 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,25 @@ static void nf_tables_table_disable(struct net *net, struct nft_table *table)
#define __NFT_TABLE_F_UPDATE (__NFT_TABLE_F_WAS_DORMANT | \
__NFT_TABLE_F_WAS_AWAKEN)

static bool nft_table_pending_update(const struct nft_ctx *ctx)
{
struct nft_trans *trans;

if (ctx->table->flags & __NFT_TABLE_F_UPDATE)
return true;

list_for_each_entry(trans, &ctx->net->nft.commit_list, list) {
if (trans->ctx.table == ctx->table &&
((trans->msg_type == NFT_MSG_NEWCHAIN &&
nft_trans_chain_update(trans)) ||
(trans->msg_type == NFT_MSG_DELCHAIN &&
nft_is_base_chain(trans->ctx.chain))))
return true;
}

return false;
}

static int nf_tables_updtable(struct nft_ctx *ctx)
{
struct nft_trans *trans;
Expand All @@ -967,11 +986,11 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
if (flags & ~NFT_TABLE_F_DORMANT)
return -EINVAL;

if (flags == ctx->table->flags)
if (flags == (ctx->table->flags & NFT_TABLE_F_MASK))
return 0;

/* No dormant off/on/off/on games in single transaction */
if (ctx->table->flags & __NFT_TABLE_F_UPDATE)
if (nft_table_pending_update(ctx))
return -EINVAL;

trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE,
Expand Down Expand Up @@ -2040,6 +2059,9 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
struct nft_stats __percpu *stats = NULL;
struct nft_chain_hook hook;

if (table->flags & __NFT_TABLE_F_UPDATE)
return -EINVAL;

err = nft_chain_parse_hook(net, nla, &hook, family, true);
if (err < 0)
return err;
Expand Down Expand Up @@ -2460,14 +2482,17 @@ EXPORT_SYMBOL_GPL(nft_unregister_expr);
static const struct nft_expr_type *__nft_expr_type_get(u8 family,
struct nlattr *nla)
{
const struct nft_expr_type *type;
const struct nft_expr_type *type, *candidate = NULL;

list_for_each_entry(type, &nf_tables_expressions, list) {
if (!nla_strcmp(nla, type->name) &&
(!type->family || type->family == family))
return type;
list_for_each_entry_rcu(type, &nf_tables_expressions, list) {
if (!nla_strcmp(nla, type->name)) {
if (!type->family && !candidate)
candidate = type;
else if (type->family == family)
candidate = type;
}
}
return NULL;
return candidate;
}

#ifdef CONFIG_MODULES
Expand All @@ -2491,9 +2516,13 @@ static const struct nft_expr_type *nft_expr_type_get(struct net *net,
if (nla == NULL)
return ERR_PTR(-EINVAL);

rcu_read_lock();
type = __nft_expr_type_get(family, nla);
if (type != NULL && try_module_get(type->owner))
if (type != NULL && try_module_get(type->owner)) {
rcu_read_unlock();
return type;
}
rcu_read_unlock();

lockdep_nfnl_nft_mutex_not_held();
#ifdef CONFIG_MODULES
Expand Down Expand Up @@ -6130,7 +6159,7 @@ static const struct nft_object_type *__nft_obj_type_get(u32 objtype)
{
const struct nft_object_type *type;

list_for_each_entry(type, &nf_tables_objects, list) {
list_for_each_entry_rcu(type, &nf_tables_objects, list) {
if (objtype == type->type)
return type;
}
Expand All @@ -6142,9 +6171,13 @@ nft_obj_type_get(struct net *net, u32 objtype)
{
const struct nft_object_type *type;

rcu_read_lock();
type = __nft_obj_type_get(objtype);
if (type != NULL && try_module_get(type->owner))
if (type != NULL && try_module_get(type->owner)) {
rcu_read_unlock();
return type;
}
rcu_read_unlock();

lockdep_nfnl_nft_mutex_not_held();
#ifdef CONFIG_MODULES
Expand Down Expand Up @@ -8465,10 +8498,11 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
struct nft_trans *trans, *next;
LIST_HEAD(set_update_list);
struct nft_trans_elem *te;
int err = 0;

if (action == NFNL_ABORT_VALIDATE &&
nf_tables_validate(net) < 0)
return -EAGAIN;
err = -EAGAIN;

list_for_each_entry_safe_reverse(trans, next, &net->nft.commit_list,
list) {
Expand Down Expand Up @@ -8612,12 +8646,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
nf_tables_abort_release(trans);
}

if (action == NFNL_ABORT_AUTOLOAD)
nf_tables_module_autoload(net);
else
nf_tables_module_autoload_cleanup(net);

gvrose8192 marked this conversation as resolved.
Show resolved Hide resolved
return 0;
return err;
}

static void nf_tables_cleanup(struct net *net)
Expand All @@ -8636,6 +8665,16 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb,
ret = __nf_tables_abort(net, action);
nft_gc_seq_end(nft_net, gc_seq);

WARN_ON_ONCE(!list_empty(&net->nft.commit_list));

/* module autoload needs to happen after GC sequence update because it
* temporarily releases and grabs mutex again.
*/
if (action == NFNL_ABORT_AUTOLOAD)
nf_tables_module_autoload(net);
else
nf_tables_module_autoload_cleanup(net);

gvrose8192 marked this conversation as resolved.
Show resolved Hide resolved
mutex_unlock(&net->nft_commit_mutex);

return ret;
Expand Down Expand Up @@ -9287,9 +9326,10 @@ static void __net_exit nf_tables_exit_net(struct net *net)

gc_seq = nft_gc_seq_begin(nft_net);

if (!list_empty(&net->nft.commit_list) ||
!list_empty(&net->nft_module_list))
__nf_tables_abort(net, NFNL_ABORT_NONE);
WARN_ON_ONCE(!list_empty(&net->nft.commit_list));

if (!list_empty(&net->nft_module_list))
nf_tables_module_autoload_cleanup(net);

__nft_release_tables(net);

Expand Down Expand Up @@ -9374,6 +9414,7 @@ static void __exit nf_tables_module_exit(void)
unregister_netdevice_notifier(&nf_tables_flowtable_notifier);
nft_chain_filter_fini();
nft_chain_route_fini();
nf_tables_trans_destroy_flush_work();
unregister_pernet_subsys(&nf_tables_net_ops);
cancel_work_sync(&trans_gc_work);
cancel_work_sync(&trans_destroy_work);
Expand Down
4 changes: 3 additions & 1 deletion net/netfilter/nft_chain_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,9 @@ static void nft_netdev_event(unsigned long event, struct net_device *dev,
return;

if (n > 1) {
nf_unregister_net_hook(ctx->net, &found->ops);
if (!(ctx->chain->table->flags & NFT_TABLE_F_DORMANT))
nf_unregister_net_hook(ctx->net, &found->ops);

list_del_rcu(&found->list);
kfree_rcu(found, rcu);
return;
Expand Down
Loading