aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorDaniel Borkmann <dborkman@redhat.com>2014-09-08 02:04:48 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-09 19:58:56 -0400
commit55309dd3d4cd7420376a3de0526d6ed24ff8fa76 (patch)
treeb1e5f70c1930fe58e534ef5371835b56b7bf3519 /arch/arm
parent738cbe72adc5c8f2016c4c68aa5162631d4f27e1 (diff)
net: bpf: arm: address randomize and write protect JIT code
This is the ARM variant for 314beb9bcab ("x86: bpf_jit_comp: secure bpf jit against spraying attacks"). It is now possible to implement it due to commits 75374ad47c64 ("ARM: mm: Define set_memory_* functions for ARM") and dca9aa92fc7c ("ARM: add DEBUG_SET_MODULE_RONX option to Kconfig") which added infrastructure for this facility. Thus, this patch makes sure the BPF generated JIT code is marked RO, as other kernel text sections, and also lets the generated JIT code start at a pseudo random offset instead on a page boundary. The holes are filled with illegal instructions. JIT tested on armv7hl 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> Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Acked-by: Mircea Gherzan <mgherzan@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/net/bpf_jit_32.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index a76623bcf722..2d1a5b93d91c 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -12,7 +12,6 @@
12#include <linux/compiler.h> 12#include <linux/compiler.h>
13#include <linux/errno.h> 13#include <linux/errno.h>
14#include <linux/filter.h> 14#include <linux/filter.h>
15#include <linux/moduleloader.h>
16#include <linux/netdevice.h> 15#include <linux/netdevice.h>
17#include <linux/string.h> 16#include <linux/string.h>
18#include <linux/slab.h> 17#include <linux/slab.h>
@@ -174,6 +173,15 @@ static inline bool is_load_to_a(u16 inst)
174 } 173 }
175} 174}
176 175
176static void jit_fill_hole(void *area, unsigned int size)
177{
178 /* Insert illegal UND instructions. */
179 u32 *ptr, fill_ins = 0xe7ffffff;
180 /* We are guaranteed to have aligned memory. */
181 for (ptr = area; size >= sizeof(u32); size -= sizeof(u32))
182 *ptr++ = fill_ins;
183}
184
177static void build_prologue(struct jit_ctx *ctx) 185static void build_prologue(struct jit_ctx *ctx)
178{ 186{
179 u16 reg_set = saved_regs(ctx); 187 u16 reg_set = saved_regs(ctx);
@@ -859,9 +867,11 @@ b_epilogue:
859 867
860void bpf_jit_compile(struct bpf_prog *fp) 868void bpf_jit_compile(struct bpf_prog *fp)
861{ 869{
870 struct bpf_binary_header *header;
862 struct jit_ctx ctx; 871 struct jit_ctx ctx;
863 unsigned tmp_idx; 872 unsigned tmp_idx;
864 unsigned alloc_size; 873 unsigned alloc_size;
874 u8 *target_ptr;
865 875
866 if (!bpf_jit_enable) 876 if (!bpf_jit_enable)
867 return; 877 return;
@@ -897,13 +907,15 @@ void bpf_jit_compile(struct bpf_prog *fp)
897 /* there's nothing after the epilogue on ARMv7 */ 907 /* there's nothing after the epilogue on ARMv7 */
898 build_epilogue(&ctx); 908 build_epilogue(&ctx);
899#endif 909#endif
900
901 alloc_size = 4 * ctx.idx; 910 alloc_size = 4 * ctx.idx;
902 ctx.target = module_alloc(alloc_size); 911 header = bpf_jit_binary_alloc(alloc_size, &target_ptr,
903 if (unlikely(ctx.target == NULL)) 912 4, jit_fill_hole);
913 if (header == NULL)
904 goto out; 914 goto out;
905 915
916 ctx.target = (u32 *) target_ptr;
906 ctx.idx = 0; 917 ctx.idx = 0;
918
907 build_prologue(&ctx); 919 build_prologue(&ctx);
908 build_body(&ctx); 920 build_body(&ctx);
909 build_epilogue(&ctx); 921 build_epilogue(&ctx);
@@ -919,6 +931,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
919 /* there are 2 passes here */ 931 /* there are 2 passes here */
920 bpf_jit_dump(fp->len, alloc_size, 2, ctx.target); 932 bpf_jit_dump(fp->len, alloc_size, 2, ctx.target);
921 933
934 set_memory_ro((unsigned long)header, header->pages);
922 fp->bpf_func = (void *)ctx.target; 935 fp->bpf_func = (void *)ctx.target;
923 fp->jited = 1; 936 fp->jited = 1;
924out: 937out:
@@ -928,8 +941,15 @@ out:
928 941
929void bpf_jit_free(struct bpf_prog *fp) 942void bpf_jit_free(struct bpf_prog *fp)
930{ 943{
931 if (fp->jited) 944 unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;
932 module_free(NULL, fp->bpf_func); 945 struct bpf_binary_header *header = (void *)addr;
946
947 if (!fp->jited)
948 goto free_filter;
949
950 set_memory_rw(addr, header->pages);
951 bpf_jit_binary_free(header);
933 952
953free_filter:
934 bpf_prog_unlock_free(fp); 954 bpf_prog_unlock_free(fp);
935} 955}