when packet headers are accessed in 'decreasing' order (like TCP port
may be fetched before the program reads IP src) the llvm may generate
the following code:
[...]                // R7=pkt(id=0,off=22,r=70)
r2 = *(u32 *)(r7 +0) // good access
[...]
r7 += 40             // R7=pkt(id=0,off=62,r=70)
r8 = *(u32 *)(r7 +0) // good access
[...]
r1 = *(u32 *)(r7 -20) // this one will fail though it's within a safe range
                      // it's doing *(u32*)(skb->data + 42)
Fix verifier to recognize such code pattern

Alos turned out that 'off > range' condition is not a verifier bug.
It's a buggy program that may do something like:
if (ptr + 50 > data_end)
  return 0;
ptr += 60;
*(u32*)ptr;
in such case emit
"invalid access to packet, off=0 size=4, R1(id=0,off=60,r=50)" error message,
so all information is available for the program author to fix the program.

Fixes: 969bf05eb3ce ("bpf: direct packet access")
Signed-off-by: Alexei Starovoitov <a...@kernel.org>
Acked-by: Daniel Borkmann <dan...@iogearbox.net>
---
 kernel/bpf/verifier.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a08d66215245..d54e34874579 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -683,15 +683,11 @@ static int check_packet_access(struct verifier_env *env, 
u32 regno, int off,
 {
        struct reg_state *regs = env->cur_state.regs;
        struct reg_state *reg = &regs[regno];
-       int linear_size = (int) reg->range - (int) reg->off;
 
-       if (linear_size < 0 || linear_size >= MAX_PACKET_OFF) {
-               verbose("verifier bug\n");
-               return -EFAULT;
-       }
-       if (off < 0 || off + size > linear_size) {
-               verbose("invalid access to packet, off=%d size=%d, 
allowed=%d\n",
-                       off, size, linear_size);
+       off += reg->off;
+       if (off < 0 || off + size > reg->range) {
+               verbose("invalid access to packet, off=%d size=%d, 
R%d(id=%d,off=%d,r=%d)\n",
+                       off, size, regno, reg->id, reg->off, reg->range);
                return -EACCES;
        }
        return 0;
-- 
2.8.0

Reply via email to