From patchwork Sat May 18 02:37:03 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Dumazet X-Patchwork-Id: 244726 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 517142C009B for ; Sat, 18 May 2013 12:37:37 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755198Ab3ERChH (ORCPT ); Fri, 17 May 2013 22:37:07 -0400 Received: from mail-pd0-f173.google.com ([209.85.192.173]:65312 "EHLO mail-pd0-f173.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753173Ab3ERChG (ORCPT ); Fri, 17 May 2013 22:37:06 -0400 Received: by mail-pd0-f173.google.com with SMTP id v10so3867547pde.4 for ; Fri, 17 May 2013 19:37:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:message-id:subject:from:to:cc:date:content-type:x-mailer :content-transfer-encoding:mime-version; bh=33AD9GBkapDX9X/KGGDxcGWVoc9yHjbA71z7XfbKXRA=; b=pHonyC9XarrJw61XD02YKrdanBeoQniQyc6tGaSxxRZ+Cd0qCOCzLpIbOg5nuLoJKP ea3cPPSMJKZHYbhvyLUJ52BYe+8k5ZZhzGW6jmLlYOMfnlw9Mpw4pc85TBZHkZtiy6Sq cOTj5KChyZ+xx4ASxseisrI2+R+3Y6SURcfwbjclCfxeNBmJ65xoeT/VozKXNIYGs8cZ l9ih9byTc4IFpGpu3dvd+CUZ4B8zhvd6pREQQzl+ZBiqRLApvy5j7foIotdYxw1PQRsq hpwUYwwRtTKjn36q630xZnJd1lcKX9gGSqp73lMImPhZtwxSs0Nty/A4+o6hThF6bJzC 0snw== X-Received: by 10.66.156.8 with SMTP id wa8mr51679223pab.76.1368844625629; Fri, 17 May 2013 19:37:05 -0700 (PDT) Received: from [172.26.54.178] ([172.26.54.178]) by mx.google.com with ESMTPSA id aa8sm14656869pad.14.2013.05.17.19.37.04 for (version=SSLv3 cipher=RC4-SHA bits=128/128); Fri, 17 May 2013 19:37:04 -0700 (PDT) Message-ID: <1368844623.3301.142.camel@edumazet-glaptop> Subject: [PATCH net-next] x86: bpf_jit_comp: secure bpf jit against spraying attacks From: Eric Dumazet To: David Miller Cc: netdev , "H. Peter Anvin" , "linux-kernel@vger.kernel.org" Date: Fri, 17 May 2013 19:37:03 -0700 X-Mailer: Evolution 3.2.3-0ubuntu6 Mime-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Eric Dumazet hpa bringed into my attention some security related issues with BPF JIT on x86. This patch makes sure the bpf generated code is marked read only, as other kernel text sections. It also splits the unused space (we vmalloc() and only use a fraction of the page) in two parts, so that the generated bpf code not starts at a known offset in the page, but a pseudo random one. Refs: http://mainisusuallyafunction.blogspot.com/2012/11/attacking-hardened-linux-systems-with.html Reported-by: H. Peter Anvin Signed-off-by: Eric Dumazet Reviewed-by: Daniel Borkmann --- arch/x86/net/bpf_jit_comp.c | 53 ++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 6 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index c0212db..79c216a 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -12,6 +12,7 @@ #include #include #include +#include /* * Conventions : @@ -144,6 +145,39 @@ static int pkt_type_offset(void) 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]; @@ -153,6 +187,7 @@ void bpf_jit_compile(struct sk_filter *fp) 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 */ @@ -693,7 +728,7 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i]; 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); @@ -717,8 +752,8 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i]; break; } if (proglen == oldproglen) { - image = module_alloc(proglen); - if (!image) + header = bpf_alloc_binary(proglen, &image); + if (!header) goto out; } oldproglen = proglen; @@ -728,7 +763,8 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i]; 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: @@ -738,6 +774,11 @@ 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); + } }