@@ -28,6 +28,28 @@ static LIST_HEAD(nf_tables_objects);
28
28
static LIST_HEAD (nf_tables_flowtables );
29
29
static u64 table_handle ;
30
30
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
+
31
53
static void nft_ctx_init (struct nft_ctx * ctx ,
32
54
struct net * net ,
33
55
const struct sk_buff * skb ,
@@ -1921,19 +1943,7 @@ static int nf_tables_newexpr(const struct nft_ctx *ctx,
1921
1943
goto err1 ;
1922
1944
}
1923
1945
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
-
1932
1946
return 0 ;
1933
-
1934
- err2 :
1935
- if (ops -> destroy )
1936
- ops -> destroy (ctx , expr );
1937
1947
err1 :
1938
1948
expr -> ops = NULL ;
1939
1949
return err ;
@@ -2299,6 +2309,53 @@ static void nf_tables_rule_release(const struct nft_ctx *ctx,
2299
2309
nf_tables_rule_destroy (ctx , rule );
2300
2310
}
2301
2311
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
+
2302
2359
#define NFT_RULE_MAXEXPRS 128
2303
2360
2304
2361
static struct nft_expr_info * info ;
@@ -2426,6 +2483,10 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
2426
2483
err = nf_tables_newexpr (& ctx , & info [i ], expr );
2427
2484
if (err < 0 )
2428
2485
goto err2 ;
2486
+
2487
+ if (info [i ].ops -> validate )
2488
+ nft_validate_state_update (net , NFT_VALIDATE_NEED );
2489
+
2429
2490
info [i ].ops = NULL ;
2430
2491
expr = nft_expr_next (expr );
2431
2492
}
@@ -2469,8 +2530,11 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
2469
2530
}
2470
2531
}
2471
2532
chain -> use ++ ;
2472
- return 0 ;
2473
2533
2534
+ if (net -> nft .validate_state == NFT_VALIDATE_DO )
2535
+ return nft_table_validate (net , table );
2536
+
2537
+ return 0 ;
2474
2538
err2 :
2475
2539
nf_tables_rule_release (& ctx , rule );
2476
2540
err1 :
@@ -4112,6 +4176,12 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
4112
4176
d2 .type , d2 .len );
4113
4177
if (err < 0 )
4114
4178
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 );
4115
4185
}
4116
4186
4117
4187
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,
4211
4281
const struct nlattr * attr ;
4212
4282
struct nft_set * set ;
4213
4283
struct nft_ctx ctx ;
4214
- int rem , err = 0 ;
4284
+ int rem , err ;
4215
4285
4216
4286
if (nla [NFTA_SET_ELEM_LIST_ELEMENTS ] == NULL )
4217
4287
return - EINVAL ;
@@ -4232,9 +4302,13 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
4232
4302
nla_for_each_nested (attr , nla [NFTA_SET_ELEM_LIST_ELEMENTS ], rem ) {
4233
4303
err = nft_add_set_elem (& ctx , set , attr , nlh -> nlmsg_flags );
4234
4304
if (err < 0 )
4235
- break ;
4305
+ return err ;
4236
4306
}
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 ;
4238
4312
}
4239
4313
4240
4314
/**
@@ -5867,6 +5941,27 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
5867
5941
},
5868
5942
};
5869
5943
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
+
5870
5965
static void nft_chain_commit_update (struct nft_trans * trans )
5871
5966
{
5872
5967
struct nft_base_chain * basechain ;
@@ -6055,6 +6150,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
6055
6150
struct nft_chain * chain ;
6056
6151
struct nft_table * table ;
6057
6152
6153
+ /* 0. Validate ruleset, otherwise roll back for error reporting. */
6154
+ if (nf_tables_validate (net ) < 0 )
6155
+ return - EAGAIN ;
6156
+
6058
6157
/* 1. Allocate space for next generation rules_gen_X[] */
6059
6158
list_for_each_entry_safe (trans , next , & net -> nft .commit_list , list ) {
6060
6159
int ret ;
@@ -6349,6 +6448,11 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
6349
6448
return 0 ;
6350
6449
}
6351
6450
6451
+ static void nf_tables_cleanup (struct net * net )
6452
+ {
6453
+ nft_validate_state_update (net , NFT_VALIDATE_SKIP );
6454
+ }
6455
+
6352
6456
static bool nf_tables_valid_genid (struct net * net , u32 genid )
6353
6457
{
6354
6458
return net -> nft .base_seq == genid ;
@@ -6361,6 +6465,7 @@ static const struct nfnetlink_subsystem nf_tables_subsys = {
6361
6465
.cb = nf_tables_cb ,
6362
6466
.commit = nf_tables_commit ,
6363
6467
.abort = nf_tables_abort ,
6468
+ .cleanup = nf_tables_cleanup ,
6364
6469
.valid_genid = nf_tables_valid_genid ,
6365
6470
};
6366
6471
@@ -6444,19 +6549,18 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
6444
6549
6445
6550
list_for_each_entry (rule , & chain -> rules , list ) {
6446
6551
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 ;
6448
6554
int err ;
6449
6555
6450
- if (! expr -> ops -> validate )
6556
+ if (strcmp ( expr -> ops -> type -> name , "immediate" ) )
6451
6557
continue ;
6452
6558
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 )
6458
6561
continue ;
6459
6562
6563
+ data = & priv -> data ;
6460
6564
switch (data -> verdict .code ) {
6461
6565
case NFT_JUMP :
6462
6566
case NFT_GOTO :
@@ -6936,6 +7040,8 @@ static int __net_init nf_tables_init_net(struct net *net)
6936
7040
INIT_LIST_HEAD (& net -> nft .tables );
6937
7041
INIT_LIST_HEAD (& net -> nft .commit_list );
6938
7042
net -> nft .base_seq = 1 ;
7043
+ net -> nft .validate_state = NFT_VALIDATE_SKIP ;
7044
+
6939
7045
return 0 ;
6940
7046
}
6941
7047
0 commit comments