#include <linux/netdevice.h>
 #include <linux/filter.h>
 #include <linux/if_vlan.h>
+#include <linux/random.h>
 
 /*
  * Conventions :
        return -1;
 }
 
+struct bpf_binary_header {
+       unsigned int    pages;
+       /* Note : for security reasons, bpf code will follow a randomly
+        * sized amount of int3 instructions
+        */
+       u8              image[];
+};
+
+static struct bpf_binary_header *bpf_alloc_binary(unsigned int proglen,
+                                                 u8 **image_ptr)
+{
+       unsigned int sz, hole;
+       struct bpf_binary_header *header;
+
+       /* Most of BPF filters are really small,
+        * but if some of them fill a page, allow at least
+        * 128 extra bytes to insert a random section of int3
+        */
+       sz = round_up(proglen + sizeof(*header) + 128, PAGE_SIZE);
+       header = module_alloc(sz);
+       if (!header)
+               return NULL;
+
+       memset(header, 0xcc, sz); /* fill whole space with int3 instructions */
+
+       header->pages = sz / PAGE_SIZE;
+       hole = sz - (proglen + sizeof(*header));
+
+       /* insert a random number of int3 instructions before BPF code */
+       *image_ptr = &header->image[prandom_u32() % hole];
+       return header;
+}
+
 void bpf_jit_compile(struct sk_filter *fp)
 {
        u8 temp[64];
        int t_offset, f_offset;
        u8 t_op, f_op, seen = 0, pass;
        u8 *image = NULL;
+       struct bpf_binary_header *header = NULL;
        u8 *func;
        int pc_ret0 = -1; /* bpf index of first RET #0 instruction (if any) */
        unsigned int cleanup_addr; /* epilogue code offset */
                                if (unlikely(proglen + ilen > oldproglen)) {
                                        pr_err("bpb_jit_compile fatal error\n");
                                        kfree(addrs);
-                                       module_free(NULL, image);
+                                       module_free(NULL, header);
                                        return;
                                }
                                memcpy(image + proglen, temp, ilen);
                        break;
                }
                if (proglen == oldproglen) {
-                       image = module_alloc(proglen);
-                       if (!image)
+                       header = bpf_alloc_binary(proglen, &image);
+                       if (!header)
                                goto out;
                }
                oldproglen = proglen;
                bpf_jit_dump(flen, proglen, pass, image);
 
        if (image) {
-               bpf_flush_icache(image, image + proglen);
+               bpf_flush_icache(header, image + proglen);
+               set_memory_ro((unsigned long)header, header->pages);
                fp->bpf_func = (void *)image;
        }
 out:
 
 void bpf_jit_free(struct sk_filter *fp)
 {
-       if (fp->bpf_func != sk_run_filter)
-               module_free(NULL, fp->bpf_func);
+       if (fp->bpf_func != sk_run_filter) {
+               unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;
+               struct bpf_binary_header *header = (void *)addr;
+
+               set_memory_rw(addr, header->pages);
+               module_free(NULL, header);
+       }
 }