mbox series

[0/4] bpf: permit JIT allocations to be served outside the module region

Message ID 20181117185715.25198-1-ard.biesheuvel@linaro.org
Headers show
Series bpf: permit JIT allocations to be served outside the module region | expand

Message

Ard Biesheuvel Nov. 17, 2018, 6:57 p.m. UTC
On arm64, modules are allocated from a 128 MB window which is close to
the core kernel, so that relative direct branches are guaranteed to be
in range (except in some KASLR configurations). Also, module_alloc()
is in charge of allocating KASAN shadow memory when running with KASAN
enabled.

This means that the way BPF reuses module_alloc()/module_memfree() is
undesirable on arm64 (and potentially other architectures as well),
and so this series refactors BPF's use of those functions to permit
architectures to change this behavior.

Patch #1 fixes a bug introduced during the merge window, where the new
alloc/free tracking does not account for memory that is freed by some
arch code.

Patch #2 refactors the freeing path so that architectures can switch to
something other than module_memfree().

Patch #3 does the same for module_alloc().

Patch #4 implements the new alloc/free overrides for arm64

Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Rick Edgecombe <rick.p.edgecombe@intel.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Jann Horn <jannh@google.com>
Cc: Kees Cook <keescook@chromium.org>

Cc: Jessica Yu <jeyu@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Paul Burton <paul.burton@mips.com>
Cc: James Hogan <jhogan@kernel.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-mips@linux-mips.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: sparclinux@vger.kernel.org
Cc: netdev@vger.kernel.org

Ard Biesheuvel (4):
  bpf: account for freed JIT allocations in arch code
  net/bpf: refactor freeing of executable allocations
  bpf: add __weak hook for allocating executable memory
  arm64/bpf: don't allocate BPF JIT programs in module memory

 arch/arm64/net/bpf_jit_comp.c     | 11 ++++++++++
 arch/mips/net/bpf_jit.c           |  7 ++-----
 arch/powerpc/net/bpf_jit_comp.c   |  7 ++-----
 arch/powerpc/net/bpf_jit_comp64.c | 12 +++--------
 arch/sparc/net/bpf_jit_comp_32.c  |  7 ++-----
 kernel/bpf/core.c                 | 22 ++++++++++----------
 6 files changed, 31 insertions(+), 35 deletions(-)

-- 
2.17.1

Comments

Y Song Nov. 18, 2018, 7:48 a.m. UTC | #1
On Sat, Nov 17, 2018 at 6:58 PM Ard Biesheuvel
<ard.biesheuvel@linaro.org> wrote:
>

> On arm64, modules are allocated from a 128 MB window which is close to

> the core kernel, so that relative direct branches are guaranteed to be

> in range (except in some KASLR configurations). Also, module_alloc()

> is in charge of allocating KASAN shadow memory when running with KASAN

> enabled.

>

> This means that the way BPF reuses module_alloc()/module_memfree() is

> undesirable on arm64 (and potentially other architectures as well),

> and so this series refactors BPF's use of those functions to permit

> architectures to change this behavior.

>

> Patch #1 fixes a bug introduced during the merge window, where the new

> alloc/free tracking does not account for memory that is freed by some

> arch code.

>

> Patch #2 refactors the freeing path so that architectures can switch to

> something other than module_memfree().

>

> Patch #3 does the same for module_alloc().

>

> Patch #4 implements the new alloc/free overrides for arm64


Except a minor comment, the whole patch set looks good to me.
Acked-by: Yonghong Song <yhs@fb.com>


>

> Cc: Daniel Borkmann <daniel@iogearbox.net>

> Cc: Alexei Starovoitov <ast@kernel.org>

> Cc: Rick Edgecombe <rick.p.edgecombe@intel.com>

> Cc: Eric Dumazet <eric.dumazet@gmail.com>

> Cc: Jann Horn <jannh@google.com>

> Cc: Kees Cook <keescook@chromium.org>

>

> Cc: Jessica Yu <jeyu@kernel.org>

> Cc: Arnd Bergmann <arnd@arndb.de>

> Cc: Catalin Marinas <catalin.marinas@arm.com>

> Cc: Will Deacon <will.deacon@arm.com>

> Cc: Mark Rutland <mark.rutland@arm.com>

> Cc: Ralf Baechle <ralf@linux-mips.org>

> Cc: Paul Burton <paul.burton@mips.com>

> Cc: James Hogan <jhogan@kernel.org>

> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>

> Cc: Paul Mackerras <paulus@samba.org>

> Cc: Michael Ellerman <mpe@ellerman.id.au>

> Cc: "David S. Miller" <davem@davemloft.net>

> Cc: linux-arm-kernel@lists.infradead.org

> Cc: linux-kernel@vger.kernel.org

> Cc: linux-mips@linux-mips.org

> Cc: linuxppc-dev@lists.ozlabs.org

> Cc: sparclinux@vger.kernel.org

> Cc: netdev@vger.kernel.org

>

