From 794e7c89d7027565fc8161ae8f0f39d19028b6ee Mon Sep 17 00:00:00 2001
From: Salvatore Bonaccorso <carnil@debian.org>
Date: Fri, 22 Dec 2017 14:25:43 +0100
Subject: [PATCH 4/8] bpf: fix 32-bit ALU op verification

---
 debian/changelog                                   |  1 +
 .../all/bpf-fix-32-bit-ALU-op-verification.patch   | 83 ++++++++++++++++++++++
 debian/patches/series                              |  1 +
 3 files changed, 85 insertions(+)
 create mode 100644 debian/patches/bugfix/all/bpf-fix-32-bit-ALU-op-verification.patch

diff --git a/debian/changelog b/debian/changelog
index 1fc3f8dc0..223f64e37 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -512,6 +512,7 @@ linux (4.14.7-1) UNRELEASED; urgency=medium
   * bpf/verifier: fix bounds calculation on BPF_RSH
   * bpf: fix incorrect sign extension in check_alu_op() (CVE-2017-16995)
   * bpf: fix incorrect tracking of register size truncation (CVE-2017-16996)
+  * bpf: fix 32-bit ALU op verification
 
   [ Vagrant Cascadian ]
   * [armhf, arm64] Backport patches from 4.15.x to support dwmac-sun8i.
diff --git a/debian/patches/bugfix/all/bpf-fix-32-bit-ALU-op-verification.patch b/debian/patches/bugfix/all/bpf-fix-32-bit-ALU-op-verification.patch
new file mode 100644
index 000000000..09a2a57cd
--- /dev/null
+++ b/debian/patches/bugfix/all/bpf-fix-32-bit-ALU-op-verification.patch
@@ -0,0 +1,83 @@
+From: Jann Horn <jannh@google.com>
+Date: Mon, 18 Dec 2017 20:11:56 -0800
+Subject: bpf: fix 32-bit ALU op verification
+Origin: https://git.kernel.org/linus/468f6eafa6c44cb2c5d8aad35e12f06c240a812a
+
+32-bit ALU ops operate on 32-bit values and have 32-bit outputs.
+Adjust the verifier accordingly.
+
+Fixes: f1174f77b50c ("bpf/verifier: rework value tracking")
+Signed-off-by: Jann Horn <jannh@google.com>
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+[carnil: backport for 4.14: refresh context]
+---
+ kernel/bpf/verifier.c | 28 +++++++++++++++++-----------
+ 1 file changed, 17 insertions(+), 11 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1984,6 +1984,10 @@ static int adjust_ptr_min_max_vals(struc
+ 	return 0;
+ }
+ 
++/* WARNING: This function does calculations on 64-bit values, but the actual
++ * execution may occur on 32-bit values. Therefore, things like bitshifts
++ * need extra checks in the 32-bit case.
++ */
+ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
+ 				      struct bpf_insn *insn,
+ 				      struct bpf_reg_state *dst_reg,
+@@ -1994,12 +1998,8 @@ static int adjust_scalar_min_max_vals(st
+ 	bool src_known, dst_known;
+ 	s64 smin_val, smax_val;
+ 	u64 umin_val, umax_val;
++	u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32;
+ 
+-	if (BPF_CLASS(insn->code) != BPF_ALU64) {
+-		/* 32-bit ALU ops are (32,32)->64 */
+-		coerce_reg_to_size(dst_reg, 4);
+-		coerce_reg_to_size(&src_reg, 4);
+-	}
+ 	smin_val = src_reg.smin_value;
+ 	smax_val = src_reg.smax_value;
+ 	umin_val = src_reg.umin_value;
+@@ -2135,9 +2135,9 @@ static int adjust_scalar_min_max_vals(st
+ 		__update_reg_bounds(dst_reg);
+ 		break;
+ 	case BPF_LSH:
+-		if (umax_val > 63) {
+-			/* Shifts greater than 63 are undefined.  This includes
+-			 * shifts by a negative number.
++		if (umax_val >= insn_bitness) {
++			/* Shifts greater than 31 or 63 are undefined.
++			 * This includes shifts by a negative number.
+ 			 */
+ 			mark_reg_unknown(regs, insn->dst_reg);
+ 			break;
+@@ -2163,9 +2163,9 @@ static int adjust_scalar_min_max_vals(st
+ 		__update_reg_bounds(dst_reg);
+ 		break;
+ 	case BPF_RSH:
+-		if (umax_val > 63) {
+-			/* Shifts greater than 63 are undefined.  This includes
+-			 * shifts by a negative number.
++		if (umax_val >= insn_bitness) {
++			/* Shifts greater than 31 or 63 are undefined.
++			 * This includes shifts by a negative number.
+ 			 */
+ 			mark_reg_unknown(regs, insn->dst_reg);
+ 			break;
+@@ -2201,6 +2201,12 @@ static int adjust_scalar_min_max_vals(st
+ 		break;
+ 	}
+ 
++	if (BPF_CLASS(insn->code) != BPF_ALU64) {
++		/* 32-bit ALU ops are (32,32)->32 */
++		coerce_reg_to_size(dst_reg, 4);
++		coerce_reg_to_size(&src_reg, 4);
++	}
++
+ 	__reg_deduce_bounds(dst_reg);
+ 	__reg_bound_offset(dst_reg);
+ 	return 0;
diff --git a/debian/patches/series b/debian/patches/series
index b8e50d3cd..e263b4ed0 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -132,6 +132,7 @@ bugfix/all/crypto-hmac-require-that-the-underlying-hash-algorit.patch
 bugfix/all/bpf-verifier-fix-bounds-calculation-on-BPF_RSH.patch
 bugfix/all/bpf-fix-incorrect-sign-extension-in-check_alu_op.patch
 bugfix/all/bpf-fix-incorrect-tracking-of-register-size-truncati.patch
+bugfix/all/bpf-fix-32-bit-ALU-op-verification.patch
 
 # Fix exported symbol versions
 bugfix/all/module-disable-matching-missing-version-crc.patch
-- 
2.15.1

