diff mbox series

[v2,04/13] bpf: move tmp variable into ax register in interpreter

Message ID 1551982504-12597-1-git-send-email-tyhicks@canonical.com
State New
Headers show
Series None | expand

Commit Message

Tyler Hicks March 7, 2019, 6:15 p.m. UTC
From: Daniel Borkmann <daniel@iogearbox.net>

This change moves the on-stack 64 bit tmp variable in ___bpf_prog_run()
into the hidden ax register. The latter is currently only used in JITs
for constant blinding as a temporary scratch register, meaning the BPF
interpreter will never see the use of ax. Therefore it is safe to use
it for the cases where tmp has been used earlier. This is needed to later
on allow restricted hidden use of ax in both interpreter and JITs.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

CVE-2019-7308

(backported from commit 144cd91c4c2bced6eb8a7e25e590f6618a11e854)
[tyhicks: Backport around context changes and missing commits
 1ea47e01ad6e and e0cea7ce988c]
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: You-Sheng Yang <vicamo.yang@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
---

* Changes since v1:
  - There were three additional uses of the tmp variable in ___bpf_prog_run()
    that needed to be converted to AX in order to fix a build failure seen with
    our i386 kernel config.

 include/linux/filter.h |  3 ++-
 kernel/bpf/core.c      | 38 +++++++++++++++++++-------------------
 2 files changed, 21 insertions(+), 20 deletions(-)

Comments

Juerg Haefliger March 8, 2019, 8:26 a.m. UTC | #1
This v2 patch came in after v1 has already been applied. I took the liberty to
replace v1 with v2 and force push bionic/master-next.

...Juerg


