From: Hari Bathini <hbathini@linux.ibm.com> Date: 2021-09-17 15:32:11
From: Ravi Bangoria <redacted>
SEEN_STACK is unused on PowerPC. Remove it. Also, have
SEEN_TAILCALL use 0x40000000.
Signed-off-by: Ravi Bangoria <redacted>
---
* No changes in v2.
arch/powerpc/net/bpf_jit.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
From: Ravi Bangoria <redacted>
SEEN_STACK is unused on PowerPC. Remove it. Also, have
SEEN_TAILCALL use 0x40000000.
Signed-off-by: Ravi Bangoria <redacted>
Reviewed-by: Christophe Leroy <redacted>
quoted hunk
---
* No changes in v2.
arch/powerpc/net/bpf_jit.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
From: Hari Bathini <hbathini@linux.ibm.com> Date: 2021-09-17 15:32:15
From: Ravi Bangoria <redacted>
In case of extra_pass, usual JIT passes are always skipped. So,
extra_pass is always false while calling bpf_jit_build_body() and
thus it can be removed.
Signed-off-by: Ravi Bangoria <redacted>
---
Changes in v2:
* Updated the changelog wording a bit.
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(-)
@@ -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);-bpf_jit_build_body(fp,code_base,&cgctx,addrs,extra_pass);+bpf_jit_build_body(fp,code_base,&cgctx,addrs);bpf_jit_build_epilogue(code_base,&cgctx);if(bpf_jit_enable>1)
From: Hari Bathini <hbathini@linux.ibm.com> Date: 2021-09-17 15:32:35
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>
---
Changes in v2:
* New patch to introduce PPC_RAW_BRANCH() macro.
arch/powerpc/include/asm/ppc-opcode.h | 2 ++
arch/powerpc/net/bpf_jit.h | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
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 <redacted>
quoted hunk
---
Changes in v2:
* New patch to introduce PPC_RAW_BRANCH() macro.
arch/powerpc/include/asm/ppc-opcode.h | 2 ++
arch/powerpc/net/bpf_jit.h | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
From: Hari Bathini <hbathini@linux.ibm.com> Date: 2021-09-17 15:33:18
From: Ravi Bangoria <redacted>
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 <redacted>
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
Changes in v2:
* Used JITing code after refactoring.
* Replaced 'xor reg,reg,reg' with 'li reg,0' where appropriate.
* Avoided unnecessary init during declaration.
arch/powerpc/net/bpf_jit.h | 5 ++-
arch/powerpc/net/bpf_jit_comp.c | 25 ++++++++++----
arch/powerpc/net/bpf_jit_comp32.c | 2 +-
arch/powerpc/net/bpf_jit_comp64.c | 57 ++++++++++++++++++++++++++++++-
4 files changed, 80 insertions(+), 9 deletions(-)
@@ -210,7 +219,11 @@ 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);-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;+gotoout_addrs;+}bpf_jit_build_epilogue(code_base,&cgctx);if(bpf_jit_enable>1)
@@ -270,9 +270,54 @@ static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32/* out: */}+/*+*Thecallershouldcheckfor(BPF_MODE(code)==BPF_PROBE_MEM)beforecalling+*thisfunction,asthisonlyappliestoBPF_PROBE_MEM,fornow.+*/+staticintbpf_add_extable_entry(structbpf_prog*fp,u32*image,intpass,+structcodegen_context*ctx,intdst_reg)+{+off_toffset;+unsignedlongpc;+structexception_table_entry*ex;+u32*fixup;++/* Populate extable entries only in the last pass */+if(pass!=2)+return0;++if(!fp->aux->extable||+WARN_ON_ONCE(ctx->exentry_idx>=fp->aux->num_exentries))+return-EINVAL;++pc=(unsignedlong)&image[ctx->idx-1];++fixup=(void*)fp->aux->extable-+(fp->aux->num_exentries*BPF_FIXUP_LEN)++(ctx->exentry_idx*BPF_FIXUP_LEN);++fixup[0]=PPC_RAW_LI(dst_reg,0);+fixup[1]=PPC_RAW_BRANCH((long)(pc+4)-(long)&fixup[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++;+return0;+}+/* Assemble the body code between the prologue & epilogue */intbpf_jit_build_body(structbpf_prog*fp,u32*image,structcodegen_context*ctx,-u32*addrs)+u32*addrs,intpass){conststructbpf_insn*insn=fp->insnsi;intflen=fp->len;
From: Ravi Bangoria <redacted>
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 <redacted>
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
Changes in v2:
* Used JITing code after refactoring.
* Replaced 'xor reg,reg,reg' with 'li reg,0' where appropriate.
* Avoided unnecessary init during declaration.
arch/powerpc/net/bpf_jit.h | 5 ++-
arch/powerpc/net/bpf_jit_comp.c | 25 ++++++++++----
arch/powerpc/net/bpf_jit_comp32.c | 2 +-
arch/powerpc/net/bpf_jit_comp64.c | 57 ++++++++++++++++++++++++++++++-
4 files changed, 80 insertions(+), 9 deletions(-)
From: Hari Bathini <hbathini@linux.ibm.com> Date: 2021-09-17 15:33:19
From: Ravi Bangoria <redacted>
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 > TASK_SIZE_MAX, 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 <redacted>
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
Changes in v2:
* Refactored the code based on Christophe's comments.
arch/powerpc/net/bpf_jit_comp64.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
From: Ravi Bangoria <redacted>
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 > TASK_SIZE_MAX, otherwise set dst_reg=0 and move on.
You should do like copy_from_kernel_nofault_allowed() and use the same
criterias as is_kernel_addr() instead of using TASK_SIZE_MAX.
quoted hunk
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 <redacted>
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
Changes in v2:
* Refactored the code based on Christophe's comments.
arch/powerpc/net/bpf_jit_comp64.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
I think it would be more explicit if you drop adjusted_idx and do :
if (BPF_SIZE(code) == BPF_DW) && (off & 3)
PPC_JMP((ctx->idx + 3) * 4);
else
PPC_JMP((ctx->idx + 2) * 4);
Refactor powerpc JITing. This simplifies adding BPF_PROBE_MEM support.
Could you describe a bit more what you are refactoring exactly ?
quoted hunk
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
Changes in v2:
* New patch to refactor a bit of JITing code.
arch/powerpc/net/bpf_jit_comp32.c | 50 +++++++++++---------
arch/powerpc/net/bpf_jit_comp64.c | 76 ++++++++++++++++---------------
2 files changed, 68 insertions(+), 58 deletions(-)
From: Hari Bathini <hbathini@linux.ibm.com> Date: 2021-09-20 13:29:22
Hi Christophe,
Thanks for reviewing the series.
On 17/09/21 9:40 pm, Christophe Leroy wrote:
Le 17/09/2021 à 17:30, Hari Bathini a écrit :
quoted
Refactor powerpc JITing. This simplifies adding BPF_PROBE_MEM support.
Could you describe a bit more what you are refactoring exactly ?
I am trying to do more than BPF_PROBE_MEM needs. Will keep the changes
minimal (BPF_PROBE_MEM specific) and update the changelog..
quoted
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
Changes in v2:
* New patch to refactor a bit of JITing code.
arch/powerpc/net/bpf_jit_comp32.c | 50 +++++++++++---------
arch/powerpc/net/bpf_jit_comp64.c | 76 ++++++++++++++++---------------
2 files changed, 68 insertions(+), 58 deletions(-)
diff --git a/arch/powerpc/net/bpf_jit_comp32.c
b/arch/powerpc/net/bpf_jit_comp32.c
index b60b59426a24..c8ae14c316e3 100644
From: Hari Bathini <hbathini@linux.ibm.com> Date: 2021-09-17 15:33:20
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>
---
Changes in v2:
* New patch to add BPF_PROBE_MEM support for PPC32.
arch/powerpc/net/bpf_jit.h | 7 +++++
arch/powerpc/net/bpf_jit_comp.c | 50 +++++++++++++++++++++++++++++++
arch/powerpc/net/bpf_jit_comp32.c | 30 +++++++++++++++++++
arch/powerpc/net/bpf_jit_comp64.c | 48 ++---------------------------
4 files changed, 89 insertions(+), 46 deletions(-)
@@ -271,3 +271,53 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)returnfp;}++/*+*Thecallershouldcheckfor(BPF_MODE(code)==BPF_PROBE_MEM)beforecalling+*thisfunction,asthisonlyappliestoBPF_PROBE_MEM,fornow.+*/+intbpf_add_extable_entry(structbpf_prog*fp,u32*image,intpass,structcodegen_context*ctx,+intinsn_idx,intjmp_off,intdst_reg)+{+off_toffset;+unsignedlongpc;+structexception_table_entry*ex;+u32*fixup;++/* Populate extable entries only in the last pass */+if(pass!=2)+return0;++if(!fp->aux->extable||+WARN_ON_ONCE(ctx->exentry_idx>=fp->aux->num_exentries))+return-EINVAL;++pc=(unsignedlong)&image[insn_idx];++fixup=(void*)fp->aux->extable-+(fp->aux->num_exentries*BPF_FIXUP_LEN)++(ctx->exentry_idx*BPF_FIXUP_LEN);++fixup[0]=PPC_RAW_LI(dst_reg,0);+#ifdef CONFIG_PPC32+fixup[1]=PPC_RAW_LI(dst_reg-1,0);/* clear higher 32-bit register too */+fixup[2]=PPC_RAW_BRANCH((long)(pc+jmp_off)-(long)&fixup[2]);+#else+fixup[1]=PPC_RAW_BRANCH((long)(pc+jmp_off)-(long)&fixup[1]);+#endif++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++;+return0;+}
@@ -270,51 +270,6 @@ static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32/* out: */}-/*-*Thecallershouldcheckfor(BPF_MODE(code)==BPF_PROBE_MEM)beforecalling-*thisfunction,asthisonlyappliestoBPF_PROBE_MEM,fornow.-*/-staticintbpf_add_extable_entry(structbpf_prog*fp,u32*image,intpass,-structcodegen_context*ctx,intdst_reg)-{-off_toffset;-unsignedlongpc;-structexception_table_entry*ex;-u32*fixup;--/* Populate extable entries only in the last pass */-if(pass!=2)-return0;--if(!fp->aux->extable||-WARN_ON_ONCE(ctx->exentry_idx>=fp->aux->num_exentries))-return-EINVAL;--pc=(unsignedlong)&image[ctx->idx-1];--fixup=(void*)fp->aux->extable--(fp->aux->num_exentries*BPF_FIXUP_LEN)+-(ctx->exentry_idx*BPF_FIXUP_LEN);--fixup[0]=PPC_RAW_LI(dst_reg,0);-fixup[1]=PPC_RAW_BRANCH((long)(pc+4)-(long)&fixup[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++;-return0;-}-/* Assemble the body code between the prologue & epilogue */intbpf_jit_build_body(structbpf_prog*fp,u32*image,structcodegen_context*ctx,u32*addrs,intpass)
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>
---
Changes in v2:
* New patch to add BPF_PROBE_MEM support for PPC32.
arch/powerpc/net/bpf_jit.h | 7 +++++
arch/powerpc/net/bpf_jit_comp.c | 50 +++++++++++++++++++++++++++++++
arch/powerpc/net/bpf_jit_comp32.c | 30 +++++++++++++++++++
arch/powerpc/net/bpf_jit_comp64.c | 48 ++---------------------------
4 files changed, 89 insertions(+), 46 deletions(-)
Modify patch 5 to get that function already in
arch/powerpc/net/bpf_jit_comp.c, so that only changes/additions to the
function appear here.
And you can have the prototype ready for the final version in patch 5
instead of adding new arguments here and having to change ppc64 call site.
And in fact you can use them already in patch 5, like jmp_off.
+ 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) +
+ (ctx->exentry_idx * BPF_FIXUP_LEN);
Use 2 or 3 for BPF_FIXUP_LEN and multiply by 4 here.
Use 2 or 3 for BPF_FIXUP_LEN and you can do
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]);
@@ -270,51 +270,6 @@ static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32/* out: */}-/*-*Thecallershouldcheckfor(BPF_MODE(code)==BPF_PROBE_MEM)beforecalling-*thisfunction,asthisonlyappliestoBPF_PROBE_MEM,fornow.-*/-staticintbpf_add_extable_entry(structbpf_prog*fp,u32*image,intpass,-structcodegen_context*ctx,intdst_reg)-{-off_toffset;-unsignedlongpc;-structexception_table_entry*ex;-u32*fixup;--/* Populate extable entries only in the last pass */-if(pass!=2)-return0;--if(!fp->aux->extable||-WARN_ON_ONCE(ctx->exentry_idx>=fp->aux->num_exentries))-return-EINVAL;--pc=(unsignedlong)&image[ctx->idx-1];--fixup=(void*)fp->aux->extable--(fp->aux->num_exentries*BPF_FIXUP_LEN)+-(ctx->exentry_idx*BPF_FIXUP_LEN);--fixup[0]=PPC_RAW_LI(dst_reg,0);-fixup[1]=PPC_RAW_BRANCH((long)(pc+4)-(long)&fixup[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++;-return0;-}-/* Assemble the body code between the prologue & epilogue */intbpf_jit_build_body(structbpf_prog*fp,u32*image,structcodegen_context*ctx,u32*addrs,intpass)
From: Hari Bathini <hbathini@linux.ibm.com> Date: 2021-09-17 15:34:51
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 > TASK_SIZE_MAX, 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>
---
Changes in v2:
* New patch to handle bad userspace pointers on PPC32.
arch/powerpc/net/bpf_jit_comp32.c | 39 +++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
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 > TASK_SIZE_MAX, otherwise set
dst_reg=0 and move on.
Same comment as patch 6.
quoted hunk
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>
---
Changes in v2:
* New patch to handle bad userspace pointers on PPC32.
arch/powerpc/net/bpf_jit_comp32.c | 39 +++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
Don't make it too complicated. That's a fallback that should never
happen, no need to optimise. You can put that instruction all the time
(or put a NOP) and keep the jumps always the same.
+
+ /*
+ * 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.
+ */
+ adjusted_idx = (size == BPF_DW) ? 1 : 0;
Same comment as patch 6, drop adjusted_idx and do an if/else directly
for the PPC_JMP.
+
+ EMIT(PPC_RAW_ADDI(b2p[TMP_REG], src_reg, off));
+ PPC_LI32(_R0, TASK_SIZE_MAX);
+ EMIT(PPC_RAW_CMPLW(b2p[TMP_REG], _R0));
+ PPC_BCC(COND_GT, (ctx->idx + 4 + (extra_insn_needed ? 1 : 0)) * 4);
+ EMIT(PPC_RAW_LI(dst_reg, 0));
+ /*
+ * 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 (extra_insn_needed)
+ EMIT(PPC_RAW_LI(dst_reg_h, 0));
+ PPC_JMP((ctx->idx + 2 + adjusted_idx) * 4);
+ }
+
switch (size) {
case BPF_B:
EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));