Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Mon, 23 May 2016 11:52:30 -0700
From: Kees Cook <>
To: "" <>
Cc: Daniel Borkmann <>, "Reshetova, Elena" <>
Subject: Re: BPF JIT spray attack - proof of concept code for modern kernel

On Tue, May 3, 2016 at 10:01 AM, Kees Cook <> wrote:
> On Mon, May 2, 2016 at 11:38 PM, Reshetova, Elena
> <> wrote:
>> Following Kees’s suggestion, I am posting here a link to the poc code that I
>> did to show the need of further BPF JIT hardening:
>> This poc is based on the 2012 poc done by McAllister:
>> I have kept his commits untouched and
>> only added mine on top that you can easily see what was modified.
>> Some description of what it does and why it does work:
>> The original 2012 poc stopped working after the address offset randomization
>> for loading the BPF was added:
>> This was due to the fact that McAllister code relied on random page guessing
>> and was assuming filter to start at the page start. This approach clearly
>> doesn’t work with new random address allocation since one would need to
>> guess both page and offset and incorrect guess most commonly results in a
>> full restart need for normal machine (after which filter address has changed
>> and you don’t gain any knowledge).
>> The main changes I did was to extend the filter size to spawn longer than 1
>> full page (to make sure it would overrun into the next page) and then repeat
>> the “get root payload” there in circles with enough of “nope” instructions
>> to render it for most success. Also, when jumping to a new random page, I
>> would try to execute the payload a number of times on the same page changing
>> just an offset that is less than 10
>> ( )
>> to make sure to walk through the “nopes” and invoke the payload if the page
>> guess was correct.
>> I have tried the poc on virtual machine with Ubuntu with 4.4 upstream kernel
>> and it works quite well. It can still in some cases completely stall the
>> machine that reboot is required, but it does reach its root goal in most of
>> the cases.
>> Also, please note that similarly as 2012 poc code, this is not a real exploit
>> because it requires an “insecure ko” kernel module to actually make a jump,
>> but it illustrates the need for further JIT hardening that Daniel is
>> currently working now on.
> This is great! Thanks for updating this research. It strongly helps
> illustrate why instruction blinding is an important defense. I'm
> looking forward to Daniel's work landing.

Just to follow up on this: the eBPF JIT blinding code has landed in
Linus's tree (which should ultimately appear in v4.7)!

See the commits in and around:

If a system already sets the bpf_jit_enable sysctl to 1 (0 is the
kernel default), the new bpf_jit_harden sysctl can be 0 (off, the
current kernel default, which will hopefully change in the future), 1
(unprivileged users get JIT blinding), or 2 (all users get JIT

As always, there's a few more things to do AIUI, if anyone has time
and interest:
- we need a blinding test added (either to lib/test_bpf.c or elsewhere)
- remaining archs (ARM, MIPS, PowerPC, Sparc) cBPF JIT needs to either
be converted to eBPF or have blinding added directly (the latter is
easier, the former is better all around). i.e. if an arch defines
bpf_jit_enable, but doesn't call bpf_int_jit_compile(), it needs the
eBPF JIT. If it does, but doesn't call bpf_jit_blind_constants(), it's
not blinding eBPF.

Thanks for all the attention on this!


Kees Cook
Chrome OS & Brillo Security

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.