linux/kernel/bpf
Yonghong Song 9fd29c08e5 bpf: improve verifier ARG_CONST_SIZE_OR_ZERO semantics
For helpers, the argument type ARG_CONST_SIZE_OR_ZERO permits the
access size to be 0 when accessing the previous argument (arg).
Right now, it requires the arg needs to be NULL when size passed
is 0 or could be 0. It also requires a non-NULL arg when the size
is proved to be non-0.

This patch changes verifier ARG_CONST_SIZE_OR_ZERO behavior
such that for size-0 or possible size-0, it is not required
the arg equal to NULL.

There are a couple of reasons for this semantics change, and
all of them intends to simplify user bpf programs which
may improve user experience and/or increase chances of
verifier acceptance. Together with the next patch which
changes bpf_probe_read arg2 type from ARG_CONST_SIZE to
ARG_CONST_SIZE_OR_ZERO, the following two examples, which
fail the verifier currently, are able to get verifier acceptance.

Example 1:
   unsigned long len = pend - pstart;
   len = len > MAX_PAYLOAD_LEN ? MAX_PAYLOAD_LEN : len;
   len &= MAX_PAYLOAD_LEN;
   bpf_probe_read(data->payload, len, pstart);

It does not have test for "len > 0" and it failed the verifier.
Users may not be aware that they have to add this test.
Converting the bpf_probe_read helper to have
ARG_CONST_SIZE_OR_ZERO helps the above code get
verifier acceptance.

Example 2:
  Here is one example where llvm "messed up" the code and
  the verifier fails.

......
   unsigned long len = pend - pstart;
   if (len > 0 && len <= MAX_PAYLOAD_LEN)
     bpf_probe_read(data->payload, len, pstart);
......

The compiler generates the following code and verifier fails:
......
39: (79) r2 = *(u64 *)(r10 -16)
40: (1f) r2 -= r8
41: (bf) r1 = r2
42: (07) r1 += -1
43: (25) if r1 > 0xffe goto pc+3
  R0=inv(id=0) R1=inv(id=0,umax_value=4094,var_off=(0x0; 0xfff))
  R2=inv(id=0) R6=map_value(id=0,off=0,ks=4,vs=4095,imm=0) R7=inv(id=0)
  R8=inv(id=0) R9=inv0 R10=fp0
44: (bf) r1 = r6
45: (bf) r3 = r8
46: (85) call bpf_probe_read#45
R2 min value is negative, either use unsigned or 'var &= const'
......

The compiler optimization is correct. If r1 = 0,
r1 - 1 = 0xffffffffffffffff > 0xffe.  If r1 != 0, r1 - 1 will not wrap.
r1 > 0xffe at insn #43 can actually capture
both "r1 > 0" and "len <= MAX_PAYLOAD_LEN".
This however causes an issue in verifier as the value range of arg2
"r2" does not properly get refined and lead to verification failure.

Relaxing bpf_prog_read arg2 from ARG_CONST_SIZE to ARG_CONST_SIZE_OR_ZERO
allows the following simplied code:
   unsigned long len = pend - pstart;
   if (len <= MAX_PAYLOAD_LEN)
     bpf_probe_read(data->payload, len, pstart);

The llvm compiler will generate less complex code and the
verifier is able to verify that the program is okay.

Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-14 16:20:03 +09:00
..
Makefile bpf: offload: add infrastructure for loading programs for a specific netdev 2017-11-05 22:26:18 +09:00
arraymap.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-10-22 13:39:14 +01:00
bpf_lru_list.c bpf: lru: Lower the PERCPU_NR_SCANS from 16 to 4 2017-04-17 13:55:52 -04:00
bpf_lru_list.h bpf: Only set node->ref = 1 if it has not been set 2017-09-01 09:57:39 -07:00
cgroup.c bpf, cgroup: implement eBPF-based device controller for cgroup v2 2017-11-05 23:26:51 +09:00
core.c bpf: Revert bpf_overrid_function() helper changes. 2017-11-11 18:24:55 +09:00
cpumap.c bpf: cpumap micro-optimization in cpu_map_enqueue 2017-11-02 16:13:14 +09:00
devmap.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-10-22 13:39:14 +01:00
disasm.c bpf: move instruction printing into a separate file 2017-10-10 12:30:16 -07:00
disasm.h bpf: move instruction printing into a separate file 2017-10-10 12:30:16 -07:00
hashtab.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-10-22 13:39:14 +01:00
helpers.c bpf: rename ARG_PTR_TO_STACK 2017-01-09 16:56:27 -05:00
inode.c bpf: Add file mode configuration into bpf maps 2017-10-20 13:32:59 +01:00
lpm_trie.c bpf: Add file mode configuration into bpf maps 2017-10-20 13:32:59 +01:00
map_in_map.c bpf: Add syscall lookup support for fd array and htab 2017-06-29 13:13:25 -04:00
map_in_map.h bpf: Add syscall lookup support for fd array and htab 2017-06-29 13:13:25 -04:00
offload.c bpf: report offload info to user space 2017-11-05 22:26:18 +09:00
percpu_freelist.c
percpu_freelist.h
sockmap.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-11-02 15:23:39 +09:00
stackmap.c bpf: Add file mode configuration into bpf maps 2017-10-20 13:32:59 +01:00
syscall.c bpf, cgroup: implement eBPF-based device controller for cgroup v2 2017-11-05 23:26:51 +09:00
tnum.c bpf/verifier: track signed and unsigned min/max values 2017-08-08 17:51:34 -07:00
verifier.c bpf: improve verifier ARG_CONST_SIZE_OR_ZERO semantics 2017-11-14 16:20:03 +09:00