Skip to content

Commit e2ae4ca

Browse files
Jakub KicinskiAlexei Starovoitov
Jakub Kicinski
authored and
Alexei Starovoitov
committed
bpf: verifier: hard wire branches to dead code
Loading programs with dead code becomes more and more common, as people begin to patch constants at load time. Turn conditional jumps to unconditional ones, to avoid potential branch misprediction penalty. This optimization is enabled for privileged users only. For branches which just fall through we could just mark them as not seen and have dead code removal take care of them, but that seems less clean. v0.2: - don't call capable(CAP_SYS_ADMIN) twice (Jiong). v3: - fix GCC warning; Signed-off-by: Jakub Kicinski <[email protected]> Acked-by: Yonghong Song <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 2cbd95a commit e2ae4ca

File tree

1 file changed

+43
-2
lines changed

1 file changed

+43
-2
lines changed

kernel/bpf/verifier.c

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6458,6 +6458,40 @@ static void sanitize_dead_code(struct bpf_verifier_env *env)
64586458
}
64596459
}
64606460

6461+
static bool insn_is_cond_jump(u8 code)
6462+
{
6463+
u8 op;
6464+
6465+
if (BPF_CLASS(code) != BPF_JMP)
6466+
return false;
6467+
6468+
op = BPF_OP(code);
6469+
return op != BPF_JA && op != BPF_EXIT && op != BPF_CALL;
6470+
}
6471+
6472+
static void opt_hard_wire_dead_code_branches(struct bpf_verifier_env *env)
6473+
{
6474+
struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
6475+
struct bpf_insn ja = BPF_JMP_IMM(BPF_JA, 0, 0, 0);
6476+
struct bpf_insn *insn = env->prog->insnsi;
6477+
const int insn_cnt = env->prog->len;
6478+
int i;
6479+
6480+
for (i = 0; i < insn_cnt; i++, insn++) {
6481+
if (!insn_is_cond_jump(insn->code))
6482+
continue;
6483+
6484+
if (!aux_data[i + 1].seen)
6485+
ja.off = insn->off;
6486+
else if (!aux_data[i + 1 + insn->off].seen)
6487+
ja.off = 0;
6488+
else
6489+
continue;
6490+
6491+
memcpy(insn, &ja, sizeof(ja));
6492+
}
6493+
}
6494+
64616495
/* convert load instructions that access fields of a context type into a
64626496
* sequence of instructions that access fields of the underlying structure:
64636497
* struct __sk_buff -> struct sk_buff
@@ -7149,6 +7183,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
71497183
struct bpf_verifier_env *env;
71507184
struct bpf_verifier_log *log;
71517185
int ret = -EINVAL;
7186+
bool is_priv;
71527187

71537188
/* no program is valid */
71547189
if (ARRAY_SIZE(bpf_verifier_ops) == 0)
@@ -7195,6 +7230,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
71957230
if (attr->prog_flags & BPF_F_ANY_ALIGNMENT)
71967231
env->strict_alignment = false;
71977232

7233+
is_priv = capable(CAP_SYS_ADMIN);
7234+
env->allow_ptr_leaks = is_priv;
7235+
71987236
ret = replace_map_fd_with_map_ptr(env);
71997237
if (ret < 0)
72007238
goto skip_full_check;
@@ -7212,8 +7250,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
72127250
if (!env->explored_states)
72137251
goto skip_full_check;
72147252

7215-
env->allow_ptr_leaks = capable(CAP_SYS_ADMIN);
7216-
72177253
ret = check_subprogs(env);
72187254
if (ret < 0)
72197255
goto skip_full_check;
@@ -7243,6 +7279,11 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
72437279
ret = check_max_stack_depth(env);
72447280

72457281
/* instruction rewrites happen after this point */
7282+
if (is_priv) {
7283+
if (ret == 0)
7284+
opt_hard_wire_dead_code_branches(env);
7285+
}
7286+
72467287
if (ret == 0)
72477288
sanitize_dead_code(env);
72487289

0 commit comments

Comments
 (0)