* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Alexei Starovoitov @ 2014-08-13 21:56 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Andy Lutomirski, David S. Miller, Ingo Molnar, Linus Torvalds,
Steven Rostedt, Daniel Borkmann, Chema Gonzalez, Eric Dumazet,
Peter Zijlstra, Andrew Morton, Kees Cook, Linux API,
Network Development, linux-kernel@vger.kernel.org
In-Reply-To: <CAMEtUuwO028MV8TQXQew1SOQjUvSbQ_bazAqorGRxojXXYXEnA@mail.gmail.com>
On Wed, Aug 13, 2014 at 2:38 PM, Alexei Starovoitov <ast@plumgrid.com> wrote:
> On Wed, Aug 13, 2014 at 2:27 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>> On 08/13/2014 02:23 PM, Andy Lutomirski wrote:
>>> On Wed, Aug 13, 2014 at 2:21 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>>>> One thing about this that may be a serious concern: allowing the user to
>>>> control 8 contiguous bytes of kernel memory may be a security hazard.
>>>
>>> I'm confused. What kind of memory? I can control a lot more than 8
>>> bytes of stack very easily.
>>>
>>> Or are you concerned about 8 contiguous bytes of *executable* memory?
>>>
>>
>> Yes. Useful for some kinds of ROP custom gadgets.
>
> I don't get it. What is ROP ?
> What is the concern about 8 bytes ?
looked it up. too many abbreviations now days.
x64 jit spraying was fixed by Eric some time ago, so JIT emitting
movabsq doesn't increase attack surface. various movs of 32-bit
immediates can be used for 'custom gadget' just as well.
Worst case JIT won't be enabled.
In classic BPF we allow junk to be stored in used fields of
'struct sock_filter' and so far that wasn't a problem.
eBPF is more paranoid regarding verification.
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Alexei Starovoitov @ 2014-08-13 21:43 UTC (permalink / raw)
To: Andy Lutomirski
Cc: H. Peter Anvin, David S. Miller, Ingo Molnar, Linus Torvalds,
Steven Rostedt, Daniel Borkmann, Chema Gonzalez, Eric Dumazet,
Peter Zijlstra, Andrew Morton, Kees Cook, Linux API,
Network Development,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CALCETrVUPofE2w2t-_iwcTim8kbdcx93yW==+CwoqVqsaNnXHg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Wed, Aug 13, 2014 at 2:41 PM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
>
> I think this is moot on non-SMEP machines. And I'm not entirely
> convinced that it's worth worrying about in general, especially if we
> take some care to randomize the location of the JIT mapping.
JIT start address is already randomized...
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Andy Lutomirski @ 2014-08-13 21:41 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Alexei Starovoitov, David S. Miller, Ingo Molnar, Linus Torvalds,
Steven Rostedt, Daniel Borkmann, Chema Gonzalez, Eric Dumazet,
Peter Zijlstra, Andrew Morton, Kees Cook, Linux API,
Network Development, linux-kernel@vger.kernel.org
In-Reply-To: <53EBD848.1060203@zytor.com>
On Wed, Aug 13, 2014 at 2:27 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 08/13/2014 02:23 PM, Andy Lutomirski wrote:
>> On Wed, Aug 13, 2014 at 2:21 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>>> One thing about this that may be a serious concern: allowing the user to
>>> control 8 contiguous bytes of kernel memory may be a security hazard.
>>
>> I'm confused. What kind of memory? I can control a lot more than 8
>> bytes of stack very easily.
>>
>> Or are you concerned about 8 contiguous bytes of *executable* memory?
>>
>
> Yes. Useful for some kinds of ROP custom gadgets.
Hmm.
I think this is moot on non-SMEP machines. And I'm not entirely
convinced that it's worth worrying about in general, especially if we
take some care to randomize the location of the JIT mapping.
But yes, gadgets like jumps relative to gs or something along those
lines could make for interesting ROP tools. But someone will probably
figure out how to turn JIT output into a NOP slide + ROP gadget
regardless, at least on x86.
--Andy
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Andy Lutomirski @ 2014-08-13 21:38 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
Network Development, linux-kernel@vger.kernel.org
In-Reply-To: <CAMEtUuyFF3Qvd8BHkbEqkjGx+UEC8KcowUYyyuBW2J_NcGA96Q@mail.gmail.com>
On Wed, Aug 13, 2014 at 2:37 PM, Alexei Starovoitov <ast@plumgrid.com> wrote:
> I don't need an instruction that loads low 32-bit. It already exists.
> It's called 'mov'.
> I'm going to try encoding:
> insn[0].code = LD | IMM | DW
> insn[1].code = 0
> zero is invalid opcode, so it's your 'continuation'.
> and it is still single 16-byte instructions without any interpreter overhead.
Works for me.
--Andy
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Alexei Starovoitov @ 2014-08-13 21:38 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Andy Lutomirski, David S. Miller, Ingo Molnar, Linus Torvalds,
Steven Rostedt, Daniel Borkmann, Chema Gonzalez, Eric Dumazet,
Peter Zijlstra, Andrew Morton, Kees Cook, Linux API,
Network Development, linux-kernel@vger.kernel.org
In-Reply-To: <53EBD848.1060203@zytor.com>
On Wed, Aug 13, 2014 at 2:27 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 08/13/2014 02:23 PM, Andy Lutomirski wrote:
>> On Wed, Aug 13, 2014 at 2:21 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>>> One thing about this that may be a serious concern: allowing the user to
>>> control 8 contiguous bytes of kernel memory may be a security hazard.
>>
>> I'm confused. What kind of memory? I can control a lot more than 8
>> bytes of stack very easily.
>>
>> Or are you concerned about 8 contiguous bytes of *executable* memory?
>>
>
> Yes. Useful for some kinds of ROP custom gadgets.
I don't get it. What is ROP ?
What is the concern about 8 bytes ?
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Alexei Starovoitov @ 2014-08-13 21:37 UTC (permalink / raw)
To: Andy Lutomirski
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
Network Development,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CALCETrVDrbD3goYmZsUdmEhVfaNxovyghCz6y+_q5+G+rVwtWg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Wed, Aug 13, 2014 at 2:17 PM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
> On Wed, Aug 13, 2014 at 2:02 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
>> On Wed, Aug 13, 2014 at 11:35 AM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
>>>
>>> The compiler can still think of it as a single insn, though, but some
>>> future compiler might not.
>>
>> I think that would be very dangerous.
>> compiler (user space) and kernel interpreter must have the same
>> understanding of ISA.
>>
>>> In any case, I think that, if you use the
>>> same code for high and for low, you need logic in the JIT that's at
>>> least as complicated.
>>
>> why do you think so? Handling of pseudo BPF_LD_IMM64 is done
>> in single patch #11 which is one of the smallest...
>>
>>> For example, what happens if you have two
>>> consecutive 64-bit immediate loads to the same register? Now you have
>>> four consecutive 8-byte insn words that differ only in their immediate
>>> values, and you need to split them correctly.
>>
>> I don't need to do anything special in this case.
>> Two 16-byte instructions back to back is not a problem.
>> Interpreter or JIT don't care whether they move the same or different
>> immediates into the same or different register. Interpreter and JITs
>> are dumb on purpose.
>> when verifier sees two back to back ld_imm64, the 2nd will simply
>> override the value loaded by first one. It's not any different than
>> two back to back 'mov dst_reg, imm32' instructions.
>
> But this patch makes the JIT code (and any interpreter) weirdly
> stateful. You have:
>
> + case BPF_LD | BPF_IMM | BPF_DW:
> + /* movabsq %rax, imm64 */
> + EMIT2(add_1mod(0x48, dst_reg), add_1reg(0xB8, dst_reg));
> + EMIT(insn->imm, 4);
> + insn++;
> + i++;
> + EMIT(insn->imm, 4);
> + break;
>
> If you have more than two BPF_LD | BPF_IMM | BPF_DW instructions in a
> row, then the way in which they pair up depends on where you start.
For JIT it's not a problem, since it's doing a linear scan. So it always
starts at instruction boundary.
But thinking about it further you're right that it's a bug in verifier.
I've tried it and indeed depending on type of branch verifier doesn't
catch a case of two 16-byte instructions back to back and jump
goes into 2nd half of 1st insn. I need to fix that.
> I think it would be a lot clearer if you made these be "load low" and
> "load high", with JIT code like:
>
> + case BPF_LOAD_LOW:
> + /* movabsq %rax, imm64 */
> + if (next insn is BPF_LOAD_HIGH) {
such 'if' will be costly in interpreter. I want to avoid it.
> (and you'd have to deal with whether load low by itself is illegal,
> zero extends, sign extends, or preserves high bits).
I don't need an instruction that loads low 32-bit. It already exists.
It's called 'mov'.
I'm going to try encoding:
insn[0].code = LD | IMM | DW
insn[1].code = 0
zero is invalid opcode, so it's your 'continuation'.
and it is still single 16-byte instructions without any interpreter overhead.
> This has a nice benefit for future-proofing: it gives you 119 bits of
> payload for 16-byte instructions.
It's already future proofed. We can add 24 byte instructions and so on
just as well. There is no point to reserve 119 bits when no one is using
them.
> On the other hand, a u8 for the opcode is kind of small, and killing
> half of that space like this is probably bad. Maybe reserve two high
> bits, with:
That's an overkill. We use ~80 opcodes out of 256.
There is plenty of room. I see no reason to switch to 16-bit opcodes
until we get even close to half of u8 space.
It feels that we're starting to bikeshed.
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: H. Peter Anvin @ 2014-08-13 21:27 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Alexei Starovoitov, David S. Miller, Ingo Molnar, Linus Torvalds,
Steven Rostedt, Daniel Borkmann, Chema Gonzalez, Eric Dumazet,
Peter Zijlstra, Andrew Morton, Kees Cook, Linux API,
Network Development,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CALCETrUghSd-Z3+z_MUierWHQnA_dDOQcJ++EKryUeGTh5LbbA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 08/13/2014 02:23 PM, Andy Lutomirski wrote:
> On Wed, Aug 13, 2014 at 2:21 PM, H. Peter Anvin <hpa-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org> wrote:
>> One thing about this that may be a serious concern: allowing the user to
>> control 8 contiguous bytes of kernel memory may be a security hazard.
>
> I'm confused. What kind of memory? I can control a lot more than 8
> bytes of stack very easily.
>
> Or are you concerned about 8 contiguous bytes of *executable* memory?
>
Yes. Useful for some kinds of ROP custom gadgets.
-hpa
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Andy Lutomirski @ 2014-08-13 21:23 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Alexei Starovoitov, David S. Miller, Ingo Molnar, Linus Torvalds,
Steven Rostedt, Daniel Borkmann, Chema Gonzalez, Eric Dumazet,
Peter Zijlstra, Andrew Morton, Kees Cook, Linux API,
Network Development, linux-kernel@vger.kernel.org
In-Reply-To: <53EBD6D5.3050706@zytor.com>
On Wed, Aug 13, 2014 at 2:21 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> One thing about this that may be a serious concern: allowing the user to
> control 8 contiguous bytes of kernel memory may be a security hazard.
I'm confused. What kind of memory? I can control a lot more than 8
bytes of stack very easily.
Or are you concerned about 8 contiguous bytes of *executable* memory?
--Andy
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: H. Peter Anvin @ 2014-08-13 21:21 UTC (permalink / raw)
To: Andy Lutomirski, Alexei Starovoitov
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
Andrew Morton, Kees Cook, Linux API, Network Development,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CALCETrVDrbD3goYmZsUdmEhVfaNxovyghCz6y+_q5+G+rVwtWg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
One thing about this that may be a serious concern: allowing the user to
control 8 contiguous bytes of kernel memory may be a security hazard.
-hpa
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Andy Lutomirski @ 2014-08-13 21:17 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
Network Development, linux-kernel@vger.kernel.org
In-Reply-To: <CAMEtUuwx6Y4qxyz4TGK9=M2BH-dXnPsm+JrusqbyjzK20yUv6A@mail.gmail.com>
On Wed, Aug 13, 2014 at 2:02 PM, Alexei Starovoitov <ast@plumgrid.com> wrote:
> On Wed, Aug 13, 2014 at 11:35 AM, Andy Lutomirski <luto@amacapital.net> wrote:
>>
>> The compiler can still think of it as a single insn, though, but some
>> future compiler might not.
>
> I think that would be very dangerous.
> compiler (user space) and kernel interpreter must have the same
> understanding of ISA.
>
>> In any case, I think that, if you use the
>> same code for high and for low, you need logic in the JIT that's at
>> least as complicated.
>
> why do you think so? Handling of pseudo BPF_LD_IMM64 is done
> in single patch #11 which is one of the smallest...
>
>> For example, what happens if you have two
>> consecutive 64-bit immediate loads to the same register? Now you have
>> four consecutive 8-byte insn words that differ only in their immediate
>> values, and you need to split them correctly.
>
> I don't need to do anything special in this case.
> Two 16-byte instructions back to back is not a problem.
> Interpreter or JIT don't care whether they move the same or different
> immediates into the same or different register. Interpreter and JITs
> are dumb on purpose.
> when verifier sees two back to back ld_imm64, the 2nd will simply
> override the value loaded by first one. It's not any different than
> two back to back 'mov dst_reg, imm32' instructions.
But this patch makes the JIT code (and any interpreter) weirdly
stateful. You have:
+ case BPF_LD | BPF_IMM | BPF_DW:
+ /* movabsq %rax, imm64 */
+ EMIT2(add_1mod(0x48, dst_reg), add_1reg(0xB8, dst_reg));
+ EMIT(insn->imm, 4);
+ insn++;
+ i++;
+ EMIT(insn->imm, 4);
+ break;
If you have more than two BPF_LD | BPF_IMM | BPF_DW instructions in a
row, then the way in which they pair up depends on where you start.
I think it would be a lot clearer if you made these be "load low" and
"load high", with JIT code like:
+ case BPF_LOAD_LOW:
+ /* movabsq %rax, imm64 */
+ if (next insn is BPF_LOAD_HIGH) {
+ EMIT2(add_1mod(0x48, dst_reg),
add_1reg(0xB8, dst_reg));
+ EMIT(insn->imm, 4);
+ insn++;
+ i++;
+ EMIT(insn->imm, 4);
+ } else {
+ emit a real load low;
+ }
+ break;
(and you'd have to deal with whether load low by itself is illegal,
zero extends, sign extends, or preserves high bits).
Alternatively, and possibly better, you could have a real encoding for
multiword instructions. Reserve a bit in the opcode to mark a
continuation of the previous instruction, and do:
+ case BPF_LD | BPF_IMM | BPF_DW:
+ assert(insn[1] in bounds && insn[1].code == BPF_CONT);
+ /* movabsq %rax, imm64 */
+ EMIT2(add_1mod(0x48, dst_reg), add_1reg(0xB8, dst_reg));
+ EMIT(insn->imm, 4);
+ insn++;
+ i++;
+ EMIT(insn->imm, 4);
+ break;
This has a nice benefit for future-proofing: it gives you 119 bits of
payload for 16-byte instructions.
On the other hand, a u8 for the opcode is kind of small, and killing
half of that space like this is probably bad. Maybe reserve two high
bits, with:
0: normal opcode or start of a multiword sequence
1: continuation of a multiword sequence
2, 3: reserved for future longer opcode numbers (e.g. 2 could indicate
that "code" is actually 16 bits)
--Andy
--
Andy Lutomirski
AMA Capital Management, LLC
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: H. Peter Anvin @ 2014-08-13 21:16 UTC (permalink / raw)
To: Alexei Starovoitov, Andy Lutomirski
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
Andrew Morton, Kees Cook, Linux API, Network Development,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAMEtUuwx6Y4qxyz4TGK9=M2BH-dXnPsm+JrusqbyjzK20yUv6A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 08/13/2014 02:02 PM, Alexei Starovoitov wrote:
> On Wed, Aug 13, 2014 at 11:35 AM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
>>
>> The compiler can still think of it as a single insn, though, but some
>> future compiler might not.
>
> I think that would be very dangerous.
> compiler (user space) and kernel interpreter must have the same
> understanding of ISA.
>
Only at the point of the interface layer. The compiler can treat it as
a single instruction internally, the JIT can do peephole optimization,
but as long as the instruction stream at the boundary matches the
official ISA spec everything is fine.
-hpa
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Alexei Starovoitov @ 2014-08-13 21:02 UTC (permalink / raw)
To: Andy Lutomirski
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
Network Development, linux-kernel@vger.kernel.org
In-Reply-To: <CALCETrXfp+7FmEzAoLiqzqY73NBzt8JsD40hzvhT3=gr-Scp=g@mail.gmail.com>
On Wed, Aug 13, 2014 at 11:35 AM, Andy Lutomirski <luto@amacapital.net> wrote:
>
> The compiler can still think of it as a single insn, though, but some
> future compiler might not.
I think that would be very dangerous.
compiler (user space) and kernel interpreter must have the same
understanding of ISA.
> In any case, I think that, if you use the
> same code for high and for low, you need logic in the JIT that's at
> least as complicated.
why do you think so? Handling of pseudo BPF_LD_IMM64 is done
in single patch #11 which is one of the smallest...
> For example, what happens if you have two
> consecutive 64-bit immediate loads to the same register? Now you have
> four consecutive 8-byte insn words that differ only in their immediate
> values, and you need to split them correctly.
I don't need to do anything special in this case.
Two 16-byte instructions back to back is not a problem.
Interpreter or JIT don't care whether they move the same or different
immediates into the same or different register. Interpreter and JITs
are dumb on purpose.
when verifier sees two back to back ld_imm64, the 2nd will simply
override the value loaded by first one. It's not any different than
two back to back 'mov dst_reg, imm32' instructions.
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Andy Lutomirski @ 2014-08-13 18:35 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
Network Development, linux-kernel@vger.kernel.org
In-Reply-To: <CAMEtUuxog0w-XkYMHM=Zto_gejy8x5agxohAWOs1zPEtXTr0Sw@mail.gmail.com>
On Wed, Aug 13, 2014 at 10:44 AM, Alexei Starovoitov <ast@plumgrid.com> wrote:
> On Wed, Aug 13, 2014 at 9:08 AM, Andy Lutomirski <luto@amacapital.net> wrote:
>> On Wed, Aug 13, 2014 at 12:57 AM, Alexei Starovoitov <ast@plumgrid.com> wrote:
>>> add BPF_LD_IMM64 instruction to load 64-bit immediate value into register.
>>> All previous instructions were 8-byte. This is first 16-byte instruction.
>>> Two consecutive 'struct bpf_insn' blocks are interpreted as single instruction:
>>> insn[0/1].code = BPF_LD | BPF_DW | BPF_IMM
>>> insn[0/1].dst_reg = destination register
>>> insn[0].imm = lower 32-bit
>>> insn[1].imm = upper 32-bit
>>
>> This might be unnecessarily difficult for fancy static analysis tools
>> to reason about. Would it make sense to assign two different codes
>> for this? For example, insn[0].code = code_for_load_low,
>> insns[1].code = code_for_load_high, along with a verifier check that
>> they come in matched pairs and that code_for_load_high isn't a jump
>> target?
>
> see my reply to David for the same thing. Short answer is that
> sequence of instructions (even if it is a pair of instructions like this)
> is very hard to detect in verifier and JITs.
> As soon as we give compiler two instructions instead of one,
> compiler may optimize them in a fancy ways. Like two loads of
> 64-bit immediate with upper 32-bit the same, may came out as
> 4 instructions: load_high, load_low, load_low, mov.
> Or in some cases as single load_low, etc.
> load 64-bit imm has to stay as single instruction to be verifiable
> and patch-able easily.
> One can argue: force compiler to emit load_low and load_hi
> always together, but then that's exactly what I have. It's a single insn.
The compiler can still think of it as a single insn, though, but some
future compiler might not. In any case, I think that, if you use the
same code for high and for low, you need logic in the JIT that's at
least as complicated. For example, what happens if you have two
consecutive 64-bit immediate loads to the same register? Now you have
four consecutive 8-byte insn words that differ only in their immediate
values, and you need to split them correctly.
>
>> (Something else that I find confusing about eBPF: the instruction
>> mnemonics are very strange. Have you considered giving them real
>> names? For example, load.imm.low instead of BPF_LD | BPF_DW | BPF_IMM
>> is easier to read and pronounce.)
>
> BPF_LD | BPF_DW | BPF_IMM is not really a name. It's macro
> for cases when instructions are generated from inside the kernel.
> Instructions mnemonics are not defined yet.
> llvm emits assembler code like:
> bpf_prog2:
> ldw r1, 16(r1)
> std -8(r10), r1
> mov r1, 1
> std -16(r10), r1
> ld_64 r1, 1
> mov r2, r10
> addi r2, -8
> call 4
> jeqi r0, 0 goto .LBB1_2
> ldd r1, 0(r0)
> addi r1, 1
> std 0(r0), r1
> .LBB1_3:
> mov r0, 0
> ret
> ...
> I'm open to change assembler/disassembler mnemonics.
Ah, ok. I didn't realize that there were mnemonics at all.
--Andy
--
Andy Lutomirski
AMA Capital Management, LLC
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 00/26] BPF syscall, maps, verifier, samples, llvm
From: Alexei Starovoitov @ 2014-08-13 18:00 UTC (permalink / raw)
To: Andy Lutomirski
Cc: David Laight, David S. Miller, Ingo Molnar, Linus Torvalds,
Steven Rostedt, Daniel Borkmann, Chema Gonzalez, Eric Dumazet,
Peter Zijlstra, H. Peter Anvin, Andrew Morton, Kees Cook,
linux-api@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <CALCETrVDJHOu7AFZqeGppxXykRhdG8qwwifpXcXVVr=argwoiQ@mail.gmail.com>
On Wed, Aug 13, 2014 at 10:40 AM, Andy Lutomirski <luto@amacapital.net> wrote:
>
> But don't you need some kind of detection anyway to handle the case
> where something jumps to the middle of the "load 64-bit immediate"? I
added few test cases to test_verifier to see that this case is caught
and it looks ok, but you got me worried. May be few more checks needed.
Thanks!
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Alexei Starovoitov @ 2014-08-13 17:44 UTC (permalink / raw)
To: Andy Lutomirski
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
Network Development,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CALCETrXzZVxMGUgDPOKwN0DPLvupU=ew1z6D4U-jHg+RoyZyLg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Wed, Aug 13, 2014 at 9:08 AM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
> On Wed, Aug 13, 2014 at 12:57 AM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
>> add BPF_LD_IMM64 instruction to load 64-bit immediate value into register.
>> All previous instructions were 8-byte. This is first 16-byte instruction.
>> Two consecutive 'struct bpf_insn' blocks are interpreted as single instruction:
>> insn[0/1].code = BPF_LD | BPF_DW | BPF_IMM
>> insn[0/1].dst_reg = destination register
>> insn[0].imm = lower 32-bit
>> insn[1].imm = upper 32-bit
>
> This might be unnecessarily difficult for fancy static analysis tools
> to reason about. Would it make sense to assign two different codes
> for this? For example, insn[0].code = code_for_load_low,
> insns[1].code = code_for_load_high, along with a verifier check that
> they come in matched pairs and that code_for_load_high isn't a jump
> target?
see my reply to David for the same thing. Short answer is that
sequence of instructions (even if it is a pair of instructions like this)
is very hard to detect in verifier and JITs.
As soon as we give compiler two instructions instead of one,
compiler may optimize them in a fancy ways. Like two loads of
64-bit immediate with upper 32-bit the same, may came out as
4 instructions: load_high, load_low, load_low, mov.
Or in some cases as single load_low, etc.
load 64-bit imm has to stay as single instruction to be verifiable
and patch-able easily.
One can argue: force compiler to emit load_low and load_hi
always together, but then that's exactly what I have. It's a single insn.
> (Something else that I find confusing about eBPF: the instruction
> mnemonics are very strange. Have you considered giving them real
> names? For example, load.imm.low instead of BPF_LD | BPF_DW | BPF_IMM
> is easier to read and pronounce.)
BPF_LD | BPF_DW | BPF_IMM is not really a name. It's macro
for cases when instructions are generated from inside the kernel.
Instructions mnemonics are not defined yet.
llvm emits assembler code like:
bpf_prog2:
ldw r1, 16(r1)
std -8(r10), r1
mov r1, 1
std -16(r10), r1
ld_64 r1, 1
mov r2, r10
addi r2, -8
call 4
jeqi r0, 0 goto .LBB1_2
ldd r1, 0(r0)
addi r1, 1
std 0(r0), r1
.LBB1_3:
mov r0, 0
ret
...
I'm open to change assembler/disassembler mnemonics.
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 00/26] BPF syscall, maps, verifier, samples, llvm
From: Andy Lutomirski @ 2014-08-13 17:40 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: David Laight, David S. Miller, Ingo Molnar, Linus Torvalds,
Steven Rostedt, Daniel Borkmann, Chema Gonzalez, Eric Dumazet,
Peter Zijlstra, H. Peter Anvin, Andrew Morton, Kees Cook,
linux-api@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <CAMEtUuyULyzVb1nkJn_Tj_aKjokcBQaw_EnWBdDvtvf9iV7uXA@mail.gmail.com>
On Wed, Aug 13, 2014 at 10:30 AM, Alexei Starovoitov <ast@plumgrid.com> wrote:
> On Wed, Aug 13, 2014 at 1:52 AM, David Laight <David.Laight@aculab.com> wrote:
>> From: Of Alexei Starovoitov
>>> one more RFC...
>>>
>>> Major difference vs previous set is a new 'load 64-bit immediate' eBPF insn.
>>> Which is first 16-byte instruction. It shows how eBPF ISA can be extended
>>> while maintaining backward compatibility, but mainly it cleans up eBPF
>>> program access to maps and improves run-time performance.
>>
>> Wouldn't it be more sensible to follow the scheme used by a lot of cpus
>> and add a 'load high' instruction (follow with 'add' or 'or').
>
> that was what I used before in pred_tree_walker->ebpf patch
> (4 existing instructions (2 movs, shift, or) to load 'pred' pointer)
> It's slower in interpreter than single instruction.
>
>> It still takes 16 bytes to load a 64bit immediate value, but the instruction
>> size remains constant.
>
> size of instruction is not important. 99% of instructions are 8 byte long
> and one is 16 byte. Big deal. It doesn't affect interpreter performance,
> easy for verifier and was straightforward to do in LLVM as well.
>
>> There is nothing to stop any JIT software detecting the instruction pair.
>
> well, it's actually very complicated to detect a sequence of
> instructions that compute single 64-bit value.
> Patch #11 detects and patches pseudo BPF_LD_IMM64 in
> a single 'for' loop (see replace_map_fd_with_map_ptr), because
> it's _single_ instruction. Any sequence of insns would require
> building control and data flow graphs for verifier and JIT.
> If you remember I resisted initially when Chema proposed
> 'load 64-bit immediate' equivalent, since back then the use cases
> didn't require it. With maps done via FDs, the need has arisen.
But don't you need some kind of detection anyway to handle the case
where something jumps to the middle of the "load 64-bit immediate"? I
think it would be fine to require a particular sequence to load 64-bit
immediates if you want the JIT to optimize it well, though.
--Andy
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Daniel Borkmann @ 2014-08-13 17:39 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Andy Lutomirski,
Steven Rostedt, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
Network Development, LKML
In-Reply-To: <CAMEtUuzo6xQkhg+y0h_WEArVZi9cxVoGAcTBDcwMXza+eQGBTw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 08/13/2014 07:34 PM, Alexei Starovoitov wrote:
> On Wed, Aug 13, 2014 at 2:17 AM, Daniel Borkmann <dborkman-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
>> On 08/13/2014 09:57 AM, Alexei Starovoitov wrote:
>>>
>>> add BPF_LD_IMM64 instruction to load 64-bit immediate value into register.
>>> All previous instructions were 8-byte. This is first 16-byte instruction.
>>> Two consecutive 'struct bpf_insn' blocks are interpreted as single
>>> instruction:
>>> insn[0/1].code = BPF_LD | BPF_DW | BPF_IMM
>>> insn[0/1].dst_reg = destination register
>>> insn[0].imm = lower 32-bit
>>> insn[1].imm = upper 32-bit
>>>
>>> Classic BPF has similar instruction: BPF_LD | BPF_W | BPF_IMM
>>> which loads 32-bit immediate value into a register.
>>>
>>> x64 JITs it as single 'movabsq %rax, imm64'
>>> arm64 may JIT as sequence of four 'movk x0, #imm16, lsl #shift' insn
>>>
>>> Note that old eBPF programs are binary compatible with new interpreter.
>>>
>>> Signed-off-by: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
>>
>>
>> For follow-ups on this series, can you put the actual motivation
>> for this change from the cover letter into this commit log as it
>> otherwise doesn't say anything clearly why it is needed. Code and
>> test case looks good to me.
>
> ok. As you saw the full explanation is long, so I opted for 'it_does_this'
> commit log. In the next rev will add more reasons to this log. Sure.
Great, thanks.
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Alexei Starovoitov @ 2014-08-13 17:34 UTC (permalink / raw)
To: Daniel Borkmann
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Andy Lutomirski,
Steven Rostedt, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
Network Development, LKML
In-Reply-To: <53EB2D31.8090204-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
On Wed, Aug 13, 2014 at 2:17 AM, Daniel Borkmann <dborkman-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> On 08/13/2014 09:57 AM, Alexei Starovoitov wrote:
>>
>> add BPF_LD_IMM64 instruction to load 64-bit immediate value into register.
>> All previous instructions were 8-byte. This is first 16-byte instruction.
>> Two consecutive 'struct bpf_insn' blocks are interpreted as single
>> instruction:
>> insn[0/1].code = BPF_LD | BPF_DW | BPF_IMM
>> insn[0/1].dst_reg = destination register
>> insn[0].imm = lower 32-bit
>> insn[1].imm = upper 32-bit
>>
>> Classic BPF has similar instruction: BPF_LD | BPF_W | BPF_IMM
>> which loads 32-bit immediate value into a register.
>>
>> x64 JITs it as single 'movabsq %rax, imm64'
>> arm64 may JIT as sequence of four 'movk x0, #imm16, lsl #shift' insn
>>
>> Note that old eBPF programs are binary compatible with new interpreter.
>>
>> Signed-off-by: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
>
>
> For follow-ups on this series, can you put the actual motivation
> for this change from the cover letter into this commit log as it
> otherwise doesn't say anything clearly why it is needed. Code and
> test case looks good to me.
ok. As you saw the full explanation is long, so I opted for 'it_does_this'
commit log. In the next rev will add more reasons to this log. Sure.
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 00/26] BPF syscall, maps, verifier, samples, llvm
From: Alexei Starovoitov @ 2014-08-13 17:30 UTC (permalink / raw)
To: David Laight
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Andy Lutomirski,
Steven Rostedt, Daniel Borkmann, Chema Gonzalez, Eric Dumazet,
Peter Zijlstra, H. Peter Anvin, Andrew Morton, Kees Cook,
linux-api@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <063D6719AE5E284EB5DD2968C1650D6D174760F3@AcuExch.aculab.com>
On Wed, Aug 13, 2014 at 1:52 AM, David Laight <David.Laight@aculab.com> wrote:
> From: Of Alexei Starovoitov
>> one more RFC...
>>
>> Major difference vs previous set is a new 'load 64-bit immediate' eBPF insn.
>> Which is first 16-byte instruction. It shows how eBPF ISA can be extended
>> while maintaining backward compatibility, but mainly it cleans up eBPF
>> program access to maps and improves run-time performance.
>
> Wouldn't it be more sensible to follow the scheme used by a lot of cpus
> and add a 'load high' instruction (follow with 'add' or 'or').
that was what I used before in pred_tree_walker->ebpf patch
(4 existing instructions (2 movs, shift, or) to load 'pred' pointer)
It's slower in interpreter than single instruction.
> It still takes 16 bytes to load a 64bit immediate value, but the instruction
> size remains constant.
size of instruction is not important. 99% of instructions are 8 byte long
and one is 16 byte. Big deal. It doesn't affect interpreter performance,
easy for verifier and was straightforward to do in LLVM as well.
> There is nothing to stop any JIT software detecting the instruction pair.
well, it's actually very complicated to detect a sequence of
instructions that compute single 64-bit value.
Patch #11 detects and patches pseudo BPF_LD_IMM64 in
a single 'for' loop (see replace_map_fd_with_map_ptr), because
it's _single_ instruction. Any sequence of insns would require
building control and data flow graphs for verifier and JIT.
If you remember I resisted initially when Chema proposed
'load 64-bit immediate' equivalent, since back then the use cases
didn't require it. With maps done via FDs, the need has arisen.
^ permalink raw reply
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Andy Lutomirski @ 2014-08-13 16:08 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
Network Development, linux-kernel@vger.kernel.org
In-Reply-To: <1407916658-8731-2-git-send-email-ast@plumgrid.com>
On Wed, Aug 13, 2014 at 12:57 AM, Alexei Starovoitov <ast@plumgrid.com> wrote:
> add BPF_LD_IMM64 instruction to load 64-bit immediate value into register.
> All previous instructions were 8-byte. This is first 16-byte instruction.
> Two consecutive 'struct bpf_insn' blocks are interpreted as single instruction:
> insn[0/1].code = BPF_LD | BPF_DW | BPF_IMM
> insn[0/1].dst_reg = destination register
> insn[0].imm = lower 32-bit
> insn[1].imm = upper 32-bit
This might be unnecessarily difficult for fancy static analysis tools
to reason about. Would it make sense to assign two different codes
for this? For example, insn[0].code = code_for_load_low,
insns[1].code = code_for_load_high, along with a verifier check that
they come in matched pairs and that code_for_load_high isn't a jump
target?
(Something else that I find confusing about eBPF: the instruction
mnemonics are very strange. Have you considered giving them real
names? For example, load.imm.low instead of BPF_LD | BPF_DW | BPF_IMM
is easier to read and pronounce.)
--Andy
^ permalink raw reply
* Re: 2038 Kernel Summit Discussion Fodder
From: Joseph S. Myers @ 2014-08-13 15:37 UTC (permalink / raw)
To: John Stultz
Cc: ksummit-discuss, lkml, Thomas Gleixner, Arnd Bergmann,
H. Peter Anvin, linux-api
In-Reply-To: <CALAqxLUcfaJnxdmkn6mucepNk3QaCQdcSPLRjjeKsk_OTp=uLA@mail.gmail.com>
On Wed, 13 Aug 2014, John Stultz wrote:
> 2) Userspace ABI modifications: This includes how we expose the new
> 64bit time_t and related structures to userland via syscalls and ioctls,
Note the point from previous discussions that whenever the kernel takes a
64-bit timespec value from 32-bit userspace (which should include x32),
the upper 32 bits of the nanoseconds value should be ignored for POSIX
compatibility (but maximum compatibility with existing x32 userspace means
you should still write those bits as 0 when writing such a value out to
userspace).
> Basically this is the same as the above, where the kernel provides both
> legacy and new time_t related interfaces. However, the libc would make a
> version break, migrating to using 64bit time_t types and syscalls. Legacy
> applications would still work using the old glibc version, but this would
> provide a stronger line in the sand between 2038 safe and unsafe
> applications and libraries, making it easier to avoid mixing the two.
> NetBSD developers discussed this same approach back in 2008 here:
> https://mail-index.netbsd.org/tech-userlevel/2008/03/22/msg000231.html
Given discussions lately of how it's no longer feasible to change the
libstdc++ soname for C++11 issues
<https://gcc.gnu.org/ml/gcc/2014-08/msg00107.html> - libstdc++ needs to
include both old and new ABI versions of all relevant interfaces - I think
we can assume the same is true to a much greater extent for the libc
soname (at least on i386). Much the same conclusion was also reached
regarding the libc soname on S/390 in discussions of jmp_buf issues.
Technically of course you can have a port variant which does have a
different soname - and a different GNU triplet - like the transition from
arm-*-linux-gnu old-ABI to arm-*-linux-gnueabi EABI. (And in principle
distributions can allow in-place upgrades - after all, it was done for the
move from libc5 to libc6.) But I don't see any likelihood that's what the
community of users and distributors on i386 would actually want.
Properly done, moving to _TIME_BITS=64 in a distribution would involve
changing the sonames of lots of affected other libraries (while keeping
compatibility versions under the old sonames to support existing binaries
users may have), and it's an open question whether distributors would wish
to do that either - or whether you get server / desktop distributions
phasing out 32-bit support by 2038, while only embedded users, with
control over everything being built for the device and less likelihood of
having to deal with old binaries from ISVs, build the whole system with a
_TIME_BITS=64 default.
> 32bit applications on 64bit kernels. In this case, we wouldn't introduce
> new 64 bit syscalls in the kernel, as the existing interfaces would just be
> typed correctly for our new virtual architecture, but we would have
The installed uapi headers would of course need conditionals in them
(based on whatever preprocessor macro is defined in userspace for the new
virtual architecture) to export the right ABI for each case.
--
Joseph S. Myers
joseph@codesourcery.com
^ permalink raw reply
* [PATCH 1/4] VFIO: PLATFORM: Add device tree info API and skeleton
From: Antonios Motakis @ 2014-08-13 11:02 UTC (permalink / raw)
To: alex.williamson-H+wXaHxf7aLQT0dZR+AlfA,
kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: tech-lrHrjnjw1UfHK3s98zE1ajGjJy/sRE9J,
a.rigo-lrHrjnjw1UfHK3s98zE1ajGjJy/sRE9J,
kvm-u79uwXL29TY76Z2rM5mHXA,
christoffer.dall-QSEj5FYQhm4dnm+yROfE0A, will.deacon-5wv7dgnIgG8,
kim.phillips-KZfg59tc24xl57MIdRCFDg,
stuart.yoder-KZfg59tc24xl57MIdRCFDg,
eric.auger-QSEj5FYQhm4dnm+yROfE0A, marc.zyngier-5wv7dgnIgG8,
Antonios Motakis, Catalin Marinas, Mark Rutland, Vladimir Murzin,
Rob Herring, Ashwin Chaugule, open list, open list:ABI/API
In-Reply-To: <1407927740-14993-1-git-send-email-a.motakis-lrHrjnjw1UfHK3s98zE1ajGjJy/sRE9J@public.gmane.org>
This patch introduced the API to return device tree info about
a PLATFORM device (if described by a device tree) and the skeleton
of the implementation for VFIO_PLATFORM. Information about any device
node bound by VFIO_PLATFORM should be queried via the introduced ioctl
VFIO_DEVICE_GET_DEVTREE_INFO.
Signed-off-by: Antonios Motakis <a.motakis-lrHrjnjw1UfHK3s98zE1ajGjJy/sRE9J@public.gmane.org>
---
drivers/vfio/platform/Makefile | 2 +-
drivers/vfio/platform/devtree.c | 27 ++++++++++++++++++++++
drivers/vfio/platform/vfio_platform.c | 11 +++++++++
drivers/vfio/platform/vfio_platform_private.h | 7 ++++++
include/uapi/linux/vfio.h | 32 ++++++++++++++++++++++++---
5 files changed, 75 insertions(+), 4 deletions(-)
create mode 100644 drivers/vfio/platform/devtree.c
diff --git a/drivers/vfio/platform/Makefile b/drivers/vfio/platform/Makefile
index 2c53327..4313fd7 100644
--- a/drivers/vfio/platform/Makefile
+++ b/drivers/vfio/platform/Makefile
@@ -1,4 +1,4 @@
-vfio-platform-y := vfio_platform.o vfio_platform_irq.o
+vfio-platform-y := vfio_platform.o vfio_platform_irq.o devtree.o
obj-$(CONFIG_VFIO_PLATFORM) += vfio-platform.o
diff --git a/drivers/vfio/platform/devtree.c b/drivers/vfio/platform/devtree.c
new file mode 100644
index 0000000..91cab88
--- /dev/null
+++ b/drivers/vfio/platform/devtree.c
@@ -0,0 +1,27 @@
+#include <linux/slab.h>
+#include <linux/vfio.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include "vfio_platform_private.h"
+
+void vfio_platform_devtree_get(struct vfio_platform_device *vdev)
+{
+ vdev->of_node = of_node_get(vdev->pdev->dev.of_node);
+}
+
+void vfio_platform_devtree_put(struct vfio_platform_device *vdev)
+{
+ of_node_put(vdev->of_node);
+ vdev->of_node = NULL;
+}
+
+bool vfio_platform_has_devtree(struct vfio_platform_device *vdev)
+{
+ return !!vdev->of_node;
+}
+
+long vfio_platform_devtree_ioctl(struct vfio_platform_device *vdev,
+ unsigned long arg)
+{
+ return -EINVAL; /* not implemented yet */
+}
diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c
index f4c06c6..e6fe05a 100644
--- a/drivers/vfio/platform/vfio_platform.c
+++ b/drivers/vfio/platform/vfio_platform.c
@@ -26,6 +26,7 @@
#include <linux/vfio.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <linux/irq.h>
#include "vfio_platform_private.h"
@@ -66,6 +67,9 @@ static int vfio_platform_regions_init(struct vfio_platform_device *vdev)
vdev->num_regions = cnt;
+ /* get device tree node for info if available */
+ vfio_platform_devtree_get(vdev);
+
return 0;
err:
kfree(vdev->region);
@@ -74,6 +78,7 @@ err:
static void vfio_platform_regions_cleanup(struct vfio_platform_device *vdev)
{
+ vfio_platform_devtree_put(vdev);
vdev->num_regions = 0;
kfree(vdev->region);
}
@@ -132,6 +137,9 @@ static long vfio_platform_ioctl(void *device_data,
return -EINVAL;
info.flags = VFIO_DEVICE_FLAGS_PLATFORM;
+ if (vfio_platform_has_devtree(vdev))
+ info.flags |= VFIO_DEVICE_FLAGS_DEVTREE;
+
info.num_regions = vdev->num_regions;
info.num_irqs = vdev->num_irqs;
@@ -210,6 +218,9 @@ static long vfio_platform_ioctl(void *device_data,
return ret;
+ } else if (cmd == VFIO_DEVICE_GET_DEVTREE_INFO) {
+ return vfio_platform_devtree_ioctl(vdev, arg);
+
} else if (cmd == VFIO_DEVICE_RESET)
return -EINVAL;
diff --git a/drivers/vfio/platform/vfio_platform_private.h b/drivers/vfio/platform/vfio_platform_private.h
index 86a9201..1c42ba0 100644
--- a/drivers/vfio/platform/vfio_platform_private.h
+++ b/drivers/vfio/platform/vfio_platform_private.h
@@ -49,6 +49,7 @@ struct vfio_platform_device {
u32 num_regions;
struct vfio_platform_irq *irq;
u32 num_irqs;
+ struct device_node *of_node;
};
extern int vfio_platform_irq_init(struct vfio_platform_device *vdev);
@@ -59,4 +60,10 @@ extern int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
uint32_t flags, unsigned index, unsigned start,
unsigned count, void *data);
+/* device tree info support in devtree.c */
+extern void vfio_platform_devtree_get(struct vfio_platform_device *vdev);
+extern void vfio_platform_devtree_put(struct vfio_platform_device *vdev);
+extern bool vfio_platform_has_devtree(struct vfio_platform_device *vdev);
+extern long vfio_platform_devtree_ioctl(struct vfio_platform_device *vdev,
+ unsigned long arg);
#endif /* VFIO_PLATFORM_PRIVATE_H */
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index d381107..60f66ec 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -153,15 +153,41 @@ struct vfio_group_status {
struct vfio_device_info {
__u32 argsz;
__u32 flags;
-#define VFIO_DEVICE_FLAGS_RESET (1 << 0) /* Device supports reset */
-#define VFIO_DEVICE_FLAGS_PCI (1 << 1) /* vfio-pci device */
-#define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2) /* vfio-platform device */
+#define VFIO_DEVICE_FLAGS_RESET (1 << 0) /* Device supports reset */
+#define VFIO_DEVICE_FLAGS_PCI (1 << 1) /* vfio-pci device */
+#define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2) /* vfio-platform device */
+#define VFIO_DEVICE_FLAGS_DEVTREE (1 << 3) /* device tree metadata */
__u32 num_regions; /* Max region index + 1 */
__u32 num_irqs; /* Max IRQ index + 1 */
};
#define VFIO_DEVICE_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 7)
/**
+ * VFIO_DEVICE_GET_DEVTREE_INFO - _IOR(VFIO_TYPE, VFIO_BASE + 16,
+ * struct vfio_devtree_info)
+ *
+ * Retrieve information from the device's device tree, if available.
+ * Caller will initialize data[] with a single string with the requested
+ * devicetree property name, and type depending on whether a array of strings
+ * or an array of u32 values is expected. On success, data[] will be extended
+ * with the requested information, either as an array of u32, or with a list
+ * of strings sepparated by the NULL terminating character.
+ * Return: 0 on success, -errno on failure.
+ */
+struct vfio_devtree_info {
+ __u32 argsz;
+ __u32 type;
+#define VFIO_DEVTREE_PROP_NAMES 0
+#define VFIO_DEVTREE_ARR_TYPE_STRING 1
+#define VFIO_DEVTREE_ARR_TYPE_U8 2
+#define VFIO_DEVTREE_ARR_TYPE_U16 3
+#define VFIO_DEVTREE_ARR_TYPE_U32 4
+ __u32 length;
+ __u8 data[];
+};
+#define VFIO_DEVICE_GET_DEVTREE_INFO _IO(VFIO_TYPE, VFIO_BASE + 17)
+
+/**
* VFIO_DEVICE_GET_REGION_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 8,
* struct vfio_region_info)
*
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Daniel Borkmann @ 2014-08-13 9:17 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Andy Lutomirski,
Steven Rostedt, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook,
linux-api-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1407916658-8731-2-git-send-email-ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
On 08/13/2014 09:57 AM, Alexei Starovoitov wrote:
> add BPF_LD_IMM64 instruction to load 64-bit immediate value into register.
> All previous instructions were 8-byte. This is first 16-byte instruction.
> Two consecutive 'struct bpf_insn' blocks are interpreted as single instruction:
> insn[0/1].code = BPF_LD | BPF_DW | BPF_IMM
> insn[0/1].dst_reg = destination register
> insn[0].imm = lower 32-bit
> insn[1].imm = upper 32-bit
>
> Classic BPF has similar instruction: BPF_LD | BPF_W | BPF_IMM
> which loads 32-bit immediate value into a register.
>
> x64 JITs it as single 'movabsq %rax, imm64'
> arm64 may JIT as sequence of four 'movk x0, #imm16, lsl #shift' insn
>
> Note that old eBPF programs are binary compatible with new interpreter.
>
> Signed-off-by: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
For follow-ups on this series, can you put the actual motivation
for this change from the cover letter into this commit log as it
otherwise doesn't say anything clearly why it is needed. Code and
test case looks good to me.
^ permalink raw reply
* RE: [PATCH RFC v4 net-next 00/26] BPF syscall, maps, verifier, samples, llvm
From: David Laight @ 2014-08-13 8:52 UTC (permalink / raw)
To: 'Alexei Starovoitov', David S. Miller
Cc: Ingo Molnar, Linus Torvalds, Andy Lutomirski, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook,
linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1407916658-8731-1-git-send-email-ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
From: Of Alexei Starovoitov
> one more RFC...
>
> Major difference vs previous set is a new 'load 64-bit immediate' eBPF insn.
> Which is first 16-byte instruction. It shows how eBPF ISA can be extended
> while maintaining backward compatibility, but mainly it cleans up eBPF
> program access to maps and improves run-time performance.
Wouldn't it be more sensible to follow the scheme used by a lot of cpus
and add a 'load high' instruction (follow with 'add' or 'or').
It still takes 16 bytes to load a 64bit immediate value, but the instruction
size remains constant.
There is nothing to stop any JIT software detecting the instruction pair.
David
^ permalink raw reply
* [PATCH RFC v4 net-next 26/26] bpf: verifier test
From: Alexei Starovoitov @ 2014-08-13 7:57 UTC (permalink / raw)
To: David S. Miller
Cc: Ingo Molnar, Linus Torvalds, Andy Lutomirski, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
H. Peter Anvin, Andrew Morton, Kees Cook, linux-api, netdev,
linux-kernel
In-Reply-To: <1407916658-8731-1-git-send-email-ast@plumgrid.com>
simple verifier test from user space. Tests valid and invalid programs
and expects predefined error log messages from kernel
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---
samples/bpf/Makefile | 3 +-
samples/bpf/test_verifier.c | 354 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 356 insertions(+), 1 deletion(-)
create mode 100644 samples/bpf/test_verifier.c
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index b865a5df5c60..e39cb4f13be9 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -2,12 +2,13 @@
obj- := dummy.o
# List of programs to build
-hostprogs-y := sock_example dropmon ex1 ex2
+hostprogs-y := sock_example dropmon ex1 ex2 test_verifier
sock_example-objs := sock_example.o libbpf.o
dropmon-objs := dropmon.o libbpf.o
ex1-objs := bpf_load.o libbpf.o ex1_user.o
ex2-objs := bpf_load.o libbpf.o ex2_user.o
+test_verifier-objs := test_verifier.o libbpf.o
# Tell kbuild to always build the programs
always := $(hostprogs-y) ex1_kern.o ex2_kern.o
diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c
new file mode 100644
index 000000000000..46cef16425e4
--- /dev/null
+++ b/samples/bpf/test_verifier.c
@@ -0,0 +1,354 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <linux/bpf.h>
+#include <errno.h>
+#include <linux/unistd.h>
+#include <string.h>
+#include <linux/filter.h>
+#include "libbpf.h"
+
+#define MAX_INSNS 512
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
+struct bpf_test {
+ const char *descr;
+ struct bpf_insn insns[MAX_INSNS];
+ int fixup[32];
+ const char *errstr;
+ enum {
+ ACCEPT,
+ REJECT
+ } result;
+};
+
+static struct bpf_test tests[] = {
+ {
+ "add+sub+mul",
+ .insns = {
+ BPF_ALU64_IMM(BPF_MOV, BPF_REG_1, 1),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 2),
+ BPF_ALU64_IMM(BPF_MOV, BPF_REG_2, 3),
+ BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_2),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -1),
+ BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, 3),
+ BPF_ALU64_REG(BPF_MOV, BPF_REG_0, BPF_REG_1),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ },
+ {
+ "dropmon",
+ .insns = {
+ BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), /* r2 = *(u64 *)(r1 + 8) */
+ BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -8), /* *(u64 *)(fp - 8) = r2 */
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = fp - 8 */
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+ BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */
+ BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
+ BPF_EXIT_INSN(),
+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 1), /* *(u64 *)(fp - 16) = 1 */
+ BPF_MOV64_REG(BPF_REG_3, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -16), /* r3 = fp - 16 */
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = fp - 8 */
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_update_elem),
+ BPF_EXIT_INSN(),
+ },
+ .fixup = {4, 16},
+ .result = ACCEPT,
+ },
+ {
+ "dropmon2",
+ .insns = {
+ BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), /* r2 = *(u64 *)(r1 + 8) */
+ BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -8), /* *(u64 *)(fp - 8) = r2 */
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = fp - 8 */
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+ BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */
+ BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
+ BPF_EXIT_INSN(),
+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 1), /* *(u64 *)(fp - 16) = 1 */
+ BPF_MOV64_REG(BPF_REG_3, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -16), /* r3 = fp - 16 */
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = fp - 8 */
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_update_elem),
+ BPF_JMP_IMM(BPF_JA, 0, 0, -10),
+ },
+ .fixup = {4, 16},
+ .result = ACCEPT,
+ },
+ {
+ "unreachable",
+ .insns = {
+ BPF_EXIT_INSN(),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "unreachable",
+ .result = REJECT,
+ },
+ {
+ "unreachable2",
+ .insns = {
+ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "unreachable",
+ .result = REJECT,
+ },
+ {
+ "out of range jump",
+ .insns = {
+ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "jump out of range",
+ .result = REJECT,
+ },
+ {
+ "out of range jump2",
+ .insns = {
+ BPF_JMP_IMM(BPF_JA, 0, 0, -2),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "jump out of range",
+ .result = REJECT,
+ },
+ {
+ "no bpf_exit",
+ .insns = {
+ BPF_ALU64_REG(BPF_MOV, BPF_REG_0, BPF_REG_2),
+ },
+ .errstr = "jump out of range",
+ .result = REJECT,
+ },
+ {
+ "loop (back-edge)",
+ .insns = {
+ BPF_JMP_IMM(BPF_JA, 0, 0, -1),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "back-edge",
+ .result = REJECT,
+ },
+ {
+ "loop2 (back-edge)",
+ .insns = {
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
+ BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
+ BPF_JMP_IMM(BPF_JA, 0, 0, -4),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "back-edge",
+ .result = REJECT,
+ },
+ {
+ "conditional loop",
+ .insns = {
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
+ BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, -3),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "back-edge",
+ .result = REJECT,
+ },
+ {
+ "read uninitialized register",
+ .insns = {
+ BPF_ALU64_REG(BPF_MOV, BPF_REG_0, BPF_REG_2),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "R2 !read_ok",
+ .result = REJECT,
+ },
+ {
+ "program doesn't init R0 before exit",
+ .insns = {
+ BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_1),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "R0 !read_ok",
+ .result = REJECT,
+ },
+ {
+ "stack out of bounds",
+ .insns = {
+ BPF_ST_MEM(BPF_DW, BPF_REG_10, 8, 0),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "invalid stack",
+ .result = REJECT,
+ },
+ {
+ "uninitialized stack",
+ .insns = {
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+ BPF_EXIT_INSN(),
+ },
+ .fixup = {2},
+ .errstr = "invalid indirect read from stack",
+ .result = REJECT,
+ },
+ {
+ "invalid map_fd for function call",
+ .insns = {
+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+ BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+ BPF_EXIT_INSN(),
+ },
+ .errstr = "fd 0 is not pointing to valid bpf_map",
+ .result = REJECT,
+ },
+ {
+ "don't check return value before access",
+ .insns = {
+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+ BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+ BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .fixup = {3},
+ .errstr = "R0 invalid mem access 'map_value_or_null'",
+ .result = REJECT,
+ },
+ {
+ "access memory with incorrect alignment",
+ .insns = {
+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+ BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+ BPF_ST_MEM(BPF_DW, BPF_REG_0, 4, 0),
+ BPF_EXIT_INSN(),
+ },
+ .fixup = {3},
+ .errstr = "misaligned access",
+ .result = REJECT,
+ },
+ {
+ "sometimes access memory with incorrect alignment",
+ .insns = {
+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+ BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
+ BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0),
+ BPF_EXIT_INSN(),
+ BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 1),
+ BPF_EXIT_INSN(),
+ },
+ .fixup = {3},
+ .errstr = "R0 invalid mem access",
+ .result = REJECT,
+ },
+};
+
+static int probe_filter_length(struct bpf_insn *fp)
+{
+ int len = 0;
+
+ for (len = MAX_INSNS - 1; len > 0; --len)
+ if (fp[len].code != 0)
+ break;
+
+ return len + 1;
+}
+
+static int create_map(void)
+{
+ long long key, value = 0;
+ int map_fd;
+
+ map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 1024);
+ if (map_fd < 0) {
+ printf("failed to create map '%s'\n", strerror(errno));
+ }
+
+ return map_fd;
+}
+
+static int test(void)
+{
+ int prog_fd, i;
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ struct bpf_insn *prog = tests[i].insns;
+ int prog_len = probe_filter_length(prog);
+ int *fixup = tests[i].fixup;
+ int map_fd = -1;
+
+ if (*fixup) {
+
+ map_fd = create_map();
+
+ do {
+ prog[*fixup].imm = map_fd;
+ fixup++;
+ } while (*fixup);
+ }
+ printf("#%d %s ", i, tests[i].descr);
+
+ prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACING_FILTER, prog,
+ prog_len * sizeof(struct bpf_insn),
+ "GPL");
+
+ if (tests[i].result == ACCEPT) {
+ if (prog_fd < 0) {
+ printf("FAIL\nfailed to load prog '%s'\n",
+ strerror(errno));
+ printf("%s", bpf_log_buf);
+ goto fail;
+ }
+ } else {
+ if (prog_fd >= 0) {
+ printf("FAIL\nunexpected success to load\n");
+ printf("%s", bpf_log_buf);
+ goto fail;
+ }
+ if (strstr(bpf_log_buf, tests[i].errstr) == 0) {
+ printf("FAIL\nunexpected error message: %s",
+ bpf_log_buf);
+ goto fail;
+ }
+ }
+
+ printf("OK\n");
+fail:
+ if (map_fd >= 0)
+ close(map_fd);
+ close(prog_fd);
+
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ return test();
+}
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox