Skip to content

Commit 8d75cf0

Browse files
committed
netfilter: nf_tables: add NFT_TRANS_PREPARE_ERROR to deal with bound set/chain
jira LE-1907 cve CVE-2023-3390 Rebuild_History Non-Buildable kernel-5.14.0-284.30.1.el9_2 commit-author Pablo Neira Ayuso <[email protected]> commit 26b5a57 Add a new state to deal with rule expressions deactivation from the newrule error path, otherwise the anonymous set remains in the list in inactive state for the next generation. Mark the set/chain transaction as unbound so the abort path releases this object, set it as inactive in the next generation so it is not reachable anymore from this transaction and reference counter is dropped. Fixes: 1240eb9 ("netfilter: nf_tables: incorrect error path handling with NFT_MSG_NEWRULE") Signed-off-by: Pablo Neira Ayuso <[email protected]> (cherry picked from commit 26b5a57) Signed-off-by: Jonathan Maple <[email protected]>
1 parent 0ce53ab commit 8d75cf0

File tree

3 files changed

+43
-7
lines changed

3 files changed

+43
-7
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,7 @@ struct nft_expr_type {
859859

860860
enum nft_trans_phase {
861861
NFT_TRANS_PREPARE,
862+
NFT_TRANS_PREPARE_ERROR,
862863
NFT_TRANS_ABORT,
863864
NFT_TRANS_COMMIT,
864865
NFT_TRANS_RELEASE
@@ -1037,6 +1038,7 @@ int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
10371038
struct nft_set_elem *elem);
10381039
int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set);
10391040
int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain);
1041+
void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain);
10401042

10411043
enum nft_chain_types {
10421044
NFT_CHAIN_T_DEFAULT = 0,

net/netfilter/nf_tables_api.c

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ static void nft_trans_destroy(struct nft_trans *trans)
171171
kfree(trans);
172172
}
173173

174-
static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
174+
static void __nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set,
175+
bool bind)
175176
{
176177
struct nftables_pernet *nft_net;
177178
struct net *net = ctx->net;
@@ -185,17 +186,28 @@ static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
185186
switch (trans->msg_type) {
186187
case NFT_MSG_NEWSET:
187188
if (nft_trans_set(trans) == set)
188-
nft_trans_set_bound(trans) = true;
189+
nft_trans_set_bound(trans) = bind;
189190
break;
190191
case NFT_MSG_NEWSETELEM:
191192
if (nft_trans_elem_set(trans) == set)
192-
nft_trans_elem_set_bound(trans) = true;
193+
nft_trans_elem_set_bound(trans) = bind;
193194
break;
194195
}
195196
}
196197
}
197198

198-
static void nft_chain_trans_bind(const struct nft_ctx *ctx, struct nft_chain *chain)
199+
static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
200+
{
201+
return __nft_set_trans_bind(ctx, set, true);
202+
}
203+
204+
static void nft_set_trans_unbind(const struct nft_ctx *ctx, struct nft_set *set)
205+
{
206+
return __nft_set_trans_bind(ctx, set, false);
207+
}
208+
209+
static void __nft_chain_trans_bind(const struct nft_ctx *ctx,
210+
struct nft_chain *chain, bool bind)
199211
{
200212
struct nftables_pernet *nft_net;
201213
struct net *net = ctx->net;
@@ -209,16 +221,22 @@ static void nft_chain_trans_bind(const struct nft_ctx *ctx, struct nft_chain *ch
209221
switch (trans->msg_type) {
210222
case NFT_MSG_NEWCHAIN:
211223
if (nft_trans_chain(trans) == chain)
212-
nft_trans_chain_bound(trans) = true;
224+
nft_trans_chain_bound(trans) = bind;
213225
break;
214226
case NFT_MSG_NEWRULE:
215227
if (trans->ctx.chain == chain)
216-
nft_trans_rule_bound(trans) = true;
228+
nft_trans_rule_bound(trans) = bind;
217229
break;
218230
}
219231
}
220232
}
221233

234+
static void nft_chain_trans_bind(const struct nft_ctx *ctx,
235+
struct nft_chain *chain)
236+
{
237+
__nft_chain_trans_bind(ctx, chain, true);
238+
}
239+
222240
int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
223241
{
224242
if (!nft_chain_binding(chain))
@@ -237,6 +255,11 @@ int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
237255
return 0;
238256
}
239257

258+
void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
259+
{
260+
__nft_chain_trans_bind(ctx, chain, false);
261+
}
262+
240263
static int nft_netdev_register_hooks(struct net *net,
241264
struct list_head *hook_list)
242265
{
@@ -3612,7 +3635,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
36123635
if (flow)
36133636
nft_flow_rule_destroy(flow);
36143637
err_release_rule:
3615-
nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE);
3638+
nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE_ERROR);
36163639
nf_tables_rule_destroy(&ctx, rule);
36173640
err_release_expr:
36183641
for (i = 0; i < n; i++) {
@@ -4894,6 +4917,13 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
48944917
enum nft_trans_phase phase)
48954918
{
48964919
switch (phase) {
4920+
case NFT_TRANS_PREPARE_ERROR:
4921+
nft_set_trans_unbind(ctx, set);
4922+
if (nft_set_is_anonymous(set))
4923+
nft_deactivate_next(ctx->net, set);
4924+
4925+
set->use--;
4926+
break;
48974927
case NFT_TRANS_PREPARE:
48984928
if (nft_set_is_anonymous(set))
48994929
nft_deactivate_next(ctx->net, set);
@@ -7346,6 +7376,7 @@ void nf_tables_deactivate_flowtable(const struct nft_ctx *ctx,
73467376
enum nft_trans_phase phase)
73477377
{
73487378
switch (phase) {
7379+
case NFT_TRANS_PREPARE_ERROR:
73497380
case NFT_TRANS_PREPARE:
73507381
case NFT_TRANS_ABORT:
73517382
case NFT_TRANS_RELEASE:

net/netfilter/nft_immediate.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ static void nft_immediate_deactivate(const struct nft_ctx *ctx,
134134
nft_rule_expr_deactivate(&chain_ctx, rule, phase);
135135

136136
switch (phase) {
137+
case NFT_TRANS_PREPARE_ERROR:
138+
nf_tables_unbind_chain(ctx, chain);
139+
fallthrough;
137140
case NFT_TRANS_PREPARE:
138141
nft_deactivate_next(ctx->net, chain);
139142
break;

0 commit comments

Comments
 (0)