diff mbox series

[bpf-next,1/2] bpf: Fix combination of jit blinding and pointers to bpf subprogs.

Message ID 20220513011025.13344-1-alexei.starovoitov@gmail.com (mailing list archive)
State Accepted
Commit 4b6313cf99b0d51b49aeaea98ec76ca8161ecb80
Delegated to: BPF
Headers show
Series [bpf-next,1/2] bpf: Fix combination of jit blinding and pointers to bpf subprogs. | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for bpf-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Single patches do not need cover letters
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 9 this patch: 9
netdev/cc_maintainers fail 2 blamed authors not CCed: yhs@fb.com ast@kernel.org; 7 maintainers not CCed: netdev@vger.kernel.org kafai@fb.com john.fastabend@gmail.com yhs@fb.com kpsingh@kernel.org songliubraving@fb.com ast@kernel.org
netdev/build_clang success Errors and warnings before: 9 this patch: 9
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 9 this patch: 9
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 16 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Kernel LATEST on z15 + selftests
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for Kernel LATEST on ubuntu-latest + selftests

Commit Message

Alexei Starovoitov May 13, 2022, 1:10 a.m. UTC
From: Alexei Starovoitov <ast@kernel.org>

The combination of jit blinding and pointers to bpf subprogs causes:
[   36.989548] BUG: unable to handle page fault for address: 0000000100000001
[   36.990342] #PF: supervisor instruction fetch in kernel mode
[   36.990968] #PF: error_code(0x0010) - not-present page
[   36.994859] RIP: 0010:0x100000001
[   36.995209] Code: Unable to access opcode bytes at RIP 0xffffffd7.
[   37.004091] Call Trace:
[   37.004351]  <TASK>
[   37.004576]  ? bpf_loop+0x4d/0x70
[   37.004932]  ? bpf_prog_3899083f75e4c5de_F+0xe3/0x13b

The jit blinding logic didn't recognize that ld_imm64 with an address
of bpf subprogram is a special instruction and proceeded to randomize it.
By itself it wouldn't have been an issue, but jit_subprogs() logic
relies on two step process to JIT all subprogs and then JIT them
again when addresses of all subprogs are known.
Blinding process in the first JIT phase caused second JIT to miss
adjustment of special ld_imm64.

Fix this issue by ignoring special ld_imm64 instructions that don't have
user controlled constants and shouldn't be blinded.

Fixes: 69c087ba6225 ("bpf: Add bpf_for_each_map_elem() helper")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
---
 kernel/bpf/core.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

Comments

Andrii Nakryiko May 13, 2022, 3:44 a.m. UTC | #1
On Thu, May 12, 2022 at 6:10 PM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> From: Alexei Starovoitov <ast@kernel.org>
>
> The combination of jit blinding and pointers to bpf subprogs causes:
> [   36.989548] BUG: unable to handle page fault for address: 0000000100000001
> [   36.990342] #PF: supervisor instruction fetch in kernel mode
> [   36.990968] #PF: error_code(0x0010) - not-present page
> [   36.994859] RIP: 0010:0x100000001
> [   36.995209] Code: Unable to access opcode bytes at RIP 0xffffffd7.
> [   37.004091] Call Trace:
> [   37.004351]  <TASK>
> [   37.004576]  ? bpf_loop+0x4d/0x70
> [   37.004932]  ? bpf_prog_3899083f75e4c5de_F+0xe3/0x13b
>
> The jit blinding logic didn't recognize that ld_imm64 with an address
> of bpf subprogram is a special instruction and proceeded to randomize it.
> By itself it wouldn't have been an issue, but jit_subprogs() logic
> relies on two step process to JIT all subprogs and then JIT them
> again when addresses of all subprogs are known.
> Blinding process in the first JIT phase caused second JIT to miss
> adjustment of special ld_imm64.
>
> Fix this issue by ignoring special ld_imm64 instructions that don't have
> user controlled constants and shouldn't be blinded.
>
> Fixes: 69c087ba6225 ("bpf: Add bpf_for_each_map_elem() helper")
> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
> ---

Thanks for the fix, LGTM.

Reported-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Andrii Nakryiko <andrii@kernel.org>


