Gary Lin a8864c
From: Daniel Borkmann <daniel@iogearbox.net>
Gary Lin a8864c
Date: Fri, 21 May 2021 10:19:22 +0000
Gary Lin a8864c
Subject: bpf: Fix mask direction swap upon off reg sign change
Gary Lin a8864c
Patch-mainline: Queued in subsystem maintainer repository
Gary Lin a8864c
Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Gary Lin a8864c
Git-commit: bb01a1bba579b4b1c5566af24d95f1767859771e
Gary Lin a8864c
References: bsc#1186484,CVE-2021-33200
Gary Lin a8864c
Gary Lin a8864c
Masking direction as indicated via mask_to_left is considered to be
Gary Lin a8864c
calculated once and then used to derive pointer limits. Thus, this
Gary Lin a8864c
needs to be placed into bpf_sanitize_info instead so we can pass it
Gary Lin a8864c
to sanitize_ptr_alu() call after the pointer move. Piotr noticed a
Gary Lin a8864c
corner case where the off reg causes masking direction change which
Gary Lin a8864c
then results in an incorrect final aux->alu_limit.
Gary Lin a8864c
Gary Lin a8864c
Fixes: 7fedb63a8307 ("bpf: Tighten speculative pointer arithmetic mask")
Gary Lin a8864c
Reported-by: Piotr Krysiuk <piotras@gmail.com>
Gary Lin a8864c
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Gary Lin a8864c
Reviewed-by: Piotr Krysiuk <piotras@gmail.com>
Gary Lin a8864c
Acked-by: Alexei Starovoitov <ast@kernel.org>
Gary Lin a8864c
Acked-by: Gary Lin <glin@suse.com>
Gary Lin a8864c
---
Gary Lin a8864c
 kernel/bpf/verifier.c |   22 ++++++++++++----------
Gary Lin a8864c
 1 file changed, 12 insertions(+), 10 deletions(-)
Gary Lin a8864c
Gary Lin a8864c
--- a/kernel/bpf/verifier.c
Gary Lin a8864c
+++ b/kernel/bpf/verifier.c
Gary Lin a8864c
@@ -4451,18 +4451,10 @@ enum {
Gary Lin a8864c
 };
Gary Lin a8864c
 
Gary Lin a8864c
 static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
Gary Lin a8864c
-			      const struct bpf_reg_state *off_reg,
Gary Lin a8864c
-			      u32 *alu_limit, u8 opcode)
Gary Lin a8864c
+			      u32 *alu_limit, bool mask_to_left)
Gary Lin a8864c
 {
Gary Lin a8864c
-	bool off_is_neg = off_reg->smin_value < 0;
Gary Lin a8864c
-	bool mask_to_left = (opcode == BPF_ADD &&  off_is_neg) ||
Gary Lin a8864c
-			    (opcode == BPF_SUB && !off_is_neg);
Gary Lin a8864c
 	u32 max = 0, ptr_limit = 0;
Gary Lin a8864c
 
Gary Lin a8864c
-	if (!tnum_is_const(off_reg->var_off) &&
Gary Lin a8864c
-	    (off_reg->smin_value < 0) != (off_reg->smax_value < 0))
Gary Lin a8864c
-		return REASON_BOUNDS;
Gary Lin a8864c
-
Gary Lin a8864c
 	switch (ptr_reg->type) {
Gary Lin a8864c
 	case PTR_TO_STACK:
Gary Lin a8864c
 		/* Offset 0 is out-of-bounds, but acceptable start for the
Gary Lin a8864c
@@ -4530,6 +4522,7 @@ static bool sanitize_needed(u8 opcode)
Gary Lin a8864c
 
Gary Lin a8864c
 struct bpf_sanitize_info {
Gary Lin a8864c
 	struct bpf_insn_aux_data aux;
Gary Lin a8864c
+	bool mask_to_left;
Gary Lin a8864c
 };
Gary Lin a8864c
 
Gary Lin a8864c
 static int sanitize_ptr_alu(struct bpf_verifier_env *env,
Gary Lin a8864c
@@ -4561,7 +4554,16 @@ static int sanitize_ptr_alu(struct bpf_v
Gary Lin a8864c
 	if (vstate->speculative)
Gary Lin a8864c
 		goto do_sim;
Gary Lin a8864c
 
Gary Lin a8864c
-	err = retrieve_ptr_limit(ptr_reg, off_reg, &alu_limit, opcode);
Gary Lin a8864c
+	if (!commit_window) {
Gary Lin a8864c
+		if (!tnum_is_const(off_reg->var_off) &&
Gary Lin a8864c
+		    (off_reg->smin_value < 0) != (off_reg->smax_value < 0))
Gary Lin a8864c
+			return REASON_BOUNDS;
Gary Lin a8864c
+
Gary Lin a8864c
+		info->mask_to_left = (opcode == BPF_ADD &&  off_is_neg) ||
Gary Lin a8864c
+				     (opcode == BPF_SUB && !off_is_neg);
Gary Lin a8864c
+	}
Gary Lin a8864c
+
Gary Lin a8864c
+	err = retrieve_ptr_limit(ptr_reg, &alu_limit, info->mask_to_left);
Gary Lin a8864c
 	if (err < 0)
Gary Lin a8864c
 		return err;
Gary Lin a8864c