Jiri Slaby a4a332
From: Luke Nelson <lukenels@cs.washington.edu>
Jiri Slaby a4a332
Date: Sat, 18 Apr 2020 16:26:53 -0700
Jiri Slaby a4a332
Subject: bpf, x86: Fix encoding for lower 8-bit registers in BPF_STX BPF_B
Jiri Slaby a4a332
Git-commit: aee194b14dd2b2bde6252b3acf57d36dccfc743a
Jiri Slaby a4a332
Patch-mainline: 5.7-rc3
Jiri Slaby a4a332
References: git-fixes
Jiri Slaby a4a332
Jiri Slaby a4a332
This patch fixes an encoding bug in emit_stx for BPF_B when the source
Jiri Slaby a4a332
register is BPF_REG_FP.
Jiri Slaby a4a332
Jiri Slaby a4a332
The current implementation for BPF_STX BPF_B in emit_stx saves one REX
Jiri Slaby a4a332
byte when the operands can be encoded using Mod-R/M alone. The lower 8
Jiri Slaby a4a332
bits of registers %rax, %rbx, %rcx, and %rdx can be accessed without using
Jiri Slaby a4a332
a REX prefix via %al, %bl, %cl, and %dl, respectively. Other registers,
Jiri Slaby a4a332
(e.g., %rsi, %rdi, %rbp, %rsp) require a REX prefix to use their 8-bit
Jiri Slaby a4a332
equivalents (%sil, %dil, %bpl, %spl).
Jiri Slaby a4a332
Jiri Slaby a4a332
The current code checks if the source for BPF_STX BPF_B is BPF_REG_1
Jiri Slaby a4a332
or BPF_REG_2 (which map to %rdi and %rsi), in which case it emits the
Jiri Slaby a4a332
required REX prefix. However, it misses the case when the source is
Jiri Slaby a4a332
BPF_REG_FP (mapped to %rbp).
Jiri Slaby a4a332
Jiri Slaby a4a332
The result is that BPF_STX BPF_B with BPF_REG_FP as the source operand
Jiri Slaby a4a332
will read from register %ch instead of the correct %bpl. This patch fixes
Jiri Slaby a4a332
the problem by fixing and refactoring the check on which registers need
Jiri Slaby a4a332
the extra REX byte. Since no BPF registers map to %rsp, there is no need
Jiri Slaby a4a332
to handle %spl.
Jiri Slaby a4a332
Jiri Slaby a4a332
Fixes: 622582786c9e0 ("net: filter: x86: internal BPF JIT")
Jiri Slaby a4a332
Signed-off-by: Xi Wang <xi.wang@gmail.com>
Jiri Slaby a4a332
Signed-off-by: Luke Nelson <luke.r.nels@gmail.com>
Jiri Slaby a4a332
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Jiri Slaby a4a332
Link: https://lore.kernel.org/bpf/20200418232655.23870-1-luke.r.nels@gmail.com
Jiri Slaby a4a332
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Jiri Slaby a4a332
---
Jiri Slaby a4a332
 arch/x86/net/bpf_jit_comp.c |   18 +++++++++++++++---
Jiri Slaby a4a332
 1 file changed, 15 insertions(+), 3 deletions(-)
Jiri Slaby a4a332
Jiri Slaby a4a332
--- a/arch/x86/net/bpf_jit_comp.c
Jiri Slaby a4a332
+++ b/arch/x86/net/bpf_jit_comp.c
Jiri Slaby a4a332
@@ -146,6 +146,19 @@ static bool is_ereg(u32 reg)
Jiri Slaby a4a332
 			     BIT(BPF_REG_AX));
Jiri Slaby a4a332
 }
Jiri Slaby a4a332
 
Jiri Slaby a4a332
+/*
Jiri Slaby a4a332
+ * is_ereg_8l() == true if BPF register 'reg' is mapped to access x86-64
Jiri Slaby a4a332
+ * lower 8-bit registers dil,sil,bpl,spl,r8b..r15b, which need extra byte
Jiri Slaby a4a332
+ * of encoding. al,cl,dl,bl have simpler encoding.
Jiri Slaby a4a332
+ */
Jiri Slaby a4a332
+static bool is_ereg_8l(u32 reg)
Jiri Slaby a4a332
+{
Jiri Slaby a4a332
+	return is_ereg(reg) ||
Jiri Slaby a4a332
+	    (1 << reg) & (BIT(BPF_REG_1) |
Jiri Slaby a4a332
+			  BIT(BPF_REG_2) |
Jiri Slaby a4a332
+			  BIT(BPF_REG_FP));
Jiri Slaby a4a332
+}
Jiri Slaby a4a332
+
Jiri Slaby a4a332
 /* add modifiers if 'reg' maps to x64 registers r8..r15 */
Jiri Slaby a4a332
 static u8 add_1mod(u8 byte, u32 reg)
Jiri Slaby a4a332
 {
Jiri Slaby a4a332
@@ -720,9 +733,8 @@ st:			if (is_imm8(insn->off))
Jiri Slaby a4a332
 			/* STX: *(u8*)(dst_reg + off) = src_reg */
Jiri Slaby a4a332
 		case BPF_STX | BPF_MEM | BPF_B:
Jiri Slaby a4a332
 			/* emit 'mov byte ptr [rax + off], al' */
Jiri Slaby a4a332
-			if (is_ereg(dst_reg) || is_ereg(src_reg) ||
Jiri Slaby a4a332
-			    /* have to add extra byte for x86 SIL, DIL regs */
Jiri Slaby a4a332
-			    src_reg == BPF_REG_1 || src_reg == BPF_REG_2)
Jiri Slaby a4a332
+			if (is_ereg(dst_reg) || is_ereg_8l(src_reg))
Jiri Slaby a4a332
+				/* Add extra byte for eregs or SIL,DIL,BPL in src_reg */
Jiri Slaby a4a332
 				EMIT2(add_2mod(0x40, dst_reg, src_reg), 0x88);
Jiri Slaby a4a332
 			else
Jiri Slaby a4a332
 				EMIT1(0x88);