Patch "bpf: Fix potential memleak and UAF in the verifier." has been added to the 5.14-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    bpf: Fix potential memleak and UAF in the verifier.

to the 5.14-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     bpf-fix-potential-memleak-and-uaf-in-the-verifier.patch
and it can be found in the queue-5.14 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit ae22934529d7953f5fe4b6353843b6aef22ff8cc
Author: He Fengqing <hefengqing@xxxxxxxxxx>
Date:   Wed Jul 14 10:18:15 2021 +0000

    bpf: Fix potential memleak and UAF in the verifier.
    
    [ Upstream commit 75f0fc7b48ad45a2e5736bcf8de26c8872fe8695 ]
    
    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: 8041902dae52 ("bpf: adjust insn_aux_data when patching insns")
    Signed-off-by: He Fengqing <hefengqing@xxxxxxxxxx>
    Signed-off-by: Alexei Starovoitov <ast@xxxxxxxxxx>
    Acked-by: Song Liu <songliubraving@xxxxxx>
    Link: https://lore.kernel.org/bpf/20210714101815.164322-1-hefengqing@xxxxxxxxxx
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 49f07e2bf23b..10084c0600dd 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -11414,10 +11414,11 @@ static void convert_pseudo_ld_imm64(struct bpf_verifier_env *env)
  * insni[off, off + cnt).  Adjust corresponding insn_aux_data by copying
  * [0, off) and [off, end) to new locations, so the patched range stays zero
  */
-static int adjust_insn_aux_data(struct bpf_verifier_env *env,
-				struct bpf_prog *new_prog, u32 off, u32 cnt)
+static void adjust_insn_aux_data(struct bpf_verifier_env *env,
+				 struct bpf_insn_aux_data *new_data,
+				 struct bpf_prog *new_prog, u32 off, u32 cnt)
 {
-	struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
+	struct bpf_insn_aux_data *old_data = env->insn_aux_data;
 	struct bpf_insn *insn = new_prog->insnsi;
 	u32 old_seen = old_data[off].seen;
 	u32 prog_len;
@@ -11430,12 +11431,9 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env,
 	old_data[off].zext_dst = insn_has_def32(env, insn + off + cnt - 1);
 
 	if (cnt == 1)
-		return 0;
+		return;
 	prog_len = new_prog->len;
-	new_data = vzalloc(array_size(prog_len,
-				      sizeof(struct bpf_insn_aux_data)));
-	if (!new_data)
-		return -ENOMEM;
+
 	memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
 	memcpy(new_data + off + cnt - 1, old_data + off,
 	       sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
@@ -11446,7 +11444,6 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env,
 	}
 	env->insn_aux_data = new_data;
 	vfree(old_data);
-	return 0;
 }
 
 static void adjust_subprog_starts(struct bpf_verifier_env *env, u32 off, u32 len)
@@ -11481,6 +11478,14 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of
 					    const struct bpf_insn *patch, u32 len)
 {
 	struct bpf_prog *new_prog;
+	struct bpf_insn_aux_data *new_data = NULL;
+
+	if (len > 1) {
+		new_data = vzalloc(array_size(env->prog->len + len - 1,
+					      sizeof(struct bpf_insn_aux_data)));
+		if (!new_data)
+			return NULL;
+	}
 
 	new_prog = bpf_patch_insn_single(env->prog, off, patch, len);
 	if (IS_ERR(new_prog)) {
@@ -11488,10 +11493,10 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of
 			verbose(env,
 				"insn %d cannot be patched due to 16-bit range\n",
 				env->insn_aux_data[off].orig_idx);
+		vfree(new_data);
 		return NULL;
 	}
-	if (adjust_insn_aux_data(env, new_prog, off, len))
-		return NULL;
+	adjust_insn_aux_data(env, new_data, new_prog, off, len);
 	adjust_subprog_starts(env, off, len);
 	adjust_poke_descs(new_prog, off, len);
 	return new_prog;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux