f20248a
From a1b14d27ed0965838350f1377ff97c93ee383492 Mon Sep 17 00:00:00 2001
f20248a
From: Daniel Borkmann <daniel@iogearbox.net>
f20248a
Date: Wed, 10 Feb 2016 16:47:11 +0100
f20248a
Subject: [PATCH] bpf: fix branch offset adjustment on backjumps after patching
f20248a
 ctx expansion
f20248a
f20248a
When ctx access is used, the kernel often needs to expand/rewrite
f20248a
instructions, so after that patching, branch offsets have to be
f20248a
adjusted for both forward and backward jumps in the new eBPF program,
f20248a
but for backward jumps it fails to account the delta. Meaning, for
f20248a
example, if the expansion happens exactly on the insn that sits at
f20248a
the jump target, it doesn't fix up the back jump offset.
f20248a
f20248a
Analysis on what the check in adjust_branches() is currently doing:
f20248a
f20248a
  /* adjust offset of jmps if necessary */
f20248a
  if (i < pos && i + insn->off + 1 > pos)
f20248a
    insn->off += delta;
f20248a
  else if (i > pos && i + insn->off + 1 < pos)
f20248a
    insn->off -= delta;
f20248a
f20248a
First condition (forward jumps):
f20248a
f20248a
  Before:                         After:
f20248a
f20248a
  insns[0]                        insns[0]
f20248a
  insns[1] <--- i/insn            insns[1] <--- i/insn
f20248a
  insns[2] <--- pos               insns[P] <--- pos
f20248a
  insns[3]                        insns[P]  `------| delta
f20248a
  insns[4] <--- target_X          insns[P]   `-----|
f20248a
  insns[5]                        insns[3]
f20248a
                                  insns[4] <--- target_X
f20248a
                                  insns[5]
f20248a
f20248a
First case is if we cross pos-boundary and the jump instruction was
f20248a
before pos. This is handeled correctly. I.e. if i == pos, then this
f20248a
would mean our jump that we currently check was the patchlet itself
f20248a
that we just injected. Since such patchlets are self-contained and
f20248a
have no awareness of any insns before or after the patched one, the
f20248a
delta is correctly not adjusted. Also, for the second condition in
f20248a
case of i + insn->off + 1 == pos, means we jump to that newly patched
f20248a
instruction, so no offset adjustment are needed. That part is correct.
f20248a
f20248a
Second condition (backward jumps):
f20248a
f20248a
  Before:                         After:
f20248a
f20248a
  insns[0]                        insns[0]
f20248a
  insns[1] <--- target_X          insns[1] <--- target_X
f20248a
  insns[2] <--- pos <-- target_Y  insns[P] <--- pos <-- target_Y
f20248a
  insns[3]                        insns[P]  `------| delta
f20248a
  insns[4] <--- i/insn            insns[P]   `-----|
f20248a
  insns[5]                        insns[3]
f20248a
                                  insns[4] <--- i/insn
f20248a
                                  insns[5]
f20248a
f20248a
Second interesting case is where we cross pos-boundary and the jump
f20248a
instruction was after pos. Backward jump with i == pos would be
f20248a
impossible and pose a bug somewhere in the patchlet, so the first
f20248a
condition checking i > pos is okay only by itself. However, i +
f20248a
insn->off + 1 < pos does not always work as intended to trigger the
f20248a
adjustment. It works when jump targets would be far off where the
f20248a
delta wouldn't matter. But, for example, where the fixed insn->off
f20248a
before pointed to pos (target_Y), it now points to pos + delta, so
f20248a
that additional room needs to be taken into account for the check.
f20248a
This means that i) both tests here need to be adjusted into pos + delta,
f20248a
and ii) for the second condition, the test needs to be <= as pos
f20248a
itself can be a target in the backjump, too.
f20248a
f20248a
Fixes: 9bac3d6d548e ("bpf: allow extended BPF programs access skb fields")
f20248a
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
f20248a
Signed-off-by: David S. Miller <davem@davemloft.net>
f20248a
---
f20248a
 kernel/bpf/verifier.c | 2 +-
f20248a
 1 file changed, 1 insertion(+), 1 deletion(-)
f20248a
f20248a
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
f20248a
index d1d3e8f57de9..2e7f7ab739e4 100644
f20248a
--- a/kernel/bpf/verifier.c
f20248a
+++ b/kernel/bpf/verifier.c
f20248a
@@ -2082,7 +2082,7 @@ static void adjust_branches(struct bpf_prog *prog, int pos, int delta)
f20248a
 		/* adjust offset of jmps if necessary */
f20248a
 		if (i < pos && i + insn->off + 1 > pos)
f20248a
 			insn->off += delta;
f20248a
-		else if (i > pos && i + insn->off + 1 < pos)
f20248a
+		else if (i > pos + delta && i + insn->off + 1 <= pos + delta)
f20248a
 			insn->off -= delta;
f20248a
 	}
f20248a
 }
f20248a
-- 
f20248a
2.5.0
f20248a