>  kernel/bpf/core.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index 76f68d0a7ae8..9cc91f0f3115 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -1434,6 +1434,16 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
>         insn = clone->insnsi;
>
>         for (i = 0; i < insn_cnt; i++, insn++) {
> +               if (bpf_pseudo_func(insn)) {
> +                       /* ld_imm64 with an address of bpf subprog is not
> +                        * a user controlled constant. Don't randomize it,
> +                        * since it will conflict with jit_subprogs() logic.
> +                        */
> +                       insn++;
> +                       i++;
> +                       continue;
> +               }
> +
>                 /* We temporarily need to hold the original ld64 insn
>                  * so that we can still access the first part in the
>                  * second blinding run.
> --
> 2.30.2
>
Alexei Starovoitov May 13, 2022, 3:45 a.m. UTC | #2
On Thu, May 12, 2022 at 8:44 PM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> On Thu, May 12, 2022 at 6:10 PM Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > From: Alexei Starovoitov <ast@kernel.org>
> >
> > The combination of jit blinding and pointers to bpf subprogs causes:
> > [   36.989548] BUG: unable to handle page fault for address: 0000000100000001
> > [   36.990342] #PF: supervisor instruction fetch in kernel mode
> > [   36.990968] #PF: error_code(0x0010) - not-present page
> > [   36.994859] RIP: 0010:0x100000001
> > [   36.995209] Code: Unable to access opcode bytes at RIP 0xffffffd7.
> > [   37.004091] Call Trace:
> > [   37.004351]  <TASK>
> > [   37.004576]  ? bpf_loop+0x4d/0x70
> > [   37.004932]  ? bpf_prog_3899083f75e4c5de_F+0xe3/0x13b
> >
> > The jit blinding logic didn't recognize that ld_imm64 with an address
> > of bpf subprogram is a special instruction and proceeded to randomize it.
> > By itself it wouldn't have been an issue, but jit_subprogs() logic
> > relies on two step process to JIT all subprogs and then JIT them
> > again when addresses of all subprogs are known.
> > Blinding process in the first JIT phase caused second JIT to miss
> > adjustment of special ld_imm64.
> >
> > Fix this issue by ignoring special ld_imm64 instructions that don't have
> > user controlled constants and shouldn't be blinded.
> >
> > Fixes: 69c087ba6225 ("bpf: Add bpf_for_each_map_elem() helper")
> > Signed-off-by: Alexei Starovoitov <ast@kernel.org>
> > ---
>
> Thanks for the fix, LGTM.
>
> Reported-by: Andrii Nakryiko <andrii@kernel.org>

Ohh. Sorry. Yes!

> Acked-by: Andrii Nakryiko <andrii@kernel.org>
Martin KaFai Lau May 13, 2022, 5:47 a.m. UTC | #3
On Thu, May 12, 2022 at 06:10:24PM -0700, Alexei Starovoitov wrote:
> From: Alexei Starovoitov <ast@kernel.org>
> 
> The combination of jit blinding and pointers to bpf subprogs causes:
> [   36.989548] BUG: unable to handle page fault for address: 0000000100000001
> [   36.990342] #PF: supervisor instruction fetch in kernel mode
> [   36.990968] #PF: error_code(0x0010) - not-present page
> [   36.994859] RIP: 0010:0x100000001
> [   36.995209] Code: Unable to access opcode bytes at RIP 0xffffffd7.
> [   37.004091] Call Trace:
> [   37.004351]  <TASK>
> [   37.004576]  ? bpf_loop+0x4d/0x70
> [   37.004932]  ? bpf_prog_3899083f75e4c5de_F+0xe3/0x13b
> 
> The jit blinding logic didn't recognize that ld_imm64 with an address
> of bpf subprogram is a special instruction and proceeded to randomize it.
> By itself it wouldn't have been an issue, but jit_subprogs() logic
> relies on two step process to JIT all subprogs and then JIT them
> again when addresses of all subprogs are known.
> Blinding process in the first JIT phase caused second JIT to miss
> adjustment of special ld_imm64.
> 
> Fix this issue by ignoring special ld_imm64 instructions that don't have
> user controlled constants and shouldn't be blinded.
Acked-by: Martin KaFai Lau <kafai@fb.com>
patchwork-bot+netdevbpf@kernel.org May 13, 2022, 1:20 p.m. UTC | #4
Hello:

This series was applied to bpf/bpf-next.git (master)
by Daniel Borkmann <daniel@iogearbox.net>:

On Thu, 12 May 2022 18:10:24 -0700 you wrote:
> From: Alexei Starovoitov <ast@kernel.org>
> 
> The combination of jit blinding and pointers to bpf subprogs causes:
> [   36.989548] BUG: unable to handle page fault for address: 0000000100000001
> [   36.990342] #PF: supervisor instruction fetch in kernel mode
> [   36.990968] #PF: error_code(0x0010) - not-present page
> [   36.994859] RIP: 0010:0x100000001
> [   36.995209] Code: Unable to access opcode bytes at RIP 0xffffffd7.
> [   37.004091] Call Trace:
> [   37.004351]  <TASK>
> [   37.004576]  ? bpf_loop+0x4d/0x70
> [   37.004932]  ? bpf_prog_3899083f75e4c5de_F+0xe3/0x13b
> 
> [...]

Here is the summary with links:
  - [bpf-next,1/2] bpf: Fix combination of jit blinding and pointers to bpf subprogs.
    https://git.kernel.org/bpf/bpf-next/c/4b6313cf99b0
  - [bpf-next,2/2] selftests/bpf: Check combination of jit blinding and pointers to bpf subprogs.
    https://git.kernel.org/bpf/bpf-next/c/365d519923a2

You are awesome, thank you!
diff mbox series

Patch

diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 76f68d0a7ae8..9cc91f0f3115 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1434,6 +1434,16 @@  struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
 	insn = clone->insnsi;
 
 	for (i = 0; i < insn_cnt; i++, insn++) {
+		if (bpf_pseudo_func(insn)) {
+			/* ld_imm64 with an address of bpf subprog is not
+			 * a user controlled constant. Don't randomize it,
+			 * since it will conflict with jit_subprogs() logic.
+			 */
+			insn++;
+			i++;
+			continue;
+		}
+
 		/* We temporarily need to hold the original ld64 insn
 		 * so that we can still access the first part in the
 		 * second blinding run.