@@ -28,6 +28,28 @@ static LIST_HEAD(nf_tables_objects);
2828static LIST_HEAD (nf_tables_flowtables );
2929static u64 table_handle ;
3030
31+ enum {
32+ NFT_VALIDATE_SKIP = 0 ,
33+ NFT_VALIDATE_NEED ,
34+ NFT_VALIDATE_DO ,
35+ };
36+
37+ static void nft_validate_state_update (struct net * net , u8 new_validate_state )
38+ {
39+ switch (net -> nft .validate_state ) {
40+ case NFT_VALIDATE_SKIP :
41+ WARN_ON_ONCE (new_validate_state == NFT_VALIDATE_DO );
42+ break ;
43+ case NFT_VALIDATE_NEED :
44+ break ;
45+ case NFT_VALIDATE_DO :
46+ if (new_validate_state == NFT_VALIDATE_NEED )
47+ return ;
48+ }
49+
50+ net -> nft .validate_state = new_validate_state ;
51+ }
52+
3153static void nft_ctx_init (struct nft_ctx * ctx ,
3254 struct net * net ,
3355 const struct sk_buff * skb ,
@@ -1921,19 +1943,7 @@ static int nf_tables_newexpr(const struct nft_ctx *ctx,
19211943 goto err1 ;
19221944 }
19231945
1924- if (ops -> validate ) {
1925- const struct nft_data * data = NULL ;
1926-
1927- err = ops -> validate (ctx , expr , & data );
1928- if (err < 0 )
1929- goto err2 ;
1930- }
1931-
19321946 return 0 ;
1933-
1934- err2 :
1935- if (ops -> destroy )
1936- ops -> destroy (ctx , expr );
19371947err1 :
19381948 expr -> ops = NULL ;
19391949 return err ;
@@ -2299,6 +2309,53 @@ static void nf_tables_rule_release(const struct nft_ctx *ctx,
22992309 nf_tables_rule_destroy (ctx , rule );
23002310}
23012311
2312+ int nft_chain_validate (const struct nft_ctx * ctx , const struct nft_chain * chain )
2313+ {
2314+ struct nft_expr * expr , * last ;
2315+ const struct nft_data * data ;
2316+ struct nft_rule * rule ;
2317+ int err ;
2318+
2319+ list_for_each_entry (rule , & chain -> rules , list ) {
2320+ if (!nft_is_active_next (ctx -> net , rule ))
2321+ continue ;
2322+
2323+ nft_rule_for_each_expr (expr , last , rule ) {
2324+ if (!expr -> ops -> validate )
2325+ continue ;
2326+
2327+ err = expr -> ops -> validate (ctx , expr , & data );
2328+ if (err < 0 )
2329+ return err ;
2330+ }
2331+ }
2332+
2333+ return 0 ;
2334+ }
2335+ EXPORT_SYMBOL_GPL (nft_chain_validate );
2336+
2337+ static int nft_table_validate (struct net * net , const struct nft_table * table )
2338+ {
2339+ struct nft_chain * chain ;
2340+ struct nft_ctx ctx = {
2341+ .net = net ,
2342+ .family = table -> family ,
2343+ };
2344+ int err ;
2345+
2346+ list_for_each_entry (chain , & table -> chains , list ) {
2347+ if (!nft_is_base_chain (chain ))
2348+ continue ;
2349+
2350+ ctx .chain = chain ;
2351+ err = nft_chain_validate (& ctx , chain );
2352+ if (err < 0 )
2353+ return err ;
2354+ }
2355+
2356+ return 0 ;
2357+ }
2358+
23022359#define NFT_RULE_MAXEXPRS 128
23032360
23042361static struct nft_expr_info * info ;
@@ -2426,6 +2483,10 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
24262483 err = nf_tables_newexpr (& ctx , & info [i ], expr );
24272484 if (err < 0 )
24282485 goto err2 ;
2486+
2487+ if (info [i ].ops -> validate )
2488+ nft_validate_state_update (net , NFT_VALIDATE_NEED );
2489+
24292490 info [i ].ops = NULL ;
24302491 expr = nft_expr_next (expr );
24312492 }
@@ -2469,8 +2530,11 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
24692530 }
24702531 }
24712532 chain -> use ++ ;
2472- return 0 ;
24732533
2534+ if (net -> nft .validate_state == NFT_VALIDATE_DO )
2535+ return nft_table_validate (net , table );
2536+
2537+ return 0 ;
24742538err2 :
24752539 nf_tables_rule_release (& ctx , rule );
24762540err1 :
@@ -4112,6 +4176,12 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
41124176 d2 .type , d2 .len );
41134177 if (err < 0 )
41144178 goto err3 ;
4179+
4180+ if (d2 .type == NFT_DATA_VERDICT &&
4181+ (data .verdict .code == NFT_GOTO ||
4182+ data .verdict .code == NFT_JUMP ))
4183+ nft_validate_state_update (ctx -> net ,
4184+ NFT_VALIDATE_NEED );
41154185 }
41164186
41174187 nft_set_ext_add_length (& tmpl , NFT_SET_EXT_DATA , d2 .len );
@@ -4211,7 +4281,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
42114281 const struct nlattr * attr ;
42124282 struct nft_set * set ;
42134283 struct nft_ctx ctx ;
4214- int rem , err = 0 ;
4284+ int rem , err ;
42154285
42164286 if (nla [NFTA_SET_ELEM_LIST_ELEMENTS ] == NULL )
42174287 return - EINVAL ;
@@ -4232,9 +4302,13 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
42324302 nla_for_each_nested (attr , nla [NFTA_SET_ELEM_LIST_ELEMENTS ], rem ) {
42334303 err = nft_add_set_elem (& ctx , set , attr , nlh -> nlmsg_flags );
42344304 if (err < 0 )
4235- break ;
4305+ return err ;
42364306 }
4237- return err ;
4307+
4308+ if (net -> nft .validate_state == NFT_VALIDATE_DO )
4309+ return nft_table_validate (net , ctx .table );
4310+
4311+ return 0 ;
42384312}
42394313
42404314/**
@@ -5867,6 +5941,27 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
58675941 },
58685942};
58695943
5944+ static int nf_tables_validate (struct net * net )
5945+ {
5946+ struct nft_table * table ;
5947+
5948+ switch (net -> nft .validate_state ) {
5949+ case NFT_VALIDATE_SKIP :
5950+ break ;
5951+ case NFT_VALIDATE_NEED :
5952+ nft_validate_state_update (net , NFT_VALIDATE_DO );
5953+ /* fall through */
5954+ case NFT_VALIDATE_DO :
5955+ list_for_each_entry (table , & net -> nft .tables , list ) {
5956+ if (nft_table_validate (net , table ) < 0 )
5957+ return - EAGAIN ;
5958+ }
5959+ break ;
5960+ }
5961+
5962+ return 0 ;
5963+ }
5964+
58705965static void nft_chain_commit_update (struct nft_trans * trans )
58715966{
58725967 struct nft_base_chain * basechain ;
@@ -6055,6 +6150,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
60556150 struct nft_chain * chain ;
60566151 struct nft_table * table ;
60576152
6153+ /* 0. Validate ruleset, otherwise roll back for error reporting. */
6154+ if (nf_tables_validate (net ) < 0 )
6155+ return - EAGAIN ;
6156+
60586157 /* 1. Allocate space for next generation rules_gen_X[] */
60596158 list_for_each_entry_safe (trans , next , & net -> nft .commit_list , list ) {
60606159 int ret ;
@@ -6349,6 +6448,11 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
63496448 return 0 ;
63506449}
63516450
6451+ static void nf_tables_cleanup (struct net * net )
6452+ {
6453+ nft_validate_state_update (net , NFT_VALIDATE_SKIP );
6454+ }
6455+
63526456static bool nf_tables_valid_genid (struct net * net , u32 genid )
63536457{
63546458 return net -> nft .base_seq == genid ;
@@ -6361,6 +6465,7 @@ static const struct nfnetlink_subsystem nf_tables_subsys = {
63616465 .cb = nf_tables_cb ,
63626466 .commit = nf_tables_commit ,
63636467 .abort = nf_tables_abort ,
6468+ .cleanup = nf_tables_cleanup ,
63646469 .valid_genid = nf_tables_valid_genid ,
63656470};
63666471
@@ -6444,19 +6549,18 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
64446549
64456550 list_for_each_entry (rule , & chain -> rules , list ) {
64466551 nft_rule_for_each_expr (expr , last , rule ) {
6447- const struct nft_data * data = NULL ;
6552+ struct nft_immediate_expr * priv ;
6553+ const struct nft_data * data ;
64486554 int err ;
64496555
6450- if (! expr -> ops -> validate )
6556+ if (strcmp ( expr -> ops -> type -> name , "immediate" ) )
64516557 continue ;
64526558
6453- err = expr -> ops -> validate (ctx , expr , & data );
6454- if (err < 0 )
6455- return err ;
6456-
6457- if (data == NULL )
6559+ priv = nft_expr_priv (expr );
6560+ if (priv -> dreg != NFT_REG_VERDICT )
64586561 continue ;
64596562
6563+ data = & priv -> data ;
64606564 switch (data -> verdict .code ) {
64616565 case NFT_JUMP :
64626566 case NFT_GOTO :
@@ -6936,6 +7040,8 @@ static int __net_init nf_tables_init_net(struct net *net)
69367040 INIT_LIST_HEAD (& net -> nft .tables );
69377041 INIT_LIST_HEAD (& net -> nft .commit_list );
69387042 net -> nft .base_seq = 1 ;
7043+ net -> nft .validate_state = NFT_VALIDATE_SKIP ;
7044+
69397045 return 0 ;
69407046}
69417047
0 commit comments