Skip to content

Commit 6a0a8d1

Browse files
committed
netfilter: nf_tables: use-after-free in failing rule with bound set
If a rule that has already a bound anonymous set fails to be added, the preparation phase releases the rule and the bound set. However, the transaction object from the abort path still has a reference to the set object that is stale, leading to a use-after-free when checking for the set->bound field. Add a new field to the transaction that specifies if the set is bound, so the abort path can skip releasing it since the rule command owns it and it takes care of releasing it. After this update, the set->bound field is removed. [ 24.649883] Unable to handle kernel paging request at virtual address 0000000000040434 [ 24.657858] Mem abort info: [ 24.660686] ESR = 0x96000004 [ 24.663769] Exception class = DABT (current EL), IL = 32 bits [ 24.669725] SET = 0, FnV = 0 [ 24.672804] EA = 0, S1PTW = 0 [ 24.675975] Data abort info: [ 24.678880] ISV = 0, ISS = 0x00000004 [ 24.682743] CM = 0, WnR = 0 [ 24.685723] user pgtable: 4k pages, 48-bit VAs, pgdp=0000000428952000 [ 24.692207] [0000000000040434] pgd=0000000000000000 [ 24.697119] Internal error: Oops: 96000004 [#1] SMP [...] [ 24.889414] Call trace: [ 24.891870] __nf_tables_abort+0x3f0/0x7a0 [ 24.895984] nf_tables_abort+0x20/0x40 [ 24.899750] nfnetlink_rcv_batch+0x17c/0x588 [ 24.904037] nfnetlink_rcv+0x13c/0x190 [ 24.907803] netlink_unicast+0x18c/0x208 [ 24.911742] netlink_sendmsg+0x1b0/0x350 [ 24.915682] sock_sendmsg+0x4c/0x68 [ 24.919185] ___sys_sendmsg+0x288/0x2c8 [ 24.923037] __sys_sendmsg+0x7c/0xd0 [ 24.926628] __arm64_sys_sendmsg+0x2c/0x38 [ 24.930744] el0_svc_common.constprop.0+0x94/0x158 [ 24.935556] el0_svc_handler+0x34/0x90 [ 24.939322] el0_svc+0x8/0xc [ 24.942216] Code: 3728030 f9404023 91014262 aa1703e (f9401863) [ 24.948336] ---[ end trace cebbb9dcbed3b56f ]--- Fixes: f6ac858 ("netfilter: nf_tables: unbind set in rule from commit path") Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 589b474 commit 6a0a8d1

File tree

2 files changed

+17
-7
lines changed

2 files changed

+17
-7
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,7 @@ struct nft_set {
421421
unsigned char *udata;
422422
/* runtime data below here */
423423
const struct nft_set_ops *ops ____cacheline_aligned;
424-
u16 flags:13,
425-
bound:1,
424+
u16 flags:14,
426425
genmask:2;
427426
u8 klen;
428427
u8 dlen;
@@ -1348,12 +1347,15 @@ struct nft_trans_rule {
13481347
struct nft_trans_set {
13491348
struct nft_set *set;
13501349
u32 set_id;
1350+
bool bound;
13511351
};
13521352

13531353
#define nft_trans_set(trans) \
13541354
(((struct nft_trans_set *)trans->data)->set)
13551355
#define nft_trans_set_id(trans) \
13561356
(((struct nft_trans_set *)trans->data)->set_id)
1357+
#define nft_trans_set_bound(trans) \
1358+
(((struct nft_trans_set *)trans->data)->bound)
13571359

13581360
struct nft_trans_chain {
13591361
bool update;
@@ -1384,12 +1386,15 @@ struct nft_trans_table {
13841386
struct nft_trans_elem {
13851387
struct nft_set *set;
13861388
struct nft_set_elem elem;
1389+
bool bound;
13871390
};
13881391

13891392
#define nft_trans_elem_set(trans) \
13901393
(((struct nft_trans_elem *)trans->data)->set)
13911394
#define nft_trans_elem(trans) \
13921395
(((struct nft_trans_elem *)trans->data)->elem)
1396+
#define nft_trans_elem_set_bound(trans) \
1397+
(((struct nft_trans_elem *)trans->data)->bound)
13931398

13941399
struct nft_trans_obj {
13951400
struct nft_object *obj;

net/netfilter/nf_tables_api.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,14 @@ static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
138138
return;
139139

140140
list_for_each_entry_reverse(trans, &net->nft.commit_list, list) {
141-
if (trans->msg_type == NFT_MSG_NEWSET &&
142-
nft_trans_set(trans) == set) {
143-
set->bound = true;
141+
switch (trans->msg_type) {
142+
case NFT_MSG_NEWSET:
143+
if (nft_trans_set(trans) == set)
144+
nft_trans_set_bound(trans) = true;
145+
break;
146+
case NFT_MSG_NEWSETELEM:
147+
if (nft_trans_elem_set(trans) == set)
148+
nft_trans_elem_set_bound(trans) = true;
144149
break;
145150
}
146151
}
@@ -6906,7 +6911,7 @@ static int __nf_tables_abort(struct net *net)
69066911
break;
69076912
case NFT_MSG_NEWSET:
69086913
trans->ctx.table->use--;
6909-
if (nft_trans_set(trans)->bound) {
6914+
if (nft_trans_set_bound(trans)) {
69106915
nft_trans_destroy(trans);
69116916
break;
69126917
}
@@ -6918,7 +6923,7 @@ static int __nf_tables_abort(struct net *net)
69186923
nft_trans_destroy(trans);
69196924
break;
69206925
case NFT_MSG_NEWSETELEM:
6921-
if (nft_trans_elem_set(trans)->bound) {
6926+
if (nft_trans_elem_set_bound(trans)) {
69226927
nft_trans_destroy(trans);
69236928
break;
69246929
}

0 commit comments

Comments
 (0)