From f9d129347bd7b6a4f2f929dbcc0f94ad2d9e818b Mon Sep 17 00:00:00 2001
From: Salvatore Bonaccorso <carnil@debian.org>
Date: Fri, 22 Dec 2017 14:25:16 +0100
Subject: [PATCH 3/8] bpf: fix incorrect tracking of register size truncation
 (CVE-2017-16996)

---
 debian/changelog                                   |   1 +
 ...orrect-tracking-of-register-size-truncati.patch | 123 +++++++++++++++++++++
 debian/patches/series                              |   1 +
 3 files changed, 125 insertions(+)
 create mode 100644 debian/patches/bugfix/all/bpf-fix-incorrect-tracking-of-register-size-truncati.patch

diff --git a/debian/changelog b/debian/changelog
index 8e8eb1cc1..1fc3f8dc0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -511,6 +511,7 @@ linux (4.14.7-1) UNRELEASED; urgency=medium
     (CVE-2017-17806)
   * 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)
 
   [ Vagrant Cascadian ]
   * [armhf, arm64] Backport patches from 4.15.x to support dwmac-sun8i.
diff --git a/debian/patches/bugfix/all/bpf-fix-incorrect-tracking-of-register-size-truncati.patch b/debian/patches/bugfix/all/bpf-fix-incorrect-tracking-of-register-size-truncati.patch
new file mode 100644
index 000000000..cc85286c5
--- /dev/null
+++ b/debian/patches/bugfix/all/bpf-fix-incorrect-tracking-of-register-size-truncati.patch
@@ -0,0 +1,123 @@
+From: Jann Horn <jannh@google.com>
+Date: Mon, 18 Dec 2017 20:11:55 -0800
+Subject: bpf: fix incorrect tracking of register size truncation
+Origin: https://git.kernel.org/linus/0c17d1d2c61936401f4702e1846e2c19b200f958
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2017-16996
+
+Properly handle register truncation to a smaller size.
+
+The old code first mirrors the clearing of the high 32 bits in the bitwise
+tristate representation, which is correct. But then, it computes the new
+arithmetic bounds as the intersection between the old arithmetic bounds and
+the bounds resulting from the bitwise tristate representation. Therefore,
+when coerce_reg_to_32() is called on a number with bounds
+[0xffff'fff8, 0x1'0000'0007], the verifier computes
+[0xffff'fff8, 0xffff'ffff] as bounds of the truncated number.
+This is incorrect: The truncated number could also be in the range [0, 7],
+and no meaningful arithmetic bounds can be computed in that case apart from
+the obvious [0, 0xffff'ffff].
+
+Starting with v4.14, this is exploitable by unprivileged users as long as
+the unprivileged_bpf_disabled sysctl isn't set.
+
+Debian assigned CVE-2017-16996 for this issue.
+
+v2:
+ - flip the mask during arithmetic bounds calculation (Ben Hutchings)
+v3:
+ - add CVE number (Ben Hutchings)
+
+Fixes: b03c9f9fdc37 ("bpf/verifier: track signed and unsigned min/max values")
+Signed-off-by: Jann Horn <jannh@google.com>
+Acked-by: Edward Cree <ecree@solarflare.com>
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+[carnil: backport 4.14:
+ - adjust context
+ - In check_mem_access: use &state->regs
+]
+---
+ kernel/bpf/verifier.c | 44 +++++++++++++++++++++++++++-----------------
+ 1 file changed, 27 insertions(+), 17 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -1068,6 +1068,29 @@ static int check_ptr_alignment(struct bp
+ 	return check_generic_ptr_alignment(reg, pointer_desc, off, size, strict);
+ }
+ 
++/* truncate register to smaller size (in bytes)
++ * must be called with size < BPF_REG_SIZE
++ */
++static void coerce_reg_to_size(struct bpf_reg_state *reg, int size)
++{
++	u64 mask;
++
++	/* clear high bits in bit representation */
++	reg->var_off = tnum_cast(reg->var_off, size);
++
++	/* fix arithmetic bounds */
++	mask = ((u64)1 << (size * 8)) - 1;
++	if ((reg->umin_value & ~mask) == (reg->umax_value & ~mask)) {
++		reg->umin_value &= mask;
++		reg->umax_value &= mask;
++	} else {
++		reg->umin_value = 0;
++		reg->umax_value = mask;
++	}
++	reg->smin_value = reg->umin_value;
++	reg->smax_value = reg->umax_value;
++}
++
+ /* check whether memory at (regno + off) is accessible for t = (read | write)
+  * if t==write, value_regno is a register which value is stored into memory
+  * if t==read, value_regno is a register which will receive the value from memory
+@@ -1200,9 +1223,7 @@ static int check_mem_access(struct bpf_v
+ 	if (!err && size < BPF_REG_SIZE && value_regno >= 0 && t == BPF_READ &&
+ 	    state->regs[value_regno].type == SCALAR_VALUE) {
+ 		/* b/h/w load zero-extends, mark upper bits as known 0 */
+-		state->regs[value_regno].var_off = tnum_cast(
+-					state->regs[value_regno].var_off, size);
+-		__update_reg_bounds(&state->regs[value_regno]);
++		coerce_reg_to_size(&state->regs[value_regno], size);
+ 	}
+ 	return err;
+ }
+@@ -1742,14 +1763,6 @@ static int check_call(struct bpf_verifie
+ 	return 0;
+ }
+ 
+-static void coerce_reg_to_32(struct bpf_reg_state *reg)
+-{
+-	/* clear high 32 bits */
+-	reg->var_off = tnum_cast(reg->var_off, 4);
+-	/* Update bounds */
+-	__update_reg_bounds(reg);
+-}
+-
+ static bool signed_add_overflows(s64 a, s64 b)
+ {
+ 	/* Do the add in u64, where overflow is well-defined */
+@@ -1984,8 +1997,8 @@ static int adjust_scalar_min_max_vals(st
+ 
+ 	if (BPF_CLASS(insn->code) != BPF_ALU64) {
+ 		/* 32-bit ALU ops are (32,32)->64 */
+-		coerce_reg_to_32(dst_reg);
+-		coerce_reg_to_32(&src_reg);
++		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;
+@@ -2364,10 +2377,7 @@ static int check_alu_op(struct bpf_verif
+ 					return -EACCES;
+ 				}
+ 				mark_reg_unknown(regs, insn->dst_reg);
+-				/* high 32 bits are known zero. */
+-				regs[insn->dst_reg].var_off = tnum_cast(
+-						regs[insn->dst_reg].var_off, 4);
+-				__update_reg_bounds(&regs[insn->dst_reg]);
++				coerce_reg_to_size(&regs[insn->dst_reg], 4);
+ 			}
+ 		} else {
+ 			/* case: R = imm
diff --git a/debian/patches/series b/debian/patches/series
index 7bfcc6581..b8e50d3cd 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -131,6 +131,7 @@ bugfix/all/crypto-salsa20-fix-blkcipher_walk-API-usage.patch
 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
 
 # Fix exported symbol versions
 bugfix/all/module-disable-matching-missing-version-crc.patch
-- 
2.15.1

