Skip to content

Commit 4d8f906

Browse files
committed
netfilter: nftables: clone set element expression template
memcpy() breaks when using connlimit in set elements. Use nft_expr_clone() to initialize the connlimit expression list, otherwise connlimit garbage collector crashes when walking on the list head copy. [ 493.064656] Workqueue: events_power_efficient nft_rhash_gc [nf_tables] [ 493.064685] RIP: 0010:find_or_evict+0x5a/0x90 [nf_conncount] [ 493.064694] Code: 2b 43 40 83 f8 01 77 0d 48 c7 c0 f5 ff ff ff 44 39 63 3c 75 df 83 6d 18 01 48 8b 43 08 48 89 de 48 8b 13 48 8b 3d ee 2f 00 00 <48> 89 42 08 48 89 10 48 b8 00 01 00 00 00 00 ad de 48 89 03 48 83 [ 493.064699] RSP: 0018:ffffc90000417dc0 EFLAGS: 00010297 [ 493.064704] RAX: 0000000000000000 RBX: ffff888134f38410 RCX: 0000000000000000 [ 493.064708] RDX: 0000000000000000 RSI: ffff888134f38410 RDI: ffff888100060cc0 [ 493.064711] RBP: ffff88812ce594a8 R08: ffff888134f38438 R09: 00000000ebb9025c [ 493.064714] R10: ffffffff8219f838 R11: 0000000000000017 R12: 0000000000000001 [ 493.064718] R13: ffffffff82146740 R14: ffff888134f38410 R15: 0000000000000000 [ 493.064721] FS: 0000000000000000(0000) GS:ffff88840e440000(0000) knlGS:0000000000000000 [ 493.064725] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 493.064729] CR2: 0000000000000008 CR3: 00000001330aa002 CR4: 00000000001706e0 [ 493.064733] Call Trace: [ 493.064737] nf_conncount_gc_list+0x8f/0x150 [nf_conncount] [ 493.064746] nft_rhash_gc+0x106/0x390 [nf_tables] Reported-by: Laura Garcia Liebana <[email protected]> Fixes: 4094445 ("netfilter: nf_tables: add elements with stateful expressions") Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent b29c457 commit 4d8f906

File tree

1 file changed

+34
-12
lines changed

1 file changed

+34
-12
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5295,16 +5295,35 @@ int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
52955295
return -ENOMEM;
52965296
}
52975297

5298-
static void nft_set_elem_expr_setup(const struct nft_set_ext *ext, int i,
5299-
struct nft_expr *expr_array[])
5298+
static int nft_set_elem_expr_setup(struct nft_ctx *ctx,
5299+
const struct nft_set_ext *ext,
5300+
struct nft_expr *expr_array[],
5301+
u32 num_exprs)
53005302
{
53015303
struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext);
5302-
struct nft_expr *expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
5304+
struct nft_expr *expr;
5305+
int i, err;
5306+
5307+
for (i = 0; i < num_exprs; i++) {
5308+
expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
5309+
err = nft_expr_clone(expr, expr_array[i]);
5310+
if (err < 0)
5311+
goto err_elem_expr_setup;
5312+
5313+
elem_expr->size += expr_array[i]->ops->size;
5314+
nft_expr_destroy(ctx, expr_array[i]);
5315+
expr_array[i] = NULL;
5316+
}
5317+
5318+
return 0;
5319+
5320+
err_elem_expr_setup:
5321+
for (; i < num_exprs; i++) {
5322+
nft_expr_destroy(ctx, expr_array[i]);
5323+
expr_array[i] = NULL;
5324+
}
53035325

5304-
memcpy(expr, expr_array[i], expr_array[i]->ops->size);
5305-
elem_expr->size += expr_array[i]->ops->size;
5306-
kfree(expr_array[i]);
5307-
expr_array[i] = NULL;
5326+
return -ENOMEM;
53085327
}
53095328

53105329
static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
@@ -5556,12 +5575,15 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
55565575
*nft_set_ext_obj(ext) = obj;
55575576
obj->use++;
55585577
}
5559-
for (i = 0; i < num_exprs; i++)
5560-
nft_set_elem_expr_setup(ext, i, expr_array);
5578+
err = nft_set_elem_expr_setup(ctx, ext, expr_array, num_exprs);
5579+
if (err < 0)
5580+
goto err_elem_expr;
55615581

55625582
trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
5563-
if (trans == NULL)
5564-
goto err_trans;
5583+
if (trans == NULL) {
5584+
err = -ENOMEM;
5585+
goto err_elem_expr;
5586+
}
55655587

55665588
ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK;
55675589
err = set->ops->insert(ctx->net, set, &elem, &ext2);
@@ -5605,7 +5627,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
56055627
set->ops->remove(ctx->net, set, &elem);
56065628
err_element_clash:
56075629
kfree(trans);
5608-
err_trans:
5630+
err_elem_expr:
56095631
if (obj)
56105632
obj->use--;
56115633

0 commit comments

Comments
 (0)