diff options
-rw-r--r-- | arch/s390/net/bpf_jit_comp.c | 51 |
1 files changed, 46 insertions, 5 deletions
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 80828bfee2ec..788e22395acd 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/netdevice.h> | 9 | #include <linux/netdevice.h> |
10 | #include <linux/if_vlan.h> | 10 | #include <linux/if_vlan.h> |
11 | #include <linux/filter.h> | 11 | #include <linux/filter.h> |
12 | #include <linux/random.h> | ||
12 | #include <asm/cacheflush.h> | 13 | #include <asm/cacheflush.h> |
13 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
14 | #include <asm/facility.h> | 15 | #include <asm/facility.h> |
@@ -738,8 +739,41 @@ out: | |||
738 | return -1; | 739 | return -1; |
739 | } | 740 | } |
740 | 741 | ||
742 | /* | ||
743 | * Note: for security reasons, bpf code will follow a randomly | ||
744 | * sized amount of illegal instructions. | ||
745 | */ | ||
746 | struct bpf_binary_header { | ||
747 | unsigned int pages; | ||
748 | u8 image[]; | ||
749 | }; | ||
750 | |||
751 | static struct bpf_binary_header *bpf_alloc_binary(unsigned int bpfsize, | ||
752 | u8 **image_ptr) | ||
753 | { | ||
754 | struct bpf_binary_header *header; | ||
755 | unsigned int sz, hole; | ||
756 | |||
757 | /* Most BPF filters are really small, but if some of them fill a page, | ||
758 | * allow at least 128 extra bytes for illegal instructions. | ||
759 | */ | ||
760 | sz = round_up(bpfsize + sizeof(*header) + 128, PAGE_SIZE); | ||
761 | header = module_alloc(sz); | ||
762 | if (!header) | ||
763 | return NULL; | ||
764 | memset(header, 0, sz); | ||
765 | header->pages = sz / PAGE_SIZE; | ||
766 | hole = sz - bpfsize + sizeof(*header); | ||
767 | /* Insert random number of illegal instructions before BPF code | ||
768 | * and make sure the first instruction starts at an even address. | ||
769 | */ | ||
770 | *image_ptr = &header->image[(prandom_u32() % hole) & -2]; | ||
771 | return header; | ||
772 | } | ||
773 | |||
741 | void bpf_jit_compile(struct sk_filter *fp) | 774 | void bpf_jit_compile(struct sk_filter *fp) |
742 | { | 775 | { |
776 | struct bpf_binary_header *header = NULL; | ||
743 | unsigned long size, prg_len, lit_len; | 777 | unsigned long size, prg_len, lit_len; |
744 | struct bpf_jit jit, cjit; | 778 | struct bpf_jit jit, cjit; |
745 | unsigned int *addrs; | 779 | unsigned int *addrs; |
@@ -775,8 +809,8 @@ void bpf_jit_compile(struct sk_filter *fp) | |||
775 | size = prg_len + lit_len; | 809 | size = prg_len + lit_len; |
776 | if (size >= BPF_SIZE_MAX) | 810 | if (size >= BPF_SIZE_MAX) |
777 | goto out; | 811 | goto out; |
778 | jit.start = module_alloc(size); | 812 | header = bpf_alloc_binary(size, &jit.start); |
779 | if (!jit.start) | 813 | if (!header) |
780 | goto out; | 814 | goto out; |
781 | jit.prg = jit.mid = jit.start + prg_len; | 815 | jit.prg = jit.mid = jit.start + prg_len; |
782 | jit.lit = jit.end = jit.start + prg_len + lit_len; | 816 | jit.lit = jit.end = jit.start + prg_len + lit_len; |
@@ -791,14 +825,21 @@ void bpf_jit_compile(struct sk_filter *fp) | |||
791 | if (jit.start) | 825 | if (jit.start) |
792 | print_fn_code(jit.start, jit.mid - jit.start); | 826 | print_fn_code(jit.start, jit.mid - jit.start); |
793 | } | 827 | } |
794 | if (jit.start) | 828 | if (jit.start) { |
829 | set_memory_ro((unsigned long)header, header->pages); | ||
795 | fp->bpf_func = (void *) jit.start; | 830 | fp->bpf_func = (void *) jit.start; |
831 | } | ||
796 | out: | 832 | out: |
797 | kfree(addrs); | 833 | kfree(addrs); |
798 | } | 834 | } |
799 | 835 | ||
800 | void bpf_jit_free(struct sk_filter *fp) | 836 | void bpf_jit_free(struct sk_filter *fp) |
801 | { | 837 | { |
802 | if (fp->bpf_func != sk_run_filter) | 838 | unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK; |
803 | module_free(NULL, fp->bpf_func); | 839 | struct bpf_binary_header *header = (void *)addr; |
840 | |||
841 | if (fp->bpf_func == sk_run_filter) | ||
842 | return; | ||
843 | set_memory_rw(addr, header->pages); | ||
844 | module_free(NULL, header); | ||
804 | } | 845 | } |