Skip to content

Commit 75f0fc7

Browse files
hefengqingAlexei Starovoitov
authored andcommitted
bpf: Fix potential memleak and UAF in the verifier.
In bpf_patch_insn_data(), we first use the bpf_patch_insn_single() to insert new instructions, then use adjust_insn_aux_data() to adjust insn_aux_data. If the old env->prog have no enough room for new inserted instructions, we use bpf_prog_realloc to construct new_prog and free the old env->prog. There have two errors here. First, if adjust_insn_aux_data() return ENOMEM, we should free the new_prog. Second, if adjust_insn_aux_data() return ENOMEM, bpf_patch_insn_data() will return NULL, and env->prog has been freed in bpf_prog_realloc, but we will use it in bpf_check(). So in this patch, we make the adjust_insn_aux_data() never fails. In bpf_patch_insn_data(), we first pre-malloc memory for the new insn_aux_data, then call bpf_patch_insn_single() to insert new instructions, at last call adjust_insn_aux_data() to adjust insn_aux_data. Fixes: 8041902 ("bpf: adjust insn_aux_data when patching insns") Signed-off-by: He Fengqing <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Song Liu <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent f170acd commit 75f0fc7

File tree

1 file changed

+16
-11
lines changed

1 file changed

+16
-11
lines changed

kernel/bpf/verifier.c

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11425,10 +11425,11 @@ static void convert_pseudo_ld_imm64(struct bpf_verifier_env *env)
1142511425
* insni[off, off + cnt). Adjust corresponding insn_aux_data by copying
1142611426
* [0, off) and [off, end) to new locations, so the patched range stays zero
1142711427
*/
11428-
static int adjust_insn_aux_data(struct bpf_verifier_env *env,
11429-
struct bpf_prog *new_prog, u32 off, u32 cnt)
11428+
static void adjust_insn_aux_data(struct bpf_verifier_env *env,
11429+
struct bpf_insn_aux_data *new_data,
11430+
struct bpf_prog *new_prog, u32 off, u32 cnt)
1143011431
{
11431-
struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
11432+
struct bpf_insn_aux_data *old_data = env->insn_aux_data;
1143211433
struct bpf_insn *insn = new_prog->insnsi;
1143311434
u32 old_seen = old_data[off].seen;
1143411435
u32 prog_len;
@@ -11441,12 +11442,9 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env,
1144111442
old_data[off].zext_dst = insn_has_def32(env, insn + off + cnt - 1);
1144211443

1144311444
if (cnt == 1)
11444-
return 0;
11445+
return;
1144511446
prog_len = new_prog->len;
11446-
new_data = vzalloc(array_size(prog_len,
11447-
sizeof(struct bpf_insn_aux_data)));
11448-
if (!new_data)
11449-
return -ENOMEM;
11447+
1145011448
memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
1145111449
memcpy(new_data + off + cnt - 1, old_data + off,
1145211450
sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
@@ -11457,7 +11455,6 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env,
1145711455
}
1145811456
env->insn_aux_data = new_data;
1145911457
vfree(old_data);
11460-
return 0;
1146111458
}
1146211459

1146311460
static void adjust_subprog_starts(struct bpf_verifier_env *env, u32 off, u32 len)
@@ -11492,17 +11489,25 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of
1149211489
const struct bpf_insn *patch, u32 len)
1149311490
{
1149411491
struct bpf_prog *new_prog;
11492+
struct bpf_insn_aux_data *new_data = NULL;
11493+
11494+
if (len > 1) {
11495+
new_data = vzalloc(array_size(env->prog->len + len - 1,
11496+
sizeof(struct bpf_insn_aux_data)));
11497+
if (!new_data)
11498+
return NULL;
11499+
}
1149511500

1149611501
new_prog = bpf_patch_insn_single(env->prog, off, patch, len);
1149711502
if (IS_ERR(new_prog)) {
1149811503
if (PTR_ERR(new_prog) == -ERANGE)
1149911504
verbose(env,
1150011505
"insn %d cannot be patched due to 16-bit range\n",
1150111506
env->insn_aux_data[off].orig_idx);
11507+
vfree(new_data);
1150211508
return NULL;
1150311509
}
11504-
if (adjust_insn_aux_data(env, new_prog, off, len))
11505-
return NULL;
11510+
adjust_insn_aux_data(env, new_data, new_prog, off, len);
1150611511
adjust_subprog_starts(env, off, len);
1150711512
adjust_poke_descs(new_prog, off, len);
1150811513
return new_prog;

0 commit comments

Comments
 (0)