diff options
Diffstat (limited to 'arch/s390/net/bpf_jit_comp.c')
-rw-r--r-- | arch/s390/net/bpf_jit_comp.c | 84 |
1 files changed, 12 insertions, 72 deletions
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 61e45b7c04d7..c52ac77408ca 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 | ||
149 | static 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 | |||
151 | static void bpf_jit_prologue(struct bpf_jit *jit) | 155 | static 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 */ |
@@ -223,37 +227,6 @@ static void bpf_jit_epilogue(struct bpf_jit *jit) | |||
223 | EMIT2(0x07fe); | 227 | EMIT2(0x07fe); |
224 | } | 228 | } |
225 | 229 | ||
226 | /* Helper to find the offset of pkt_type in sk_buff | ||
227 | * Make sure its still a 3bit field starting at the MSBs within a byte. | ||
228 | */ | ||
229 | #define PKT_TYPE_MAX 0xe0 | ||
230 | static int pkt_type_offset; | ||
231 | |||
232 | static int __init bpf_pkt_type_offset_init(void) | ||
233 | { | ||
234 | struct sk_buff skb_probe = { | ||
235 | .pkt_type = ~0, | ||
236 | }; | ||
237 | char *ct = (char *)&skb_probe; | ||
238 | int off; | ||
239 | |||
240 | pkt_type_offset = -1; | ||
241 | for (off = 0; off < sizeof(struct sk_buff); off++) { | ||
242 | if (!ct[off]) | ||
243 | continue; | ||
244 | if (ct[off] == PKT_TYPE_MAX) | ||
245 | pkt_type_offset = off; | ||
246 | else { | ||
247 | /* Found non matching bit pattern, fix needed. */ | ||
248 | WARN_ON_ONCE(1); | ||
249 | pkt_type_offset = -1; | ||
250 | return -1; | ||
251 | } | ||
252 | } | ||
253 | return 0; | ||
254 | } | ||
255 | device_initcall(bpf_pkt_type_offset_init); | ||
256 | |||
257 | /* | 230 | /* |
258 | * make sure we dont leak kernel information to user | 231 | * make sure we dont leak kernel information to user |
259 | */ | 232 | */ |
@@ -753,12 +726,10 @@ call_fn: /* lg %r1,<d(function)>(%r13) */ | |||
753 | } | 726 | } |
754 | break; | 727 | break; |
755 | case BPF_ANC | SKF_AD_PKTTYPE: | 728 | case BPF_ANC | SKF_AD_PKTTYPE: |
756 | if (pkt_type_offset < 0) | ||
757 | goto out; | ||
758 | /* lhi %r5,0 */ | 729 | /* lhi %r5,0 */ |
759 | EMIT4(0xa7580000); | 730 | EMIT4(0xa7580000); |
760 | /* ic %r5,<d(pkt_type_offset)>(%r2) */ | 731 | /* ic %r5,<d(pkt_type_offset)>(%r2) */ |
761 | EMIT4_DISP(0x43502000, pkt_type_offset); | 732 | EMIT4_DISP(0x43502000, PKT_TYPE_OFFSET()); |
762 | /* srl %r5,5 */ | 733 | /* srl %r5,5 */ |
763 | EMIT4_DISP(0x88500000, 5); | 734 | EMIT4_DISP(0x88500000, 5); |
764 | break; | 735 | break; |
@@ -780,38 +751,6 @@ out: | |||
780 | return -1; | 751 | return -1; |
781 | } | 752 | } |
782 | 753 | ||
783 | /* | ||
784 | * Note: for security reasons, bpf code will follow a randomly | ||
785 | * sized amount of illegal instructions. | ||
786 | */ | ||
787 | struct bpf_binary_header { | ||
788 | unsigned int pages; | ||
789 | u8 image[]; | ||
790 | }; | ||
791 | |||
792 | static 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 | |||
815 | void bpf_jit_compile(struct bpf_prog *fp) | 754 | void bpf_jit_compile(struct bpf_prog *fp) |
816 | { | 755 | { |
817 | struct bpf_binary_header *header = NULL; | 756 | struct bpf_binary_header *header = NULL; |
@@ -850,7 +789,8 @@ void bpf_jit_compile(struct bpf_prog *fp) | |||
850 | size = prg_len + lit_len; | 789 | size = prg_len + lit_len; |
851 | if (size >= BPF_SIZE_MAX) | 790 | if (size >= BPF_SIZE_MAX) |
852 | goto out; | 791 | goto out; |
853 | header = bpf_alloc_binary(size, &jit.start); | 792 | header = bpf_jit_binary_alloc(size, &jit.start, |
793 | 2, bpf_jit_fill_hole); | ||
854 | if (!header) | 794 | if (!header) |
855 | goto out; | 795 | goto out; |
856 | jit.prg = jit.mid = jit.start + prg_len; | 796 | jit.prg = jit.mid = jit.start + prg_len; |
@@ -869,7 +809,7 @@ void bpf_jit_compile(struct bpf_prog *fp) | |||
869 | if (jit.start) { | 809 | if (jit.start) { |
870 | set_memory_ro((unsigned long)header, header->pages); | 810 | set_memory_ro((unsigned long)header, header->pages); |
871 | fp->bpf_func = (void *) jit.start; | 811 | fp->bpf_func = (void *) jit.start; |
872 | fp->jited = 1; | 812 | fp->jited = true; |
873 | } | 813 | } |
874 | out: | 814 | out: |
875 | kfree(addrs); | 815 | kfree(addrs); |
@@ -884,8 +824,8 @@ void bpf_jit_free(struct bpf_prog *fp) | |||
884 | goto free_filter; | 824 | goto free_filter; |
885 | 825 | ||
886 | set_memory_rw(addr, header->pages); | 826 | set_memory_rw(addr, header->pages); |
887 | module_free(NULL, header); | 827 | bpf_jit_binary_free(header); |
888 | 828 | ||
889 | free_filter: | 829 | free_filter: |
890 | kfree(fp); | 830 | bpf_prog_unlock_free(fp); |
891 | } | 831 | } |