]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/s390/net/bpf_jit_comp.c
Merge remote-tracking branch 'grant/devicetree/next' into for-next
[karo-tx-linux.git] / arch / s390 / net / bpf_jit_comp.c
index 61e45b7c04d7bdf122a195903face00cfb6c2ce3..bbd1981cc15007fcdb779ca201553ed28012f20d 100644 (file)
@@ -5,11 +5,9 @@
  *
  * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
-#include <linux/moduleloader.h>
 #include <linux/netdevice.h>
 #include <linux/if_vlan.h>
 #include <linux/filter.h>
-#include <linux/random.h>
 #include <linux/init.h>
 #include <asm/cacheflush.h>
 #include <asm/facility.h>
@@ -148,6 +146,12 @@ struct bpf_jit {
        ret;                                            \
 })
 
+static void bpf_jit_fill_hole(void *area, unsigned int size)
+{
+       /* Fill whole space with illegal instructions */
+       memset(area, 0, size);
+}
+
 static void bpf_jit_prologue(struct bpf_jit *jit)
 {
        /* Save registers and create stack frame if necessary */
@@ -223,37 +227,6 @@ static void bpf_jit_epilogue(struct bpf_jit *jit)
        EMIT2(0x07fe);
 }
 
-/* Helper to find the offset of pkt_type in sk_buff
- * Make sure its still a 3bit field starting at the MSBs within a byte.
- */
-#define PKT_TYPE_MAX 0xe0
-static int pkt_type_offset;
-
-static int __init bpf_pkt_type_offset_init(void)
-{
-       struct sk_buff skb_probe = {
-               .pkt_type = ~0,
-       };
-       char *ct = (char *)&skb_probe;
-       int off;
-
-       pkt_type_offset = -1;
-       for (off = 0; off < sizeof(struct sk_buff); off++) {
-               if (!ct[off])
-                       continue;
-               if (ct[off] == PKT_TYPE_MAX)
-                       pkt_type_offset = off;
-               else {
-                       /* Found non matching bit pattern, fix needed. */
-                       WARN_ON_ONCE(1);
-                       pkt_type_offset = -1;
-                       return -1;
-               }
-       }
-       return 0;
-}
-device_initcall(bpf_pkt_type_offset_init);
-
 /*
  * make sure we dont leak kernel information to user
  */
@@ -458,8 +431,8 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
                EMIT4_DISP(0x88500000, K);
                break;
        case BPF_ALU | BPF_NEG: /* A = -A */
-               /* lnr %r5,%r5 */
-               EMIT2(0x1155);
+               /* lcr %r5,%r5 */
+               EMIT2(0x1355);
                break;
        case BPF_JMP | BPF_JA: /* ip += K */
                offset = addrs[i + K] + jit->start - jit->prg;
@@ -475,15 +448,12 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
                mask = 0x800000; /* je */
 kbranch:       /* Emit compare if the branch targets are different */
                if (filter->jt != filter->jf) {
-                       if (K <= 16383)
-                               /* chi %r5,<K> */
-                               EMIT4_IMM(0xa75e0000, K);
-                       else if (test_facility(21))
+                       if (test_facility(21))
                                /* clfi %r5,<K> */
                                EMIT6_IMM(0xc25f0000, K);
                        else
-                               /* c %r5,<d(K)>(%r13) */
-                               EMIT4_DISP(0x5950d000, EMIT_CONST(K));
+                               /* cl %r5,<d(K)>(%r13) */
+                               EMIT4_DISP(0x5550d000, EMIT_CONST(K));
                }
 branch:                if (filter->jt == filter->jf) {
                        if (filter->jt == 0)
@@ -529,8 +499,8 @@ branch:             if (filter->jt == filter->jf) {
 xbranch:       /* Emit compare if the branch targets are different */
                if (filter->jt != filter->jf) {
                        jit->seen |= SEEN_XREG;
-                       /* cr %r5,%r12 */
-                       EMIT2(0x195c);
+                       /* clr %r5,%r12 */
+                       EMIT2(0x155c);
                }
                goto branch;
        case BPF_JMP | BPF_JSET | BPF_X: /* ip += (A & X) ? jt : jf */
@@ -753,12 +723,10 @@ call_fn:  /* lg %r1,<d(function)>(%r13) */
                }
                break;
        case BPF_ANC | SKF_AD_PKTTYPE:
-               if (pkt_type_offset < 0)
-                       goto out;
                /* lhi %r5,0 */
                EMIT4(0xa7580000);
                /* ic %r5,<d(pkt_type_offset)>(%r2) */
-               EMIT4_DISP(0x43502000, pkt_type_offset);
+               EMIT4_DISP(0x43502000, PKT_TYPE_OFFSET());
                /* srl %r5,5 */
                EMIT4_DISP(0x88500000, 5);
                break;
@@ -780,38 +748,6 @@ out:
        return -1;
 }
 
-/*
- * Note: for security reasons, bpf code will follow a randomly
- *      sized amount of illegal instructions.
- */
-struct bpf_binary_header {
-       unsigned int pages;
-       u8 image[];
-};
-
-static struct bpf_binary_header *bpf_alloc_binary(unsigned int bpfsize,
-                                                 u8 **image_ptr)
-{
-       struct bpf_binary_header *header;
-       unsigned int sz, hole;
-
-       /* Most BPF filters are really small, but if some of them fill a page,
-        * allow at least 128 extra bytes for illegal instructions.
-        */
-       sz = round_up(bpfsize + sizeof(*header) + 128, PAGE_SIZE);
-       header = module_alloc(sz);
-       if (!header)
-               return NULL;
-       memset(header, 0, sz);
-       header->pages = sz / PAGE_SIZE;
-       hole = min(sz - (bpfsize + sizeof(*header)), PAGE_SIZE - sizeof(*header));
-       /* Insert random number of illegal instructions before BPF code
-        * and make sure the first instruction starts at an even address.
-        */
-       *image_ptr = &header->image[(prandom_u32() % hole) & -2];
-       return header;
-}
-
 void bpf_jit_compile(struct bpf_prog *fp)
 {
        struct bpf_binary_header *header = NULL;
@@ -850,7 +786,8 @@ void bpf_jit_compile(struct bpf_prog *fp)
                        size = prg_len + lit_len;
                        if (size >= BPF_SIZE_MAX)
                                goto out;
-                       header = bpf_alloc_binary(size, &jit.start);
+                       header = bpf_jit_binary_alloc(size, &jit.start,
+                                                     2, bpf_jit_fill_hole);
                        if (!header)
                                goto out;
                        jit.prg = jit.mid = jit.start + prg_len;
@@ -869,7 +806,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
        if (jit.start) {
                set_memory_ro((unsigned long)header, header->pages);
                fp->bpf_func = (void *) jit.start;
-               fp->jited = 1;
+               fp->jited = true;
        }
 out:
        kfree(addrs);
@@ -884,8 +821,8 @@ void bpf_jit_free(struct bpf_prog *fp)
                goto free_filter;
 
        set_memory_rw(addr, header->pages);
-       module_free(NULL, header);
+       bpf_jit_binary_free(header);
 
 free_filter:
-       kfree(fp);
+       bpf_prog_unlock_free(fp);
 }