]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 21 Nov 2019 22:52:46 +0000 (23:52 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 21 Nov 2019 22:52:46 +0000 (23:52 +0100)
added patches:
bpf-x32-fix-bug-for-bpf_alu64-bpf_neg.patch
bpf-x32-fix-bug-for-bpf_jmp-bpf_jsgt-bpf_jsle-bpf_jslt-bpf_jsge.patch
bpf-x32-fix-bug-with-alu64-lsh-rsh-arsh-bpf_k-shift-by-0.patch
bpf-x32-fix-bug-with-alu64-lsh-rsh-arsh-bpf_x-shift-by-0.patch

queue-4.19/bpf-x32-fix-bug-for-bpf_alu64-bpf_neg.patch [new file with mode: 0644]
queue-4.19/bpf-x32-fix-bug-for-bpf_jmp-bpf_jsgt-bpf_jsle-bpf_jslt-bpf_jsge.patch [new file with mode: 0644]
queue-4.19/bpf-x32-fix-bug-with-alu64-lsh-rsh-arsh-bpf_k-shift-by-0.patch [new file with mode: 0644]
queue-4.19/bpf-x32-fix-bug-with-alu64-lsh-rsh-arsh-bpf_x-shift-by-0.patch [new file with mode: 0644]
queue-4.19/series

diff --git a/queue-4.19/bpf-x32-fix-bug-for-bpf_alu64-bpf_neg.patch b/queue-4.19/bpf-x32-fix-bug-for-bpf_alu64-bpf_neg.patch
new file mode 100644 (file)
index 0000000..831ee62
--- /dev/null
@@ -0,0 +1,82 @@
+From b9aa0b35d878dff9ed19f94101fe353a4de00cc4 Mon Sep 17 00:00:00 2001
+From: Wang YanQing <udknight@gmail.com>
+Date: Sun, 28 Apr 2019 10:33:02 +0800
+Subject: bpf, x32: Fix bug for BPF_ALU64 | BPF_NEG
+
+From: Wang YanQing <udknight@gmail.com>
+
+commit b9aa0b35d878dff9ed19f94101fe353a4de00cc4 upstream.
+
+The current implementation has two errors:
+
+1: The second xor instruction will clear carry flag which
+   is necessary for following sbb instruction.
+2: The select coding for sbb instruction is wrong, the coding
+   is "sbb dreg_hi,ecx", but what we need is "sbb ecx,dreg_hi".
+
+This patch rewrites the implementation and fixes the errors.
+
+This patch fixes below errors reported by bpf/test_verifier in x32
+platform when the jit is enabled:
+
+"
+0: (b4) w1 = 4
+1: (b4) w2 = 4
+2: (1f) r2 -= r1
+3: (4f) r2 |= r1
+4: (87) r2 = -r2
+5: (c7) r2 s>>= 63
+6: (5f) r1 &= r2
+7: (bf) r0 = r1
+8: (95) exit
+processed 9 insns (limit 131072), stack depth 0
+0: (b4) w1 = 4
+1: (b4) w2 = 4
+2: (1f) r2 -= r1
+3: (4f) r2 |= r1
+4: (87) r2 = -r2
+5: (c7) r2 s>>= 63
+6: (5f) r1 &= r2
+7: (bf) r0 = r1
+8: (95) exit
+processed 9 insns (limit 131072), stack depth 0
+......
+Summary: 1189 PASSED, 125 SKIPPED, 15 FAILED
+"
+
+Signed-off-by: Wang YanQing <udknight@gmail.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/net/bpf_jit_comp32.c |   19 ++++++-------------
+ 1 file changed, 6 insertions(+), 13 deletions(-)
+
+--- a/arch/x86/net/bpf_jit_comp32.c
++++ b/arch/x86/net/bpf_jit_comp32.c
+@@ -698,19 +698,12 @@ static inline void emit_ia32_neg64(const
+                     STACK_VAR(dst_hi));
+       }
+-      /* xor ecx,ecx */
+-      EMIT2(0x31, add_2reg(0xC0, IA32_ECX, IA32_ECX));
+-      /* sub dreg_lo,ecx */
+-      EMIT2(0x2B, add_2reg(0xC0, dreg_lo, IA32_ECX));
+-      /* mov dreg_lo,ecx */
+-      EMIT2(0x89, add_2reg(0xC0, dreg_lo, IA32_ECX));
+-
+-      /* xor ecx,ecx */
+-      EMIT2(0x31, add_2reg(0xC0, IA32_ECX, IA32_ECX));
+-      /* sbb dreg_hi,ecx */
+-      EMIT2(0x19, add_2reg(0xC0, dreg_hi, IA32_ECX));
+-      /* mov dreg_hi,ecx */
+-      EMIT2(0x89, add_2reg(0xC0, dreg_hi, IA32_ECX));
++      /* neg dreg_lo */
++      EMIT2(0xF7, add_1reg(0xD8, dreg_lo));
++      /* adc dreg_hi,0x0 */
++      EMIT3(0x83, add_1reg(0xD0, dreg_hi), 0x00);
++      /* neg dreg_hi */
++      EMIT2(0xF7, add_1reg(0xD8, dreg_hi));
+       if (dstk) {
+               /* mov dword ptr [ebp+off],dreg_lo */
diff --git a/queue-4.19/bpf-x32-fix-bug-for-bpf_jmp-bpf_jsgt-bpf_jsle-bpf_jslt-bpf_jsge.patch b/queue-4.19/bpf-x32-fix-bug-for-bpf_jmp-bpf_jsgt-bpf_jsle-bpf_jslt-bpf_jsge.patch
new file mode 100644 (file)
index 0000000..01dfe1a
--- /dev/null
@@ -0,0 +1,314 @@
+From 711aef1bbf88212a21f7103e88f397b47a528805 Mon Sep 17 00:00:00 2001
+From: Wang YanQing <udknight@gmail.com>
+Date: Sat, 27 Apr 2019 16:28:26 +0800
+Subject: bpf, x32: Fix bug for BPF_JMP | {BPF_JSGT, BPF_JSLE, BPF_JSLT, BPF_JSGE}
+
+From: Wang YanQing <udknight@gmail.com>
+
+commit 711aef1bbf88212a21f7103e88f397b47a528805 upstream.
+
+The current method to compare 64-bit numbers for conditional jump is:
+
+1) Compare the high 32-bit first.
+
+2) If the high 32-bit isn't the same, then goto step 4.
+
+3) Compare the low 32-bit.
+
+4) Check the desired condition.
+
+This method is right for unsigned comparison, but it is buggy for signed
+comparison, because it does signed comparison for low 32-bit too.
+
+There is only one sign bit in 64-bit number, that is the MSB in the 64-bit
+number, it is wrong to treat low 32-bit as signed number and do the signed
+comparison for it.
+
+This patch fixes the bug and adds a testcase in selftests/bpf for such bug.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=205469
+Reported-by: Tony Ambardar <itugrok@yahoo.com>
+Cc: Tony Ambardar <itugrok@yahoo.com>
+Cc: stable@vger.kernel.org #v4.19
+Signed-off-by: Wang YanQing <udknight@gmail.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/net/bpf_jit_comp32.c |  221 +++++++++++++++++++++++++++++++-----------
+ 1 file changed, 168 insertions(+), 53 deletions(-)
+
+--- a/arch/x86/net/bpf_jit_comp32.c
++++ b/arch/x86/net/bpf_jit_comp32.c
+@@ -117,6 +117,8 @@ static bool is_simm32(s64 value)
+ #define IA32_JLE 0x7E
+ #define IA32_JG  0x7F
++#define COND_JMP_OPCODE_INVALID       (0xFF)
++
+ /*
+  * Map eBPF registers to IA32 32bit registers or stack scratch space.
+  *
+@@ -1380,6 +1382,75 @@ static inline void emit_push_r64(const u
+       *pprog = prog;
+ }
++static u8 get_cond_jmp_opcode(const u8 op, bool is_cmp_lo)
++{
++      u8 jmp_cond;
++
++      /* Convert BPF opcode to x86 */
++      switch (op) {
++      case BPF_JEQ:
++              jmp_cond = IA32_JE;
++              break;
++      case BPF_JSET:
++      case BPF_JNE:
++              jmp_cond = IA32_JNE;
++              break;
++      case BPF_JGT:
++              /* GT is unsigned '>', JA in x86 */
++              jmp_cond = IA32_JA;
++              break;
++      case BPF_JLT:
++              /* LT is unsigned '<', JB in x86 */
++              jmp_cond = IA32_JB;
++              break;
++      case BPF_JGE:
++              /* GE is unsigned '>=', JAE in x86 */
++              jmp_cond = IA32_JAE;
++              break;
++      case BPF_JLE:
++              /* LE is unsigned '<=', JBE in x86 */
++              jmp_cond = IA32_JBE;
++              break;
++      case BPF_JSGT:
++              if (!is_cmp_lo)
++                      /* Signed '>', GT in x86 */
++                      jmp_cond = IA32_JG;
++              else
++                      /* GT is unsigned '>', JA in x86 */
++                      jmp_cond = IA32_JA;
++              break;
++      case BPF_JSLT:
++              if (!is_cmp_lo)
++                      /* Signed '<', LT in x86 */
++                      jmp_cond = IA32_JL;
++              else
++                      /* LT is unsigned '<', JB in x86 */
++                      jmp_cond = IA32_JB;
++              break;
++      case BPF_JSGE:
++              if (!is_cmp_lo)
++                      /* Signed '>=', GE in x86 */
++                      jmp_cond = IA32_JGE;
++              else
++                      /* GE is unsigned '>=', JAE in x86 */
++                      jmp_cond = IA32_JAE;
++              break;
++      case BPF_JSLE:
++              if (!is_cmp_lo)
++                      /* Signed '<=', LE in x86 */
++                      jmp_cond = IA32_JLE;
++              else
++                      /* LE is unsigned '<=', JBE in x86 */
++                      jmp_cond = IA32_JBE;
++              break;
++      default: /* to silence GCC warning */
++              jmp_cond = COND_JMP_OPCODE_INVALID;
++              break;
++      }
++
++      return jmp_cond;
++}
++
+ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
+                 int oldproglen, struct jit_context *ctx)
+ {
+@@ -1835,11 +1906,7 @@ static int do_jit(struct bpf_prog *bpf_p
+               case BPF_JMP | BPF_JGT | BPF_X:
+               case BPF_JMP | BPF_JLT | BPF_X:
+               case BPF_JMP | BPF_JGE | BPF_X:
+-              case BPF_JMP | BPF_JLE | BPF_X:
+-              case BPF_JMP | BPF_JSGT | BPF_X:
+-              case BPF_JMP | BPF_JSLE | BPF_X:
+-              case BPF_JMP | BPF_JSLT | BPF_X:
+-              case BPF_JMP | BPF_JSGE | BPF_X: {
++              case BPF_JMP | BPF_JLE | BPF_X: {
+                       u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
+                       u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
+                       u8 sreg_lo = sstk ? IA32_ECX : src_lo;
+@@ -1866,6 +1933,40 @@ static int do_jit(struct bpf_prog *bpf_p
+                       EMIT2(0x39, add_2reg(0xC0, dreg_lo, sreg_lo));
+                       goto emit_cond_jmp;
+               }
++              case BPF_JMP | BPF_JSGT | BPF_X:
++              case BPF_JMP | BPF_JSLE | BPF_X:
++              case BPF_JMP | BPF_JSLT | BPF_X:
++              case BPF_JMP | BPF_JSGE | BPF_X: {
++                      u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
++                      u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
++                      u8 sreg_lo = sstk ? IA32_ECX : src_lo;
++                      u8 sreg_hi = sstk ? IA32_EBX : src_hi;
++
++                      if (dstk) {
++                              EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
++                                    STACK_VAR(dst_lo));
++                              EMIT3(0x8B,
++                                    add_2reg(0x40, IA32_EBP,
++                                             IA32_EDX),
++                                    STACK_VAR(dst_hi));
++                      }
++
++                      if (sstk) {
++                              EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_ECX),
++                                    STACK_VAR(src_lo));
++                              EMIT3(0x8B,
++                                    add_2reg(0x40, IA32_EBP,
++                                             IA32_EBX),
++                                    STACK_VAR(src_hi));
++                      }
++
++                      /* cmp dreg_hi,sreg_hi */
++                      EMIT2(0x39, add_2reg(0xC0, dreg_hi, sreg_hi));
++                      EMIT2(IA32_JNE, 10);
++                      /* cmp dreg_lo,sreg_lo */
++                      EMIT2(0x39, add_2reg(0xC0, dreg_lo, sreg_lo));
++                      goto emit_cond_jmp_signed;
++              }
+               case BPF_JMP | BPF_JSET | BPF_X: {
+                       u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
+                       u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
+@@ -1926,11 +2027,7 @@ static int do_jit(struct bpf_prog *bpf_p
+               case BPF_JMP | BPF_JGT | BPF_K:
+               case BPF_JMP | BPF_JLT | BPF_K:
+               case BPF_JMP | BPF_JGE | BPF_K:
+-              case BPF_JMP | BPF_JLE | BPF_K:
+-              case BPF_JMP | BPF_JSGT | BPF_K:
+-              case BPF_JMP | BPF_JSLE | BPF_K:
+-              case BPF_JMP | BPF_JSLT | BPF_K:
+-              case BPF_JMP | BPF_JSGE | BPF_K: {
++              case BPF_JMP | BPF_JLE | BPF_K: {
+                       u32 hi;
+                       u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
+                       u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
+@@ -1956,50 +2053,9 @@ static int do_jit(struct bpf_prog *bpf_p
+                       /* cmp dreg_lo,sreg_lo */
+                       EMIT2(0x39, add_2reg(0xC0, dreg_lo, sreg_lo));
+-emit_cond_jmp:                /* Convert BPF opcode to x86 */
+-                      switch (BPF_OP(code)) {
+-                      case BPF_JEQ:
+-                              jmp_cond = IA32_JE;
+-                              break;
+-                      case BPF_JSET:
+-                      case BPF_JNE:
+-                              jmp_cond = IA32_JNE;
+-                              break;
+-                      case BPF_JGT:
+-                              /* GT is unsigned '>', JA in x86 */
+-                              jmp_cond = IA32_JA;
+-                              break;
+-                      case BPF_JLT:
+-                              /* LT is unsigned '<', JB in x86 */
+-                              jmp_cond = IA32_JB;
+-                              break;
+-                      case BPF_JGE:
+-                              /* GE is unsigned '>=', JAE in x86 */
+-                              jmp_cond = IA32_JAE;
+-                              break;
+-                      case BPF_JLE:
+-                              /* LE is unsigned '<=', JBE in x86 */
+-                              jmp_cond = IA32_JBE;
+-                              break;
+-                      case BPF_JSGT:
+-                              /* Signed '>', GT in x86 */
+-                              jmp_cond = IA32_JG;
+-                              break;
+-                      case BPF_JSLT:
+-                              /* Signed '<', LT in x86 */
+-                              jmp_cond = IA32_JL;
+-                              break;
+-                      case BPF_JSGE:
+-                              /* Signed '>=', GE in x86 */
+-                              jmp_cond = IA32_JGE;
+-                              break;
+-                      case BPF_JSLE:
+-                              /* Signed '<=', LE in x86 */
+-                              jmp_cond = IA32_JLE;
+-                              break;
+-                      default: /* to silence GCC warning */
++emit_cond_jmp:                jmp_cond = get_cond_jmp_opcode(BPF_OP(code), false);
++                      if (jmp_cond == COND_JMP_OPCODE_INVALID)
+                               return -EFAULT;
+-                      }
+                       jmp_offset = addrs[i + insn->off] - addrs[i];
+                       if (is_imm8(jmp_offset)) {
+                               EMIT2(jmp_cond, jmp_offset);
+@@ -2009,7 +2065,66 @@ emit_cond_jmp:          /* Convert BPF opcode to
+                               pr_err("cond_jmp gen bug %llx\n", jmp_offset);
+                               return -EFAULT;
+                       }
++                      break;
++              }
++              case BPF_JMP | BPF_JSGT | BPF_K:
++              case BPF_JMP | BPF_JSLE | BPF_K:
++              case BPF_JMP | BPF_JSLT | BPF_K:
++              case BPF_JMP | BPF_JSGE | BPF_K: {
++                      u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
++                      u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
++                      u8 sreg_lo = IA32_ECX;
++                      u8 sreg_hi = IA32_EBX;
++                      u32 hi;
++
++                      if (dstk) {
++                              EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
++                                    STACK_VAR(dst_lo));
++                              EMIT3(0x8B,
++                                    add_2reg(0x40, IA32_EBP,
++                                             IA32_EDX),
++                                    STACK_VAR(dst_hi));
++                      }
++
++                      /* mov ecx,imm32 */
++                      EMIT2_off32(0xC7, add_1reg(0xC0, IA32_ECX), imm32);
++                      hi = imm32 & (1 << 31) ? (u32)~0 : 0;
++                      /* mov ebx,imm32 */
++                      EMIT2_off32(0xC7, add_1reg(0xC0, IA32_EBX), hi);
++                      /* cmp dreg_hi,sreg_hi */
++                      EMIT2(0x39, add_2reg(0xC0, dreg_hi, sreg_hi));
++                      EMIT2(IA32_JNE, 10);
++                      /* cmp dreg_lo,sreg_lo */
++                      EMIT2(0x39, add_2reg(0xC0, dreg_lo, sreg_lo));
++
++                      /*
++                       * For simplicity of branch offset computation,
++                       * let's use fixed jump coding here.
++                       */
++emit_cond_jmp_signed: /* Check the condition for low 32-bit comparison */
++                      jmp_cond = get_cond_jmp_opcode(BPF_OP(code), true);
++                      if (jmp_cond == COND_JMP_OPCODE_INVALID)
++                              return -EFAULT;
++                      jmp_offset = addrs[i + insn->off] - addrs[i] + 8;
++                      if (is_simm32(jmp_offset)) {
++                              EMIT2_off32(0x0F, jmp_cond + 0x10, jmp_offset);
++                      } else {
++                              pr_err("cond_jmp gen bug %llx\n", jmp_offset);
++                              return -EFAULT;
++                      }
++                      EMIT2(0xEB, 6);
++                      /* Check the condition for high 32-bit comparison */
++                      jmp_cond = get_cond_jmp_opcode(BPF_OP(code), false);
++                      if (jmp_cond == COND_JMP_OPCODE_INVALID)
++                              return -EFAULT;
++                      jmp_offset = addrs[i + insn->off] - addrs[i];
++                      if (is_simm32(jmp_offset)) {
++                              EMIT2_off32(0x0F, jmp_cond + 0x10, jmp_offset);
++                      } else {
++                              pr_err("cond_jmp gen bug %llx\n", jmp_offset);
++                              return -EFAULT;
++                      }
+                       break;
+               }
+               case BPF_JMP | BPF_JA:
diff --git a/queue-4.19/bpf-x32-fix-bug-with-alu64-lsh-rsh-arsh-bpf_k-shift-by-0.patch b/queue-4.19/bpf-x32-fix-bug-with-alu64-lsh-rsh-arsh-bpf_k-shift-by-0.patch
new file mode 100644 (file)
index 0000000..21a7f98
--- /dev/null
@@ -0,0 +1,130 @@
+From 6fa632e719eec4d1b1ebf3ddc0b2d667997b057b Mon Sep 17 00:00:00 2001
+From: Luke Nelson <lukenels@cs.washington.edu>
+Date: Fri, 28 Jun 2019 22:57:50 -0700
+Subject: bpf, x32: Fix bug with ALU64 {LSH, RSH, ARSH} BPF_K shift by 0
+
+From: Luke Nelson <lukenels@cs.washington.edu>
+
+commit 6fa632e719eec4d1b1ebf3ddc0b2d667997b057b upstream.
+
+The current x32 BPF JIT does not correctly compile shift operations when
+the immediate shift amount is 0. The expected behavior is for this to
+be a no-op.
+
+The following program demonstrates the bug. The expexceted result is 1,
+but the current JITed code returns 2.
+
+  r0 = 1
+  r1 = 1
+  r1 <<= 0
+  if r1 == 1 goto end
+  r0 = 2
+end:
+  exit
+
+This patch simplifies the code and fixes the bug.
+
+Fixes: 03f5781be2c7 ("bpf, x86_32: add eBPF JIT compiler for ia32")
+Co-developed-by: Xi Wang <xi.wang@gmail.com>
+Signed-off-by: Xi Wang <xi.wang@gmail.com>
+Signed-off-by: Luke Nelson <luke.r.nels@gmail.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Wang YanQing <udknight@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/net/bpf_jit_comp32.c |   63 ++++--------------------------------------
+ 1 file changed, 6 insertions(+), 57 deletions(-)
+
+--- a/arch/x86/net/bpf_jit_comp32.c
++++ b/arch/x86/net/bpf_jit_comp32.c
+@@ -892,27 +892,10 @@ static inline void emit_ia32_lsh_i64(con
+       }
+       /* Do LSH operation */
+       if (val < 32) {
+-              /* shl dreg_hi,imm8 */
+-              EMIT3(0xC1, add_1reg(0xE0, dreg_hi), val);
+-              /* mov ebx,dreg_lo */
+-              EMIT2(0x8B, add_2reg(0xC0, dreg_lo, IA32_EBX));
++              /* shld dreg_hi,dreg_lo,imm8 */
++              EMIT4(0x0F, 0xA4, add_2reg(0xC0, dreg_hi, dreg_lo), val);
+               /* shl dreg_lo,imm8 */
+               EMIT3(0xC1, add_1reg(0xE0, dreg_lo), val);
+-
+-              /* IA32_ECX = 32 - val */
+-              /* mov ecx,val */
+-              EMIT2(0xB1, val);
+-              /* movzx ecx,ecx */
+-              EMIT3(0x0F, 0xB6, add_2reg(0xC0, IA32_ECX, IA32_ECX));
+-              /* neg ecx */
+-              EMIT2(0xF7, add_1reg(0xD8, IA32_ECX));
+-              /* add ecx,32 */
+-              EMIT3(0x83, add_1reg(0xC0, IA32_ECX), 32);
+-
+-              /* shr ebx,cl */
+-              EMIT2(0xD3, add_1reg(0xE8, IA32_EBX));
+-              /* or dreg_hi,ebx */
+-              EMIT2(0x09, add_2reg(0xC0, dreg_hi, IA32_EBX));
+       } else if (val >= 32 && val < 64) {
+               u32 value = val - 32;
+@@ -958,27 +941,10 @@ static inline void emit_ia32_rsh_i64(con
+       /* Do RSH operation */
+       if (val < 32) {
+-              /* shr dreg_lo,imm8 */
+-              EMIT3(0xC1, add_1reg(0xE8, dreg_lo), val);
+-              /* mov ebx,dreg_hi */
+-              EMIT2(0x8B, add_2reg(0xC0, dreg_hi, IA32_EBX));
++              /* shrd dreg_lo,dreg_hi,imm8 */
++              EMIT4(0x0F, 0xAC, add_2reg(0xC0, dreg_lo, dreg_hi), val);
+               /* shr dreg_hi,imm8 */
+               EMIT3(0xC1, add_1reg(0xE8, dreg_hi), val);
+-
+-              /* IA32_ECX = 32 - val */
+-              /* mov ecx,val */
+-              EMIT2(0xB1, val);
+-              /* movzx ecx,ecx */
+-              EMIT3(0x0F, 0xB6, add_2reg(0xC0, IA32_ECX, IA32_ECX));
+-              /* neg ecx */
+-              EMIT2(0xF7, add_1reg(0xD8, IA32_ECX));
+-              /* add ecx,32 */
+-              EMIT3(0x83, add_1reg(0xC0, IA32_ECX), 32);
+-
+-              /* shl ebx,cl */
+-              EMIT2(0xD3, add_1reg(0xE0, IA32_EBX));
+-              /* or dreg_lo,ebx */
+-              EMIT2(0x09, add_2reg(0xC0, dreg_lo, IA32_EBX));
+       } else if (val >= 32 && val < 64) {
+               u32 value = val - 32;
+@@ -1023,27 +989,10 @@ static inline void emit_ia32_arsh_i64(co
+       }
+       /* Do RSH operation */
+       if (val < 32) {
+-              /* shr dreg_lo,imm8 */
+-              EMIT3(0xC1, add_1reg(0xE8, dreg_lo), val);
+-              /* mov ebx,dreg_hi */
+-              EMIT2(0x8B, add_2reg(0xC0, dreg_hi, IA32_EBX));
++              /* shrd dreg_lo,dreg_hi,imm8 */
++              EMIT4(0x0F, 0xAC, add_2reg(0xC0, dreg_lo, dreg_hi), val);
+               /* ashr dreg_hi,imm8 */
+               EMIT3(0xC1, add_1reg(0xF8, dreg_hi), val);
+-
+-              /* IA32_ECX = 32 - val */
+-              /* mov ecx,val */
+-              EMIT2(0xB1, val);
+-              /* movzx ecx,ecx */
+-              EMIT3(0x0F, 0xB6, add_2reg(0xC0, IA32_ECX, IA32_ECX));
+-              /* neg ecx */
+-              EMIT2(0xF7, add_1reg(0xD8, IA32_ECX));
+-              /* add ecx,32 */
+-              EMIT3(0x83, add_1reg(0xC0, IA32_ECX), 32);
+-
+-              /* shl ebx,cl */
+-              EMIT2(0xD3, add_1reg(0xE0, IA32_EBX));
+-              /* or dreg_lo,ebx */
+-              EMIT2(0x09, add_2reg(0xC0, dreg_lo, IA32_EBX));
+       } else if (val >= 32 && val < 64) {
+               u32 value = val - 32;
diff --git a/queue-4.19/bpf-x32-fix-bug-with-alu64-lsh-rsh-arsh-bpf_x-shift-by-0.patch b/queue-4.19/bpf-x32-fix-bug-with-alu64-lsh-rsh-arsh-bpf_x-shift-by-0.patch
new file mode 100644 (file)
index 0000000..eb69b40
--- /dev/null
@@ -0,0 +1,337 @@
+From 68a8357ec15bdce55266e9fba8b8b3b8143fa7d2 Mon Sep 17 00:00:00 2001
+From: Luke Nelson <lukenels@cs.washington.edu>
+Date: Fri, 28 Jun 2019 22:57:49 -0700
+Subject: bpf, x32: Fix bug with ALU64 {LSH, RSH, ARSH} BPF_X shift by 0
+
+From: Luke Nelson <lukenels@cs.washington.edu>
+
+commit 68a8357ec15bdce55266e9fba8b8b3b8143fa7d2 upstream.
+
+The current x32 BPF JIT for shift operations is not correct when the
+shift amount in a register is 0. The expected behavior is a no-op, whereas
+the current implementation changes bits in the destination register.
+
+The following example demonstrates the bug. The expected result of this
+program is 1, but the current JITed code returns 2.
+
+  r0 = 1
+  r1 = 1
+  r2 = 0
+  r1 <<= r2
+  if r1 == 1 goto end
+  r0 = 2
+end:
+  exit
+
+The bug is caused by an incorrect assumption by the JIT that a shift by
+32 clear the register. On x32 however, shifts use the lower 5 bits of
+the source, making a shift by 32 equivalent to a shift by 0.
+
+This patch fixes the bug using double-precision shifts, which also
+simplifies the code.
+
+Fixes: 03f5781be2c7 ("bpf, x86_32: add eBPF JIT compiler for ia32")
+Co-developed-by: Xi Wang <xi.wang@gmail.com>
+Signed-off-by: Xi Wang <xi.wang@gmail.com>
+Signed-off-by: Luke Nelson <luke.r.nels@gmail.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Wang YanQing <udknight@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/net/bpf_jit_comp32.c |  221 ++++--------------------------------------
+ 1 file changed, 23 insertions(+), 198 deletions(-)
+
+--- a/arch/x86/net/bpf_jit_comp32.c
++++ b/arch/x86/net/bpf_jit_comp32.c
+@@ -722,9 +722,6 @@ static inline void emit_ia32_lsh_r64(con
+ {
+       u8 *prog = *pprog;
+       int cnt = 0;
+-      static int jmp_label1 = -1;
+-      static int jmp_label2 = -1;
+-      static int jmp_label3 = -1;
+       u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
+       u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
+@@ -743,79 +740,23 @@ static inline void emit_ia32_lsh_r64(con
+               /* mov ecx,src_lo */
+               EMIT2(0x8B, add_2reg(0xC0, src_lo, IA32_ECX));
+-      /* cmp ecx,32 */
+-      EMIT3(0x83, add_1reg(0xF8, IA32_ECX), 32);
+-      /* Jumps when >= 32 */
+-      if (is_imm8(jmp_label(jmp_label1, 2)))
+-              EMIT2(IA32_JAE, jmp_label(jmp_label1, 2));
+-      else
+-              EMIT2_off32(0x0F, IA32_JAE + 0x10, jmp_label(jmp_label1, 6));
+-
+-      /* < 32 */
+-      /* shl dreg_hi,cl */
+-      EMIT2(0xD3, add_1reg(0xE0, dreg_hi));
+-      /* mov ebx,dreg_lo */
+-      EMIT2(0x8B, add_2reg(0xC0, dreg_lo, IA32_EBX));
++      /* shld dreg_hi,dreg_lo,cl */
++      EMIT3(0x0F, 0xA5, add_2reg(0xC0, dreg_hi, dreg_lo));
+       /* shl dreg_lo,cl */
+       EMIT2(0xD3, add_1reg(0xE0, dreg_lo));
+-      /* IA32_ECX = -IA32_ECX + 32 */
+-      /* neg ecx */
+-      EMIT2(0xF7, add_1reg(0xD8, IA32_ECX));
+-      /* add ecx,32 */
+-      EMIT3(0x83, add_1reg(0xC0, IA32_ECX), 32);
+-
+-      /* shr ebx,cl */
+-      EMIT2(0xD3, add_1reg(0xE8, IA32_EBX));
+-      /* or dreg_hi,ebx */
+-      EMIT2(0x09, add_2reg(0xC0, dreg_hi, IA32_EBX));
+-
+-      /* goto out; */
+-      if (is_imm8(jmp_label(jmp_label3, 2)))
+-              EMIT2(0xEB, jmp_label(jmp_label3, 2));
+-      else
+-              EMIT1_off32(0xE9, jmp_label(jmp_label3, 5));
++      /* if ecx >= 32, mov dreg_lo into dreg_hi and clear dreg_lo */
+-      /* >= 32 */
+-      if (jmp_label1 == -1)
+-              jmp_label1 = cnt;
+-
+-      /* cmp ecx,64 */
+-      EMIT3(0x83, add_1reg(0xF8, IA32_ECX), 64);
+-      /* Jumps when >= 64 */
+-      if (is_imm8(jmp_label(jmp_label2, 2)))
+-              EMIT2(IA32_JAE, jmp_label(jmp_label2, 2));
+-      else
+-              EMIT2_off32(0x0F, IA32_JAE + 0x10, jmp_label(jmp_label2, 6));
++      /* cmp ecx,32 */
++      EMIT3(0x83, add_1reg(0xF8, IA32_ECX), 32);
++      /* skip the next two instructions (4 bytes) when < 32 */
++      EMIT2(IA32_JB, 4);
+-      /* >= 32 && < 64 */
+-      /* sub ecx,32 */
+-      EMIT3(0x83, add_1reg(0xE8, IA32_ECX), 32);
+-      /* shl dreg_lo,cl */
+-      EMIT2(0xD3, add_1reg(0xE0, dreg_lo));
+       /* mov dreg_hi,dreg_lo */
+       EMIT2(0x89, add_2reg(0xC0, dreg_hi, dreg_lo));
+-
+       /* xor dreg_lo,dreg_lo */
+       EMIT2(0x33, add_2reg(0xC0, dreg_lo, dreg_lo));
+-      /* goto out; */
+-      if (is_imm8(jmp_label(jmp_label3, 2)))
+-              EMIT2(0xEB, jmp_label(jmp_label3, 2));
+-      else
+-              EMIT1_off32(0xE9, jmp_label(jmp_label3, 5));
+-
+-      /* >= 64 */
+-      if (jmp_label2 == -1)
+-              jmp_label2 = cnt;
+-      /* xor dreg_lo,dreg_lo */
+-      EMIT2(0x33, add_2reg(0xC0, dreg_lo, dreg_lo));
+-      /* xor dreg_hi,dreg_hi */
+-      EMIT2(0x33, add_2reg(0xC0, dreg_hi, dreg_hi));
+-
+-      if (jmp_label3 == -1)
+-              jmp_label3 = cnt;
+-
+       if (dstk) {
+               /* mov dword ptr [ebp+off],dreg_lo */
+               EMIT3(0x89, add_2reg(0x40, IA32_EBP, dreg_lo),
+@@ -834,9 +775,6 @@ static inline void emit_ia32_arsh_r64(co
+ {
+       u8 *prog = *pprog;
+       int cnt = 0;
+-      static int jmp_label1 = -1;
+-      static int jmp_label2 = -1;
+-      static int jmp_label3 = -1;
+       u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
+       u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
+@@ -855,79 +793,23 @@ static inline void emit_ia32_arsh_r64(co
+               /* mov ecx,src_lo */
+               EMIT2(0x8B, add_2reg(0xC0, src_lo, IA32_ECX));
+-      /* cmp ecx,32 */
+-      EMIT3(0x83, add_1reg(0xF8, IA32_ECX), 32);
+-      /* Jumps when >= 32 */
+-      if (is_imm8(jmp_label(jmp_label1, 2)))
+-              EMIT2(IA32_JAE, jmp_label(jmp_label1, 2));
+-      else
+-              EMIT2_off32(0x0F, IA32_JAE + 0x10, jmp_label(jmp_label1, 6));
+-
+-      /* < 32 */
+-      /* lshr dreg_lo,cl */
+-      EMIT2(0xD3, add_1reg(0xE8, dreg_lo));
+-      /* mov ebx,dreg_hi */
+-      EMIT2(0x8B, add_2reg(0xC0, dreg_hi, IA32_EBX));
+-      /* ashr dreg_hi,cl */
++      /* shrd dreg_lo,dreg_hi,cl */
++      EMIT3(0x0F, 0xAD, add_2reg(0xC0, dreg_lo, dreg_hi));
++      /* sar dreg_hi,cl */
+       EMIT2(0xD3, add_1reg(0xF8, dreg_hi));
+-      /* IA32_ECX = -IA32_ECX + 32 */
+-      /* neg ecx */
+-      EMIT2(0xF7, add_1reg(0xD8, IA32_ECX));
+-      /* add ecx,32 */
+-      EMIT3(0x83, add_1reg(0xC0, IA32_ECX), 32);
+-
+-      /* shl ebx,cl */
+-      EMIT2(0xD3, add_1reg(0xE0, IA32_EBX));
+-      /* or dreg_lo,ebx */
+-      EMIT2(0x09, add_2reg(0xC0, dreg_lo, IA32_EBX));
+-
+-      /* goto out; */
+-      if (is_imm8(jmp_label(jmp_label3, 2)))
+-              EMIT2(0xEB, jmp_label(jmp_label3, 2));
+-      else
+-              EMIT1_off32(0xE9, jmp_label(jmp_label3, 5));
++      /* if ecx >= 32, mov dreg_hi to dreg_lo and set/clear dreg_hi depending on sign */
+-      /* >= 32 */
+-      if (jmp_label1 == -1)
+-              jmp_label1 = cnt;
+-
+-      /* cmp ecx,64 */
+-      EMIT3(0x83, add_1reg(0xF8, IA32_ECX), 64);
+-      /* Jumps when >= 64 */
+-      if (is_imm8(jmp_label(jmp_label2, 2)))
+-              EMIT2(IA32_JAE, jmp_label(jmp_label2, 2));
+-      else
+-              EMIT2_off32(0x0F, IA32_JAE + 0x10, jmp_label(jmp_label2, 6));
++      /* cmp ecx,32 */
++      EMIT3(0x83, add_1reg(0xF8, IA32_ECX), 32);
++      /* skip the next two instructions (5 bytes) when < 32 */
++      EMIT2(IA32_JB, 5);
+-      /* >= 32 && < 64 */
+-      /* sub ecx,32 */
+-      EMIT3(0x83, add_1reg(0xE8, IA32_ECX), 32);
+-      /* ashr dreg_hi,cl */
+-      EMIT2(0xD3, add_1reg(0xF8, dreg_hi));
+       /* mov dreg_lo,dreg_hi */
+       EMIT2(0x89, add_2reg(0xC0, dreg_lo, dreg_hi));
+-
+-      /* ashr dreg_hi,imm8 */
++      /* sar dreg_hi,31 */
+       EMIT3(0xC1, add_1reg(0xF8, dreg_hi), 31);
+-      /* goto out; */
+-      if (is_imm8(jmp_label(jmp_label3, 2)))
+-              EMIT2(0xEB, jmp_label(jmp_label3, 2));
+-      else
+-              EMIT1_off32(0xE9, jmp_label(jmp_label3, 5));
+-
+-      /* >= 64 */
+-      if (jmp_label2 == -1)
+-              jmp_label2 = cnt;
+-      /* ashr dreg_hi,imm8 */
+-      EMIT3(0xC1, add_1reg(0xF8, dreg_hi), 31);
+-      /* mov dreg_lo,dreg_hi */
+-      EMIT2(0x89, add_2reg(0xC0, dreg_lo, dreg_hi));
+-
+-      if (jmp_label3 == -1)
+-              jmp_label3 = cnt;
+-
+       if (dstk) {
+               /* mov dword ptr [ebp+off],dreg_lo */
+               EMIT3(0x89, add_2reg(0x40, IA32_EBP, dreg_lo),
+@@ -946,9 +828,6 @@ static inline void emit_ia32_rsh_r64(con
+ {
+       u8 *prog = *pprog;
+       int cnt = 0;
+-      static int jmp_label1 = -1;
+-      static int jmp_label2 = -1;
+-      static int jmp_label3 = -1;
+       u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
+       u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
+@@ -967,77 +846,23 @@ static inline void emit_ia32_rsh_r64(con
+               /* mov ecx,src_lo */
+               EMIT2(0x8B, add_2reg(0xC0, src_lo, IA32_ECX));
+-      /* cmp ecx,32 */
+-      EMIT3(0x83, add_1reg(0xF8, IA32_ECX), 32);
+-      /* Jumps when >= 32 */
+-      if (is_imm8(jmp_label(jmp_label1, 2)))
+-              EMIT2(IA32_JAE, jmp_label(jmp_label1, 2));
+-      else
+-              EMIT2_off32(0x0F, IA32_JAE + 0x10, jmp_label(jmp_label1, 6));
+-
+-      /* < 32 */
+-      /* lshr dreg_lo,cl */
+-      EMIT2(0xD3, add_1reg(0xE8, dreg_lo));
+-      /* mov ebx,dreg_hi */
+-      EMIT2(0x8B, add_2reg(0xC0, dreg_hi, IA32_EBX));
++      /* shrd dreg_lo,dreg_hi,cl */
++      EMIT3(0x0F, 0xAD, add_2reg(0xC0, dreg_lo, dreg_hi));
+       /* shr dreg_hi,cl */
+       EMIT2(0xD3, add_1reg(0xE8, dreg_hi));
+-      /* IA32_ECX = -IA32_ECX + 32 */
+-      /* neg ecx */
+-      EMIT2(0xF7, add_1reg(0xD8, IA32_ECX));
+-      /* add ecx,32 */
+-      EMIT3(0x83, add_1reg(0xC0, IA32_ECX), 32);
+-
+-      /* shl ebx,cl */
+-      EMIT2(0xD3, add_1reg(0xE0, IA32_EBX));
+-      /* or dreg_lo,ebx */
+-      EMIT2(0x09, add_2reg(0xC0, dreg_lo, IA32_EBX));
+-
+-      /* goto out; */
+-      if (is_imm8(jmp_label(jmp_label3, 2)))
+-              EMIT2(0xEB, jmp_label(jmp_label3, 2));
+-      else
+-              EMIT1_off32(0xE9, jmp_label(jmp_label3, 5));
++      /* if ecx >= 32, mov dreg_hi to dreg_lo and clear dreg_hi */
+-      /* >= 32 */
+-      if (jmp_label1 == -1)
+-              jmp_label1 = cnt;
+-      /* cmp ecx,64 */
+-      EMIT3(0x83, add_1reg(0xF8, IA32_ECX), 64);
+-      /* Jumps when >= 64 */
+-      if (is_imm8(jmp_label(jmp_label2, 2)))
+-              EMIT2(IA32_JAE, jmp_label(jmp_label2, 2));
+-      else
+-              EMIT2_off32(0x0F, IA32_JAE + 0x10, jmp_label(jmp_label2, 6));
++      /* cmp ecx,32 */
++      EMIT3(0x83, add_1reg(0xF8, IA32_ECX), 32);
++      /* skip the next two instructions (4 bytes) when < 32 */
++      EMIT2(IA32_JB, 4);
+-      /* >= 32 && < 64 */
+-      /* sub ecx,32 */
+-      EMIT3(0x83, add_1reg(0xE8, IA32_ECX), 32);
+-      /* shr dreg_hi,cl */
+-      EMIT2(0xD3, add_1reg(0xE8, dreg_hi));
+       /* mov dreg_lo,dreg_hi */
+       EMIT2(0x89, add_2reg(0xC0, dreg_lo, dreg_hi));
+       /* xor dreg_hi,dreg_hi */
+       EMIT2(0x33, add_2reg(0xC0, dreg_hi, dreg_hi));
+-      /* goto out; */
+-      if (is_imm8(jmp_label(jmp_label3, 2)))
+-              EMIT2(0xEB, jmp_label(jmp_label3, 2));
+-      else
+-              EMIT1_off32(0xE9, jmp_label(jmp_label3, 5));
+-
+-      /* >= 64 */
+-      if (jmp_label2 == -1)
+-              jmp_label2 = cnt;
+-      /* xor dreg_lo,dreg_lo */
+-      EMIT2(0x33, add_2reg(0xC0, dreg_lo, dreg_lo));
+-      /* xor dreg_hi,dreg_hi */
+-      EMIT2(0x33, add_2reg(0xC0, dreg_hi, dreg_hi));
+-
+-      if (jmp_label3 == -1)
+-              jmp_label3 = cnt;
+-
+       if (dstk) {
+               /* mov dword ptr [ebp+off],dreg_lo */
+               EMIT3(0x89, add_2reg(0x40, IA32_EBP, dreg_lo),
index e7caf57e7287d71fe4eeb7ebcd73258d209d666f..d3294be4287d692f1690884f91696da44bf8adb7 100644 (file)
@@ -8,3 +8,7 @@ mm-memory_hotplug-don-t-access-uninitialized-memmaps-in-shrink_pgdat_span.patch
 mm-memory_hotplug-fix-updating-the-node-span.patch
 arm64-uaccess-ensure-pan-is-re-enabled-after-unhandled-uaccess-fault.patch
 fbdev-ditch-fb_edid_add_monspecs.patch
+bpf-x32-fix-bug-for-bpf_alu64-bpf_neg.patch
+bpf-x32-fix-bug-with-alu64-lsh-rsh-arsh-bpf_x-shift-by-0.patch
+bpf-x32-fix-bug-with-alu64-lsh-rsh-arsh-bpf_k-shift-by-0.patch
+bpf-x32-fix-bug-for-bpf_jmp-bpf_jsgt-bpf_jsle-bpf_jslt-bpf_jsge.patch