aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
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 /arch/x86
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>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/net/bpf_jit_comp.c50
1 files changed, 11 insertions, 39 deletions
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);