Skip to content

Commit 1c7f04f

Browse files
ummakynessmb49
authored andcommitted
netfilter: nf_tables: add NFT_TRANS_PREPARE_ERROR to deal with bound set/chain
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 <pablo@netfilter.org> CVE-2023-4015 (cherry picked from commit 26b5a57) Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> Acked-by: Tim Gardner <tim.gardner@canonical.com> Acked-by: Roxana Nicolescu <roxana.nicolescu@canonical.com> Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
1 parent c534743 commit 1c7f04f

3 files changed

Lines changed: 43 additions & 7 deletions

File tree

include/net/netfilter/nf_tables.h

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

900900
enum nft_trans_phase {
901901
NFT_TRANS_PREPARE,
902+
NFT_TRANS_PREPARE_ERROR,
902903
NFT_TRANS_ABORT,
903904
NFT_TRANS_COMMIT,
904905
NFT_TRANS_RELEASE
@@ -1094,6 +1095,7 @@ int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
10941095
struct nft_set_elem *elem);
10951096
int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set);
10961097
int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain);
1098+
void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain);
10971099

10981100
enum nft_chain_types {
10991101
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
{
@@ -3768,7 +3791,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
37683791
if (flow)
37693792
nft_flow_rule_destroy(flow);
37703793
err_release_rule:
3771-
nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE);
3794+
nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE_ERROR);
37723795
nf_tables_rule_destroy(&ctx, rule);
37733796
err_release_expr:
37743797
for (i = 0; i < n; i++) {
@@ -5050,6 +5073,13 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
50505073
enum nft_trans_phase phase)
50515074
{
50525075
switch (phase) {
5076+
case NFT_TRANS_PREPARE_ERROR:
5077+
nft_set_trans_unbind(ctx, set);
5078+
if (nft_set_is_anonymous(set))
5079+
nft_deactivate_next(ctx->net, set);
5080+
5081+
set->use--;
5082+
break;
50535083
case NFT_TRANS_PREPARE:
50545084
if (nft_set_is_anonymous(set))
50555085
nft_deactivate_next(ctx->net, set);
@@ -7554,6 +7584,7 @@ void nf_tables_deactivate_flowtable(const struct nft_ctx *ctx,
75547584
enum nft_trans_phase phase)
75557585
{
75567586
switch (phase) {
7587+
case NFT_TRANS_PREPARE_ERROR:
75577588
case NFT_TRANS_PREPARE:
75587589
case NFT_TRANS_ABORT:
75597590
case NFT_TRANS_RELEASE:

net/netfilter/nft_immediate.c

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

152152
switch (phase) {
153+
case NFT_TRANS_PREPARE_ERROR:
154+
nf_tables_unbind_chain(ctx, chain);
155+
fallthrough;
153156
case NFT_TRANS_PREPARE:
154157
nft_deactivate_next(ctx->net, chain);
155158
break;

0 commit comments

Comments
 (0)