@@ -74,15 +74,77 @@ static void nft_trans_destroy(struct nft_trans *trans)
74
74
kfree (trans );
75
75
}
76
76
77
+ /* removal requests are queued in the commit_list, but not acted upon
78
+ * until after all new rules are in place.
79
+ *
80
+ * Therefore, nf_register_net_hook(net, &nat_hook) runs before pending
81
+ * nf_unregister_net_hook().
82
+ *
83
+ * nf_register_net_hook thus fails if a nat hook is already in place
84
+ * even if the conflicting hook is about to be removed.
85
+ *
86
+ * If collision is detected, search commit_log for DELCHAIN matching
87
+ * the new nat hooknum; if we find one collision is temporary:
88
+ *
89
+ * Either transaction is aborted (new/colliding hook is removed), or
90
+ * transaction is committed (old hook is removed).
91
+ */
92
+ static bool nf_tables_allow_nat_conflict (const struct net * net ,
93
+ const struct nf_hook_ops * ops )
94
+ {
95
+ const struct nft_trans * trans ;
96
+ bool ret = false;
97
+
98
+ if (!ops -> nat_hook )
99
+ return false;
100
+
101
+ list_for_each_entry (trans , & net -> nft .commit_list , list ) {
102
+ const struct nf_hook_ops * pending_ops ;
103
+ const struct nft_chain * pending ;
104
+
105
+ if (trans -> msg_type != NFT_MSG_NEWCHAIN &&
106
+ trans -> msg_type != NFT_MSG_DELCHAIN )
107
+ continue ;
108
+
109
+ pending = trans -> ctx .chain ;
110
+ if (!nft_is_base_chain (pending ))
111
+ continue ;
112
+
113
+ pending_ops = & nft_base_chain (pending )-> ops ;
114
+ if (pending_ops -> nat_hook &&
115
+ pending_ops -> pf == ops -> pf &&
116
+ pending_ops -> hooknum == ops -> hooknum ) {
117
+ /* other hook registration already pending? */
118
+ if (trans -> msg_type == NFT_MSG_NEWCHAIN )
119
+ return false;
120
+
121
+ ret = true;
122
+ }
123
+ }
124
+
125
+ return ret ;
126
+ }
127
+
77
128
static int nf_tables_register_hook (struct net * net ,
78
129
const struct nft_table * table ,
79
130
struct nft_chain * chain )
80
131
{
132
+ struct nf_hook_ops * ops ;
133
+ int ret ;
134
+
81
135
if (table -> flags & NFT_TABLE_F_DORMANT ||
82
136
!nft_is_base_chain (chain ))
83
137
return 0 ;
84
138
85
- return nf_register_net_hook (net , & nft_base_chain (chain )-> ops );
139
+ ops = & nft_base_chain (chain )-> ops ;
140
+ ret = nf_register_net_hook (net , ops );
141
+ if (ret == - EBUSY && nf_tables_allow_nat_conflict (net , ops )) {
142
+ ops -> nat_hook = false;
143
+ ret = nf_register_net_hook (net , ops );
144
+ ops -> nat_hook = true;
145
+ }
146
+
147
+ return ret ;
86
148
}
87
149
88
150
static void nf_tables_unregister_hook (struct net * net ,
@@ -1226,8 +1288,6 @@ static void nf_tables_chain_destroy(struct nft_chain *chain)
1226
1288
free_percpu (basechain -> stats );
1227
1289
if (basechain -> stats )
1228
1290
static_branch_dec (& nft_counters_enabled );
1229
- if (basechain -> ops .dev != NULL )
1230
- dev_put (basechain -> ops .dev );
1231
1291
kfree (chain -> name );
1232
1292
kfree (basechain );
1233
1293
} else {
@@ -1294,7 +1354,7 @@ static int nft_chain_parse_hook(struct net *net,
1294
1354
}
1295
1355
1296
1356
nla_strlcpy (ifname , ha [NFTA_HOOK_DEV ], IFNAMSIZ );
1297
- dev = dev_get_by_name (net , ifname );
1357
+ dev = __dev_get_by_name (net , ifname );
1298
1358
if (!dev ) {
1299
1359
module_put (type -> owner );
1300
1360
return - ENOENT ;
@@ -1311,8 +1371,6 @@ static int nft_chain_parse_hook(struct net *net,
1311
1371
static void nft_chain_release_hook (struct nft_chain_hook * hook )
1312
1372
{
1313
1373
module_put (hook -> type -> owner );
1314
- if (hook -> dev != NULL )
1315
- dev_put (hook -> dev );
1316
1374
}
1317
1375
1318
1376
static int nf_tables_addchain (struct nft_ctx * ctx , u8 family , u8 genmask ,
@@ -1911,6 +1969,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
1911
1969
[NFTA_RULE_POSITION ] = { .type = NLA_U64 },
1912
1970
[NFTA_RULE_USERDATA ] = { .type = NLA_BINARY ,
1913
1971
.len = NFT_USERDATA_MAXLEN },
1972
+ [NFTA_RULE_ID ] = { .type = NLA_U32 },
1914
1973
};
1915
1974
1916
1975
static int nf_tables_fill_rule_info (struct sk_buff * skb , struct net * net ,
@@ -2446,6 +2505,9 @@ EXPORT_SYMBOL_GPL(nft_unregister_set);
2446
2505
2447
2506
static bool nft_set_ops_candidate (const struct nft_set_ops * ops , u32 flags )
2448
2507
{
2508
+ if ((flags & NFT_SET_EVAL ) && !ops -> update )
2509
+ return false;
2510
+
2449
2511
return (flags & ops -> features ) == (flags & NFT_SET_FEATURES );
2450
2512
}
2451
2513
@@ -2510,7 +2572,7 @@ nft_select_set_ops(const struct nft_ctx *ctx,
2510
2572
if (est .space == best .space &&
2511
2573
est .lookup < best .lookup )
2512
2574
break ;
2513
- } else if (est .size < best .size ) {
2575
+ } else if (est .size < best .size || ! bops ) {
2514
2576
break ;
2515
2577
}
2516
2578
continue ;
@@ -3315,6 +3377,8 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
3315
3377
[NFTA_SET_ELEM_TIMEOUT ] = { .type = NLA_U64 },
3316
3378
[NFTA_SET_ELEM_USERDATA ] = { .type = NLA_BINARY ,
3317
3379
.len = NFT_USERDATA_MAXLEN },
3380
+ [NFTA_SET_ELEM_EXPR ] = { .type = NLA_NESTED },
3381
+ [NFTA_SET_ELEM_OBJREF ] = { .type = NLA_STRING },
3318
3382
};
3319
3383
3320
3384
static const struct nla_policy nft_set_elem_list_policy [NFTA_SET_ELEM_LIST_MAX + 1 ] = {
@@ -4864,8 +4928,6 @@ nf_tables_flowtable_lookup_byhandle(const struct nft_table *table,
4864
4928
return ERR_PTR (- ENOENT );
4865
4929
}
4866
4930
4867
- #define NFT_FLOWTABLE_DEVICE_MAX 8
4868
-
4869
4931
static int nf_tables_parse_devices (const struct nft_ctx * ctx ,
4870
4932
const struct nlattr * attr ,
4871
4933
struct net_device * dev_array [], int * len )
@@ -4882,7 +4944,7 @@ static int nf_tables_parse_devices(const struct nft_ctx *ctx,
4882
4944
}
4883
4945
4884
4946
nla_strlcpy (ifname , tmp , IFNAMSIZ );
4885
- dev = dev_get_by_name (ctx -> net , ifname );
4947
+ dev = __dev_get_by_name (ctx -> net , ifname );
4886
4948
if (!dev ) {
4887
4949
err = - ENOENT ;
4888
4950
goto err1 ;
@@ -4938,13 +5000,11 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx,
4938
5000
err = nf_tables_parse_devices (ctx , tb [NFTA_FLOWTABLE_HOOK_DEVS ],
4939
5001
dev_array , & n );
4940
5002
if (err < 0 )
4941
- goto err1 ;
5003
+ return err ;
4942
5004
4943
5005
ops = kzalloc (sizeof (struct nf_hook_ops ) * n , GFP_KERNEL );
4944
- if (!ops ) {
4945
- err = - ENOMEM ;
4946
- goto err1 ;
4947
- }
5006
+ if (!ops )
5007
+ return - ENOMEM ;
4948
5008
4949
5009
flowtable -> hooknum = hooknum ;
4950
5010
flowtable -> priority = priority ;
@@ -4958,13 +5018,10 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx,
4958
5018
flowtable -> ops [i ].priv = & flowtable -> data .rhashtable ;
4959
5019
flowtable -> ops [i ].hook = flowtable -> data .type -> hook ;
4960
5020
flowtable -> ops [i ].dev = dev_array [i ];
5021
+ flowtable -> dev_name [i ] = kstrdup (dev_array [i ]-> name ,
5022
+ GFP_KERNEL );
4961
5023
}
4962
5024
4963
- err = 0 ;
4964
- err1 :
4965
- for (i = 0 ; i < n ; i ++ )
4966
- dev_put (dev_array [i ]);
4967
-
4968
5025
return err ;
4969
5026
}
4970
5027
@@ -5135,8 +5192,10 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
5135
5192
err5 :
5136
5193
i = flowtable -> ops_len ;
5137
5194
err4 :
5138
- for (k = i - 1 ; k >= 0 ; k -- )
5195
+ for (k = i - 1 ; k >= 0 ; k -- ) {
5196
+ kfree (flowtable -> dev_name [k ]);
5139
5197
nf_unregister_net_hook (net , & flowtable -> ops [k ]);
5198
+ }
5140
5199
5141
5200
kfree (flowtable -> ops );
5142
5201
err3 :
@@ -5226,9 +5285,9 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
5226
5285
goto nla_put_failure ;
5227
5286
5228
5287
for (i = 0 ; i < flowtable -> ops_len ; i ++ ) {
5229
- if (flowtable -> ops [i ]. dev &&
5288
+ if (flowtable -> dev_name [i ][ 0 ] &&
5230
5289
nla_put_string (skb , NFTA_DEVICE_NAME ,
5231
- flowtable -> ops [i ]. dev -> name ))
5290
+ flowtable -> dev_name [i ]))
5232
5291
goto nla_put_failure ;
5233
5292
}
5234
5293
nla_nest_end (skb , nest_devs );
@@ -5470,6 +5529,7 @@ static void nft_flowtable_event(unsigned long event, struct net_device *dev,
5470
5529
continue ;
5471
5530
5472
5531
nf_unregister_net_hook (dev_net (dev ), & flowtable -> ops [i ]);
5532
+ flowtable -> dev_name [i ][0 ] = '\0' ;
5473
5533
flowtable -> ops [i ].dev = NULL ;
5474
5534
break ;
5475
5535
}
0 commit comments