> Ard Biesheuvel (4):

>   bpf: account for freed JIT allocations in arch code

>   net/bpf: refactor freeing of executable allocations

>   bpf: add __weak hook for allocating executable memory

>   arm64/bpf: don't allocate BPF JIT programs in module memory

>

>  arch/arm64/net/bpf_jit_comp.c     | 11 ++++++++++

>  arch/mips/net/bpf_jit.c           |  7 ++-----

>  arch/powerpc/net/bpf_jit_comp.c   |  7 ++-----

>  arch/powerpc/net/bpf_jit_comp64.c | 12 +++--------

>  arch/sparc/net/bpf_jit_comp_32.c  |  7 ++-----

>  kernel/bpf/core.c                 | 22 ++++++++++----------

>  6 files changed, 31 insertions(+), 35 deletions(-)

>

> --

> 2.17.1

>
Daniel Borkmann Nov. 19, 2018, 10:37 a.m. UTC | #2
On 11/17/2018 07:57 PM, Ard Biesheuvel wrote:
> Commit ede95a63b5e84 ("bpf: add bpf_jit_limit knob to restrict unpriv

> allocations") added a call to bpf_jit_uncharge_modmem() to the routine

> bpf_jit_binary_free() which is called from the __weak bpf_jit_free().

> This function is overridden by arches, some of which do not call

> bpf_jit_binary_free() to release the memory, and so the released

> memory is not accounted for, potentially leading to spurious allocation

> failures.

> 

> So replace the direct calls to module_memfree() in the arch code with

> calls to bpf_jit_binary_free().


Sorry but this patch is completely buggy, and above description on the
accounting incorrect as well. Looks like this patch was not tested at all.

The below cBPF JITs that use module_memfree() which you replace with
bpf_jit_binary_free() are using module_alloc() internally to get the JIT
image buffer ...

> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---

>  arch/mips/net/bpf_jit.c           | 2 +-

>  arch/powerpc/net/bpf_jit_comp.c   | 2 +-

>  arch/powerpc/net/bpf_jit_comp64.c | 5 +----

>  arch/sparc/net/bpf_jit_comp_32.c  | 2 +-

>  4 files changed, 4 insertions(+), 7 deletions(-)

> 

> diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c

> index 4d8cb9bb8365..1b69897274a1 100644

> --- a/arch/mips/net/bpf_jit.c

> +++ b/arch/mips/net/bpf_jit.c

> @@ -1264,7 +1264,7 @@ void bpf_jit_compile(struct bpf_prog *fp)

>  void bpf_jit_free(struct bpf_prog *fp)

>  {

>  	if (fp->jited)

> -		module_memfree(fp->bpf_func);

> +		bpf_jit_binary_free(bpf_jit_binary_hdr(fp));

>  

>  	bpf_prog_unlock_free(fp);

>  }

> diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c

> index d5bfe24bb3b5..a1ea1ea6b40d 100644

> --- a/arch/powerpc/net/bpf_jit_comp.c

> +++ b/arch/powerpc/net/bpf_jit_comp.c

> @@ -683,7 +683,7 @@ void bpf_jit_compile(struct bpf_prog *fp)

>  void bpf_jit_free(struct bpf_prog *fp)

>  {

>  	if (fp->jited)

> -		module_memfree(fp->bpf_func);

> +		bpf_jit_binary_free(bpf_jit_binary_hdr(fp));

>  

>  	bpf_prog_unlock_free(fp);

>  }

> diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c

> index 50b129785aee..84c8f013a6c6 100644

> --- a/arch/powerpc/net/bpf_jit_comp64.c

> +++ b/arch/powerpc/net/bpf_jit_comp64.c

> @@ -1024,11 +1024,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)

>  /* Overriding bpf_jit_free() as we don't set images read-only. */

>  void bpf_jit_free(struct bpf_prog *fp)

>  {

> -	unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;

> -	struct bpf_binary_header *bpf_hdr = (void *)addr;

> -

>  	if (fp->jited)

> -		bpf_jit_binary_free(bpf_hdr);

> +		bpf_jit_binary_free(bpf_jit_binary_hdr(fp));

>  

>  	bpf_prog_unlock_free(fp);

>  }

> diff --git a/arch/sparc/net/bpf_jit_comp_32.c b/arch/sparc/net/bpf_jit_comp_32.c

> index a5ff88643d5c..01bda6bc9e7f 100644

> --- a/arch/sparc/net/bpf_jit_comp_32.c

> +++ b/arch/sparc/net/bpf_jit_comp_32.c

> @@ -759,7 +759,7 @@ cond_branch:			f_offset = addrs[i + filter[i].jf];

>  void bpf_jit_free(struct bpf_prog *fp)

>  {

>  	if (fp->jited)

> -		module_memfree(fp->bpf_func);

> +		bpf_jit_binary_free(bpf_jit_binary_hdr(fp));

>  

>  	bpf_prog_unlock_free(fp);

>  }

>