netfilter: nf_tables: initialize set before expression setup
nft_set_elem_expr_alloc() needs an initialized set if expression sets on
the NFT_EXPR_GC flag. Move set fields initialization before expression
setup.
[4512935.019450] ==================================================================
[4512935.019456] BUG: KASAN: null-ptr-deref in nft_set_elem_expr_alloc+0x84/0xd0 [nf_tables]
[4512935.019487] Read of size 8 at addr 0000000000000070 by task nft/23532
[4512935.019494] CPU: 1 PID: 23532 Comm: nft Not tainted 5.12.0-rc4+ #48
[...]
[4512935.019502] Call Trace:
[4512935.019505] dump_stack+0x89/0xb4
[4512935.019512] ? nft_set_elem_expr_alloc+0x84/0xd0 [nf_tables]
[4512935.019536] ? nft_set_elem_expr_alloc+0x84/0xd0 [nf_tables]
[4512935.019560] kasan_report.cold.12+0x5f/0xd8
[4512935.019566] ? nft_set_elem_expr_alloc+0x84/0xd0 [nf_tables]
[4512935.019590] nft_set_elem_expr_alloc+0x84/0xd0 [nf_tables]
[4512935.019615] nf_tables_newset+0xc7f/0x1460 [nf_tables]
Reported-by: syzbot+ce96ca2b1d0b37c6422d@syzkaller.appspotmail.com
Fixes: 65038428b2
("netfilter: nf_tables: allow to specify stateful expression in set definition")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Родитель
f2386cf7c5
Коммит
ad9f151e56
|
@ -4364,44 +4364,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||||
err = nf_tables_set_alloc_name(&ctx, set, name);
|
err = nf_tables_set_alloc_name(&ctx, set, name);
|
||||||
kfree(name);
|
kfree(name);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err_set_alloc_name;
|
goto err_set_name;
|
||||||
|
|
||||||
if (nla[NFTA_SET_EXPR]) {
|
|
||||||
expr = nft_set_elem_expr_alloc(&ctx, set, nla[NFTA_SET_EXPR]);
|
|
||||||
if (IS_ERR(expr)) {
|
|
||||||
err = PTR_ERR(expr);
|
|
||||||
goto err_set_alloc_name;
|
|
||||||
}
|
|
||||||
set->exprs[0] = expr;
|
|
||||||
set->num_exprs++;
|
|
||||||
} else if (nla[NFTA_SET_EXPRESSIONS]) {
|
|
||||||
struct nft_expr *expr;
|
|
||||||
struct nlattr *tmp;
|
|
||||||
int left;
|
|
||||||
|
|
||||||
if (!(flags & NFT_SET_EXPR)) {
|
|
||||||
err = -EINVAL;
|
|
||||||
goto err_set_alloc_name;
|
|
||||||
}
|
|
||||||
i = 0;
|
|
||||||
nla_for_each_nested(tmp, nla[NFTA_SET_EXPRESSIONS], left) {
|
|
||||||
if (i == NFT_SET_EXPR_MAX) {
|
|
||||||
err = -E2BIG;
|
|
||||||
goto err_set_init;
|
|
||||||
}
|
|
||||||
if (nla_type(tmp) != NFTA_LIST_ELEM) {
|
|
||||||
err = -EINVAL;
|
|
||||||
goto err_set_init;
|
|
||||||
}
|
|
||||||
expr = nft_set_elem_expr_alloc(&ctx, set, tmp);
|
|
||||||
if (IS_ERR(expr)) {
|
|
||||||
err = PTR_ERR(expr);
|
|
||||||
goto err_set_init;
|
|
||||||
}
|
|
||||||
set->exprs[i++] = expr;
|
|
||||||
set->num_exprs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
udata = NULL;
|
udata = NULL;
|
||||||
if (udlen) {
|
if (udlen) {
|
||||||
|
@ -4413,20 +4376,19 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||||
INIT_LIST_HEAD(&set->catchall_list);
|
INIT_LIST_HEAD(&set->catchall_list);
|
||||||
set->table = table;
|
set->table = table;
|
||||||
write_pnet(&set->net, net);
|
write_pnet(&set->net, net);
|
||||||
set->ops = ops;
|
set->ops = ops;
|
||||||
set->ktype = ktype;
|
set->ktype = ktype;
|
||||||
set->klen = desc.klen;
|
set->klen = desc.klen;
|
||||||
set->dtype = dtype;
|
set->dtype = dtype;
|
||||||
set->objtype = objtype;
|
set->objtype = objtype;
|
||||||
set->dlen = desc.dlen;
|
set->dlen = desc.dlen;
|
||||||
set->flags = flags;
|
set->flags = flags;
|
||||||
set->size = desc.size;
|
set->size = desc.size;
|
||||||
set->policy = policy;
|
set->policy = policy;
|
||||||
set->udlen = udlen;
|
set->udlen = udlen;
|
||||||
set->udata = udata;
|
set->udata = udata;
|
||||||
set->timeout = timeout;
|
set->timeout = timeout;
|
||||||
set->gc_int = gc_int;
|
set->gc_int = gc_int;
|
||||||
set->handle = nf_tables_alloc_handle(table);
|
|
||||||
|
|
||||||
set->field_count = desc.field_count;
|
set->field_count = desc.field_count;
|
||||||
for (i = 0; i < desc.field_count; i++)
|
for (i = 0; i < desc.field_count; i++)
|
||||||
|
@ -4436,20 +4398,59 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err_set_init;
|
goto err_set_init;
|
||||||
|
|
||||||
|
if (nla[NFTA_SET_EXPR]) {
|
||||||
|
expr = nft_set_elem_expr_alloc(&ctx, set, nla[NFTA_SET_EXPR]);
|
||||||
|
if (IS_ERR(expr)) {
|
||||||
|
err = PTR_ERR(expr);
|
||||||
|
goto err_set_expr_alloc;
|
||||||
|
}
|
||||||
|
set->exprs[0] = expr;
|
||||||
|
set->num_exprs++;
|
||||||
|
} else if (nla[NFTA_SET_EXPRESSIONS]) {
|
||||||
|
struct nft_expr *expr;
|
||||||
|
struct nlattr *tmp;
|
||||||
|
int left;
|
||||||
|
|
||||||
|
if (!(flags & NFT_SET_EXPR)) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err_set_expr_alloc;
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
nla_for_each_nested(tmp, nla[NFTA_SET_EXPRESSIONS], left) {
|
||||||
|
if (i == NFT_SET_EXPR_MAX) {
|
||||||
|
err = -E2BIG;
|
||||||
|
goto err_set_expr_alloc;
|
||||||
|
}
|
||||||
|
if (nla_type(tmp) != NFTA_LIST_ELEM) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err_set_expr_alloc;
|
||||||
|
}
|
||||||
|
expr = nft_set_elem_expr_alloc(&ctx, set, tmp);
|
||||||
|
if (IS_ERR(expr)) {
|
||||||
|
err = PTR_ERR(expr);
|
||||||
|
goto err_set_expr_alloc;
|
||||||
|
}
|
||||||
|
set->exprs[i++] = expr;
|
||||||
|
set->num_exprs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set->handle = nf_tables_alloc_handle(table);
|
||||||
|
|
||||||
err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
|
err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err_set_trans;
|
goto err_set_expr_alloc;
|
||||||
|
|
||||||
list_add_tail_rcu(&set->list, &table->sets);
|
list_add_tail_rcu(&set->list, &table->sets);
|
||||||
table->use++;
|
table->use++;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_set_trans:
|
err_set_expr_alloc:
|
||||||
ops->destroy(set);
|
|
||||||
err_set_init:
|
|
||||||
for (i = 0; i < set->num_exprs; i++)
|
for (i = 0; i < set->num_exprs; i++)
|
||||||
nft_expr_destroy(&ctx, set->exprs[i]);
|
nft_expr_destroy(&ctx, set->exprs[i]);
|
||||||
err_set_alloc_name:
|
|
||||||
|
ops->destroy(set);
|
||||||
|
err_set_init:
|
||||||
kfree(set->name);
|
kfree(set->name);
|
||||||
err_set_name:
|
err_set_name:
|
||||||
kvfree(set);
|
kvfree(set);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче