aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@fb.com>2016-05-19 21:17:13 -0400
committerDavid S. Miller <davem@davemloft.net>2016-05-20 19:53:03 -0400
commitd91b28ed42de99217efb2e8cb0357263d6fb737c (patch)
treeb75e365810041e821fbcfe0824e18aef0e36820e /kernel
parent238a9584e9e2c7b3ea23924e9183fee05d584789 (diff)
bpf: support decreasing order in direct packet access
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 <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/verifier.c12
1 files 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,
683{ 683{
684 struct reg_state *regs = env->cur_state.regs; 684 struct reg_state *regs = env->cur_state.regs;
685 struct reg_state *reg = &regs[regno]; 685 struct reg_state *reg = &regs[regno];
686 int linear_size = (int) reg->range - (int) reg->off;
687 686
688 if (linear_size < 0 || linear_size >= MAX_PACKET_OFF) { 687 off += reg->off;
689 verbose("verifier bug\n"); 688 if (off < 0 || off + size > reg->range) {
690 return -EFAULT; 689 verbose("invalid access to packet, off=%d size=%d, R%d(id=%d,off=%d,r=%d)\n",
691 } 690 off, size, regno, reg->id, reg->off, reg->range);
692 if (off < 0 || off + size > linear_size) {
693 verbose("invalid access to packet, off=%d size=%d, allowed=%d\n",
694 off, size, linear_size);
695 return -EACCES; 691 return -EACCES;
696 } 692 }
697 return 0; 693 return 0;