aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <dborkman@redhat.com>2014-09-08 02:04:47 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-09 19:58:56 -0400
commit738cbe72adc5c8f2016c4c68aa5162631d4f27e1 (patch)
tree4c207c0a763ea8998dddda89a7a1d9eb98866b60
parentca777eff51f7fbaebd954e645d8ecb781a906b4a (diff)
net: bpf: consolidate JIT binary allocator
Introduced in commit 314beb9bcabf ("x86: bpf_jit_comp: secure bpf jit against spraying attacks") and later on replicated in aa2d2c73c21f ("s390/bpf,jit: address randomize and write protect jit code") for s390 architecture, write protection for BPF JIT images got added and a random start address of the JIT code, so that it's not on a page boundary anymore. Since both use a very similar allocator for the BPF binary header, we can consolidate this code into the BPF core as it's mostly JIT independant anyway. This will also allow for future archs that support DEBUG_SET_MODULE_RONX to just reuse instead of reimplementing it. JIT tested on x86_64 and s390x with BPF test suite. Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Acked-by: Alexei Starovoitov <ast@plumgrid.com> Cc: Eric Dumazet <edumazet@google.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/s390/net/bpf_jit_comp.c45
-rw-r--r--arch/x86/net/bpf_jit_comp.c50
-rw-r--r--include/linux/filter.h13
-rw-r--r--kernel/bpf/core.c39
4 files changed, 72 insertions, 75 deletions
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index f2833c5b218a..b734f975c22e 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -5,11 +5,9 @@
5 * 5 *
6 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 6 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
7 */ 7 */
8#include <linux/moduleloader.h>
9#include <linux/netdevice.h> 8#include <linux/netdevice.h>
10#include <linux/if_vlan.h> 9#include <linux/if_vlan.h>
11#include <linux/filter.h> 10#include <linux/filter.h>
12#include <linux/random.h>
13#include <linux/init.h> 11#include <linux/init.h>
14#include <asm/cacheflush.h> 12#include <asm/cacheflush.h>
15#include <asm/facility.h> 13#include <asm/facility.h>
@@ -148,6 +146,12 @@ struct bpf_jit {
148 ret; \ 146 ret; \
149}) 147})
150 148
149static void bpf_jit_fill_hole(void *area, unsigned int size)
150{
151 /* Fill whole space with illegal instructions */
152 memset(area, 0, size);
153}
154
151static void bpf_jit_prologue(struct bpf_jit *jit) 155static void bpf_jit_prologue(struct bpf_jit *jit)
152{ 156{
153 /* Save registers and create stack frame if necessary */ 157 /* Save registers and create stack frame if necessary */
@@ -780,38 +784,6 @@ out:
780 return -1; 784 return -1;
781} 785}
782 786
783/*
784 * Note: for security reasons, bpf code will follow a randomly
785 * sized amount of illegal instructions.
786 */
787struct bpf_binary_header {
788 unsigned int pages;
789 u8 image[];
790};
791
792static struct bpf_binary_header *bpf_alloc_binary(unsigned int bpfsize,
793 u8 **image_ptr)
794{
795 struct bpf_binary_header *header;
796 unsigned int sz, hole;
797
798 /* Most BPF filters are really small, but if some of them fill a page,
799 * allow at least 128 extra bytes for illegal instructions.
800 */
801 sz = round_up(bpfsize + sizeof(*header) + 128, PAGE_SIZE);
802 header = module_alloc(sz);
803 if (!header)
804 return NULL;
805 memset(header, 0, sz);
806 header->pages = sz / PAGE_SIZE;
807 hole = min(sz - (bpfsize + sizeof(*header)), PAGE_SIZE - sizeof(*header));
808 /* Insert random number of illegal instructions before BPF code
809 * and make sure the first instruction starts at an even address.
810 */
811 *image_ptr = &header->image[(prandom_u32() % hole) & -2];
812 return header;
813}
814
815void bpf_jit_compile(struct bpf_prog *fp) 787void bpf_jit_compile(struct bpf_prog *fp)
816{ 788{
817 struct bpf_binary_header *header = NULL; 789 struct bpf_binary_header *header = NULL;
@@ -850,7 +822,8 @@ void bpf_jit_compile(struct bpf_prog *fp)
850 size = prg_len + lit_len; 822 size = prg_len + lit_len;
851 if (size >= BPF_SIZE_MAX) 823 if (size >= BPF_SIZE_MAX)
852 goto out; 824 goto out;
853 header = bpf_alloc_binary(size, &jit.start); 825 header = bpf_jit_binary_alloc(size, &jit.start,
826 2, bpf_jit_fill_hole);
854 if (!header) 827 if (!header)
855 goto out; 828 goto out;
856 jit.prg = jit.mid = jit.start + prg_len; 829 jit.prg = jit.mid = jit.start + prg_len;
@@ -884,7 +857,7 @@ void bpf_jit_free(struct bpf_prog *fp)
884 goto free_filter; 857 goto free_filter;
885 858
886 set_memory_rw(addr, header->pages); 859 set_memory_rw(addr, header->pages);
887 module_free(NULL, header); 860 bpf_jit_binary_free(header);
888 861
889free_filter: 862free_filter:
890 bpf_prog_unlock_free(fp); 863 bpf_prog_unlock_free(fp);
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 06f8c17f5484..9de0b5476b0c 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -8,12 +8,10 @@
8 * as published by the Free Software Foundation; version 2 8 * as published by the Free Software Foundation; version 2
9 * of the License. 9 * of the License.
10 */ 10 */
11#include <linux/moduleloader.h>
12#include <asm/cacheflush.h>
13#include <linux/netdevice.h> 11#include <linux/netdevice.h>
14#include <linux/filter.h> 12#include <linux/filter.h>
15#include <linux/if_vlan.h> 13#include <linux/if_vlan.h>
16#include <linux/random.h> 14#include <asm/cacheflush.h>
17 15
18int bpf_jit_enable __read_mostly; 16int bpf_jit_enable __read_mostly;
19 17
@@ -109,39 +107,6 @@ static inline void bpf_flush_icache(void *start, void *end)
109#define CHOOSE_LOAD_FUNC(K, func) \ 107#define CHOOSE_LOAD_FUNC(K, func) \
110 ((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset) 108 ((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset)
111 109
112struct bpf_binary_header {
113 unsigned int pages;
114 /* Note : for security reasons, bpf code will follow a randomly
115 * sized amount of int3 instructions
116 */
117 u8 image[];
118};
119
120static struct bpf_binary_header *bpf_alloc_binary(unsigned int proglen,
121 u8 **image_ptr)
122{
123 unsigned int sz, hole;
124 struct bpf_binary_header *header;
125
126 /* Most of BPF filters are really small,
127 * but if some of them fill a page, allow at least
128 * 128 extra bytes to insert a random section of int3
129 */
130 sz = round_up(proglen + sizeof(*header) + 128, PAGE_SIZE);
131 header = module_alloc(sz);
132 if (!header)
133 return NULL;
134
135 memset(header, 0xcc, sz); /* fill whole space with int3 instructions */
136
137 header->pages = sz / PAGE_SIZE;
138 hole = min(sz - (proglen + sizeof(*header)), PAGE_SIZE - sizeof(*header));
139
140 /* insert a random number of int3 instructions before BPF code */
141 *image_ptr = &header->image[prandom_u32() % hole];
142 return header;
143}
144
145/* pick a register outside of BPF range for JIT internal work */ 110/* pick a register outside of BPF range for JIT internal work */
146#define AUX_REG (MAX_BPF_REG + 1) 111#define AUX_REG (MAX_BPF_REG + 1)
147 112
@@ -206,6 +171,12 @@ static inline u8 add_2reg(u8 byte, u32 dst_reg, u32 src_reg)
206 return byte + reg2hex[dst_reg] + (reg2hex[src_reg] << 3); 171 return byte + reg2hex[dst_reg] + (reg2hex[src_reg] << 3);
207} 172}
208 173
174static void jit_fill_hole(void *area, unsigned int size)
175{
176 /* fill whole space with int3 instructions */
177 memset(area, 0xcc, size);
178}
179
209struct jit_context { 180struct jit_context {
210 unsigned int cleanup_addr; /* epilogue code offset */ 181 unsigned int cleanup_addr; /* epilogue code offset */
211 bool seen_ld_abs; 182 bool seen_ld_abs;
@@ -959,7 +930,7 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
959 if (proglen <= 0) { 930 if (proglen <= 0) {
960 image = NULL; 931 image = NULL;
961 if (header) 932 if (header)
962 module_free(NULL, header); 933 bpf_jit_binary_free(header);
963 goto out; 934 goto out;
964 } 935 }
965 if (image) { 936 if (image) {
@@ -969,7 +940,8 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
969 break; 940 break;
970 } 941 }
971 if (proglen == oldproglen) { 942 if (proglen == oldproglen) {
972 header = bpf_alloc_binary(proglen, &image); 943 header = bpf_jit_binary_alloc(proglen, &image,
944 1, jit_fill_hole);
973 if (!header) 945 if (!header)
974 goto out; 946 goto out;
975 } 947 }
@@ -998,7 +970,7 @@ void bpf_jit_free(struct bpf_prog *fp)
998 goto free_filter; 970 goto free_filter;
999 971
1000 set_memory_rw(addr, header->pages); 972 set_memory_rw(addr, header->pages);
1001 module_free(NULL, header); 973 bpf_jit_binary_free(header);
1002 974
1003free_filter: 975free_filter:
1004 bpf_prog_unlock_free(fp); 976 bpf_prog_unlock_free(fp);
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 8f82ef3f1cdd..868764fcffb8 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -289,6 +289,11 @@ struct sock_fprog_kern {
289 struct sock_filter *filter; 289 struct sock_filter *filter;
290}; 290};
291 291
292struct bpf_binary_header {
293 unsigned int pages;
294 u8 image[];
295};
296
292struct bpf_work_struct { 297struct bpf_work_struct {
293 struct bpf_prog *prog; 298 struct bpf_prog *prog;
294 struct work_struct work; 299 struct work_struct work;
@@ -358,6 +363,14 @@ struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
358 gfp_t gfp_extra_flags); 363 gfp_t gfp_extra_flags);
359void __bpf_prog_free(struct bpf_prog *fp); 364void __bpf_prog_free(struct bpf_prog *fp);
360 365
366typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size);
367
368struct bpf_binary_header *
369bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
370 unsigned int alignment,
371 bpf_jit_fill_hole_t bpf_fill_ill_insns);
372void bpf_jit_binary_free(struct bpf_binary_header *hdr);
373
361static inline void bpf_prog_unlock_free(struct bpf_prog *fp) 374static inline void bpf_prog_unlock_free(struct bpf_prog *fp)
362{ 375{
363 bpf_prog_unlock_ro(fp); 376 bpf_prog_unlock_ro(fp);
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 2c2bfaacce66..8ee520f0ec70 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -20,9 +20,12 @@
20 * Andi Kleen - Fix a few bad bugs and races. 20 * Andi Kleen - Fix a few bad bugs and races.
21 * Kris Katterjohn - Added many additional checks in bpf_check_classic() 21 * Kris Katterjohn - Added many additional checks in bpf_check_classic()
22 */ 22 */
23
23#include <linux/filter.h> 24#include <linux/filter.h>
24#include <linux/skbuff.h> 25#include <linux/skbuff.h>
25#include <linux/vmalloc.h> 26#include <linux/vmalloc.h>
27#include <linux/random.h>
28#include <linux/moduleloader.h>
26#include <asm/unaligned.h> 29#include <asm/unaligned.h>
27 30
28/* Registers */ 31/* Registers */
@@ -125,6 +128,42 @@ void __bpf_prog_free(struct bpf_prog *fp)
125} 128}
126EXPORT_SYMBOL_GPL(__bpf_prog_free); 129EXPORT_SYMBOL_GPL(__bpf_prog_free);
127 130
131struct bpf_binary_header *
132bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
133 unsigned int alignment,
134 bpf_jit_fill_hole_t bpf_fill_ill_insns)
135{
136 struct bpf_binary_header *hdr;
137 unsigned int size, hole, start;
138
139 /* Most of BPF filters are really small, but if some of them
140 * fill a page, allow at least 128 extra bytes to insert a
141 * random section of illegal instructions.
142 */
143 size = round_up(proglen + sizeof(*hdr) + 128, PAGE_SIZE);
144 hdr = module_alloc(size);
145 if (hdr == NULL)
146 return NULL;
147
148 /* Fill space with illegal/arch-dep instructions. */
149 bpf_fill_ill_insns(hdr, size);
150
151 hdr->pages = size / PAGE_SIZE;
152 hole = min_t(unsigned int, size - (proglen + sizeof(*hdr)),
153 PAGE_SIZE - sizeof(*hdr));
154 start = (prandom_u32() % hole) & ~(alignment - 1);
155
156 /* Leave a random number of instructions before BPF code. */
157 *image_ptr = &hdr->image[start];
158
159 return hdr;
160}
161
162void bpf_jit_binary_free(struct bpf_binary_header *hdr)
163{
164 module_free(NULL, hdr);
165}
166
128/* Base function for offset calculation. Needs to go into .text section, 167/* Base function for offset calculation. Needs to go into .text section,
129 * therefore keeping it non-static as well; will also be used by JITs 168 * therefore keeping it non-static as well; will also be used by JITs
130 * anyway later on, so do not let the compiler omit it. 169 * anyway later on, so do not let the compiler omit it.