Skip to content

Commit

Permalink
s390/bpf,jit: address randomize and write protect jit code
Browse files Browse the repository at this point in the history
This is the s390 variant of 314beb9 "x86: bpf_jit_comp: secure bpf
jit against spraying attacks".
With this change the whole jit code and literal pool will be write
protected after creation. In addition the start address of the jit
code won't be always on a page boundary anymore.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
  • Loading branch information
Heiko Carstens authored and Martin Schwidefsky committed Jul 18, 2013
1 parent fee1b54 commit aa2d2c7
Showing 1 changed file with 46 additions and 5 deletions.
51 changes: 46 additions & 5 deletions arch/s390/net/bpf_jit_comp.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <linux/filter.h>
#include <linux/random.h>
#include <asm/cacheflush.h>
#include <asm/processor.h>
#include <asm/facility.h>
Expand Down Expand Up @@ -738,8 +739,41 @@ load_abs: if ((int) K < 0)
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 = sz - bpfsize + 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 sk_filter *fp)
{
struct bpf_binary_header *header = NULL;
unsigned long size, prg_len, lit_len;
struct bpf_jit jit, cjit;
unsigned int *addrs;
Expand Down Expand Up @@ -775,8 +809,8 @@ void bpf_jit_compile(struct sk_filter *fp)
size = prg_len + lit_len;
if (size >= BPF_SIZE_MAX)
goto out;
jit.start = module_alloc(size);
if (!jit.start)
header = bpf_alloc_binary(size, &jit.start);
if (!header)
goto out;
jit.prg = jit.mid = jit.start + prg_len;
jit.lit = jit.end = jit.start + prg_len + lit_len;
Expand All @@ -791,14 +825,21 @@ void bpf_jit_compile(struct sk_filter *fp)
if (jit.start)
print_fn_code(jit.start, jit.mid - jit.start);
}
if (jit.start)
if (jit.start) {
set_memory_ro((unsigned long)header, header->pages);
fp->bpf_func = (void *) jit.start;
}
out:
kfree(addrs);
}

void bpf_jit_free(struct sk_filter *fp)
{
if (fp->bpf_func != sk_run_filter)
module_free(NULL, fp->bpf_func);
unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;
struct bpf_binary_header *header = (void *)addr;

if (fp->bpf_func == sk_run_filter)
return;
set_memory_rw(addr, header->pages);
module_free(NULL, header);
}

0 comments on commit aa2d2c7

Please sign in to comment.