Skip to content

Commit 2cbd95a

Browse files
Jakub KicinskiAlexei Starovoitov
Jakub Kicinski
authored and
Alexei Starovoitov
committed
bpf: change parameters of call/branch offset adjustment
In preparation for code removal change parameters to branch and call adjustment functions to be more universal. The current parameters assume we are patching a single instruction with a longer set. A diagram may help reading the change, this is for the patch single case, patching instruction 1 with a replacement of 4: ____ 0 |____| 1 |____| <-- pos ^ 2 | | <-- end old ^ | 3 | | | delta | len 4 |____| | | (patch region) 5 | | <-- end new v v 6 |____| end_old = pos + 1 end_new = pos + delta + 1 If we are before the patch region - curr variable and the target are fully in old coordinates (hence comparing against end_old). If we are after the region curr is in new coordinates (hence the comparison to end_new) but target is in mixed coordinates, so we just check if it falls before end_new, and if so it needs the adjustment. Note that we will not fix up branches which land in removed region in case of removal, which should be okay, as we are only going to remove dead code. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Acked-by: Yonghong Song <yhs@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent bbebce8 commit 2cbd95a

File tree

1 file changed

+21
-19
lines changed

1 file changed

+21
-19
lines changed

kernel/bpf/core.c

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -307,15 +307,16 @@ int bpf_prog_calc_tag(struct bpf_prog *fp)
307307
return 0;
308308
}
309309

310-
static int bpf_adj_delta_to_imm(struct bpf_insn *insn, u32 pos, u32 delta,
311-
u32 curr, const bool probe_pass)
310+
static int bpf_adj_delta_to_imm(struct bpf_insn *insn, u32 pos, s32 end_old,
311+
s32 end_new, u32 curr, const bool probe_pass)
312312
{
313313
const s64 imm_min = S32_MIN, imm_max = S32_MAX;
314+
s32 delta = end_new - end_old;
314315
s64 imm = insn->imm;
315316

316-
if (curr < pos && curr + imm + 1 > pos)
317+
if (curr < pos && curr + imm + 1 >= end_old)
317318
imm += delta;
318-
else if (curr > pos + delta && curr + imm + 1 <= pos + delta)
319+
else if (curr >= end_new && curr + imm + 1 < end_new)
319320
imm -= delta;
320321
if (imm < imm_min || imm > imm_max)
321322
return -ERANGE;
@@ -324,15 +325,16 @@ static int bpf_adj_delta_to_imm(struct bpf_insn *insn, u32 pos, u32 delta,
324325
return 0;
325326
}
326327

327-
static int bpf_adj_delta_to_off(struct bpf_insn *insn, u32 pos, u32 delta,
328-
u32 curr, const bool probe_pass)
328+
static int bpf_adj_delta_to_off(struct bpf_insn *insn, u32 pos, s32 end_old,
329+
s32 end_new, u32 curr, const bool probe_pass)
329330
{
330331
const s32 off_min = S16_MIN, off_max = S16_MAX;
332+
s32 delta = end_new - end_old;
331333
s32 off = insn->off;
332334

333-
if (curr < pos && curr + off + 1 > pos)
335+
if (curr < pos && curr + off + 1 >= end_old)
334336
off += delta;
335-
else if (curr > pos + delta && curr + off + 1 <= pos + delta)
337+
else if (curr >= end_new && curr + off + 1 < end_new)
336338
off -= delta;
337339
if (off < off_min || off > off_max)
338340
return -ERANGE;
@@ -341,10 +343,10 @@ static int bpf_adj_delta_to_off(struct bpf_insn *insn, u32 pos, u32 delta,
341343
return 0;
342344
}
343345

344-
static int bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta,
345-
const bool probe_pass)
346+
static int bpf_adj_branches(struct bpf_prog *prog, u32 pos, s32 end_old,
347+
s32 end_new, const bool probe_pass)
346348
{
347-
u32 i, insn_cnt = prog->len + (probe_pass ? delta : 0);
349+
u32 i, insn_cnt = prog->len + (probe_pass ? end_new - end_old : 0);
348350
struct bpf_insn *insn = prog->insnsi;
349351
int ret = 0;
350352

@@ -356,8 +358,8 @@ static int bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta,
356358
* do any other adjustments. Therefore skip the patchlet.
357359
*/
358360
if (probe_pass && i == pos) {
359-
i += delta + 1;
360-
insn++;
361+
i = end_new;
362+
insn = prog->insnsi + end_old;
361363
}
362364
code = insn->code;
363365
if (BPF_CLASS(code) != BPF_JMP ||
@@ -367,11 +369,11 @@ static int bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta,
367369
if (BPF_OP(code) == BPF_CALL) {
368370
if (insn->src_reg != BPF_PSEUDO_CALL)
369371
continue;
370-
ret = bpf_adj_delta_to_imm(insn, pos, delta, i,
371-
probe_pass);
372+
ret = bpf_adj_delta_to_imm(insn, pos, end_old,
373+
end_new, i, probe_pass);
372374
} else {
373-
ret = bpf_adj_delta_to_off(insn, pos, delta, i,
374-
probe_pass);
375+
ret = bpf_adj_delta_to_off(insn, pos, end_old,
376+
end_new, i, probe_pass);
375377
}
376378
if (ret)
377379
break;
@@ -421,7 +423,7 @@ struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
421423
* we afterwards may not fail anymore.
422424
*/
423425
if (insn_adj_cnt > cnt_max &&
424-
bpf_adj_branches(prog, off, insn_delta, true))
426+
bpf_adj_branches(prog, off, off + 1, off + len, true))
425427
return NULL;
426428

427429
/* Several new instructions need to be inserted. Make room
@@ -453,7 +455,7 @@ struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
453455
* the ship has sailed to reverse to the original state. An
454456
* overflow cannot happen at this point.
455457
*/
456-
BUG_ON(bpf_adj_branches(prog_adj, off, insn_delta, false));
458+
BUG_ON(bpf_adj_branches(prog_adj, off, off + 1, off + len, false));
457459

458460
bpf_adj_linfo(prog_adj, off, insn_delta);
459461

0 commit comments

Comments
 (0)