> From: Daniel Borkmann <daniel@iogearbox.net>
> 
> This change moves the on-stack 64 bit tmp variable in ___bpf_prog_run()
> into the hidden ax register. The latter is currently only used in JITs
> for constant blinding as a temporary scratch register, meaning the BPF
> interpreter will never see the use of ax. Therefore it is safe to use
> it for the cases where tmp has been used earlier. This is needed to later
> on allow restricted hidden use of ax in both interpreter and JITs.
> 
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> Acked-by: Alexei Starovoitov <ast@kernel.org>
> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
> 
> CVE-2019-7308
> 
> (backported from commit 144cd91c4c2bced6eb8a7e25e590f6618a11e854)
> [tyhicks: Backport around context changes and missing commits
>  1ea47e01ad6e and e0cea7ce988c]
> Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
> Acked-by: You-Sheng Yang <vicamo.yang@canonical.com>
> Acked-by: Stefan Bader <stefan.bader@canonical.com>
> Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
> ---
> 
> * Changes since v1:
>   - There were three additional uses of the tmp variable in ___bpf_prog_run()
>     that needed to be converted to AX in order to fix a build failure seen with
>     our i386 kernel config.
> 
>  include/linux/filter.h |  3 ++-
>  kernel/bpf/core.c      | 38 +++++++++++++++++++-------------------
>  2 files changed, 21 insertions(+), 20 deletions(-)
> 
> diff --git a/include/linux/filter.h b/include/linux/filter.h
> index e85292a16467..ec944f15f1a4 100644
> --- a/include/linux/filter.h
> +++ b/include/linux/filter.h
> @@ -53,7 +53,8 @@ struct bpf_prog_aux;
>   * constants. See JIT pre-step in bpf_jit_blind_constants().
>   */
>  #define BPF_REG_AX		MAX_BPF_REG
> -#define MAX_BPF_JIT_REG		(MAX_BPF_REG + 1)
> +#define MAX_BPF_EXT_REG		(MAX_BPF_REG + 1)
> +#define MAX_BPF_JIT_REG		MAX_BPF_EXT_REG
>  
>  /* unused opcode to mark special call to bpf_tail_call() helper */
>  #define BPF_TAIL_CALL	0xf0
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index 7949e8b8f94e..439574daf1f0 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -51,6 +51,7 @@
>  #define DST	regs[insn->dst_reg]
>  #define SRC	regs[insn->src_reg]
>  #define FP	regs[BPF_REG_FP]
> +#define AX	regs[BPF_REG_AX]
>  #define ARG1	regs[BPF_REG_ARG1]
>  #define CTX	regs[BPF_REG_CTX]
>  #define IMM	insn->imm
> @@ -778,7 +779,6 @@ EXPORT_SYMBOL_GPL(__bpf_call_base);
>  static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
>  				    u64 *stack)
>  {
> -	u64 tmp;
>  	static const void *jumptable[256] = {
>  		[0 ... 255] = &&default_label,
>  		/* Now overwrite non-defaults ... */
> @@ -952,22 +952,22 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
>  	ALU64_MOD_X:
>  		if (unlikely(SRC == 0))
>  			return 0;
> -		div64_u64_rem(DST, SRC, &tmp);
> -		DST = tmp;
> +		div64_u64_rem(DST, SRC, &AX);
> +		DST = AX;
>  		CONT;
>  	ALU_MOD_X:
>  		if (unlikely((u32)SRC == 0))
>  			return 0;
> -		tmp = (u32) DST;
> -		DST = do_div(tmp, (u32) SRC);
> +		AX = (u32) DST;
> +		DST = do_div(AX, (u32) SRC);
>  		CONT;
>  	ALU64_MOD_K:
> -		div64_u64_rem(DST, IMM, &tmp);
> -		DST = tmp;
> +		div64_u64_rem(DST, IMM, &AX);
> +		DST = AX;
>  		CONT;
>  	ALU_MOD_K:
> -		tmp = (u32) DST;
> -		DST = do_div(tmp, (u32) IMM);
> +		AX = (u32) DST;
> +		DST = do_div(AX, (u32) IMM);
>  		CONT;
>  	ALU64_DIV_X:
>  		if (unlikely(SRC == 0))
> @@ -977,17 +977,17 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
>  	ALU_DIV_X:
>  		if (unlikely((u32)SRC == 0))
>  			return 0;
> -		tmp = (u32) DST;
> -		do_div(tmp, (u32) SRC);
> -		DST = (u32) tmp;
> +		AX = (u32) DST;
> +		do_div(AX, (u32) SRC);
> +		DST = (u32) AX;
>  		CONT;
>  	ALU64_DIV_K:
>  		DST = div64_u64(DST, IMM);
>  		CONT;
>  	ALU_DIV_K:
> -		tmp = (u32) DST;
> -		do_div(tmp, (u32) IMM);
> -		DST = (u32) tmp;
> +		AX = (u32) DST;
> +		do_div(AX, (u32) IMM);
> +		DST = (u32) AX;
>  		CONT;
>  	ALU_END_TO_BE:
>  		switch (IMM) {
> @@ -1242,7 +1242,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
>  		 *   BPF_R0 - 8/16/32-bit skb data converted to cpu endianness
>  		 */
>  
> -		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp);
> +		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &AX);
>  		if (likely(ptr != NULL)) {
>  			BPF_R0 = get_unaligned_be32(ptr);
>  			CONT;
> @@ -1252,7 +1252,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
>  	LD_ABS_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + imm32)) */
>  		off = IMM;
>  load_half:
> -		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp);
> +		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &AX);
>  		if (likely(ptr != NULL)) {
>  			BPF_R0 = get_unaligned_be16(ptr);
>  			CONT;
> @@ -1262,7 +1262,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
>  	LD_ABS_B: /* BPF_R0 = *(u8 *) (skb->data + imm32) */
>  		off = IMM;
>  load_byte:
> -		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp);
> +		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &AX);
>  		if (likely(ptr != NULL)) {
>  			BPF_R0 = *(u8 *)ptr;
>  			CONT;
> @@ -1291,7 +1291,7 @@ STACK_FRAME_NON_STANDARD(___bpf_prog_run); /* jump table */
>  static unsigned int PROG_NAME(stack_size)(const void *ctx, const struct bpf_insn *insn) \
>  { \
>  	u64 stack[stack_size / sizeof(u64)]; \
> -	u64 regs[MAX_BPF_REG]; \
> +	u64 regs[MAX_BPF_EXT_REG]; \
>  \
>  	FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; \
>  	ARG1 = (u64) (unsigned long) ctx; \
diff mbox series

Patch

diff --git a/include/linux/filter.h b/include/linux/filter.h
index e85292a16467..ec944f15f1a4 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -53,7 +53,8 @@  struct bpf_prog_aux;
  * constants. See JIT pre-step in bpf_jit_blind_constants().
  */
 #define BPF_REG_AX		MAX_BPF_REG
-#define MAX_BPF_JIT_REG		(MAX_BPF_REG + 1)
+#define MAX_BPF_EXT_REG		(MAX_BPF_REG + 1)
+#define MAX_BPF_JIT_REG		MAX_BPF_EXT_REG
 
 /* unused opcode to mark special call to bpf_tail_call() helper */
 #define BPF_TAIL_CALL	0xf0
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 7949e8b8f94e..439574daf1f0 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -51,6 +51,7 @@ 
 #define DST	regs[insn->dst_reg]
 #define SRC	regs[insn->src_reg]
 #define FP	regs[BPF_REG_FP]
+#define AX	regs[BPF_REG_AX]
 #define ARG1	regs[BPF_REG_ARG1]
 #define CTX	regs[BPF_REG_CTX]
 #define IMM	insn->imm
@@ -778,7 +779,6 @@  EXPORT_SYMBOL_GPL(__bpf_call_base);
 static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
 				    u64 *stack)
 {
-	u64 tmp;
 	static const void *jumptable[256] = {
 		[0 ... 255] = &&default_label,
 		/* Now overwrite non-defaults ... */
@@ -952,22 +952,22 @@  static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
 	ALU64_MOD_X:
 		if (unlikely(SRC == 0))
 			return 0;
-		div64_u64_rem(DST, SRC, &tmp);
-		DST = tmp;
+		div64_u64_rem(DST, SRC, &AX);
+		DST = AX;
 		CONT;
 	ALU_MOD_X:
 		if (unlikely((u32)SRC == 0))
 			return 0;
-		tmp = (u32) DST;
-		DST = do_div(tmp, (u32) SRC);
+		AX = (u32) DST;
+		DST = do_div(AX, (u32) SRC);
 		CONT;
 	ALU64_MOD_K:
-		div64_u64_rem(DST, IMM, &tmp);
-		DST = tmp;
+		div64_u64_rem(DST, IMM, &AX);
+		DST = AX;
 		CONT;
 	ALU_MOD_K:
-		tmp = (u32) DST;
-		DST = do_div(tmp, (u32) IMM);
+		AX = (u32) DST;
+		DST = do_div(AX, (u32) IMM);
 		CONT;
 	ALU64_DIV_X:
 		if (unlikely(SRC == 0))
@@ -977,17 +977,17 @@  static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
 	ALU_DIV_X:
 		if (unlikely((u32)SRC == 0))
 			return 0;
-		tmp = (u32) DST;
-		do_div(tmp, (u32) SRC);
-		DST = (u32) tmp;
+		AX = (u32) DST;
+		do_div(AX, (u32) SRC);
+		DST = (u32) AX;
 		CONT;
 	ALU64_DIV_K:
 		DST = div64_u64(DST, IMM);
 		CONT;
 	ALU_DIV_K:
-		tmp = (u32) DST;
-		do_div(tmp, (u32) IMM);
-		DST = (u32) tmp;
+		AX = (u32) DST;
+		do_div(AX, (u32) IMM);
+		DST = (u32) AX;
 		CONT;
 	ALU_END_TO_BE:
 		switch (IMM) {
@@ -1242,7 +1242,7 @@  static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
 		 *   BPF_R0 - 8/16/32-bit skb data converted to cpu endianness
 		 */
 
-		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp);
+		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &AX);
 		if (likely(ptr != NULL)) {
 			BPF_R0 = get_unaligned_be32(ptr);
 			CONT;
@@ -1252,7 +1252,7 @@  static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
 	LD_ABS_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + imm32)) */
 		off = IMM;
 load_half:
-		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp);
+		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &AX);
 		if (likely(ptr != NULL)) {
 			BPF_R0 = get_unaligned_be16(ptr);
 			CONT;
@@ -1262,7 +1262,7 @@  static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
 	LD_ABS_B: /* BPF_R0 = *(u8 *) (skb->data + imm32) */
 		off = IMM;
 load_byte:
-		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp);
+		ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &AX);
 		if (likely(ptr != NULL)) {
 			BPF_R0 = *(u8 *)ptr;
 			CONT;
@@ -1291,7 +1291,7 @@  STACK_FRAME_NON_STANDARD(___bpf_prog_run); /* jump table */
 static unsigned int PROG_NAME(stack_size)(const void *ctx, const struct bpf_insn *insn) \
 { \
 	u64 stack[stack_size / sizeof(u64)]; \
-	u64 regs[MAX_BPF_REG]; \
+	u64 regs[MAX_BPF_EXT_REG]; \
 \
 	FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; \
 	ARG1 = (u64) (unsigned long) ctx; \