Commit 6e2d91c6 authored by Alexei Starovoitov's avatar Alexei Starovoitov Committed by Greg Kroah-Hartman

sparc: bpf_jit: fix support for ldx/stx mem and SKF_AD_VLAN_TAG

[ Upstream commit f6f2332d ]

fix several issues in sparc BPF JIT compiler.

ldx/stx related:
. classic BPF instructions that access mem[] slots were not setting
  SEEN_MEM flag, so stack wasn't allocated. Fix that by advertising
  correct flags

. LDX/STX instructions were missing SEEN_XREG, so register value
  could have leaked to user space. Fix it.

. since stack for mem[] slots is allocated with 'sub %sp' instead
  of 'save %sp', use %sp as base register instead of %fp.

. ldx mem[0] means first slot in classic BPF which should have
  -4 offset instead of 0.

. sparc64 needs 2047 stack bias as per ABI to access stack

. emit_stmem() was using LD32I macro instead of ST32I

SKF_AD_VLAN_TAG* related:
. SKF_AD_VLAN_TAG_PRESENT must return 1 or 0 instead of '> 0' or 0
  as per classic BPF de facto standard

. SKF_AD_VLAN_TAG needs to mask the field correctly

Fixes: 2809a208 ("net: filter: Just In Time compiler for sparc")
Signed-off-by: default avatarAlexei Starovoitov <ast@plumgrid.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a068a292
...@@ -234,12 +234,18 @@ do { BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u8)); \ ...@@ -234,12 +234,18 @@ do { BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u8)); \
__emit_load8(BASE, STRUCT, FIELD, DEST); \ __emit_load8(BASE, STRUCT, FIELD, DEST); \
} while (0) } while (0)
#define emit_ldmem(OFF, DEST) \ #ifdef CONFIG_SPARC64
do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(DEST); \ #define BIAS (STACK_BIAS - 4)
#else
#define BIAS (-4)
#endif
#define emit_ldmem(OFF, DEST) \
do { *prog++ = LD32I | RS1(SP) | S13(BIAS - (OFF)) | RD(DEST); \
} while (0) } while (0)
#define emit_stmem(OFF, SRC) \ #define emit_stmem(OFF, SRC) \
do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(SRC); \ do { *prog++ = ST32I | RS1(SP) | S13(BIAS - (OFF)) | RD(SRC); \
} while (0) } while (0)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -615,10 +621,11 @@ void bpf_jit_compile(struct sk_filter *fp) ...@@ -615,10 +621,11 @@ void bpf_jit_compile(struct sk_filter *fp)
case BPF_ANC | SKF_AD_VLAN_TAG: case BPF_ANC | SKF_AD_VLAN_TAG:
case BPF_ANC | SKF_AD_VLAN_TAG_PRESENT: case BPF_ANC | SKF_AD_VLAN_TAG_PRESENT:
emit_skb_load16(vlan_tci, r_A); emit_skb_load16(vlan_tci, r_A);
if (code == (BPF_ANC | SKF_AD_VLAN_TAG)) { if (code != (BPF_ANC | SKF_AD_VLAN_TAG)) {
emit_andi(r_A, VLAN_VID_MASK, r_A); emit_alu_K(SRL, 12);
emit_andi(r_A, 1, r_A);
} else { } else {
emit_loadimm(VLAN_TAG_PRESENT, r_TMP); emit_loadimm(~VLAN_TAG_PRESENT, r_TMP);
emit_and(r_A, r_TMP, r_A); emit_and(r_A, r_TMP, r_A);
} }
break; break;
...@@ -630,15 +637,19 @@ void bpf_jit_compile(struct sk_filter *fp) ...@@ -630,15 +637,19 @@ void bpf_jit_compile(struct sk_filter *fp)
emit_loadimm(K, r_X); emit_loadimm(K, r_X);
break; break;
case BPF_LD | BPF_MEM: case BPF_LD | BPF_MEM:
seen |= SEEN_MEM;
emit_ldmem(K * 4, r_A); emit_ldmem(K * 4, r_A);
break; break;
case BPF_LDX | BPF_MEM: case BPF_LDX | BPF_MEM:
seen |= SEEN_MEM | SEEN_XREG;
emit_ldmem(K * 4, r_X); emit_ldmem(K * 4, r_X);
break; break;
case BPF_ST: case BPF_ST:
seen |= SEEN_MEM;
emit_stmem(K * 4, r_A); emit_stmem(K * 4, r_A);
break; break;
case BPF_STX: case BPF_STX:
seen |= SEEN_MEM | SEEN_XREG;
emit_stmem(K * 4, r_X); emit_stmem(K * 4, r_X);
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment