summaryrefslogtreecommitdiff
path: root/kernel/bpf/cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/cfg.c')
-rw-r--r--kernel/bpf/cfg.c38
1 files changed, 36 insertions, 2 deletions
diff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c
index 26d37066465f..0f13c13f4133 100644
--- a/kernel/bpf/cfg.c
+++ b/kernel/bpf/cfg.c
@@ -5,6 +5,8 @@
#include <linux/filter.h>
#include <linux/sort.h>
+#include "diagnostics.h"
+
#define verbose(env, fmt, args...) bpf_verifier_log_write(env, fmt, ##args)
/* non-recursive DFS pseudo code
@@ -47,7 +49,6 @@ enum {
BRANCH = 2,
};
-
static void mark_subprog_changes_pkt_data(struct bpf_verifier_env *env, int off)
{
struct bpf_subprog_info *subprog;
@@ -113,6 +114,10 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env)
if (w < 0 || w >= env->prog->len) {
verbose_linfo(env, t, "%d: ", t);
verbose(env, "jump out of range from insn %d to %d\n", t, w);
+ bpf_diag_program_structure(
+ env, t, "jump out of range", "Keep branch targets inside the program.",
+ "Instruction %d jumps to instruction %d, but the program only contains instructions 0 through %d.",
+ t, w, env->prog->len - 1);
return -EINVAL;
}
@@ -136,6 +141,11 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env)
verbose_linfo(env, t, "%d: ", t);
verbose_linfo(env, w, "%d: ", w);
verbose(env, "back-edge from insn %d to %d\n", t, w);
+ bpf_diag_program_structure(
+ env, t, "back-edge is not allowed",
+ "Load with privileges that allow this back-edge, or rewrite the control flow so it does not branch backward.",
+ "Instruction %d branches back to instruction %d. This program is being rejected without the privilege needed for this back-edge.",
+ t, w);
return -EINVAL;
} else if (insn_state[w] == EXPLORED) {
/* forward- or cross-edge */
@@ -316,6 +326,11 @@ static struct bpf_iarray *jt_from_subprog(struct bpf_verifier_env *env,
if (!jt) {
verbose(env, "no jump tables found for subprog starting at %u\n", subprog_start);
+ bpf_diag_program_structure(
+ env, subprog_start, "missing jump table",
+ "Make sure subprograms containing gotox instructions are accompanied by jump tables referencing these subprograms.",
+ "No jump table was found for the subprogram that starts at instruction %u.",
+ subprog_start);
return ERR_PTR(-EINVAL);
}
@@ -343,6 +358,11 @@ create_jt(int t, struct bpf_verifier_env *env)
if (jt->items[i] < subprog_start || jt->items[i] >= subprog_end) {
verbose(env, "jump table for insn %d points outside of the subprog [%u,%u]\n",
t, subprog_start, subprog_end);
+ bpf_diag_program_structure(
+ env, t, "jump table target out of range",
+ "Keep every jump-table target inside the same subprogram.",
+ "The jump table for instruction %d points outside subprogram range [%u,%u).",
+ t, subprog_start, subprog_end);
kvfree(jt);
return ERR_PTR(-EINVAL);
}
@@ -374,6 +394,11 @@ static int visit_gotox_insn(int t, struct bpf_verifier_env *env)
w = jt->items[i];
if (w < 0 || w >= env->prog->len) {
verbose(env, "indirect jump out of range from insn %d to %d\n", t, w);
+ bpf_diag_program_structure(
+ env, t, "indirect jump out of range",
+ "Keep indirect jump targets inside the program.",
+ "Instruction %d can jump indirectly to instruction %d, but the program only contains instructions 0 through %d.",
+ t, w, env->prog->len - 1);
return -EINVAL;
}
@@ -491,7 +516,7 @@ static int visit_insn(int t, struct bpf_verifier_env *env)
return ret;
}
} else if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
- struct bpf_kfunc_call_arg_meta meta;
+ struct bpf_call_arg_meta meta;
ret = bpf_fetch_kfunc_arg_meta(env, insn->imm, insn->off, &meta);
if (ret == 0 && bpf_is_iter_next_kfunc(&meta)) {
@@ -624,12 +649,21 @@ walk_cfg:
if (insn_state[i] != EXPLORED) {
verbose(env, "unreachable insn %d\n", i);
+ bpf_diag_program_structure(
+ env, i, "unreachable instruction",
+ "Remove the unreachable instruction or add valid control flow that reaches it.",
+ "Instruction %d is not reachable from the program entry point.", i);
ret = -EINVAL;
goto err_free;
}
if (bpf_is_ldimm64(insn)) {
if (insn_state[i + 1] != 0) {
verbose(env, "jump into the middle of ldimm64 insn %d\n", i);
+ bpf_diag_program_structure(
+ env, i, "jump into ldimm64 immediate",
+ "Target the first instruction of the ldimm64 pair, or restructure the jump target.",
+ "Control flow reaches the second half of the ldimm64 instruction pair that starts at instruction %d.",
+ i);
ret = -EINVAL;
goto err_free;
}