Skip to content

Commit

Permalink
netfilter: nf_tables: make validation state per table
Browse files Browse the repository at this point in the history
We only need to validate tables that saw changes in the current
transaction.

The existing code revalidates all tables, but this isn't needed as
cross-table jumps are not allowed (chains have table scope).

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Florian Westphal authored and ummakynes committed Apr 21, 2023
1 parent 9a32e98 commit 00c320f
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 21 deletions.
3 changes: 2 additions & 1 deletion include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);
* @genmask: generation mask
* @afinfo: address family info
* @name: name of the table
* @validate_state: internal, set when transaction adds jumps
*/
struct nft_table {
struct list_head list;
Expand All @@ -1227,6 +1228,7 @@ struct nft_table {
char *name;
u16 udlen;
u8 *udata;
u8 validate_state;
};

static inline bool nft_table_has_owner(const struct nft_table *table)
Expand Down Expand Up @@ -1698,7 +1700,6 @@ struct nftables_pernet {
struct mutex commit_mutex;
u64 table_handle;
unsigned int base_seq;
u8 validate_state;
};

extern unsigned int nf_tables_net_id;
Expand Down
38 changes: 18 additions & 20 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,9 @@ static const u8 nft2audit_op[NFT_MSG_MAX] = { // enum nf_tables_msg_types
[NFT_MSG_DELFLOWTABLE] = AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,
};

static void nft_validate_state_update(struct net *net, u8 new_validate_state)
static void nft_validate_state_update(struct nft_table *table, u8 new_validate_state)
{
struct nftables_pernet *nft_net = nft_pernet(net);

switch (nft_net->validate_state) {
switch (table->validate_state) {
case NFT_VALIDATE_SKIP:
WARN_ON_ONCE(new_validate_state == NFT_VALIDATE_DO);
break;
Expand All @@ -117,7 +115,7 @@ static void nft_validate_state_update(struct net *net, u8 new_validate_state)
return;
}

nft_net->validate_state = new_validate_state;
table->validate_state = new_validate_state;
}
static void nf_tables_trans_destroy_work(struct work_struct *w);
static DECLARE_WORK(trans_destroy_work, nf_tables_trans_destroy_work);
Expand Down Expand Up @@ -1224,6 +1222,7 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
if (table == NULL)
goto err_kzalloc;

table->validate_state = NFT_VALIDATE_SKIP;
table->name = nla_strdup(attr, GFP_KERNEL_ACCOUNT);
if (table->name == NULL)
goto err_strdup;
Expand Down Expand Up @@ -3660,7 +3659,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
}

if (expr_info[i].ops->validate)
nft_validate_state_update(net, NFT_VALIDATE_NEED);
nft_validate_state_update(table, NFT_VALIDATE_NEED);

expr_info[i].ops = NULL;
expr = nft_expr_next(expr);
Expand Down Expand Up @@ -3710,7 +3709,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
if (flow)
nft_trans_flow_rule(trans) = flow;

if (nft_net->validate_state == NFT_VALIDATE_DO)
if (table->validate_state == NFT_VALIDATE_DO)
return nft_table_validate(net, table);

return 0;
Expand Down Expand Up @@ -6312,7 +6311,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (desc.type == NFT_DATA_VERDICT &&
(elem.data.val.verdict.code == NFT_GOTO ||
elem.data.val.verdict.code == NFT_JUMP))
nft_validate_state_update(ctx->net,
nft_validate_state_update(ctx->table,
NFT_VALIDATE_NEED);
}

Expand Down Expand Up @@ -6437,7 +6436,6 @@ static int nf_tables_newsetelem(struct sk_buff *skb,
const struct nfnl_info *info,
const struct nlattr * const nla[])
{
struct nftables_pernet *nft_net = nft_pernet(info->net);
struct netlink_ext_ack *extack = info->extack;
u8 genmask = nft_genmask_next(info->net);
u8 family = info->nfmsg->nfgen_family;
Expand Down Expand Up @@ -6476,7 +6474,7 @@ static int nf_tables_newsetelem(struct sk_buff *skb,
}
}

if (nft_net->validate_state == NFT_VALIDATE_DO)
if (table->validate_state == NFT_VALIDATE_DO)
return nft_table_validate(net, table);

return 0;
Expand Down Expand Up @@ -8628,19 +8626,20 @@ static int nf_tables_validate(struct net *net)
struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_table *table;

switch (nft_net->validate_state) {
case NFT_VALIDATE_SKIP:
break;
case NFT_VALIDATE_NEED:
nft_validate_state_update(net, NFT_VALIDATE_DO);
fallthrough;
case NFT_VALIDATE_DO:
list_for_each_entry(table, &nft_net->tables, list) {
list_for_each_entry(table, &nft_net->tables, list) {
switch (table->validate_state) {
case NFT_VALIDATE_SKIP:
continue;
case NFT_VALIDATE_NEED:
nft_validate_state_update(table, NFT_VALIDATE_DO);
fallthrough;
case NFT_VALIDATE_DO:
if (nft_table_validate(net, table) < 0)
return -EAGAIN;

nft_validate_state_update(table, NFT_VALIDATE_SKIP);
}

nft_validate_state_update(net, NFT_VALIDATE_SKIP);
break;
}

Expand Down Expand Up @@ -10355,7 +10354,6 @@ static int __net_init nf_tables_init_net(struct net *net)
INIT_LIST_HEAD(&nft_net->notify_list);
mutex_init(&nft_net->commit_mutex);
nft_net->base_seq = 1;
nft_net->validate_state = NFT_VALIDATE_SKIP;

return 0;
}
Expand Down

0 comments on commit 00c320f

Please sign in to comment.