| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
| |
Which attach types are available to a BPF program depends on its type.
We can encode this using conditional fields to reduce the time syzkaller
loses on unsupported combinations of (program type; attach type).
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The new BPF_TOKEN_CREATE bpf(2) command was introduced in commit [1]
upstream. This command takes a BPF filesystem fd and returns a BPF
token [2]. This token can then be passed to commands BPF_PROG_LOAD,
BPF_MAP_CREATE, and BPF_BTF_LOAD and the kernel will use it to check if
the operation is allowed. What operations a token allows is defined by
the mount options of the BPF filesystem.
No flags are currently supported for the BPF_TOKEN_CREATE command.
The fd should point to the BPF filesystem, but we don't have a specific
resource for this yet so just point to a generic fd. This command also
doesn't add support for the new mount options.
1 - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=35f96de04127
2 - https://lwn.net/Articles/947173/
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
|
| |
This new field for the bpf(2) command BPF_MAP_CREATE was introduced in
[1] upstream. It is conditioned on both the map type and its flags
(BPF_F_VTYPE_BTF_OBJ_FD).
1 - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fcc2c1fb0651
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Our test programs with BPF helper calls are used to verify that the
syzkaller descriptions for BPF helpers are correct. We don't really need
to run those BPF programs to check that the descriptions are correct;
the real test is to pass the verifier, which happens at load time.
This commit therefore removes syscalls to run the BPF programs. We are
limited in how many syscalls we can have per syzkaller programs so we
might as well make the most of it.
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
| |
This commit adds more complex format modifiers for the bpf_snprintf BPF
helper. Those correspond to a bunch of cases that are uncovered in
syzbot's coverage of bpf_bprintf_prepare.
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
| |
The bpf_trace_printk helper supports a limited set of format specifiers
[1]. This commit ensures they are all covered in the union.
1 - https://man7.org/linux/man-pages/man7/bpf-helpers.7.html
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
| |
These occurences were found with the command:
git grep -lP "{(AUTO,\s)*AUTO}"
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
BPF helpers bpf_ringbuf_{discard,submit,output} take a set of flags.
This commit describes those flags.
The default is a zero value, but the kernel doesn't have a macro for
that. Thus, "0" is simply added to the flag definition.
Note bpf_ringbuf_reserve also has a flags argument, but it is currently
unused on the kernel side.
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
This helper has the prototype:
bpf_ringbuf_output(void *ringbuf, void *data, u64 size, u64 flags)
We need to prepare the second argument (R2) on the stack. We use an
8 bytes data value initialized to some random value on the stack and
pointed to by R2. The third argument therefore needs to be 8 (for 8
bytes).
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
| |
This BPF helper has the prototype:
bpf_ringbuf_query(void *ringbuf, u64 flags)
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
| |
Including this helper call in our descriptions is trivial since it takes
the same arguments and returns the same (void) as the already described
bpf_ringbuf_submit helper call.
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This commit adds a new struct with two BPF instructions to perform a
null check on a given pointer. It is then used to update our small ringbuf
program to null check the ringbuf reserved data pointer as follows.
u64 *e;
e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0);
if (!e) return 0;
[...]
bpf_ringbuf_submit(e, 0);
return 0;
With this null check, our test case corresponding to this program now
passes the verifier and is successfully loaded.
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This helper has the verifier prototype:
.ret_type = RET_VOID,
.arg1_type = ARG_PTR_TO_RINGBUF_MEM | OBJ_RELEASE,
.arg2_type = ARG_ANYTHING,
We therefore need to pass the pointer retrieved with bpf_ringbuf_reserve
via R2. We saved that pointer to R9 so we can retrieve it from there.
Since bpf_ringbuf_submit doesn't return anything, we need to write
something in R0 before we exit the program.
Our BPF program now looks like:
u64 *e;
e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0);
[...]
bpf_ringbuf_submit(e, 0);
return 0;
It will still fail, but with EACCES instead of EINVAL, due to the
following verifier error:
0: R1=ctx(off=0,imm=0) R10=fp0
0: (18) r0 = 0x0 ; R0_w=0
2: (18) r1 = 0xffff984f66f93600 ; R1_w=map_ptr(off=0,ks=0,vs=0,imm=0)
4: (b7) r2 = 20 ; R2_w=20
5: (b7) r3 = 0 ; R3_w=0
6: (85) call bpf_ringbuf_reserve#131 ; R0_w=ringbuf_mem_or_null(id=2,ref_obj_id=2,off=0,imm=0) refs=2
7: (bf) r9 = r0 ; R0_w=ringbuf_mem_or_null(id=2,ref_obj_id=2,off=0,imm=0)
R9_w=ringbuf_mem_or_null(id=2,ref_obj_id=2,off=0,imm=0) refs=2
8: (bf) r1 = r9 ; R1_w=ringbuf_mem_or_null(id=2,ref_obj_id=2,off=0,imm=0)
R9_w=ringbuf_mem_or_null(id=2,ref_obj_id=2,off=0,imm=0) refs=2
9: (b7) r2 = 0 ; R2_w=0 refs=2
10: (85) call bpf_ringbuf_submit#132
R1 type=ringbuf_mem_or_null expected=ringbuf_mem
In short, we didn't check that the pointer returned by
bpf_ringbug_reserve isn't null.
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Describe a full call to bpf_ringbuf_reserve, using the map type created
in the previous commit. The test corresponds to this simple line:
u64 *e;
e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0);
[...]
return e;
The pointer returned by bpf_ringbuf_reserve is kept in R9. The goal is
to keep it around so we can use it in other instructions later; several
other helpers take a pointer to ringbuf data as argument. There's of
course a risk that some instruction in between will clobber R9, but I
don't know another way. R9 is at least safe for calls (only R1--R5 get
clobbered).
We expect the program loading to fail with EINVAL because we never
release the reference to the ringbuf data. The verifier will therefore
reject the program with:
0: R1=ctx(off=0,imm=0) R10=fp0
0: (18) r0 = 0x0 ; R0_w=0
2: (18) r1 = 0xffff984e4b55da00 ; R1_w=map_ptr(off=0,ks=0,vs=0,imm=0)
4: (b7) r2 = 20 ; R2_w=20
5: (b7) r3 = 0 ; R3_w=0
6: (85) call bpf_ringbuf_reserve#131 ; R0_w=ringbuf_mem_or_null(id=2,ref_obj_id=2,off=0,imm=0) refs=2
7: (bf) r9 = r0 ; R0_w=ringbuf_mem_or_null(id=2,ref_obj_id=2,off=0,imm=0)
R9_w=ringbuf_mem_or_null(id=2,ref_obj_id=2,off=0,imm=0) refs=2
8: (95) exit
Unreleased reference id=2 alloc_insn=6
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
The corresponding test does the same as this map declaration:
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} rb SEC(".maps");
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This test case corresponds to the BPF program below (bcc syntax for the
map).
BPF_PROG_ARRAY(prog_array, 10);
int tail_call_prog(void *ctx) {
char str[8] = {0};
u64 data = 0x1234;
bpf_snprintf(str, sizeof(str), "%d ", &data, sizeof(data));
return 0;
}
int do_tail_call(void *ctx) {
prog_array.call(ctx, 0);
return 0;
}
It reuses the program defined to test bpf_snprintf, as the target of the
tail call.
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This commit adds a new test case for the bpf_snprintf description
introduced in the previous commit. It corresponds to the BPF code:
char str[8] = {0};
u64 data = 0x1234;
bpf_snprintf(str, sizeof(str), "%d ", &data, sizeof(data));
exit 0;
The fmt (3rd) argument must be stored in a read-only array map which is
prepared with the first three syscalls. Once loaded, the program is
executed with BPF_PROG_TEST_RUN.
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|
|
|
This commit adds a new test case for the bpf_trace_printk description
introduced in the previous commit. It corresponds to the code:
bpf_trace_printk("%d ", 8, 0x1234);
exit 0;
in a BPF program that is then executed via BPF_PROG_TEST_RUN.
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
|