* [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler
@ 2021-10-12 12:30 ` Hari Bathini
0 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev, Hari Bathini
Patch #1 & #2 are simple cleanup patches. Patch #3 refactors JIT
compiler code with the aim to simplify adding BPF_PROBE_MEM support.
Patch #4 introduces PPC_RAW_BRANCH() macro instead of open coding
branch instruction. Patch #5 & #7 add BPF_PROBE_MEM support for PPC64
& PPC32 JIT compilers respectively. Patch #6 & #8 handle bad userspace
pointers for PPC64 & PPC32 cases respectively.
Resending v4 after rebasing the series on top of bpf fix patches
posted by Naveen:
- https://patchwork.ozlabs.org/project/linuxppc-dev/cover/cover.1633464148.git.naveen.n.rao@linux.vnet.ibm.com/
("[v2,00/10] powerpc/bpf: Various fixes")
Also, added Reviewed-by tag from Christophe for patches #3, #5, #6, #7 & #8.
Hari Bathini (4):
bpf powerpc: refactor JIT compiler code
powerpc/ppc-opcode: introduce PPC_RAW_BRANCH() macro
bpf ppc32: Add BPF_PROBE_MEM support for JIT
bpf ppc32: Access only if addr is kernel address
Ravi Bangoria (4):
bpf powerpc: Remove unused SEEN_STACK
bpf powerpc: Remove extra_pass from bpf_jit_build_body()
bpf ppc64: Add BPF_PROBE_MEM support for JIT
bpf ppc64: Access only if addr is kernel address
arch/powerpc/include/asm/ppc-opcode.h | 2 +
arch/powerpc/net/bpf_jit.h | 17 ++++-
arch/powerpc/net/bpf_jit_comp.c | 68 +++++++++++++++--
arch/powerpc/net/bpf_jit_comp32.c | 101 ++++++++++++++++++++++----
arch/powerpc/net/bpf_jit_comp64.c | 72 ++++++++++++++----
5 files changed, 219 insertions(+), 41 deletions(-)
--
2.31.1
^ permalink raw reply [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler
@ 2021-10-12 12:30 ` Hari Bathini
0 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: songliubraving, netdev, john.fastabend, andrii, kpsingh, paulus,
yhs, bpf, linuxppc-dev, kafai, Hari Bathini
Patch #1 & #2 are simple cleanup patches. Patch #3 refactors JIT
compiler code with the aim to simplify adding BPF_PROBE_MEM support.
Patch #4 introduces PPC_RAW_BRANCH() macro instead of open coding
branch instruction. Patch #5 & #7 add BPF_PROBE_MEM support for PPC64
& PPC32 JIT compilers respectively. Patch #6 & #8 handle bad userspace
pointers for PPC64 & PPC32 cases respectively.
Resending v4 after rebasing the series on top of bpf fix patches
posted by Naveen:
- https://patchwork.ozlabs.org/project/linuxppc-dev/cover/cover.1633464148.git.naveen.n.rao@linux.vnet.ibm.com/
("[v2,00/10] powerpc/bpf: Various fixes")
Also, added Reviewed-by tag from Christophe for patches #3, #5, #6, #7 & #8.
Hari Bathini (4):
bpf powerpc: refactor JIT compiler code
powerpc/ppc-opcode: introduce PPC_RAW_BRANCH() macro
bpf ppc32: Add BPF_PROBE_MEM support for JIT
bpf ppc32: Access only if addr is kernel address
Ravi Bangoria (4):
bpf powerpc: Remove unused SEEN_STACK
bpf powerpc: Remove extra_pass from bpf_jit_build_body()
bpf ppc64: Add BPF_PROBE_MEM support for JIT
bpf ppc64: Access only if addr is kernel address
arch/powerpc/include/asm/ppc-opcode.h | 2 +
arch/powerpc/net/bpf_jit.h | 17 ++++-
arch/powerpc/net/bpf_jit_comp.c | 68 +++++++++++++++--
arch/powerpc/net/bpf_jit_comp32.c | 101 ++++++++++++++++++++++----
arch/powerpc/net/bpf_jit_comp64.c | 72 ++++++++++++++----
5 files changed, 219 insertions(+), 41 deletions(-)
--
2.31.1
^ permalink raw reply [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 1/8] bpf powerpc: Remove unused SEEN_STACK
2021-10-12 12:30 ` Hari Bathini
@ 2021-10-12 12:30 ` Hari Bathini
-1 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev, Ravi Bangoria
From: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
SEEN_STACK is unused on PowerPC. Remove it. Also, have
SEEN_TAILCALL use 0x40000000.
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
* No changes in v4.
arch/powerpc/net/bpf_jit.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 7e9b978b768e..89bd744c2bff 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -125,8 +125,7 @@
#define COND_LE (CR0_GT | COND_CMP_FALSE)
#define SEEN_FUNC 0x20000000 /* might call external helpers */
-#define SEEN_STACK 0x40000000 /* uses BPF stack */
-#define SEEN_TAILCALL 0x80000000 /* uses tail calls */
+#define SEEN_TAILCALL 0x40000000 /* uses tail calls */
#define SEEN_VREG_MASK 0x1ff80000 /* Volatile registers r3-r12 */
#define SEEN_NVREG_MASK 0x0003ffff /* Non volatile registers r14-r31 */
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 1/8] bpf powerpc: Remove unused SEEN_STACK
@ 2021-10-12 12:30 ` Hari Bathini
0 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: Ravi Bangoria, songliubraving, netdev, john.fastabend, andrii,
kpsingh, paulus, yhs, bpf, linuxppc-dev, kafai
From: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
SEEN_STACK is unused on PowerPC. Remove it. Also, have
SEEN_TAILCALL use 0x40000000.
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
* No changes in v4.
arch/powerpc/net/bpf_jit.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 7e9b978b768e..89bd744c2bff 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -125,8 +125,7 @@
#define COND_LE (CR0_GT | COND_CMP_FALSE)
#define SEEN_FUNC 0x20000000 /* might call external helpers */
-#define SEEN_STACK 0x40000000 /* uses BPF stack */
-#define SEEN_TAILCALL 0x80000000 /* uses tail calls */
+#define SEEN_TAILCALL 0x40000000 /* uses tail calls */
#define SEEN_VREG_MASK 0x1ff80000 /* Volatile registers r3-r12 */
#define SEEN_NVREG_MASK 0x0003ffff /* Non volatile registers r14-r31 */
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 2/8] bpf powerpc: Remove extra_pass from bpf_jit_build_body()
2021-10-12 12:30 ` Hari Bathini
@ 2021-10-12 12:30 ` Hari Bathini
-1 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev, Ravi Bangoria
From: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
In case of extra_pass, usual JIT passes are always skipped. So,
extra_pass is always false while calling bpf_jit_build_body() and
can be removed.
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
---
* No changes in v4.
arch/powerpc/net/bpf_jit.h | 2 +-
arch/powerpc/net/bpf_jit_comp.c | 6 +++---
arch/powerpc/net/bpf_jit_comp32.c | 4 ++--
arch/powerpc/net/bpf_jit_comp64.c | 4 ++--
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 89bd744c2bff..7145b651fc2a 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -175,7 +175,7 @@ static inline void bpf_clear_seen_register(struct codegen_context *ctx, int i)
void bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, u64 func);
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs, bool extra_pass);
+ u32 *addrs);
void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx);
void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx);
void bpf_jit_realloc_regs(struct codegen_context *ctx);
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index fcbf7a917c56..f7972b2c21f6 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -149,7 +149,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
cgctx.stack_size = round_up(fp->aux->stack_depth, 16);
/* Scouting faux-generate pass 0 */
- if (bpf_jit_build_body(fp, 0, &cgctx, addrs, false)) {
+ if (bpf_jit_build_body(fp, 0, &cgctx, addrs)) {
/* We hit something illegal or unsupported. */
fp = org_fp;
goto out_addrs;
@@ -162,7 +162,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
*/
if (cgctx.seen & SEEN_TAILCALL) {
cgctx.idx = 0;
- if (bpf_jit_build_body(fp, 0, &cgctx, addrs, false)) {
+ if (bpf_jit_build_body(fp, 0, &cgctx, addrs)) {
fp = org_fp;
goto out_addrs;
}
@@ -210,7 +210,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
/* Now build the prologue, body code & epilogue for real. */
cgctx.idx = 0;
bpf_jit_build_prologue(code_base, &cgctx);
- if (bpf_jit_build_body(fp, code_base, &cgctx, addrs, extra_pass)) {
+ if (bpf_jit_build_body(fp, code_base, &cgctx, addrs)) {
bpf_jit_binary_free(bpf_hdr);
fp = org_fp;
goto out_addrs;
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 0da31d41d413..903f945601c0 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -268,7 +268,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
/* Assemble the body code between the prologue & epilogue */
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs, bool extra_pass)
+ u32 *addrs)
{
const struct bpf_insn *insn = fp->insnsi;
int flen = fp->len;
@@ -862,7 +862,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
case BPF_JMP | BPF_CALL:
ctx->seen |= SEEN_FUNC;
- ret = bpf_jit_get_func_addr(fp, &insn[i], extra_pass,
+ ret = bpf_jit_get_func_addr(fp, &insn[i], false,
&func_addr, &func_addr_fixed);
if (ret < 0)
return ret;
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index 8b5157ccfeba..b25bf9b11b9d 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -297,7 +297,7 @@ asm (
/* Assemble the body code between the prologue & epilogue */
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs, bool extra_pass)
+ u32 *addrs)
{
enum stf_barrier_type stf_barrier = stf_barrier_type_get();
const struct bpf_insn *insn = fp->insnsi;
@@ -831,7 +831,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
case BPF_JMP | BPF_CALL:
ctx->seen |= SEEN_FUNC;
- ret = bpf_jit_get_func_addr(fp, &insn[i], extra_pass,
+ ret = bpf_jit_get_func_addr(fp, &insn[i], false,
&func_addr, &func_addr_fixed);
if (ret < 0)
return ret;
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 2/8] bpf powerpc: Remove extra_pass from bpf_jit_build_body()
@ 2021-10-12 12:30 ` Hari Bathini
0 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: Ravi Bangoria, songliubraving, netdev, john.fastabend, andrii,
kpsingh, paulus, yhs, bpf, linuxppc-dev, kafai
From: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
In case of extra_pass, usual JIT passes are always skipped. So,
extra_pass is always false while calling bpf_jit_build_body() and
can be removed.
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
---
* No changes in v4.
arch/powerpc/net/bpf_jit.h | 2 +-
arch/powerpc/net/bpf_jit_comp.c | 6 +++---
arch/powerpc/net/bpf_jit_comp32.c | 4 ++--
arch/powerpc/net/bpf_jit_comp64.c | 4 ++--
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 89bd744c2bff..7145b651fc2a 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -175,7 +175,7 @@ static inline void bpf_clear_seen_register(struct codegen_context *ctx, int i)
void bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, u64 func);
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs, bool extra_pass);
+ u32 *addrs);
void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx);
void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx);
void bpf_jit_realloc_regs(struct codegen_context *ctx);
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index fcbf7a917c56..f7972b2c21f6 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -149,7 +149,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
cgctx.stack_size = round_up(fp->aux->stack_depth, 16);
/* Scouting faux-generate pass 0 */
- if (bpf_jit_build_body(fp, 0, &cgctx, addrs, false)) {
+ if (bpf_jit_build_body(fp, 0, &cgctx, addrs)) {
/* We hit something illegal or unsupported. */
fp = org_fp;
goto out_addrs;
@@ -162,7 +162,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
*/
if (cgctx.seen & SEEN_TAILCALL) {
cgctx.idx = 0;
- if (bpf_jit_build_body(fp, 0, &cgctx, addrs, false)) {
+ if (bpf_jit_build_body(fp, 0, &cgctx, addrs)) {
fp = org_fp;
goto out_addrs;
}
@@ -210,7 +210,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
/* Now build the prologue, body code & epilogue for real. */
cgctx.idx = 0;
bpf_jit_build_prologue(code_base, &cgctx);
- if (bpf_jit_build_body(fp, code_base, &cgctx, addrs, extra_pass)) {
+ if (bpf_jit_build_body(fp, code_base, &cgctx, addrs)) {
bpf_jit_binary_free(bpf_hdr);
fp = org_fp;
goto out_addrs;
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 0da31d41d413..903f945601c0 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -268,7 +268,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
/* Assemble the body code between the prologue & epilogue */
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs, bool extra_pass)
+ u32 *addrs)
{
const struct bpf_insn *insn = fp->insnsi;
int flen = fp->len;
@@ -862,7 +862,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
case BPF_JMP | BPF_CALL:
ctx->seen |= SEEN_FUNC;
- ret = bpf_jit_get_func_addr(fp, &insn[i], extra_pass,
+ ret = bpf_jit_get_func_addr(fp, &insn[i], false,
&func_addr, &func_addr_fixed);
if (ret < 0)
return ret;
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index 8b5157ccfeba..b25bf9b11b9d 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -297,7 +297,7 @@ asm (
/* Assemble the body code between the prologue & epilogue */
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs, bool extra_pass)
+ u32 *addrs)
{
enum stf_barrier_type stf_barrier = stf_barrier_type_get();
const struct bpf_insn *insn = fp->insnsi;
@@ -831,7 +831,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
case BPF_JMP | BPF_CALL:
ctx->seen |= SEEN_FUNC;
- ret = bpf_jit_get_func_addr(fp, &insn[i], extra_pass,
+ ret = bpf_jit_get_func_addr(fp, &insn[i], false,
&func_addr, &func_addr_fixed);
if (ret < 0)
return ret;
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 3/8] bpf powerpc: refactor JIT compiler code
2021-10-12 12:30 ` Hari Bathini
@ 2021-10-12 12:30 ` Hari Bathini
-1 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev, Hari Bathini
Refactor powerpc LDX JITing code to simplify adding BPF_PROBE_MEM
support.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
Changes in v4:
* Dropped the default case in the switch statement for bpf size.
* Dropped explicit fallthrough statement for empty switch cases.
arch/powerpc/net/bpf_jit_comp32.c | 33 ++++++++++++++++++-------------
arch/powerpc/net/bpf_jit_comp64.c | 31 +++++++++++++++++------------
2 files changed, 37 insertions(+), 27 deletions(-)
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 903f945601c0..8b2ac1c27f1f 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -284,6 +284,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
u32 src_reg = bpf_to_ppc(ctx, insn[i].src_reg);
u32 src_reg_h = src_reg - 1;
u32 tmp_reg = bpf_to_ppc(ctx, TMP_REG);
+ u32 size = BPF_SIZE(code);
s16 off = insn[i].off;
s32 imm = insn[i].imm;
bool func_addr_fixed;
@@ -812,23 +813,27 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
* BPF_LDX
*/
case BPF_LDX | BPF_MEM | BPF_B: /* dst = *(u8 *)(ul) (src + off) */
- EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
- if (!fp->aux->verifier_zext)
- EMIT(PPC_RAW_LI(dst_reg_h, 0));
- break;
case BPF_LDX | BPF_MEM | BPF_H: /* dst = *(u16 *)(ul) (src + off) */
- EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
- if (!fp->aux->verifier_zext)
- EMIT(PPC_RAW_LI(dst_reg_h, 0));
- break;
case BPF_LDX | BPF_MEM | BPF_W: /* dst = *(u32 *)(ul) (src + off) */
- EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
- if (!fp->aux->verifier_zext)
- EMIT(PPC_RAW_LI(dst_reg_h, 0));
- break;
case BPF_LDX | BPF_MEM | BPF_DW: /* dst = *(u64 *)(ul) (src + off) */
- EMIT(PPC_RAW_LWZ(dst_reg_h, src_reg, off));
- EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off + 4));
+ switch (size) {
+ case BPF_B:
+ EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
+ break;
+ case BPF_H:
+ EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
+ break;
+ case BPF_W:
+ EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
+ break;
+ case BPF_DW:
+ EMIT(PPC_RAW_LWZ(dst_reg_h, src_reg, off));
+ EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off + 4));
+ break;
+ }
+
+ if (size != BPF_DW && !fp->aux->verifier_zext)
+ EMIT(PPC_RAW_LI(dst_reg_h, 0));
break;
/*
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index b25bf9b11b9d..ad852f15ca61 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -311,6 +311,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
u32 code = insn[i].code;
u32 dst_reg = b2p[insn[i].dst_reg];
u32 src_reg = b2p[insn[i].src_reg];
+ u32 size = BPF_SIZE(code);
s16 off = insn[i].off;
s32 imm = insn[i].imm;
bool func_addr_fixed;
@@ -778,25 +779,29 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
*/
/* dst = *(u8 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_B:
- EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
- if (insn_is_zext(&insn[i + 1]))
- addrs[++i] = ctx->idx * 4;
- break;
/* dst = *(u16 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_H:
- EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
- if (insn_is_zext(&insn[i + 1]))
- addrs[++i] = ctx->idx * 4;
- break;
/* dst = *(u32 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_W:
- EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
- if (insn_is_zext(&insn[i + 1]))
- addrs[++i] = ctx->idx * 4;
- break;
/* dst = *(u64 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_DW:
- PPC_BPF_LL(dst_reg, src_reg, off);
+ switch (size) {
+ case BPF_B:
+ EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
+ break;
+ case BPF_H:
+ EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
+ break;
+ case BPF_W:
+ EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
+ break;
+ case BPF_DW:
+ PPC_BPF_LL(dst_reg, src_reg, off);
+ break;
+ }
+
+ if (size != BPF_DW && insn_is_zext(&insn[i + 1]))
+ addrs[++i] = ctx->idx * 4;
break;
/*
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 3/8] bpf powerpc: refactor JIT compiler code
@ 2021-10-12 12:30 ` Hari Bathini
0 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: songliubraving, netdev, john.fastabend, andrii, kpsingh, paulus,
yhs, bpf, linuxppc-dev, kafai, Hari Bathini
Refactor powerpc LDX JITing code to simplify adding BPF_PROBE_MEM
support.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
Changes in v4:
* Dropped the default case in the switch statement for bpf size.
* Dropped explicit fallthrough statement for empty switch cases.
arch/powerpc/net/bpf_jit_comp32.c | 33 ++++++++++++++++++-------------
arch/powerpc/net/bpf_jit_comp64.c | 31 +++++++++++++++++------------
2 files changed, 37 insertions(+), 27 deletions(-)
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 903f945601c0..8b2ac1c27f1f 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -284,6 +284,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
u32 src_reg = bpf_to_ppc(ctx, insn[i].src_reg);
u32 src_reg_h = src_reg - 1;
u32 tmp_reg = bpf_to_ppc(ctx, TMP_REG);
+ u32 size = BPF_SIZE(code);
s16 off = insn[i].off;
s32 imm = insn[i].imm;
bool func_addr_fixed;
@@ -812,23 +813,27 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
* BPF_LDX
*/
case BPF_LDX | BPF_MEM | BPF_B: /* dst = *(u8 *)(ul) (src + off) */
- EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
- if (!fp->aux->verifier_zext)
- EMIT(PPC_RAW_LI(dst_reg_h, 0));
- break;
case BPF_LDX | BPF_MEM | BPF_H: /* dst = *(u16 *)(ul) (src + off) */
- EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
- if (!fp->aux->verifier_zext)
- EMIT(PPC_RAW_LI(dst_reg_h, 0));
- break;
case BPF_LDX | BPF_MEM | BPF_W: /* dst = *(u32 *)(ul) (src + off) */
- EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
- if (!fp->aux->verifier_zext)
- EMIT(PPC_RAW_LI(dst_reg_h, 0));
- break;
case BPF_LDX | BPF_MEM | BPF_DW: /* dst = *(u64 *)(ul) (src + off) */
- EMIT(PPC_RAW_LWZ(dst_reg_h, src_reg, off));
- EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off + 4));
+ switch (size) {
+ case BPF_B:
+ EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
+ break;
+ case BPF_H:
+ EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
+ break;
+ case BPF_W:
+ EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
+ break;
+ case BPF_DW:
+ EMIT(PPC_RAW_LWZ(dst_reg_h, src_reg, off));
+ EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off + 4));
+ break;
+ }
+
+ if (size != BPF_DW && !fp->aux->verifier_zext)
+ EMIT(PPC_RAW_LI(dst_reg_h, 0));
break;
/*
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index b25bf9b11b9d..ad852f15ca61 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -311,6 +311,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
u32 code = insn[i].code;
u32 dst_reg = b2p[insn[i].dst_reg];
u32 src_reg = b2p[insn[i].src_reg];
+ u32 size = BPF_SIZE(code);
s16 off = insn[i].off;
s32 imm = insn[i].imm;
bool func_addr_fixed;
@@ -778,25 +779,29 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
*/
/* dst = *(u8 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_B:
- EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
- if (insn_is_zext(&insn[i + 1]))
- addrs[++i] = ctx->idx * 4;
- break;
/* dst = *(u16 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_H:
- EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
- if (insn_is_zext(&insn[i + 1]))
- addrs[++i] = ctx->idx * 4;
- break;
/* dst = *(u32 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_W:
- EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
- if (insn_is_zext(&insn[i + 1]))
- addrs[++i] = ctx->idx * 4;
- break;
/* dst = *(u64 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_DW:
- PPC_BPF_LL(dst_reg, src_reg, off);
+ switch (size) {
+ case BPF_B:
+ EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
+ break;
+ case BPF_H:
+ EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
+ break;
+ case BPF_W:
+ EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
+ break;
+ case BPF_DW:
+ PPC_BPF_LL(dst_reg, src_reg, off);
+ break;
+ }
+
+ if (size != BPF_DW && insn_is_zext(&insn[i + 1]))
+ addrs[++i] = ctx->idx * 4;
break;
/*
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 4/8] powerpc/ppc-opcode: introduce PPC_RAW_BRANCH() macro
2021-10-12 12:30 ` Hari Bathini
@ 2021-10-12 12:30 ` Hari Bathini
-1 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev, Hari Bathini
Define and use PPC_RAW_BRANCH() macro instead of open coding it. This
macro is used while adding BPF_PROBE_MEM support.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
* No changes in v4.
arch/powerpc/include/asm/ppc-opcode.h | 2 ++
arch/powerpc/net/bpf_jit.h | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index baea657bc868..f50213e2a3e0 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -566,6 +566,8 @@
#define PPC_RAW_MTSPR(spr, d) (0x7c0003a6 | ___PPC_RS(d) | __PPC_SPR(spr))
#define PPC_RAW_EIEIO() (0x7c0006ac)
+#define PPC_RAW_BRANCH(addr) (PPC_INST_BRANCH | ((addr) & 0x03fffffc))
+
/* Deal with instructions that older assemblers aren't aware of */
#define PPC_BCCTR_FLUSH stringify_in_c(.long PPC_INST_BCCTR_FLUSH)
#define PPC_CP_ABORT stringify_in_c(.long PPC_RAW_CP_ABORT)
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 7145b651fc2a..6a945f6211f4 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -31,7 +31,7 @@
pr_err_ratelimited("Branch offset 0x%lx (@%u) out of range\n", offset, ctx->idx); \
return -ERANGE; \
} \
- EMIT(PPC_INST_BRANCH | (offset & 0x03fffffc)); \
+ EMIT(PPC_RAW_BRANCH(offset)); \
} while (0)
/* blr; (unconditional 'branch' with link) to absolute address */
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 4/8] powerpc/ppc-opcode: introduce PPC_RAW_BRANCH() macro
@ 2021-10-12 12:30 ` Hari Bathini
0 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: songliubraving, netdev, john.fastabend, andrii, kpsingh, paulus,
yhs, bpf, linuxppc-dev, kafai, Hari Bathini
Define and use PPC_RAW_BRANCH() macro instead of open coding it. This
macro is used while adding BPF_PROBE_MEM support.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
* No changes in v4.
arch/powerpc/include/asm/ppc-opcode.h | 2 ++
arch/powerpc/net/bpf_jit.h | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index baea657bc868..f50213e2a3e0 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -566,6 +566,8 @@
#define PPC_RAW_MTSPR(spr, d) (0x7c0003a6 | ___PPC_RS(d) | __PPC_SPR(spr))
#define PPC_RAW_EIEIO() (0x7c0006ac)
+#define PPC_RAW_BRANCH(addr) (PPC_INST_BRANCH | ((addr) & 0x03fffffc))
+
/* Deal with instructions that older assemblers aren't aware of */
#define PPC_BCCTR_FLUSH stringify_in_c(.long PPC_INST_BCCTR_FLUSH)
#define PPC_CP_ABORT stringify_in_c(.long PPC_RAW_CP_ABORT)
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 7145b651fc2a..6a945f6211f4 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -31,7 +31,7 @@
pr_err_ratelimited("Branch offset 0x%lx (@%u) out of range\n", offset, ctx->idx); \
return -ERANGE; \
} \
- EMIT(PPC_INST_BRANCH | (offset & 0x03fffffc)); \
+ EMIT(PPC_RAW_BRANCH(offset)); \
} while (0)
/* blr; (unconditional 'branch' with link) to absolute address */
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 5/8] bpf ppc64: Add BPF_PROBE_MEM support for JIT
2021-10-12 12:30 ` Hari Bathini
@ 2021-10-12 12:30 ` Hari Bathini
-1 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev, Ravi Bangoria, Hari Bathini
From: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
BPF load instruction with BPF_PROBE_MEM mode can cause a fault
inside kernel. Append exception table for such instructions
within BPF program.
Unlike other archs which uses extable 'fixup' field to pass dest_reg
and nip, BPF exception table on PowerPC follows the generic PowerPC
exception table design, where it populates both fixup and extable
sections within BPF program. fixup section contains two instructions,
first instruction clears dest_reg and 2nd jumps to next instruction
in the BPF code. extable 'insn' field contains relative offset of
the instruction and 'fixup' field contains relative offset of the
fixup entry. Example layout of BPF program with extable present:
+------------------+
| |
| |
0x4020 -->| ld r27,4(r3) |
| |
| |
0x40ac -->| lwz r3,0(r4) |
| |
| |
|------------------|
0x4280 -->| li r27,0 | \ fixup entry
| b 0x4024 | /
0x4288 -->| li r3,0 |
| b 0x40b0 |
|------------------|
0x4290 -->| insn=0xfffffd90 | \ extable entry
| fixup=0xffffffec | /
0x4298 -->| insn=0xfffffe14 |
| fixup=0xffffffec |
+------------------+
(Addresses shown here are chosen random, not real)
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
Changes in v4:
* Dropped explicit fallthrough statement for empty switch cases.
arch/powerpc/net/bpf_jit.h | 8 +++-
arch/powerpc/net/bpf_jit_comp.c | 66 ++++++++++++++++++++++++++++---
arch/powerpc/net/bpf_jit_comp32.c | 2 +-
arch/powerpc/net/bpf_jit_comp64.c | 13 +++++-
4 files changed, 80 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 6a945f6211f4..444c9debce91 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -150,8 +150,11 @@ struct codegen_context {
unsigned int idx;
unsigned int stack_size;
int b2p[ARRAY_SIZE(b2p)];
+ unsigned int exentry_idx;
};
+#define BPF_FIXUP_LEN 2 /* Two instructions => 8 bytes */
+
static inline void bpf_flush_icache(void *start, void *end)
{
smp_wmb(); /* smp write barrier */
@@ -175,11 +178,14 @@ static inline void bpf_clear_seen_register(struct codegen_context *ctx, int i)
void bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, u64 func);
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs);
+ u32 *addrs, int pass);
void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx);
void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx);
void bpf_jit_realloc_regs(struct codegen_context *ctx);
+int bpf_add_extable_entry(struct bpf_prog *fp, u32 *image, int pass, struct codegen_context *ctx,
+ int insn_idx, int jmp_off, int dst_reg);
+
#endif
#endif
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index f7972b2c21f6..f02457c6b54f 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -101,6 +101,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
struct bpf_prog *tmp_fp;
bool bpf_blinded = false;
bool extra_pass = false;
+ u32 extable_len;
+ u32 fixup_len;
if (!fp->jit_requested)
return org_fp;
@@ -131,7 +133,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
image = jit_data->image;
bpf_hdr = jit_data->header;
proglen = jit_data->proglen;
- alloclen = proglen + FUNCTION_DESCR_SIZE;
extra_pass = true;
goto skip_init_ctx;
}
@@ -149,7 +150,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
cgctx.stack_size = round_up(fp->aux->stack_depth, 16);
/* Scouting faux-generate pass 0 */
- if (bpf_jit_build_body(fp, 0, &cgctx, addrs)) {
+ if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0)) {
/* We hit something illegal or unsupported. */
fp = org_fp;
goto out_addrs;
@@ -162,7 +163,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
*/
if (cgctx.seen & SEEN_TAILCALL) {
cgctx.idx = 0;
- if (bpf_jit_build_body(fp, 0, &cgctx, addrs)) {
+ if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0)) {
fp = org_fp;
goto out_addrs;
}
@@ -177,8 +178,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
bpf_jit_build_prologue(0, &cgctx);
bpf_jit_build_epilogue(0, &cgctx);
+ fixup_len = fp->aux->num_exentries * BPF_FIXUP_LEN * 4;
+ extable_len = fp->aux->num_exentries * sizeof(struct exception_table_entry);
+
proglen = cgctx.idx * 4;
- alloclen = proglen + FUNCTION_DESCR_SIZE;
+ alloclen = proglen + FUNCTION_DESCR_SIZE + fixup_len + extable_len;
bpf_hdr = bpf_jit_binary_alloc(alloclen, &image, 4, bpf_jit_fill_ill_insns);
if (!bpf_hdr) {
@@ -186,6 +190,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
goto out_addrs;
}
+ if (extable_len)
+ fp->aux->extable = (void *)image + FUNCTION_DESCR_SIZE + proglen + fixup_len;
+
skip_init_ctx:
code_base = (u32 *)(image + FUNCTION_DESCR_SIZE);
@@ -210,7 +217,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
/* Now build the prologue, body code & epilogue for real. */
cgctx.idx = 0;
bpf_jit_build_prologue(code_base, &cgctx);
- if (bpf_jit_build_body(fp, code_base, &cgctx, addrs)) {
+ if (bpf_jit_build_body(fp, code_base, &cgctx, addrs, pass)) {
bpf_jit_binary_free(bpf_hdr);
fp = org_fp;
goto out_addrs;
@@ -238,7 +245,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
fp->bpf_func = (void *)image;
fp->jited = 1;
- fp->jited_len = alloclen;
+ fp->jited_len = proglen + FUNCTION_DESCR_SIZE;
bpf_flush_icache(bpf_hdr, (u8 *)bpf_hdr + (bpf_hdr->pages * PAGE_SIZE));
bpf_jit_binary_lock_ro(bpf_hdr);
@@ -262,3 +269,50 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
return fp;
}
+
+/*
+ * The caller should check for (BPF_MODE(code) == BPF_PROBE_MEM) before calling
+ * this function, as this only applies to BPF_PROBE_MEM, for now.
+ */
+int bpf_add_extable_entry(struct bpf_prog *fp, u32 *image, int pass, struct codegen_context *ctx,
+ int insn_idx, int jmp_off, int dst_reg)
+{
+ off_t offset;
+ unsigned long pc;
+ struct exception_table_entry *ex;
+ u32 *fixup;
+
+ /* Populate extable entries only in the last pass */
+ if (pass != 2)
+ return 0;
+
+ if (!fp->aux->extable ||
+ WARN_ON_ONCE(ctx->exentry_idx >= fp->aux->num_exentries))
+ return -EINVAL;
+
+ pc = (unsigned long)&image[insn_idx];
+
+ fixup = (void *)fp->aux->extable -
+ (fp->aux->num_exentries * BPF_FIXUP_LEN * 4) +
+ (ctx->exentry_idx * BPF_FIXUP_LEN * 4);
+
+ fixup[0] = PPC_RAW_LI(dst_reg, 0);
+
+ fixup[BPF_FIXUP_LEN - 1] =
+ PPC_RAW_BRANCH((long)(pc + jmp_off) - (long)&fixup[BPF_FIXUP_LEN - 1]);
+
+ ex = &fp->aux->extable[ctx->exentry_idx];
+
+ offset = pc - (long)&ex->insn;
+ if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN))
+ return -ERANGE;
+ ex->insn = offset;
+
+ offset = (long)fixup - (long)&ex->fixup;
+ if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN))
+ return -ERANGE;
+ ex->fixup = offset;
+
+ ctx->exentry_idx++;
+ return 0;
+}
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 8b2ac1c27f1f..54e7cef3e1f2 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -268,7 +268,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
/* Assemble the body code between the prologue & epilogue */
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs)
+ u32 *addrs, int pass)
{
const struct bpf_insn *insn = fp->insnsi;
int flen = fp->len;
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index ad852f15ca61..ede8cb3e453f 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -297,7 +297,7 @@ asm (
/* Assemble the body code between the prologue & epilogue */
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs)
+ u32 *addrs, int pass)
{
enum stf_barrier_type stf_barrier = stf_barrier_type_get();
const struct bpf_insn *insn = fp->insnsi;
@@ -779,12 +779,16 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
*/
/* dst = *(u8 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_B:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_B:
/* dst = *(u16 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_H:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_H:
/* dst = *(u32 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_W:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_W:
/* dst = *(u64 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_DW:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
switch (size) {
case BPF_B:
EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
@@ -802,6 +806,13 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
if (size != BPF_DW && insn_is_zext(&insn[i + 1]))
addrs[++i] = ctx->idx * 4;
+
+ if (BPF_MODE(code) == BPF_PROBE_MEM) {
+ ret = bpf_add_extable_entry(fp, image, pass, ctx, ctx->idx - 1,
+ 4, dst_reg);
+ if (ret)
+ return ret;
+ }
break;
/*
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 5/8] bpf ppc64: Add BPF_PROBE_MEM support for JIT
@ 2021-10-12 12:30 ` Hari Bathini
0 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: Ravi Bangoria, songliubraving, netdev, john.fastabend, andrii,
kpsingh, paulus, yhs, bpf, linuxppc-dev, kafai, Hari Bathini
From: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
BPF load instruction with BPF_PROBE_MEM mode can cause a fault
inside kernel. Append exception table for such instructions
within BPF program.
Unlike other archs which uses extable 'fixup' field to pass dest_reg
and nip, BPF exception table on PowerPC follows the generic PowerPC
exception table design, where it populates both fixup and extable
sections within BPF program. fixup section contains two instructions,
first instruction clears dest_reg and 2nd jumps to next instruction
in the BPF code. extable 'insn' field contains relative offset of
the instruction and 'fixup' field contains relative offset of the
fixup entry. Example layout of BPF program with extable present:
+------------------+
| |
| |
0x4020 -->| ld r27,4(r3) |
| |
| |
0x40ac -->| lwz r3,0(r4) |
| |
| |
|------------------|
0x4280 -->| li r27,0 | \ fixup entry
| b 0x4024 | /
0x4288 -->| li r3,0 |
| b 0x40b0 |
|------------------|
0x4290 -->| insn=0xfffffd90 | \ extable entry
| fixup=0xffffffec | /
0x4298 -->| insn=0xfffffe14 |
| fixup=0xffffffec |
+------------------+
(Addresses shown here are chosen random, not real)
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
Changes in v4:
* Dropped explicit fallthrough statement for empty switch cases.
arch/powerpc/net/bpf_jit.h | 8 +++-
arch/powerpc/net/bpf_jit_comp.c | 66 ++++++++++++++++++++++++++++---
arch/powerpc/net/bpf_jit_comp32.c | 2 +-
arch/powerpc/net/bpf_jit_comp64.c | 13 +++++-
4 files changed, 80 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 6a945f6211f4..444c9debce91 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -150,8 +150,11 @@ struct codegen_context {
unsigned int idx;
unsigned int stack_size;
int b2p[ARRAY_SIZE(b2p)];
+ unsigned int exentry_idx;
};
+#define BPF_FIXUP_LEN 2 /* Two instructions => 8 bytes */
+
static inline void bpf_flush_icache(void *start, void *end)
{
smp_wmb(); /* smp write barrier */
@@ -175,11 +178,14 @@ static inline void bpf_clear_seen_register(struct codegen_context *ctx, int i)
void bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, u64 func);
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs);
+ u32 *addrs, int pass);
void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx);
void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx);
void bpf_jit_realloc_regs(struct codegen_context *ctx);
+int bpf_add_extable_entry(struct bpf_prog *fp, u32 *image, int pass, struct codegen_context *ctx,
+ int insn_idx, int jmp_off, int dst_reg);
+
#endif
#endif
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index f7972b2c21f6..f02457c6b54f 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -101,6 +101,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
struct bpf_prog *tmp_fp;
bool bpf_blinded = false;
bool extra_pass = false;
+ u32 extable_len;
+ u32 fixup_len;
if (!fp->jit_requested)
return org_fp;
@@ -131,7 +133,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
image = jit_data->image;
bpf_hdr = jit_data->header;
proglen = jit_data->proglen;
- alloclen = proglen + FUNCTION_DESCR_SIZE;
extra_pass = true;
goto skip_init_ctx;
}
@@ -149,7 +150,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
cgctx.stack_size = round_up(fp->aux->stack_depth, 16);
/* Scouting faux-generate pass 0 */
- if (bpf_jit_build_body(fp, 0, &cgctx, addrs)) {
+ if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0)) {
/* We hit something illegal or unsupported. */
fp = org_fp;
goto out_addrs;
@@ -162,7 +163,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
*/
if (cgctx.seen & SEEN_TAILCALL) {
cgctx.idx = 0;
- if (bpf_jit_build_body(fp, 0, &cgctx, addrs)) {
+ if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0)) {
fp = org_fp;
goto out_addrs;
}
@@ -177,8 +178,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
bpf_jit_build_prologue(0, &cgctx);
bpf_jit_build_epilogue(0, &cgctx);
+ fixup_len = fp->aux->num_exentries * BPF_FIXUP_LEN * 4;
+ extable_len = fp->aux->num_exentries * sizeof(struct exception_table_entry);
+
proglen = cgctx.idx * 4;
- alloclen = proglen + FUNCTION_DESCR_SIZE;
+ alloclen = proglen + FUNCTION_DESCR_SIZE + fixup_len + extable_len;
bpf_hdr = bpf_jit_binary_alloc(alloclen, &image, 4, bpf_jit_fill_ill_insns);
if (!bpf_hdr) {
@@ -186,6 +190,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
goto out_addrs;
}
+ if (extable_len)
+ fp->aux->extable = (void *)image + FUNCTION_DESCR_SIZE + proglen + fixup_len;
+
skip_init_ctx:
code_base = (u32 *)(image + FUNCTION_DESCR_SIZE);
@@ -210,7 +217,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
/* Now build the prologue, body code & epilogue for real. */
cgctx.idx = 0;
bpf_jit_build_prologue(code_base, &cgctx);
- if (bpf_jit_build_body(fp, code_base, &cgctx, addrs)) {
+ if (bpf_jit_build_body(fp, code_base, &cgctx, addrs, pass)) {
bpf_jit_binary_free(bpf_hdr);
fp = org_fp;
goto out_addrs;
@@ -238,7 +245,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
fp->bpf_func = (void *)image;
fp->jited = 1;
- fp->jited_len = alloclen;
+ fp->jited_len = proglen + FUNCTION_DESCR_SIZE;
bpf_flush_icache(bpf_hdr, (u8 *)bpf_hdr + (bpf_hdr->pages * PAGE_SIZE));
bpf_jit_binary_lock_ro(bpf_hdr);
@@ -262,3 +269,50 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
return fp;
}
+
+/*
+ * The caller should check for (BPF_MODE(code) == BPF_PROBE_MEM) before calling
+ * this function, as this only applies to BPF_PROBE_MEM, for now.
+ */
+int bpf_add_extable_entry(struct bpf_prog *fp, u32 *image, int pass, struct codegen_context *ctx,
+ int insn_idx, int jmp_off, int dst_reg)
+{
+ off_t offset;
+ unsigned long pc;
+ struct exception_table_entry *ex;
+ u32 *fixup;
+
+ /* Populate extable entries only in the last pass */
+ if (pass != 2)
+ return 0;
+
+ if (!fp->aux->extable ||
+ WARN_ON_ONCE(ctx->exentry_idx >= fp->aux->num_exentries))
+ return -EINVAL;
+
+ pc = (unsigned long)&image[insn_idx];
+
+ fixup = (void *)fp->aux->extable -
+ (fp->aux->num_exentries * BPF_FIXUP_LEN * 4) +
+ (ctx->exentry_idx * BPF_FIXUP_LEN * 4);
+
+ fixup[0] = PPC_RAW_LI(dst_reg, 0);
+
+ fixup[BPF_FIXUP_LEN - 1] =
+ PPC_RAW_BRANCH((long)(pc + jmp_off) - (long)&fixup[BPF_FIXUP_LEN - 1]);
+
+ ex = &fp->aux->extable[ctx->exentry_idx];
+
+ offset = pc - (long)&ex->insn;
+ if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN))
+ return -ERANGE;
+ ex->insn = offset;
+
+ offset = (long)fixup - (long)&ex->fixup;
+ if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN))
+ return -ERANGE;
+ ex->fixup = offset;
+
+ ctx->exentry_idx++;
+ return 0;
+}
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 8b2ac1c27f1f..54e7cef3e1f2 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -268,7 +268,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
/* Assemble the body code between the prologue & epilogue */
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs)
+ u32 *addrs, int pass)
{
const struct bpf_insn *insn = fp->insnsi;
int flen = fp->len;
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index ad852f15ca61..ede8cb3e453f 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -297,7 +297,7 @@ asm (
/* Assemble the body code between the prologue & epilogue */
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
- u32 *addrs)
+ u32 *addrs, int pass)
{
enum stf_barrier_type stf_barrier = stf_barrier_type_get();
const struct bpf_insn *insn = fp->insnsi;
@@ -779,12 +779,16 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
*/
/* dst = *(u8 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_B:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_B:
/* dst = *(u16 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_H:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_H:
/* dst = *(u32 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_W:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_W:
/* dst = *(u64 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_DW:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
switch (size) {
case BPF_B:
EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
@@ -802,6 +806,13 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
if (size != BPF_DW && insn_is_zext(&insn[i + 1]))
addrs[++i] = ctx->idx * 4;
+
+ if (BPF_MODE(code) == BPF_PROBE_MEM) {
+ ret = bpf_add_extable_entry(fp, image, pass, ctx, ctx->idx - 1,
+ 4, dst_reg);
+ if (ret)
+ return ret;
+ }
break;
/*
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 6/8] bpf ppc64: Access only if addr is kernel address
2021-10-12 12:30 ` Hari Bathini
@ 2021-10-12 12:30 ` Hari Bathini
-1 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev, Ravi Bangoria, Hari Bathini
From: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
On PPC64 with KUAP enabled, any kernel code which wants to
access userspace needs to be surrounded by disable-enable KUAP.
But that is not happening for BPF_PROBE_MEM load instruction.
So, when BPF program tries to access invalid userspace address,
page-fault handler considers it as bad KUAP fault:
Kernel attempted to read user page (d0000000) - exploit attempt? (uid: 0)
Considering the fact that PTR_TO_BTF_ID (which uses BPF_PROBE_MEM
mode) could either be a valid kernel pointer or NULL but should
never be a pointer to userspace address, execute BPF_PROBE_MEM load
only if addr is kernel address, otherwise set dst_reg=0 and move on.
This will catch NULL, valid or invalid userspace pointers. Only bad
kernel pointer will be handled by BPF exception table.
[Alexei suggested for x86]
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
Changes in v4:
* Used IS_ENABLED() instead of #ifdef.
* Dropped the else case that is not applicable for PPC64.
arch/powerpc/net/bpf_jit_comp64.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index ede8cb3e453f..472d4a551945 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -789,6 +789,32 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
/* dst = *(u64 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_DW:
case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
+ /*
+ * As PTR_TO_BTF_ID that uses BPF_PROBE_MEM mode could either be a valid
+ * kernel pointer or NULL but not a userspace address, execute BPF_PROBE_MEM
+ * load only if addr is kernel address (see is_kernel_addr()), otherwise
+ * set dst_reg=0 and move on.
+ */
+ if (BPF_MODE(code) == BPF_PROBE_MEM) {
+ EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], src_reg, off));
+ if (IS_ENABLED(CONFIG_PPC_BOOK3E_64))
+ PPC_LI64(b2p[TMP_REG_2], 0x8000000000000000ul);
+ else /* BOOK3S_64 */
+ PPC_LI64(b2p[TMP_REG_2], PAGE_OFFSET);
+ EMIT(PPC_RAW_CMPLD(b2p[TMP_REG_1], b2p[TMP_REG_2]));
+ PPC_BCC(COND_GT, (ctx->idx + 4) * 4);
+ EMIT(PPC_RAW_LI(dst_reg, 0));
+ /*
+ * Check if 'off' is word aligned because PPC_BPF_LL()
+ * (BPF_DW case) generates two instructions if 'off' is not
+ * word-aligned and one instruction otherwise.
+ */
+ if (BPF_SIZE(code) == BPF_DW && (off & 3))
+ PPC_JMP((ctx->idx + 3) * 4);
+ else
+ PPC_JMP((ctx->idx + 2) * 4);
+ }
+
switch (size) {
case BPF_B:
EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 6/8] bpf ppc64: Access only if addr is kernel address
@ 2021-10-12 12:30 ` Hari Bathini
0 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: Ravi Bangoria, songliubraving, netdev, john.fastabend, andrii,
kpsingh, paulus, yhs, bpf, linuxppc-dev, kafai, Hari Bathini
From: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
On PPC64 with KUAP enabled, any kernel code which wants to
access userspace needs to be surrounded by disable-enable KUAP.
But that is not happening for BPF_PROBE_MEM load instruction.
So, when BPF program tries to access invalid userspace address,
page-fault handler considers it as bad KUAP fault:
Kernel attempted to read user page (d0000000) - exploit attempt? (uid: 0)
Considering the fact that PTR_TO_BTF_ID (which uses BPF_PROBE_MEM
mode) could either be a valid kernel pointer or NULL but should
never be a pointer to userspace address, execute BPF_PROBE_MEM load
only if addr is kernel address, otherwise set dst_reg=0 and move on.
This will catch NULL, valid or invalid userspace pointers. Only bad
kernel pointer will be handled by BPF exception table.
[Alexei suggested for x86]
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
Changes in v4:
* Used IS_ENABLED() instead of #ifdef.
* Dropped the else case that is not applicable for PPC64.
arch/powerpc/net/bpf_jit_comp64.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index ede8cb3e453f..472d4a551945 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -789,6 +789,32 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
/* dst = *(u64 *)(ul) (src + off) */
case BPF_LDX | BPF_MEM | BPF_DW:
case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
+ /*
+ * As PTR_TO_BTF_ID that uses BPF_PROBE_MEM mode could either be a valid
+ * kernel pointer or NULL but not a userspace address, execute BPF_PROBE_MEM
+ * load only if addr is kernel address (see is_kernel_addr()), otherwise
+ * set dst_reg=0 and move on.
+ */
+ if (BPF_MODE(code) == BPF_PROBE_MEM) {
+ EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], src_reg, off));
+ if (IS_ENABLED(CONFIG_PPC_BOOK3E_64))
+ PPC_LI64(b2p[TMP_REG_2], 0x8000000000000000ul);
+ else /* BOOK3S_64 */
+ PPC_LI64(b2p[TMP_REG_2], PAGE_OFFSET);
+ EMIT(PPC_RAW_CMPLD(b2p[TMP_REG_1], b2p[TMP_REG_2]));
+ PPC_BCC(COND_GT, (ctx->idx + 4) * 4);
+ EMIT(PPC_RAW_LI(dst_reg, 0));
+ /*
+ * Check if 'off' is word aligned because PPC_BPF_LL()
+ * (BPF_DW case) generates two instructions if 'off' is not
+ * word-aligned and one instruction otherwise.
+ */
+ if (BPF_SIZE(code) == BPF_DW && (off & 3))
+ PPC_JMP((ctx->idx + 3) * 4);
+ else
+ PPC_JMP((ctx->idx + 2) * 4);
+ }
+
switch (size) {
case BPF_B:
EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 7/8] bpf ppc32: Add BPF_PROBE_MEM support for JIT
2021-10-12 12:30 ` Hari Bathini
@ 2021-10-12 12:30 ` Hari Bathini
-1 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev, Hari Bathini
BPF load instruction with BPF_PROBE_MEM mode can cause a fault
inside kernel. Append exception table for such instructions
within BPF program.
Unlike other archs which uses extable 'fixup' field to pass dest_reg
and nip, BPF exception table on PowerPC follows the generic PowerPC
exception table design, where it populates both fixup and extable
sections within BPF program. fixup section contains 3 instructions,
first 2 instructions clear dest_reg (lower & higher 32-bit registers)
and last instruction jumps to next instruction in the BPF code.
extable 'insn' field contains relative offset of the instruction and
'fixup' field contains relative offset of the fixup entry. Example
layout of BPF program with extable present:
+------------------+
| |
| |
0x4020 -->| lwz r28,4(r4) |
| |
| |
0x40ac -->| lwz r3,0(r24) |
| lwz r4,4(r24) |
| |
| |
|------------------|
0x4278 -->| li r28,0 | \
| li r27,0 | | fixup entry
| b 0x4024 | /
0x4284 -->| li r4,0 |
| li r3,0 |
| b 0x40b4 |
|------------------|
0x4290 -->| insn=0xfffffd90 | \ extable entry
| fixup=0xffffffe4 | /
0x4298 -->| insn=0xfffffe14 |
| fixup=0xffffffe8 |
+------------------+
(Addresses shown here are chosen random, not real)
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
Changes in v4:
* Dropped explicit fallthrough statement for empty switch cases.
arch/powerpc/net/bpf_jit.h | 4 ++++
arch/powerpc/net/bpf_jit_comp.c | 2 ++
arch/powerpc/net/bpf_jit_comp32.c | 30 ++++++++++++++++++++++++++++++
3 files changed, 36 insertions(+)
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 444c9debce91..b20a2a83a6e7 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -153,7 +153,11 @@ struct codegen_context {
unsigned int exentry_idx;
};
+#ifdef CONFIG_PPC32
+#define BPF_FIXUP_LEN 3 /* Three instructions => 12 bytes */
+#else
#define BPF_FIXUP_LEN 2 /* Two instructions => 8 bytes */
+#endif
static inline void bpf_flush_icache(void *start, void *end)
{
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index f02457c6b54f..1a0041997050 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -297,6 +297,8 @@ int bpf_add_extable_entry(struct bpf_prog *fp, u32 *image, int pass, struct code
(ctx->exentry_idx * BPF_FIXUP_LEN * 4);
fixup[0] = PPC_RAW_LI(dst_reg, 0);
+ if (IS_ENABLED(CONFIG_PPC32))
+ fixup[1] = PPC_RAW_LI(dst_reg - 1, 0); /* clear higher 32-bit register too */
fixup[BPF_FIXUP_LEN - 1] =
PPC_RAW_BRANCH((long)(pc + jmp_off) - (long)&fixup[BPF_FIXUP_LEN - 1]);
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 54e7cef3e1f2..5dc45e393d1d 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -813,9 +813,13 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
* BPF_LDX
*/
case BPF_LDX | BPF_MEM | BPF_B: /* dst = *(u8 *)(ul) (src + off) */
+ case BPF_LDX | BPF_PROBE_MEM | BPF_B:
case BPF_LDX | BPF_MEM | BPF_H: /* dst = *(u16 *)(ul) (src + off) */
+ case BPF_LDX | BPF_PROBE_MEM | BPF_H:
case BPF_LDX | BPF_MEM | BPF_W: /* dst = *(u32 *)(ul) (src + off) */
+ case BPF_LDX | BPF_PROBE_MEM | BPF_W:
case BPF_LDX | BPF_MEM | BPF_DW: /* dst = *(u64 *)(ul) (src + off) */
+ case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
switch (size) {
case BPF_B:
EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
@@ -834,6 +838,32 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
if (size != BPF_DW && !fp->aux->verifier_zext)
EMIT(PPC_RAW_LI(dst_reg_h, 0));
+
+ if (BPF_MODE(code) == BPF_PROBE_MEM) {
+ int insn_idx = ctx->idx - 1;
+ int jmp_off = 4;
+
+ /*
+ * In case of BPF_DW, two lwz instructions are emitted, one
+ * for higher 32-bit and another for lower 32-bit. So, set
+ * ex->insn to the first of the two and jump over both
+ * instructions in fixup.
+ *
+ * Similarly, with !verifier_zext, two instructions are
+ * emitted for BPF_B/H/W case. So, set ex->insn to the
+ * instruction that could fault and skip over both
+ * instructions.
+ */
+ if (size == BPF_DW || !fp->aux->verifier_zext) {
+ insn_idx -= 1;
+ jmp_off += 4;
+ }
+
+ ret = bpf_add_extable_entry(fp, image, pass, ctx, insn_idx,
+ jmp_off, dst_reg);
+ if (ret)
+ return ret;
+ }
break;
/*
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 7/8] bpf ppc32: Add BPF_PROBE_MEM support for JIT
@ 2021-10-12 12:30 ` Hari Bathini
0 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: songliubraving, netdev, john.fastabend, andrii, kpsingh, paulus,
yhs, bpf, linuxppc-dev, kafai, Hari Bathini
BPF load instruction with BPF_PROBE_MEM mode can cause a fault
inside kernel. Append exception table for such instructions
within BPF program.
Unlike other archs which uses extable 'fixup' field to pass dest_reg
and nip, BPF exception table on PowerPC follows the generic PowerPC
exception table design, where it populates both fixup and extable
sections within BPF program. fixup section contains 3 instructions,
first 2 instructions clear dest_reg (lower & higher 32-bit registers)
and last instruction jumps to next instruction in the BPF code.
extable 'insn' field contains relative offset of the instruction and
'fixup' field contains relative offset of the fixup entry. Example
layout of BPF program with extable present:
+------------------+
| |
| |
0x4020 -->| lwz r28,4(r4) |
| |
| |
0x40ac -->| lwz r3,0(r24) |
| lwz r4,4(r24) |
| |
| |
|------------------|
0x4278 -->| li r28,0 | \
| li r27,0 | | fixup entry
| b 0x4024 | /
0x4284 -->| li r4,0 |
| li r3,0 |
| b 0x40b4 |
|------------------|
0x4290 -->| insn=0xfffffd90 | \ extable entry
| fixup=0xffffffe4 | /
0x4298 -->| insn=0xfffffe14 |
| fixup=0xffffffe8 |
+------------------+
(Addresses shown here are chosen random, not real)
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
Changes in v4:
* Dropped explicit fallthrough statement for empty switch cases.
arch/powerpc/net/bpf_jit.h | 4 ++++
arch/powerpc/net/bpf_jit_comp.c | 2 ++
arch/powerpc/net/bpf_jit_comp32.c | 30 ++++++++++++++++++++++++++++++
3 files changed, 36 insertions(+)
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 444c9debce91..b20a2a83a6e7 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -153,7 +153,11 @@ struct codegen_context {
unsigned int exentry_idx;
};
+#ifdef CONFIG_PPC32
+#define BPF_FIXUP_LEN 3 /* Three instructions => 12 bytes */
+#else
#define BPF_FIXUP_LEN 2 /* Two instructions => 8 bytes */
+#endif
static inline void bpf_flush_icache(void *start, void *end)
{
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index f02457c6b54f..1a0041997050 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -297,6 +297,8 @@ int bpf_add_extable_entry(struct bpf_prog *fp, u32 *image, int pass, struct code
(ctx->exentry_idx * BPF_FIXUP_LEN * 4);
fixup[0] = PPC_RAW_LI(dst_reg, 0);
+ if (IS_ENABLED(CONFIG_PPC32))
+ fixup[1] = PPC_RAW_LI(dst_reg - 1, 0); /* clear higher 32-bit register too */
fixup[BPF_FIXUP_LEN - 1] =
PPC_RAW_BRANCH((long)(pc + jmp_off) - (long)&fixup[BPF_FIXUP_LEN - 1]);
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 54e7cef3e1f2..5dc45e393d1d 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -813,9 +813,13 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
* BPF_LDX
*/
case BPF_LDX | BPF_MEM | BPF_B: /* dst = *(u8 *)(ul) (src + off) */
+ case BPF_LDX | BPF_PROBE_MEM | BPF_B:
case BPF_LDX | BPF_MEM | BPF_H: /* dst = *(u16 *)(ul) (src + off) */
+ case BPF_LDX | BPF_PROBE_MEM | BPF_H:
case BPF_LDX | BPF_MEM | BPF_W: /* dst = *(u32 *)(ul) (src + off) */
+ case BPF_LDX | BPF_PROBE_MEM | BPF_W:
case BPF_LDX | BPF_MEM | BPF_DW: /* dst = *(u64 *)(ul) (src + off) */
+ case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
switch (size) {
case BPF_B:
EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
@@ -834,6 +838,32 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
if (size != BPF_DW && !fp->aux->verifier_zext)
EMIT(PPC_RAW_LI(dst_reg_h, 0));
+
+ if (BPF_MODE(code) == BPF_PROBE_MEM) {
+ int insn_idx = ctx->idx - 1;
+ int jmp_off = 4;
+
+ /*
+ * In case of BPF_DW, two lwz instructions are emitted, one
+ * for higher 32-bit and another for lower 32-bit. So, set
+ * ex->insn to the first of the two and jump over both
+ * instructions in fixup.
+ *
+ * Similarly, with !verifier_zext, two instructions are
+ * emitted for BPF_B/H/W case. So, set ex->insn to the
+ * instruction that could fault and skip over both
+ * instructions.
+ */
+ if (size == BPF_DW || !fp->aux->verifier_zext) {
+ insn_idx -= 1;
+ jmp_off += 4;
+ }
+
+ ret = bpf_add_extable_entry(fp, image, pass, ctx, insn_idx,
+ jmp_off, dst_reg);
+ if (ret)
+ return ret;
+ }
break;
/*
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 8/8] bpf ppc32: Access only if addr is kernel address
2021-10-12 12:30 ` Hari Bathini
@ 2021-10-12 12:30 ` Hari Bathini
-1 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev, Hari Bathini
With KUAP enabled, any kernel code which wants to access userspace
needs to be surrounded by disable-enable KUAP. But that is not
happening for BPF_PROBE_MEM load instruction. Though PPC32 does not
support read protection, considering the fact that PTR_TO_BTF_ID
(which uses BPF_PROBE_MEM mode) could either be a valid kernel pointer
or NULL but should never be a pointer to userspace address, execute
BPF_PROBE_MEM load only if addr is kernel address, otherwise set
dst_reg=0 and move on.
This will catch NULL, valid or invalid userspace pointers. Only bad
kernel pointer will be handled by BPF exception table.
[Alexei suggested for x86]
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
Changes in v4:
* Adjusted the emit code to avoid using temporary reg.
arch/powerpc/net/bpf_jit_comp32.c | 34 +++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 5dc45e393d1d..d3a52cd42f53 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -820,6 +820,40 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
case BPF_LDX | BPF_PROBE_MEM | BPF_W:
case BPF_LDX | BPF_MEM | BPF_DW: /* dst = *(u64 *)(ul) (src + off) */
case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
+ /*
+ * As PTR_TO_BTF_ID that uses BPF_PROBE_MEM mode could either be a valid
+ * kernel pointer or NULL but not a userspace address, execute BPF_PROBE_MEM
+ * load only if addr is kernel address (see is_kernel_addr()), otherwise
+ * set dst_reg=0 and move on.
+ */
+ if (BPF_MODE(code) == BPF_PROBE_MEM) {
+ PPC_LI32(_R0, TASK_SIZE - off);
+ EMIT(PPC_RAW_CMPLW(src_reg, _R0));
+ PPC_BCC(COND_GT, (ctx->idx + 5) * 4);
+ EMIT(PPC_RAW_LI(dst_reg, 0));
+ /*
+ * For BPF_DW case, "li reg_h,0" would be needed when
+ * !fp->aux->verifier_zext. Emit NOP otherwise.
+ *
+ * Note that "li reg_h,0" is emitted for BPF_B/H/W case,
+ * if necessary. So, jump there insted of emitting an
+ * additional "li reg_h,0" instruction.
+ */
+ if (size == BPF_DW && !fp->aux->verifier_zext)
+ EMIT(PPC_RAW_LI(dst_reg_h, 0));
+ else
+ EMIT(PPC_RAW_NOP());
+ /*
+ * Need to jump two instructions instead of one for BPF_DW case
+ * as there are two load instructions for dst_reg_h & dst_reg
+ * respectively.
+ */
+ if (size == BPF_DW)
+ PPC_JMP((ctx->idx + 3) * 4);
+ else
+ PPC_JMP((ctx->idx + 2) * 4);
+ }
+
switch (size) {
case BPF_B:
EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [RESEND PATCH v4 8/8] bpf ppc32: Access only if addr is kernel address
@ 2021-10-12 12:30 ` Hari Bathini
0 siblings, 0 replies; 27+ messages in thread
From: Hari Bathini @ 2021-10-12 12:30 UTC (permalink / raw)
To: naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: songliubraving, netdev, john.fastabend, andrii, kpsingh, paulus,
yhs, bpf, linuxppc-dev, kafai, Hari Bathini
With KUAP enabled, any kernel code which wants to access userspace
needs to be surrounded by disable-enable KUAP. But that is not
happening for BPF_PROBE_MEM load instruction. Though PPC32 does not
support read protection, considering the fact that PTR_TO_BTF_ID
(which uses BPF_PROBE_MEM mode) could either be a valid kernel pointer
or NULL but should never be a pointer to userspace address, execute
BPF_PROBE_MEM load only if addr is kernel address, otherwise set
dst_reg=0 and move on.
This will catch NULL, valid or invalid userspace pointers. Only bad
kernel pointer will be handled by BPF exception table.
[Alexei suggested for x86]
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
Changes in v4:
* Adjusted the emit code to avoid using temporary reg.
arch/powerpc/net/bpf_jit_comp32.c | 34 +++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 5dc45e393d1d..d3a52cd42f53 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -820,6 +820,40 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
case BPF_LDX | BPF_PROBE_MEM | BPF_W:
case BPF_LDX | BPF_MEM | BPF_DW: /* dst = *(u64 *)(ul) (src + off) */
case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
+ /*
+ * As PTR_TO_BTF_ID that uses BPF_PROBE_MEM mode could either be a valid
+ * kernel pointer or NULL but not a userspace address, execute BPF_PROBE_MEM
+ * load only if addr is kernel address (see is_kernel_addr()), otherwise
+ * set dst_reg=0 and move on.
+ */
+ if (BPF_MODE(code) == BPF_PROBE_MEM) {
+ PPC_LI32(_R0, TASK_SIZE - off);
+ EMIT(PPC_RAW_CMPLW(src_reg, _R0));
+ PPC_BCC(COND_GT, (ctx->idx + 5) * 4);
+ EMIT(PPC_RAW_LI(dst_reg, 0));
+ /*
+ * For BPF_DW case, "li reg_h,0" would be needed when
+ * !fp->aux->verifier_zext. Emit NOP otherwise.
+ *
+ * Note that "li reg_h,0" is emitted for BPF_B/H/W case,
+ * if necessary. So, jump there insted of emitting an
+ * additional "li reg_h,0" instruction.
+ */
+ if (size == BPF_DW && !fp->aux->verifier_zext)
+ EMIT(PPC_RAW_LI(dst_reg_h, 0));
+ else
+ EMIT(PPC_RAW_NOP());
+ /*
+ * Need to jump two instructions instead of one for BPF_DW case
+ * as there are two load instructions for dst_reg_h & dst_reg
+ * respectively.
+ */
+ if (size == BPF_DW)
+ PPC_JMP((ctx->idx + 3) * 4);
+ else
+ PPC_JMP((ctx->idx + 2) * 4);
+ }
+
switch (size) {
case BPF_B:
EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
--
2.31.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* RE: [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler
2021-10-12 12:30 ` Hari Bathini
@ 2021-10-14 8:15 ` David Laight
-1 siblings, 0 replies; 27+ messages in thread
From: David Laight @ 2021-10-14 8:15 UTC (permalink / raw)
To: 'Hari Bathini', naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev
From: Hari Bathini
> Sent: 12 October 2021 13:31
>
> Patch #1 & #2 are simple cleanup patches. Patch #3 refactors JIT
> compiler code with the aim to simplify adding BPF_PROBE_MEM support.
> Patch #4 introduces PPC_RAW_BRANCH() macro instead of open coding
> branch instruction. Patch #5 & #7 add BPF_PROBE_MEM support for PPC64
> & PPC32 JIT compilers respectively. Patch #6 & #8 handle bad userspace
> pointers for PPC64 & PPC32 cases respectively.
I thought that BPF was only allowed to do fairly restricted
memory accesses - so WTF does it need a BPF_PROBE_MEM instruction?
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
^ permalink raw reply [flat|nested] 27+ messages in thread
* RE: [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler
@ 2021-10-14 8:15 ` David Laight
0 siblings, 0 replies; 27+ messages in thread
From: David Laight @ 2021-10-14 8:15 UTC (permalink / raw)
To: 'Hari Bathini', naveen.n.rao, christophe.leroy, mpe, ast, daniel
Cc: songliubraving, netdev, john.fastabend, andrii, kpsingh, paulus,
yhs, bpf, linuxppc-dev, kafai
From: Hari Bathini
> Sent: 12 October 2021 13:31
>
> Patch #1 & #2 are simple cleanup patches. Patch #3 refactors JIT
> compiler code with the aim to simplify adding BPF_PROBE_MEM support.
> Patch #4 introduces PPC_RAW_BRANCH() macro instead of open coding
> branch instruction. Patch #5 & #7 add BPF_PROBE_MEM support for PPC64
> & PPC32 JIT compilers respectively. Patch #6 & #8 handle bad userspace
> pointers for PPC64 & PPC32 cases respectively.
I thought that BPF was only allowed to do fairly restricted
memory accesses - so WTF does it need a BPF_PROBE_MEM instruction?
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler
2021-10-14 8:15 ` David Laight
@ 2021-10-14 8:33 ` Christophe Leroy
-1 siblings, 0 replies; 27+ messages in thread
From: Christophe Leroy @ 2021-10-14 8:33 UTC (permalink / raw)
To: David Laight, 'Hari Bathini', naveen.n.rao, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev
Le 14/10/2021 à 10:15, David Laight a écrit :
> From: Hari Bathini
>> Sent: 12 October 2021 13:31
>>
>> Patch #1 & #2 are simple cleanup patches. Patch #3 refactors JIT
>> compiler code with the aim to simplify adding BPF_PROBE_MEM support.
>> Patch #4 introduces PPC_RAW_BRANCH() macro instead of open coding
>> branch instruction. Patch #5 & #7 add BPF_PROBE_MEM support for PPC64
>> & PPC32 JIT compilers respectively. Patch #6 & #8 handle bad userspace
>> pointers for PPC64 & PPC32 cases respectively.
>
> I thought that BPF was only allowed to do fairly restricted
> memory accesses - so WTF does it need a BPF_PROBE_MEM instruction?
>
Looks like it's been added by commit 2a02759ef5f8 ("bpf: Add support for
BTF pointers to interpreter")
They say in the log:
Pointer to BTF object is a pointer to kernel object or NULL.
The memory access in the interpreter has to be done via
probe_kernel_read
to avoid page faults.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler
@ 2021-10-14 8:33 ` Christophe Leroy
0 siblings, 0 replies; 27+ messages in thread
From: Christophe Leroy @ 2021-10-14 8:33 UTC (permalink / raw)
To: David Laight, 'Hari Bathini', naveen.n.rao, mpe, ast, daniel
Cc: songliubraving, netdev, john.fastabend, andrii, kpsingh, paulus,
yhs, bpf, linuxppc-dev, kafai
Le 14/10/2021 à 10:15, David Laight a écrit :
> From: Hari Bathini
>> Sent: 12 October 2021 13:31
>>
>> Patch #1 & #2 are simple cleanup patches. Patch #3 refactors JIT
>> compiler code with the aim to simplify adding BPF_PROBE_MEM support.
>> Patch #4 introduces PPC_RAW_BRANCH() macro instead of open coding
>> branch instruction. Patch #5 & #7 add BPF_PROBE_MEM support for PPC64
>> & PPC32 JIT compilers respectively. Patch #6 & #8 handle bad userspace
>> pointers for PPC64 & PPC32 cases respectively.
>
> I thought that BPF was only allowed to do fairly restricted
> memory accesses - so WTF does it need a BPF_PROBE_MEM instruction?
>
Looks like it's been added by commit 2a02759ef5f8 ("bpf: Add support for
BTF pointers to interpreter")
They say in the log:
Pointer to BTF object is a pointer to kernel object or NULL.
The memory access in the interpreter has to be done via
probe_kernel_read
to avoid page faults.
^ permalink raw reply [flat|nested] 27+ messages in thread
* RE: [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler
2021-10-14 8:33 ` Christophe Leroy
@ 2021-10-14 9:52 ` David Laight
-1 siblings, 0 replies; 27+ messages in thread
From: David Laight @ 2021-10-14 9:52 UTC (permalink / raw)
To: 'Christophe Leroy', 'Hari Bathini',
naveen.n.rao, mpe, ast, daniel
Cc: paulus, andrii, kafai, songliubraving, yhs, john.fastabend,
kpsingh, netdev, bpf, linuxppc-dev
From: Christophe Leroy
> Sent: 14 October 2021 09:34
>
> Le 14/10/2021 à 10:15, David Laight a écrit :
> > From: Hari Bathini
> >> Sent: 12 October 2021 13:31
> >>
> >> Patch #1 & #2 are simple cleanup patches. Patch #3 refactors JIT
> >> compiler code with the aim to simplify adding BPF_PROBE_MEM support.
> >> Patch #4 introduces PPC_RAW_BRANCH() macro instead of open coding
> >> branch instruction. Patch #5 & #7 add BPF_PROBE_MEM support for PPC64
> >> & PPC32 JIT compilers respectively. Patch #6 & #8 handle bad userspace
> >> pointers for PPC64 & PPC32 cases respectively.
> >
> > I thought that BPF was only allowed to do fairly restricted
> > memory accesses - so WTF does it need a BPF_PROBE_MEM instruction?
> >
>
>
> Looks like it's been added by commit 2a02759ef5f8 ("bpf: Add support for
> BTF pointers to interpreter")
>
> They say in the log:
>
> Pointer to BTF object is a pointer to kernel object or NULL.
> The memory access in the interpreter has to be done via
> probe_kernel_read to avoid page faults.
Hmmm....
Either the pointer should be valid (if not NULL) or they should
verify that it is the address of an interpreter.
If the value is being passed to/from userspace then they
are leaking kernel address - and that needs to be squashed.
They should be using an opaque identifier for the interpreter.
My gut feeling is that a lot of the changes to bpf over the last
few years means that it is no longer a verifiably safe simple
filter engine.
As such the you might as well load a normal kernel module.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
^ permalink raw reply [flat|nested] 27+ messages in thread
* RE: [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler
@ 2021-10-14 9:52 ` David Laight
0 siblings, 0 replies; 27+ messages in thread
From: David Laight @ 2021-10-14 9:52 UTC (permalink / raw)
To: 'Christophe Leroy', 'Hari Bathini',
naveen.n.rao, mpe, ast, daniel
Cc: songliubraving, netdev, john.fastabend, andrii, kpsingh, paulus,
yhs, bpf, linuxppc-dev, kafai
From: Christophe Leroy
> Sent: 14 October 2021 09:34
>
> Le 14/10/2021 à 10:15, David Laight a écrit :
> > From: Hari Bathini
> >> Sent: 12 October 2021 13:31
> >>
> >> Patch #1 & #2 are simple cleanup patches. Patch #3 refactors JIT
> >> compiler code with the aim to simplify adding BPF_PROBE_MEM support.
> >> Patch #4 introduces PPC_RAW_BRANCH() macro instead of open coding
> >> branch instruction. Patch #5 & #7 add BPF_PROBE_MEM support for PPC64
> >> & PPC32 JIT compilers respectively. Patch #6 & #8 handle bad userspace
> >> pointers for PPC64 & PPC32 cases respectively.
> >
> > I thought that BPF was only allowed to do fairly restricted
> > memory accesses - so WTF does it need a BPF_PROBE_MEM instruction?
> >
>
>
> Looks like it's been added by commit 2a02759ef5f8 ("bpf: Add support for
> BTF pointers to interpreter")
>
> They say in the log:
>
> Pointer to BTF object is a pointer to kernel object or NULL.
> The memory access in the interpreter has to be done via
> probe_kernel_read to avoid page faults.
Hmmm....
Either the pointer should be valid (if not NULL) or they should
verify that it is the address of an interpreter.
If the value is being passed to/from userspace then they
are leaking kernel address - and that needs to be squashed.
They should be using an opaque identifier for the interpreter.
My gut feeling is that a lot of the changes to bpf over the last
few years means that it is no longer a verifiably safe simple
filter engine.
As such the you might as well load a normal kernel module.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [RESEND PATCH v4 6/8] bpf ppc64: Access only if addr is kernel address
2021-10-12 12:30 ` Hari Bathini
(?)
@ 2021-11-08 13:04 ` kernel test robot
-1 siblings, 0 replies; 27+ messages in thread
From: kernel test robot @ 2021-11-08 13:04 UTC (permalink / raw)
To: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 23158 bytes --]
Hi Hari,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on v5.15-rc5]
[also build test WARNING on next-20211108]
[cannot apply to powerpc/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Hari-Bathini/bpf-powerpc-Add-BPF_PROBE_MEM-support-in-powerpc-JIT-compiler/20211012-205813
base: DEBUG invalid remote for branch v5.15-rc5 64570fbc14f8d7cb3fe3995f20e26bc25ce4b2cc
config: powerpc64-randconfig-s031-20211016 (attached as .config)
compiler: powerpc64-linux-gcc (GCC) 11.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# apt-get install sparse
# sparse version: v0.6.4-dirty
# https://github.com/0day-ci/linux/commit/be6c692c4b1d002a5511309c5cfd2b555dec4af8
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Hari-Bathini/bpf-powerpc-Add-BPF_PROBE_MEM-support-in-powerpc-JIT-compiler/20211012-205813
git checkout be6c692c4b1d002a5511309c5cfd2b555dec4af8
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=powerpc SHELL=/bin/bash arch/powerpc/mm/nohash/ arch/powerpc/net/
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
sparse warnings: (new ones prefixed by >>)
>> arch/powerpc/net/bpf_jit_comp64.c:801:41: sparse: sparse: cast truncates bits from constant value (8000000000000000 becomes 0)
>> arch/powerpc/net/bpf_jit_comp64.c:801:41: sparse: sparse: cast truncates bits from constant value (8000000000000000 becomes 0)
>> arch/powerpc/net/bpf_jit_comp64.c:803:41: sparse: sparse: cast truncates bits from constant value (c000000000000000 becomes 0)
>> arch/powerpc/net/bpf_jit_comp64.c:803:41: sparse: sparse: cast truncates bits from constant value (c000000000000000 becomes 0)
vim +801 arch/powerpc/net/bpf_jit_comp64.c
297
298 /* Assemble the body code between the prologue & epilogue */
299 int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
300 u32 *addrs, int pass)
301 {
302 enum stf_barrier_type stf_barrier = stf_barrier_type_get();
303 const struct bpf_insn *insn = fp->insnsi;
304 int flen = fp->len;
305 int i, ret;
306
307 /* Start of epilogue code - will only be valid 2nd pass onwards */
308 u32 exit_addr = addrs[flen];
309
310 for (i = 0; i < flen; i++) {
311 u32 code = insn[i].code;
312 u32 dst_reg = b2p[insn[i].dst_reg];
313 u32 src_reg = b2p[insn[i].src_reg];
314 u32 size = BPF_SIZE(code);
315 s16 off = insn[i].off;
316 s32 imm = insn[i].imm;
317 bool func_addr_fixed;
318 u64 func_addr;
319 u64 imm64;
320 u32 true_cond;
321 u32 tmp_idx;
322
323 /*
324 * addrs[] maps a BPF bytecode address into a real offset from
325 * the start of the body code.
326 */
327 addrs[i] = ctx->idx * 4;
328
329 /*
330 * As an optimization, we note down which non-volatile registers
331 * are used so that we can only save/restore those in our
332 * prologue and epilogue. We do this here regardless of whether
333 * the actual BPF instruction uses src/dst registers or not
334 * (for instance, BPF_CALL does not use them). The expectation
335 * is that those instructions will have src_reg/dst_reg set to
336 * 0. Even otherwise, we just lose some prologue/epilogue
337 * optimization but everything else should work without
338 * any issues.
339 */
340 if (dst_reg >= BPF_PPC_NVR_MIN && dst_reg < 32)
341 bpf_set_seen_register(ctx, dst_reg);
342 if (src_reg >= BPF_PPC_NVR_MIN && src_reg < 32)
343 bpf_set_seen_register(ctx, src_reg);
344
345 switch (code) {
346 /*
347 * Arithmetic operations: ADD/SUB/MUL/DIV/MOD/NEG
348 */
349 case BPF_ALU | BPF_ADD | BPF_X: /* (u32) dst += (u32) src */
350 case BPF_ALU64 | BPF_ADD | BPF_X: /* dst += src */
351 EMIT(PPC_RAW_ADD(dst_reg, dst_reg, src_reg));
352 goto bpf_alu32_trunc;
353 case BPF_ALU | BPF_SUB | BPF_X: /* (u32) dst -= (u32) src */
354 case BPF_ALU64 | BPF_SUB | BPF_X: /* dst -= src */
355 EMIT(PPC_RAW_SUB(dst_reg, dst_reg, src_reg));
356 goto bpf_alu32_trunc;
357 case BPF_ALU | BPF_ADD | BPF_K: /* (u32) dst += (u32) imm */
358 case BPF_ALU64 | BPF_ADD | BPF_K: /* dst += imm */
359 if (!imm) {
360 goto bpf_alu32_trunc;
361 } else if (imm >= -32768 && imm < 32768) {
362 EMIT(PPC_RAW_ADDI(dst_reg, dst_reg, IMM_L(imm)));
363 } else {
364 PPC_LI32(b2p[TMP_REG_1], imm);
365 EMIT(PPC_RAW_ADD(dst_reg, dst_reg, b2p[TMP_REG_1]));
366 }
367 goto bpf_alu32_trunc;
368 case BPF_ALU | BPF_SUB | BPF_K: /* (u32) dst -= (u32) imm */
369 case BPF_ALU64 | BPF_SUB | BPF_K: /* dst -= imm */
370 if (!imm) {
371 goto bpf_alu32_trunc;
372 } else if (imm > -32768 && imm <= 32768) {
373 EMIT(PPC_RAW_ADDI(dst_reg, dst_reg, IMM_L(-imm)));
374 } else {
375 PPC_LI32(b2p[TMP_REG_1], imm);
376 EMIT(PPC_RAW_SUB(dst_reg, dst_reg, b2p[TMP_REG_1]));
377 }
378 goto bpf_alu32_trunc;
379 case BPF_ALU | BPF_MUL | BPF_X: /* (u32) dst *= (u32) src */
380 case BPF_ALU64 | BPF_MUL | BPF_X: /* dst *= src */
381 if (BPF_CLASS(code) == BPF_ALU)
382 EMIT(PPC_RAW_MULW(dst_reg, dst_reg, src_reg));
383 else
384 EMIT(PPC_RAW_MULD(dst_reg, dst_reg, src_reg));
385 goto bpf_alu32_trunc;
386 case BPF_ALU | BPF_MUL | BPF_K: /* (u32) dst *= (u32) imm */
387 case BPF_ALU64 | BPF_MUL | BPF_K: /* dst *= imm */
388 if (imm >= -32768 && imm < 32768)
389 EMIT(PPC_RAW_MULI(dst_reg, dst_reg, IMM_L(imm)));
390 else {
391 PPC_LI32(b2p[TMP_REG_1], imm);
392 if (BPF_CLASS(code) == BPF_ALU)
393 EMIT(PPC_RAW_MULW(dst_reg, dst_reg,
394 b2p[TMP_REG_1]));
395 else
396 EMIT(PPC_RAW_MULD(dst_reg, dst_reg,
397 b2p[TMP_REG_1]));
398 }
399 goto bpf_alu32_trunc;
400 case BPF_ALU | BPF_DIV | BPF_X: /* (u32) dst /= (u32) src */
401 case BPF_ALU | BPF_MOD | BPF_X: /* (u32) dst %= (u32) src */
402 if (BPF_OP(code) == BPF_MOD) {
403 EMIT(PPC_RAW_DIVWU(b2p[TMP_REG_1], dst_reg, src_reg));
404 EMIT(PPC_RAW_MULW(b2p[TMP_REG_1], src_reg,
405 b2p[TMP_REG_1]));
406 EMIT(PPC_RAW_SUB(dst_reg, dst_reg, b2p[TMP_REG_1]));
407 } else
408 EMIT(PPC_RAW_DIVWU(dst_reg, dst_reg, src_reg));
409 goto bpf_alu32_trunc;
410 case BPF_ALU64 | BPF_DIV | BPF_X: /* dst /= src */
411 case BPF_ALU64 | BPF_MOD | BPF_X: /* dst %= src */
412 if (BPF_OP(code) == BPF_MOD) {
413 EMIT(PPC_RAW_DIVDU(b2p[TMP_REG_1], dst_reg, src_reg));
414 EMIT(PPC_RAW_MULD(b2p[TMP_REG_1], src_reg,
415 b2p[TMP_REG_1]));
416 EMIT(PPC_RAW_SUB(dst_reg, dst_reg, b2p[TMP_REG_1]));
417 } else
418 EMIT(PPC_RAW_DIVDU(dst_reg, dst_reg, src_reg));
419 break;
420 case BPF_ALU | BPF_MOD | BPF_K: /* (u32) dst %= (u32) imm */
421 case BPF_ALU | BPF_DIV | BPF_K: /* (u32) dst /= (u32) imm */
422 case BPF_ALU64 | BPF_MOD | BPF_K: /* dst %= imm */
423 case BPF_ALU64 | BPF_DIV | BPF_K: /* dst /= imm */
424 if (imm == 0)
425 return -EINVAL;
426 if (imm == 1) {
427 if (BPF_OP(code) == BPF_DIV) {
428 goto bpf_alu32_trunc;
429 } else {
430 EMIT(PPC_RAW_LI(dst_reg, 0));
431 break;
432 }
433 }
434
435 PPC_LI32(b2p[TMP_REG_1], imm);
436 switch (BPF_CLASS(code)) {
437 case BPF_ALU:
438 if (BPF_OP(code) == BPF_MOD) {
439 EMIT(PPC_RAW_DIVWU(b2p[TMP_REG_2],
440 dst_reg,
441 b2p[TMP_REG_1]));
442 EMIT(PPC_RAW_MULW(b2p[TMP_REG_1],
443 b2p[TMP_REG_1],
444 b2p[TMP_REG_2]));
445 EMIT(PPC_RAW_SUB(dst_reg, dst_reg,
446 b2p[TMP_REG_1]));
447 } else
448 EMIT(PPC_RAW_DIVWU(dst_reg, dst_reg,
449 b2p[TMP_REG_1]));
450 break;
451 case BPF_ALU64:
452 if (BPF_OP(code) == BPF_MOD) {
453 EMIT(PPC_RAW_DIVDU(b2p[TMP_REG_2],
454 dst_reg,
455 b2p[TMP_REG_1]));
456 EMIT(PPC_RAW_MULD(b2p[TMP_REG_1],
457 b2p[TMP_REG_1],
458 b2p[TMP_REG_2]));
459 EMIT(PPC_RAW_SUB(dst_reg, dst_reg,
460 b2p[TMP_REG_1]));
461 } else
462 EMIT(PPC_RAW_DIVDU(dst_reg, dst_reg,
463 b2p[TMP_REG_1]));
464 break;
465 }
466 goto bpf_alu32_trunc;
467 case BPF_ALU | BPF_NEG: /* (u32) dst = -dst */
468 case BPF_ALU64 | BPF_NEG: /* dst = -dst */
469 EMIT(PPC_RAW_NEG(dst_reg, dst_reg));
470 goto bpf_alu32_trunc;
471
472 /*
473 * Logical operations: AND/OR/XOR/[A]LSH/[A]RSH
474 */
475 case BPF_ALU | BPF_AND | BPF_X: /* (u32) dst = dst & src */
476 case BPF_ALU64 | BPF_AND | BPF_X: /* dst = dst & src */
477 EMIT(PPC_RAW_AND(dst_reg, dst_reg, src_reg));
478 goto bpf_alu32_trunc;
479 case BPF_ALU | BPF_AND | BPF_K: /* (u32) dst = dst & imm */
480 case BPF_ALU64 | BPF_AND | BPF_K: /* dst = dst & imm */
481 if (!IMM_H(imm))
482 EMIT(PPC_RAW_ANDI(dst_reg, dst_reg, IMM_L(imm)));
483 else {
484 /* Sign-extended */
485 PPC_LI32(b2p[TMP_REG_1], imm);
486 EMIT(PPC_RAW_AND(dst_reg, dst_reg, b2p[TMP_REG_1]));
487 }
488 goto bpf_alu32_trunc;
489 case BPF_ALU | BPF_OR | BPF_X: /* dst = (u32) dst | (u32) src */
490 case BPF_ALU64 | BPF_OR | BPF_X: /* dst = dst | src */
491 EMIT(PPC_RAW_OR(dst_reg, dst_reg, src_reg));
492 goto bpf_alu32_trunc;
493 case BPF_ALU | BPF_OR | BPF_K:/* dst = (u32) dst | (u32) imm */
494 case BPF_ALU64 | BPF_OR | BPF_K:/* dst = dst | imm */
495 if (imm < 0 && BPF_CLASS(code) == BPF_ALU64) {
496 /* Sign-extended */
497 PPC_LI32(b2p[TMP_REG_1], imm);
498 EMIT(PPC_RAW_OR(dst_reg, dst_reg, b2p[TMP_REG_1]));
499 } else {
500 if (IMM_L(imm))
501 EMIT(PPC_RAW_ORI(dst_reg, dst_reg, IMM_L(imm)));
502 if (IMM_H(imm))
503 EMIT(PPC_RAW_ORIS(dst_reg, dst_reg, IMM_H(imm)));
504 }
505 goto bpf_alu32_trunc;
506 case BPF_ALU | BPF_XOR | BPF_X: /* (u32) dst ^= src */
507 case BPF_ALU64 | BPF_XOR | BPF_X: /* dst ^= src */
508 EMIT(PPC_RAW_XOR(dst_reg, dst_reg, src_reg));
509 goto bpf_alu32_trunc;
510 case BPF_ALU | BPF_XOR | BPF_K: /* (u32) dst ^= (u32) imm */
511 case BPF_ALU64 | BPF_XOR | BPF_K: /* dst ^= imm */
512 if (imm < 0 && BPF_CLASS(code) == BPF_ALU64) {
513 /* Sign-extended */
514 PPC_LI32(b2p[TMP_REG_1], imm);
515 EMIT(PPC_RAW_XOR(dst_reg, dst_reg, b2p[TMP_REG_1]));
516 } else {
517 if (IMM_L(imm))
518 EMIT(PPC_RAW_XORI(dst_reg, dst_reg, IMM_L(imm)));
519 if (IMM_H(imm))
520 EMIT(PPC_RAW_XORIS(dst_reg, dst_reg, IMM_H(imm)));
521 }
522 goto bpf_alu32_trunc;
523 case BPF_ALU | BPF_LSH | BPF_X: /* (u32) dst <<= (u32) src */
524 /* slw clears top 32 bits */
525 EMIT(PPC_RAW_SLW(dst_reg, dst_reg, src_reg));
526 /* skip zero extension move, but set address map. */
527 if (insn_is_zext(&insn[i + 1]))
528 addrs[++i] = ctx->idx * 4;
529 break;
530 case BPF_ALU64 | BPF_LSH | BPF_X: /* dst <<= src; */
531 EMIT(PPC_RAW_SLD(dst_reg, dst_reg, src_reg));
532 break;
533 case BPF_ALU | BPF_LSH | BPF_K: /* (u32) dst <<== (u32) imm */
534 /* with imm 0, we still need to clear top 32 bits */
535 EMIT(PPC_RAW_SLWI(dst_reg, dst_reg, imm));
536 if (insn_is_zext(&insn[i + 1]))
537 addrs[++i] = ctx->idx * 4;
538 break;
539 case BPF_ALU64 | BPF_LSH | BPF_K: /* dst <<== imm */
540 if (imm != 0)
541 EMIT(PPC_RAW_SLDI(dst_reg, dst_reg, imm));
542 break;
543 case BPF_ALU | BPF_RSH | BPF_X: /* (u32) dst >>= (u32) src */
544 EMIT(PPC_RAW_SRW(dst_reg, dst_reg, src_reg));
545 if (insn_is_zext(&insn[i + 1]))
546 addrs[++i] = ctx->idx * 4;
547 break;
548 case BPF_ALU64 | BPF_RSH | BPF_X: /* dst >>= src */
549 EMIT(PPC_RAW_SRD(dst_reg, dst_reg, src_reg));
550 break;
551 case BPF_ALU | BPF_RSH | BPF_K: /* (u32) dst >>= (u32) imm */
552 EMIT(PPC_RAW_SRWI(dst_reg, dst_reg, imm));
553 if (insn_is_zext(&insn[i + 1]))
554 addrs[++i] = ctx->idx * 4;
555 break;
556 case BPF_ALU64 | BPF_RSH | BPF_K: /* dst >>= imm */
557 if (imm != 0)
558 EMIT(PPC_RAW_SRDI(dst_reg, dst_reg, imm));
559 break;
560 case BPF_ALU | BPF_ARSH | BPF_X: /* (s32) dst >>= src */
561 EMIT(PPC_RAW_SRAW(dst_reg, dst_reg, src_reg));
562 goto bpf_alu32_trunc;
563 case BPF_ALU64 | BPF_ARSH | BPF_X: /* (s64) dst >>= src */
564 EMIT(PPC_RAW_SRAD(dst_reg, dst_reg, src_reg));
565 break;
566 case BPF_ALU | BPF_ARSH | BPF_K: /* (s32) dst >>= imm */
567 EMIT(PPC_RAW_SRAWI(dst_reg, dst_reg, imm));
568 goto bpf_alu32_trunc;
569 case BPF_ALU64 | BPF_ARSH | BPF_K: /* (s64) dst >>= imm */
570 if (imm != 0)
571 EMIT(PPC_RAW_SRADI(dst_reg, dst_reg, imm));
572 break;
573
574 /*
575 * MOV
576 */
577 case BPF_ALU | BPF_MOV | BPF_X: /* (u32) dst = src */
578 case BPF_ALU64 | BPF_MOV | BPF_X: /* dst = src */
579 if (imm == 1) {
580 /* special mov32 for zext */
581 EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 0, 0, 31));
582 break;
583 }
584 EMIT(PPC_RAW_MR(dst_reg, src_reg));
585 goto bpf_alu32_trunc;
586 case BPF_ALU | BPF_MOV | BPF_K: /* (u32) dst = imm */
587 case BPF_ALU64 | BPF_MOV | BPF_K: /* dst = (s64) imm */
588 PPC_LI32(dst_reg, imm);
589 if (imm < 0)
590 goto bpf_alu32_trunc;
591 else if (insn_is_zext(&insn[i + 1]))
592 addrs[++i] = ctx->idx * 4;
593 break;
594
595 bpf_alu32_trunc:
596 /* Truncate to 32-bits */
597 if (BPF_CLASS(code) == BPF_ALU && !fp->aux->verifier_zext)
598 EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 0, 0, 31));
599 break;
600
601 /*
602 * BPF_FROM_BE/LE
603 */
604 case BPF_ALU | BPF_END | BPF_FROM_LE:
605 case BPF_ALU | BPF_END | BPF_FROM_BE:
606 #ifdef __BIG_ENDIAN__
607 if (BPF_SRC(code) == BPF_FROM_BE)
608 goto emit_clear;
609 #else /* !__BIG_ENDIAN__ */
610 if (BPF_SRC(code) == BPF_FROM_LE)
611 goto emit_clear;
612 #endif
613 switch (imm) {
614 case 16:
615 /* Rotate 8 bits left & mask with 0x0000ff00 */
616 EMIT(PPC_RAW_RLWINM(b2p[TMP_REG_1], dst_reg, 8, 16, 23));
617 /* Rotate 8 bits right & insert LSB to reg */
618 EMIT(PPC_RAW_RLWIMI(b2p[TMP_REG_1], dst_reg, 24, 24, 31));
619 /* Move result back to dst_reg */
620 EMIT(PPC_RAW_MR(dst_reg, b2p[TMP_REG_1]));
621 break;
622 case 32:
623 /*
624 * Rotate word left by 8 bits:
625 * 2 bytes are already in their final position
626 * -- byte 2 and 4 (of bytes 1, 2, 3 and 4)
627 */
628 EMIT(PPC_RAW_RLWINM(b2p[TMP_REG_1], dst_reg, 8, 0, 31));
629 /* Rotate 24 bits and insert byte 1 */
630 EMIT(PPC_RAW_RLWIMI(b2p[TMP_REG_1], dst_reg, 24, 0, 7));
631 /* Rotate 24 bits and insert byte 3 */
632 EMIT(PPC_RAW_RLWIMI(b2p[TMP_REG_1], dst_reg, 24, 16, 23));
633 EMIT(PPC_RAW_MR(dst_reg, b2p[TMP_REG_1]));
634 break;
635 case 64:
636 /*
637 * Way easier and faster(?) to store the value
638 * into stack and then use ldbrx
639 *
640 * ctx->seen will be reliable in pass2, but
641 * the instructions generated will remain the
642 * same across all passes
643 */
644 PPC_BPF_STL(dst_reg, 1, bpf_jit_stack_local(ctx));
645 EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], 1, bpf_jit_stack_local(ctx)));
646 EMIT(PPC_RAW_LDBRX(dst_reg, 0, b2p[TMP_REG_1]));
647 break;
648 }
649 break;
650
651 emit_clear:
652 switch (imm) {
653 case 16:
654 /* zero-extend 16 bits into 64 bits */
655 EMIT(PPC_RAW_RLDICL(dst_reg, dst_reg, 0, 48));
656 if (insn_is_zext(&insn[i + 1]))
657 addrs[++i] = ctx->idx * 4;
658 break;
659 case 32:
660 if (!fp->aux->verifier_zext)
661 /* zero-extend 32 bits into 64 bits */
662 EMIT(PPC_RAW_RLDICL(dst_reg, dst_reg, 0, 32));
663 break;
664 case 64:
665 /* nop */
666 break;
667 }
668 break;
669
670 /*
671 * BPF_ST NOSPEC (speculation barrier)
672 */
673 case BPF_ST | BPF_NOSPEC:
674 if (!security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) ||
675 !security_ftr_enabled(SEC_FTR_STF_BARRIER))
676 break;
677
678 switch (stf_barrier) {
679 case STF_BARRIER_EIEIO:
680 EMIT(PPC_RAW_EIEIO() | 0x02000000);
681 break;
682 case STF_BARRIER_SYNC_ORI:
683 EMIT(PPC_RAW_SYNC());
684 EMIT(PPC_RAW_LD(b2p[TMP_REG_1], _R13, 0));
685 EMIT(PPC_RAW_ORI(_R31, _R31, 0));
686 break;
687 case STF_BARRIER_FALLBACK:
688 EMIT(PPC_RAW_MFLR(b2p[TMP_REG_1]));
689 PPC_LI64(12, dereference_kernel_function_descriptor(bpf_stf_barrier));
690 EMIT(PPC_RAW_MTCTR(12));
691 EMIT(PPC_RAW_BCTRL());
692 EMIT(PPC_RAW_MTLR(b2p[TMP_REG_1]));
693 break;
694 case STF_BARRIER_NONE:
695 break;
696 }
697 break;
698
699 /*
700 * BPF_ST(X)
701 */
702 case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src */
703 case BPF_ST | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = imm */
704 if (BPF_CLASS(code) == BPF_ST) {
705 EMIT(PPC_RAW_LI(b2p[TMP_REG_1], imm));
706 src_reg = b2p[TMP_REG_1];
707 }
708 EMIT(PPC_RAW_STB(src_reg, dst_reg, off));
709 break;
710 case BPF_STX | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = src */
711 case BPF_ST | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = imm */
712 if (BPF_CLASS(code) == BPF_ST) {
713 EMIT(PPC_RAW_LI(b2p[TMP_REG_1], imm));
714 src_reg = b2p[TMP_REG_1];
715 }
716 EMIT(PPC_RAW_STH(src_reg, dst_reg, off));
717 break;
718 case BPF_STX | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = src */
719 case BPF_ST | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = imm */
720 if (BPF_CLASS(code) == BPF_ST) {
721 PPC_LI32(b2p[TMP_REG_1], imm);
722 src_reg = b2p[TMP_REG_1];
723 }
724 EMIT(PPC_RAW_STW(src_reg, dst_reg, off));
725 break;
726 case BPF_STX | BPF_MEM | BPF_DW: /* (u64 *)(dst + off) = src */
727 case BPF_ST | BPF_MEM | BPF_DW: /* *(u64 *)(dst + off) = imm */
728 if (BPF_CLASS(code) == BPF_ST) {
729 PPC_LI32(b2p[TMP_REG_1], imm);
730 src_reg = b2p[TMP_REG_1];
731 }
732 PPC_BPF_STL(src_reg, dst_reg, off);
733 break;
734
735 /*
736 * BPF_STX ATOMIC (atomic ops)
737 */
738 case BPF_STX | BPF_ATOMIC | BPF_W:
739 if (imm != BPF_ADD) {
740 pr_err_ratelimited(
741 "eBPF filter atomic op code %02x (@%d) unsupported\n",
742 code, i);
743 return -ENOTSUPP;
744 }
745
746 /* *(u32 *)(dst + off) += src */
747
748 /* Get EA into TMP_REG_1 */
749 EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], dst_reg, off));
750 tmp_idx = ctx->idx * 4;
751 /* load value from memory into TMP_REG_2 */
752 EMIT(PPC_RAW_LWARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0));
753 /* add value from src_reg into this */
754 EMIT(PPC_RAW_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg));
755 /* store result back */
756 EMIT(PPC_RAW_STWCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]));
757 /* we're done if this succeeded */
758 PPC_BCC_SHORT(COND_NE, tmp_idx);
759 break;
760 case BPF_STX | BPF_ATOMIC | BPF_DW:
761 if (imm != BPF_ADD) {
762 pr_err_ratelimited(
763 "eBPF filter atomic op code %02x (@%d) unsupported\n",
764 code, i);
765 return -ENOTSUPP;
766 }
767 /* *(u64 *)(dst + off) += src */
768
769 EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], dst_reg, off));
770 tmp_idx = ctx->idx * 4;
771 EMIT(PPC_RAW_LDARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0));
772 EMIT(PPC_RAW_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg));
773 EMIT(PPC_RAW_STDCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]));
774 PPC_BCC_SHORT(COND_NE, tmp_idx);
775 break;
776
777 /*
778 * BPF_LDX
779 */
780 /* dst = *(u8 *)(ul) (src + off) */
781 case BPF_LDX | BPF_MEM | BPF_B:
782 case BPF_LDX | BPF_PROBE_MEM | BPF_B:
783 /* dst = *(u16 *)(ul) (src + off) */
784 case BPF_LDX | BPF_MEM | BPF_H:
785 case BPF_LDX | BPF_PROBE_MEM | BPF_H:
786 /* dst = *(u32 *)(ul) (src + off) */
787 case BPF_LDX | BPF_MEM | BPF_W:
788 case BPF_LDX | BPF_PROBE_MEM | BPF_W:
789 /* dst = *(u64 *)(ul) (src + off) */
790 case BPF_LDX | BPF_MEM | BPF_DW:
791 case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
792 /*
793 * As PTR_TO_BTF_ID that uses BPF_PROBE_MEM mode could either be a valid
794 * kernel pointer or NULL but not a userspace address, execute BPF_PROBE_MEM
795 * load only if addr is kernel address (see is_kernel_addr()), otherwise
796 * set dst_reg=0 and move on.
797 */
798 if (BPF_MODE(code) == BPF_PROBE_MEM) {
799 EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], src_reg, off));
800 if (IS_ENABLED(CONFIG_PPC_BOOK3E_64))
> 801 PPC_LI64(b2p[TMP_REG_2], 0x8000000000000000ul);
802 else /* BOOK3S_64 */
> 803 PPC_LI64(b2p[TMP_REG_2], PAGE_OFFSET);
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 37979 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler
2021-10-12 12:30 ` Hari Bathini
@ 2021-11-25 9:36 ` Michael Ellerman
-1 siblings, 0 replies; 27+ messages in thread
From: Michael Ellerman @ 2021-11-25 9:36 UTC (permalink / raw)
To: ast, daniel, naveen.n.rao, mpe, christophe.leroy, Hari Bathini
Cc: songliubraving, netdev, john.fastabend, andrii, kpsingh, paulus,
yhs, bpf, linuxppc-dev, kafai
On Tue, 12 Oct 2021 18:00:48 +0530, Hari Bathini wrote:
> Patch #1 & #2 are simple cleanup patches. Patch #3 refactors JIT
> compiler code with the aim to simplify adding BPF_PROBE_MEM support.
> Patch #4 introduces PPC_RAW_BRANCH() macro instead of open coding
> branch instruction. Patch #5 & #7 add BPF_PROBE_MEM support for PPC64
> & PPC32 JIT compilers respectively. Patch #6 & #8 handle bad userspace
> pointers for PPC64 & PPC32 cases respectively.
>
> [...]
Applied to powerpc/next.
[1/8] bpf powerpc: Remove unused SEEN_STACK
https://git.kernel.org/powerpc/c/c9ce7c36e4870bd307101ba7a00a39d9aad270f3
[2/8] bpf powerpc: Remove extra_pass from bpf_jit_build_body()
https://git.kernel.org/powerpc/c/04c04205bc35d0ecdc57146995ca9eb957d4f379
[3/8] bpf powerpc: refactor JIT compiler code
https://git.kernel.org/powerpc/c/efa95f031bf38c85cf865413335a3dc044e3194e
[4/8] powerpc/ppc-opcode: introduce PPC_RAW_BRANCH() macro
https://git.kernel.org/powerpc/c/f15a71b3880bf07b40810644e5ac6f177c2a7c8f
[5/8] bpf ppc64: Add BPF_PROBE_MEM support for JIT
https://git.kernel.org/powerpc/c/983bdc0245a29cdefcd30d9d484d3edbc4b6d787
[6/8] bpf ppc64: Access only if addr is kernel address
https://git.kernel.org/powerpc/c/9c70c7147ffec31de67d33243570a533b29f9759
[7/8] bpf ppc32: Add BPF_PROBE_MEM support for JIT
https://git.kernel.org/powerpc/c/23b51916ee129833453d8a3d6bde0ff392f82fce
[8/8] bpf ppc32: Access only if addr is kernel address
https://git.kernel.org/powerpc/c/e919c0b2323bedec00e1ecc6280498ff81f59b15
cheers
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler
@ 2021-11-25 9:36 ` Michael Ellerman
0 siblings, 0 replies; 27+ messages in thread
From: Michael Ellerman @ 2021-11-25 9:36 UTC (permalink / raw)
To: ast, daniel, naveen.n.rao, mpe, christophe.leroy, Hari Bathini
Cc: songliubraving, yhs, andrii, john.fastabend, bpf, paulus,
kpsingh, kafai, netdev, linuxppc-dev
On Tue, 12 Oct 2021 18:00:48 +0530, Hari Bathini wrote:
> Patch #1 & #2 are simple cleanup patches. Patch #3 refactors JIT
> compiler code with the aim to simplify adding BPF_PROBE_MEM support.
> Patch #4 introduces PPC_RAW_BRANCH() macro instead of open coding
> branch instruction. Patch #5 & #7 add BPF_PROBE_MEM support for PPC64
> & PPC32 JIT compilers respectively. Patch #6 & #8 handle bad userspace
> pointers for PPC64 & PPC32 cases respectively.
>
> [...]
Applied to powerpc/next.
[1/8] bpf powerpc: Remove unused SEEN_STACK
https://git.kernel.org/powerpc/c/c9ce7c36e4870bd307101ba7a00a39d9aad270f3
[2/8] bpf powerpc: Remove extra_pass from bpf_jit_build_body()
https://git.kernel.org/powerpc/c/04c04205bc35d0ecdc57146995ca9eb957d4f379
[3/8] bpf powerpc: refactor JIT compiler code
https://git.kernel.org/powerpc/c/efa95f031bf38c85cf865413335a3dc044e3194e
[4/8] powerpc/ppc-opcode: introduce PPC_RAW_BRANCH() macro
https://git.kernel.org/powerpc/c/f15a71b3880bf07b40810644e5ac6f177c2a7c8f
[5/8] bpf ppc64: Add BPF_PROBE_MEM support for JIT
https://git.kernel.org/powerpc/c/983bdc0245a29cdefcd30d9d484d3edbc4b6d787
[6/8] bpf ppc64: Access only if addr is kernel address
https://git.kernel.org/powerpc/c/9c70c7147ffec31de67d33243570a533b29f9759
[7/8] bpf ppc32: Add BPF_PROBE_MEM support for JIT
https://git.kernel.org/powerpc/c/23b51916ee129833453d8a3d6bde0ff392f82fce
[8/8] bpf ppc32: Access only if addr is kernel address
https://git.kernel.org/powerpc/c/e919c0b2323bedec00e1ecc6280498ff81f59b15
cheers
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2021-11-25 9:49 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-12 12:30 [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler Hari Bathini
2021-10-12 12:30 ` Hari Bathini
2021-10-12 12:30 ` [RESEND PATCH v4 1/8] bpf powerpc: Remove unused SEEN_STACK Hari Bathini
2021-10-12 12:30 ` Hari Bathini
2021-10-12 12:30 ` [RESEND PATCH v4 2/8] bpf powerpc: Remove extra_pass from bpf_jit_build_body() Hari Bathini
2021-10-12 12:30 ` Hari Bathini
2021-10-12 12:30 ` [RESEND PATCH v4 3/8] bpf powerpc: refactor JIT compiler code Hari Bathini
2021-10-12 12:30 ` Hari Bathini
2021-10-12 12:30 ` [RESEND PATCH v4 4/8] powerpc/ppc-opcode: introduce PPC_RAW_BRANCH() macro Hari Bathini
2021-10-12 12:30 ` Hari Bathini
2021-10-12 12:30 ` [RESEND PATCH v4 5/8] bpf ppc64: Add BPF_PROBE_MEM support for JIT Hari Bathini
2021-10-12 12:30 ` Hari Bathini
2021-10-12 12:30 ` [RESEND PATCH v4 6/8] bpf ppc64: Access only if addr is kernel address Hari Bathini
2021-10-12 12:30 ` Hari Bathini
2021-11-08 13:04 ` kernel test robot
2021-10-12 12:30 ` [RESEND PATCH v4 7/8] bpf ppc32: Add BPF_PROBE_MEM support for JIT Hari Bathini
2021-10-12 12:30 ` Hari Bathini
2021-10-12 12:30 ` [RESEND PATCH v4 8/8] bpf ppc32: Access only if addr is kernel address Hari Bathini
2021-10-12 12:30 ` Hari Bathini
2021-10-14 8:15 ` [RESEND PATCH v4 0/8] bpf powerpc: Add BPF_PROBE_MEM support in powerpc JIT compiler David Laight
2021-10-14 8:15 ` David Laight
2021-10-14 8:33 ` Christophe Leroy
2021-10-14 8:33 ` Christophe Leroy
2021-10-14 9:52 ` David Laight
2021-10-14 9:52 ` David Laight
2021-11-25 9:36 ` Michael Ellerman
2021-11-25 9:36 ` Michael Ellerman
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.