Message ID | 1410543308-27449-1-git-send-email-dborkman@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, Sep 12, 2014 at 10:35 AM, Daniel Borkmann <dborkman@redhat.com> wrote: > This is the ARM64 variant for 314beb9bcab ("x86: bpf_jit_comp: secure bpf > jit against spraying attacks"). > > Thanks to commit 11d91a770f1f ("arm64: Add CONFIG_DEBUG_SET_MODULE_RONX > support") which added necessary infrastructure, we can now implement > RO marking of eBPF generated JIT image pages and randomize start offset > for the JIT code, so that it does not reside directly on a page boundary > anymore. Likewise, the holes are filled with illegal instructions. > > This is basically the ARM64 variant of what we already have in ARM via > commit 55309dd3d4cd ("net: bpf: arm: address randomize and write protect > JIT code"). Moreover, this commit also presents a merge resolution due to > conflicts with commit 60a3b2253c41 ("net: bpf: make eBPF interpreter images > read-only") as we don't use kfree() in bpf_jit_free() anymore to release > the locked bpf_prog structure, but instead bpf_prog_unlock_free() through > a different allocator. > > JIT tested on aarch64 with BPF test suite. > > Reference: http://mainisusuallyafunction.blogspot.com/2012/11/attacking-hardened-linux-systems-with.html > Signed-off-by: Daniel Borkmann <dborkman@redhat.com> > Cc: Zi Shen Lim <zlim.lnx@gmail.com> > Cc: Will Deacon <will.deacon@arm.com> > Cc: Catalin Marinas <catalin.marinas@arm.com> > Cc: David S. Miller <davem@davemloft.net> > Cc: Alexei Starovoitov <ast@plumgrid.com> > --- > v1 -> v2: > - Use brk insn as suggested by Catalin, thanks a lot for > your feedback! Rest unchanged. > Note: > - This patch depends on net-next being merged to mainline due > to the mentioned merge conflict. > > arch/arm64/net/bpf_jit_comp.c | 38 +++++++++++++++++++++++++++++--------- > 1 file changed, 29 insertions(+), 9 deletions(-) > > diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c > index 7ae3354..4b71779 100644 > --- a/arch/arm64/net/bpf_jit_comp.c > +++ b/arch/arm64/net/bpf_jit_comp.c > @@ -19,7 +19,6 @@ > #define pr_fmt(fmt) "bpf_jit: " fmt > > #include <linux/filter.h> > -#include <linux/moduleloader.h> > #include <linux/printk.h> > #include <linux/skbuff.h> > #include <linux/slab.h> > @@ -119,6 +118,15 @@ static inline int bpf2a64_offset(int bpf_to, int bpf_from, > return to - from; > } > > +static void jit_fill_hole(void *area, unsigned int size) > +{ > + /* We use brk #0x100 to trigger a fault. */ > + u32 *ptr, fill_ins = 0xd4202000; Missed this on first round of review, I think we also need cpu_to_le32(...) here. > + /* We are guaranteed to have aligned memory. */ > + for (ptr = area; size >= sizeof(u32); size -= sizeof(u32)) > + *ptr++ = fill_ins; > +} > + [...] Thanks Daniel.
On 09/13/2014 06:32 AM, Z Lim wrote: > On Fri, Sep 12, 2014 at 10:35 AM, Daniel Borkmann <dborkman@redhat.com> wrote: >> This is the ARM64 variant for 314beb9bcab ("x86: bpf_jit_comp: secure bpf >> jit against spraying attacks"). >> >> Thanks to commit 11d91a770f1f ("arm64: Add CONFIG_DEBUG_SET_MODULE_RONX >> support") which added necessary infrastructure, we can now implement >> RO marking of eBPF generated JIT image pages and randomize start offset >> for the JIT code, so that it does not reside directly on a page boundary >> anymore. Likewise, the holes are filled with illegal instructions. >> >> This is basically the ARM64 variant of what we already have in ARM via >> commit 55309dd3d4cd ("net: bpf: arm: address randomize and write protect >> JIT code"). Moreover, this commit also presents a merge resolution due to >> conflicts with commit 60a3b2253c41 ("net: bpf: make eBPF interpreter images >> read-only") as we don't use kfree() in bpf_jit_free() anymore to release >> the locked bpf_prog structure, but instead bpf_prog_unlock_free() through >> a different allocator. >> >> JIT tested on aarch64 with BPF test suite. >> >> Reference: http://mainisusuallyafunction.blogspot.com/2012/11/attacking-hardened-linux-systems-with.html >> Signed-off-by: Daniel Borkmann <dborkman@redhat.com> >> Cc: Zi Shen Lim <zlim.lnx@gmail.com> >> Cc: Will Deacon <will.deacon@arm.com> >> Cc: Catalin Marinas <catalin.marinas@arm.com> >> Cc: David S. Miller <davem@davemloft.net> >> Cc: Alexei Starovoitov <ast@plumgrid.com> >> --- >> v1 -> v2: >> - Use brk insn as suggested by Catalin, thanks a lot for >> your feedback! Rest unchanged. >> Note: >> - This patch depends on net-next being merged to mainline due >> to the mentioned merge conflict. >> >> arch/arm64/net/bpf_jit_comp.c | 38 +++++++++++++++++++++++++++++--------- >> 1 file changed, 29 insertions(+), 9 deletions(-) >> >> diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c >> index 7ae3354..4b71779 100644 >> --- a/arch/arm64/net/bpf_jit_comp.c >> +++ b/arch/arm64/net/bpf_jit_comp.c >> @@ -19,7 +19,6 @@ >> #define pr_fmt(fmt) "bpf_jit: " fmt >> >> #include <linux/filter.h> >> -#include <linux/moduleloader.h> >> #include <linux/printk.h> >> #include <linux/skbuff.h> >> #include <linux/slab.h> >> @@ -119,6 +118,15 @@ static inline int bpf2a64_offset(int bpf_to, int bpf_from, >> return to - from; >> } >> >> +static void jit_fill_hole(void *area, unsigned int size) >> +{ >> + /* We use brk #0x100 to trigger a fault. */ >> + u32 *ptr, fill_ins = 0xd4202000; > > Missed this on first round of review, I think we also need > cpu_to_le32(...) here. Just wondering ... so that would also hold true in case I build/run my kernel in big-endian (CPU_BIG_ENDIAN)? >> + /* We are guaranteed to have aligned memory. */ >> + for (ptr = area; size >= sizeof(u32); size -= sizeof(u32)) >> + *ptr++ = fill_ins; >> +} >> + > [...] > > Thanks Daniel.
On Mon, Sep 15, 2014 at 02:52:40PM +0100, Daniel Borkmann wrote: > On 09/13/2014 06:32 AM, Z Lim wrote: > > On Fri, Sep 12, 2014 at 10:35 AM, Daniel Borkmann <dborkman@redhat.com> wrote: > >> This is the ARM64 variant for 314beb9bcab ("x86: bpf_jit_comp: secure bpf > >> jit against spraying attacks"). > >> > >> Thanks to commit 11d91a770f1f ("arm64: Add CONFIG_DEBUG_SET_MODULE_RONX > >> support") which added necessary infrastructure, we can now implement > >> RO marking of eBPF generated JIT image pages and randomize start offset > >> for the JIT code, so that it does not reside directly on a page boundary > >> anymore. Likewise, the holes are filled with illegal instructions. > >> > >> This is basically the ARM64 variant of what we already have in ARM via > >> commit 55309dd3d4cd ("net: bpf: arm: address randomize and write protect > >> JIT code"). Moreover, this commit also presents a merge resolution due to > >> conflicts with commit 60a3b2253c41 ("net: bpf: make eBPF interpreter images > >> read-only") as we don't use kfree() in bpf_jit_free() anymore to release > >> the locked bpf_prog structure, but instead bpf_prog_unlock_free() through > >> a different allocator. > >> > >> JIT tested on aarch64 with BPF test suite. > >> > >> Reference: http://mainisusuallyafunction.blogspot.com/2012/11/attacking-hardened-linux-systems-with.html > >> Signed-off-by: Daniel Borkmann <dborkman@redhat.com> > >> Cc: Zi Shen Lim <zlim.lnx@gmail.com> > >> Cc: Will Deacon <will.deacon@arm.com> > >> Cc: Catalin Marinas <catalin.marinas@arm.com> > >> Cc: David S. Miller <davem@davemloft.net> > >> Cc: Alexei Starovoitov <ast@plumgrid.com> > >> --- > >> v1 -> v2: > >> - Use brk insn as suggested by Catalin, thanks a lot for > >> your feedback! Rest unchanged. > >> Note: > >> - This patch depends on net-next being merged to mainline due > >> to the mentioned merge conflict. > >> > >> arch/arm64/net/bpf_jit_comp.c | 38 +++++++++++++++++++++++++++++--------- > >> 1 file changed, 29 insertions(+), 9 deletions(-) > >> > >> diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c > >> index 7ae3354..4b71779 100644 > >> --- a/arch/arm64/net/bpf_jit_comp.c > >> +++ b/arch/arm64/net/bpf_jit_comp.c > >> @@ -19,7 +19,6 @@ > >> #define pr_fmt(fmt) "bpf_jit: " fmt > >> > >> #include <linux/filter.h> > >> -#include <linux/moduleloader.h> > >> #include <linux/printk.h> > >> #include <linux/skbuff.h> > >> #include <linux/slab.h> > >> @@ -119,6 +118,15 @@ static inline int bpf2a64_offset(int bpf_to, int bpf_from, > >> return to - from; > >> } > >> > >> +static void jit_fill_hole(void *area, unsigned int size) > >> +{ > >> + /* We use brk #0x100 to trigger a fault. */ > >> + u32 *ptr, fill_ins = 0xd4202000; > > > > Missed this on first round of review, I think we also need > > cpu_to_le32(...) here. > > Just wondering ... so that would also hold true in case I build/run my > kernel in big-endian (CPU_BIG_ENDIAN)? Yes, the instruction stream is always little endian so the conversion is required. Will > >> + /* We are guaranteed to have aligned memory. */ > >> + for (ptr = area; size >= sizeof(u32); size -= sizeof(u32)) > >> + *ptr++ = fill_ins; > >> +} > >> + > > [...] > > > > Thanks Daniel. >
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 7ae3354..4b71779 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -19,7 +19,6 @@ #define pr_fmt(fmt) "bpf_jit: " fmt #include <linux/filter.h> -#include <linux/moduleloader.h> #include <linux/printk.h> #include <linux/skbuff.h> #include <linux/slab.h> @@ -119,6 +118,15 @@ static inline int bpf2a64_offset(int bpf_to, int bpf_from, return to - from; } +static void jit_fill_hole(void *area, unsigned int size) +{ + /* We use brk #0x100 to trigger a fault. */ + u32 *ptr, fill_ins = 0xd4202000; + /* We are guaranteed to have aligned memory. */ + for (ptr = area; size >= sizeof(u32); size -= sizeof(u32)) + *ptr++ = fill_ins; +} + static inline int epilogue_offset(const struct jit_ctx *ctx) { int to = ctx->offset[ctx->prog->len - 1]; @@ -613,8 +621,10 @@ void bpf_jit_compile(struct bpf_prog *prog) void bpf_int_jit_compile(struct bpf_prog *prog) { + struct bpf_binary_header *header; struct jit_ctx ctx; int image_size; + u8 *image_ptr; if (!bpf_jit_enable) return; @@ -636,23 +646,25 @@ void bpf_int_jit_compile(struct bpf_prog *prog) goto out; build_prologue(&ctx); - build_epilogue(&ctx); /* Now we know the actual image size. */ image_size = sizeof(u32) * ctx.idx; - ctx.image = module_alloc(image_size); - if (unlikely(ctx.image == NULL)) + header = bpf_jit_binary_alloc(image_size, &image_ptr, + sizeof(u32), jit_fill_hole); + if (header == NULL) goto out; /* 2. Now, the actual pass. */ + ctx.image = (u32 *)image_ptr; ctx.idx = 0; + build_prologue(&ctx); ctx.body_offset = ctx.idx; if (build_body(&ctx)) { - module_free(NULL, ctx.image); + bpf_jit_binary_free(header); goto out; } @@ -663,17 +675,25 @@ void bpf_int_jit_compile(struct bpf_prog *prog) bpf_jit_dump(prog->len, image_size, 2, ctx.image); bpf_flush_icache(ctx.image, ctx.image + ctx.idx); + + set_memory_ro((unsigned long)header, header->pages); prog->bpf_func = (void *)ctx.image; prog->jited = 1; - out: kfree(ctx.offset); } void bpf_jit_free(struct bpf_prog *prog) { - if (prog->jited) - module_free(NULL, prog->bpf_func); + unsigned long addr = (unsigned long)prog->bpf_func & PAGE_MASK; + struct bpf_binary_header *header = (void *)addr; + + if (!prog->jited) + goto free_filter; + + set_memory_rw(addr, header->pages); + bpf_jit_binary_free(header); - kfree(prog); +free_filter: + bpf_prog_unlock_free(prog); }
This is the ARM64 variant for 314beb9bcab ("x86: bpf_jit_comp: secure bpf jit against spraying attacks"). Thanks to commit 11d91a770f1f ("arm64: Add CONFIG_DEBUG_SET_MODULE_RONX support") which added necessary infrastructure, we can now implement RO marking of eBPF generated JIT image pages and randomize start offset for the JIT code, so that it does not reside directly on a page boundary anymore. Likewise, the holes are filled with illegal instructions. This is basically the ARM64 variant of what we already have in ARM via commit 55309dd3d4cd ("net: bpf: arm: address randomize and write protect JIT code"). Moreover, this commit also presents a merge resolution due to conflicts with commit 60a3b2253c41 ("net: bpf: make eBPF interpreter images read-only") as we don't use kfree() in bpf_jit_free() anymore to release the locked bpf_prog structure, but instead bpf_prog_unlock_free() through a different allocator. JIT tested on aarch64 with BPF test suite. Reference: http://mainisusuallyafunction.blogspot.com/2012/11/attacking-hardened-linux-systems-with.html Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Cc: Zi Shen Lim <zlim.lnx@gmail.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: David S. Miller <davem@davemloft.net> Cc: Alexei Starovoitov <ast@plumgrid.com> --- v1 -> v2: - Use brk insn as suggested by Catalin, thanks a lot for your feedback! Rest unchanged. Note: - This patch depends on net-next being merged to mainline due to the mentioned merge conflict. arch/arm64/net/bpf_jit_comp.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-)