bpf: Return -EFAULT on misconfigurations

Mark these cases as non-recoverable to later prevent them from being
caught when they occur during speculative path verification.

Eduard writes [1]:

  The only pace I'm aware of that might act upon specific error code
  from verifier syscall is libbpf. Looking through libbpf code, it seems
  that this change does not interfere with libbpf.

[1] https://lore.kernel.org/all/785b4531ce3b44a84059a4feb4ba458c68fce719.camel@gmail.com/

Signed-off-by: Luis Gerhorst <luis.gerhorst@fau.de>
Reviewed-by: Eduard Zingerman <eddyz87@gmail.com>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Henriette Herzog <henriette.herzog@rub.de>
Cc: Maximilian Ott <ott@cs.fau.de>
Cc: Milan Stephan <milan.stephan@fau.de>
Link: https://lore.kernel.org/r/20250603205800.334980-3-luis.gerhorst@fau.de
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
pull/1309/head
Luis Gerhorst 2025-06-03 22:57:53 +02:00 committed by Alexei Starovoitov
parent 8b7df50fd4
commit fd508bde5d
1 changed files with 18 additions and 18 deletions

View File

@ -8955,7 +8955,7 @@ static int resolve_map_arg_type(struct bpf_verifier_env *env,
if (!meta->map_ptr) { if (!meta->map_ptr) {
/* kernel subsystem misconfigured verifier */ /* kernel subsystem misconfigured verifier */
verbose(env, "invalid map_ptr to access map->type\n"); verbose(env, "invalid map_ptr to access map->type\n");
return -EACCES; return -EFAULT;
} }
switch (meta->map_ptr->map_type) { switch (meta->map_ptr->map_type) {
@ -9643,7 +9643,7 @@ skip_type_check:
* that kernel subsystem misconfigured verifier * that kernel subsystem misconfigured verifier
*/ */
verbose(env, "invalid map_ptr to access map->key\n"); verbose(env, "invalid map_ptr to access map->key\n");
return -EACCES; return -EFAULT;
} }
key_size = meta->map_ptr->key_size; key_size = meta->map_ptr->key_size;
err = check_helper_mem_access(env, regno, key_size, BPF_READ, false, NULL); err = check_helper_mem_access(env, regno, key_size, BPF_READ, false, NULL);
@ -9670,7 +9670,7 @@ skip_type_check:
if (!meta->map_ptr) { if (!meta->map_ptr) {
/* kernel subsystem misconfigured verifier */ /* kernel subsystem misconfigured verifier */
verbose(env, "invalid map_ptr to access map->value\n"); verbose(env, "invalid map_ptr to access map->value\n");
return -EACCES; return -EFAULT;
} }
meta->raw_mode = arg_type & MEM_UNINIT; meta->raw_mode = arg_type & MEM_UNINIT;
err = check_helper_mem_access(env, regno, meta->map_ptr->value_size, err = check_helper_mem_access(env, regno, meta->map_ptr->value_size,
@ -10966,7 +10966,7 @@ record_func_map(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
if (map == NULL) { if (map == NULL) {
verbose(env, "kernel subsystem misconfigured verifier\n"); verbose(env, "kernel subsystem misconfigured verifier\n");
return -EINVAL; return -EFAULT;
} }
/* In case of read-only, some additional restrictions /* In case of read-only, some additional restrictions
@ -11005,7 +11005,7 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
return 0; return 0;
if (!map || map->map_type != BPF_MAP_TYPE_PROG_ARRAY) { if (!map || map->map_type != BPF_MAP_TYPE_PROG_ARRAY) {
verbose(env, "kernel subsystem misconfigured verifier\n"); verbose(env, "kernel subsystem misconfigured verifier\n");
return -EINVAL; return -EFAULT;
} }
reg = &regs[BPF_REG_3]; reg = &regs[BPF_REG_3];
@ -11259,7 +11259,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
if (changes_data && fn->arg1_type != ARG_PTR_TO_CTX) { if (changes_data && fn->arg1_type != ARG_PTR_TO_CTX) {
verbose(env, "kernel subsystem misconfigured func %s#%d: r1 != ctx\n", verbose(env, "kernel subsystem misconfigured func %s#%d: r1 != ctx\n",
func_id_name(func_id), func_id); func_id_name(func_id), func_id);
return -EINVAL; return -EFAULT;
} }
memset(&meta, 0, sizeof(meta)); memset(&meta, 0, sizeof(meta));
@ -11561,7 +11561,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
if (meta.map_ptr == NULL) { if (meta.map_ptr == NULL) {
verbose(env, verbose(env,
"kernel subsystem misconfigured verifier\n"); "kernel subsystem misconfigured verifier\n");
return -EINVAL; return -EFAULT;
} }
if (func_id == BPF_FUNC_map_lookup_elem && if (func_id == BPF_FUNC_map_lookup_elem &&
@ -16738,7 +16738,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
dst_reg->type = CONST_PTR_TO_MAP; dst_reg->type = CONST_PTR_TO_MAP;
} else { } else {
verbose(env, "bpf verifier is misconfigured\n"); verbose(env, "bpf verifier is misconfigured\n");
return -EINVAL; return -EFAULT;
} }
return 0; return 0;
@ -16785,7 +16785,7 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
if (!env->ops->gen_ld_abs) { if (!env->ops->gen_ld_abs) {
verbose(env, "bpf verifier is misconfigured\n"); verbose(env, "bpf verifier is misconfigured\n");
return -EINVAL; return -EFAULT;
} }
if (insn->dst_reg != BPF_REG_0 || insn->off != 0 || if (insn->dst_reg != BPF_REG_0 || insn->off != 0 ||
@ -20825,7 +20825,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
-(subprogs[0].stack_depth + 8)); -(subprogs[0].stack_depth + 8));
if (epilogue_cnt >= INSN_BUF_SIZE) { if (epilogue_cnt >= INSN_BUF_SIZE) {
verbose(env, "bpf verifier is misconfigured\n"); verbose(env, "bpf verifier is misconfigured\n");
return -EINVAL; return -EFAULT;
} else if (epilogue_cnt) { } else if (epilogue_cnt) {
/* Save the ARG_PTR_TO_CTX for the epilogue to use */ /* Save the ARG_PTR_TO_CTX for the epilogue to use */
cnt = 0; cnt = 0;
@ -20848,13 +20848,13 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
if (ops->gen_prologue || env->seen_direct_write) { if (ops->gen_prologue || env->seen_direct_write) {
if (!ops->gen_prologue) { if (!ops->gen_prologue) {
verbose(env, "bpf verifier is misconfigured\n"); verbose(env, "bpf verifier is misconfigured\n");
return -EINVAL; return -EFAULT;
} }
cnt = ops->gen_prologue(insn_buf, env->seen_direct_write, cnt = ops->gen_prologue(insn_buf, env->seen_direct_write,
env->prog); env->prog);
if (cnt >= INSN_BUF_SIZE) { if (cnt >= INSN_BUF_SIZE) {
verbose(env, "bpf verifier is misconfigured\n"); verbose(env, "bpf verifier is misconfigured\n");
return -EINVAL; return -EFAULT;
} else if (cnt) { } else if (cnt) {
new_prog = bpf_patch_insn_data(env, 0, insn_buf, cnt); new_prog = bpf_patch_insn_data(env, 0, insn_buf, cnt);
if (!new_prog) if (!new_prog)
@ -21011,7 +21011,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
if (type == BPF_WRITE) { if (type == BPF_WRITE) {
verbose(env, "bpf verifier narrow ctx access misconfigured\n"); verbose(env, "bpf verifier narrow ctx access misconfigured\n");
return -EINVAL; return -EFAULT;
} }
size_code = BPF_H; size_code = BPF_H;
@ -21030,7 +21030,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
if (cnt == 0 || cnt >= INSN_BUF_SIZE || if (cnt == 0 || cnt >= INSN_BUF_SIZE ||
(ctx_field_size && !target_size)) { (ctx_field_size && !target_size)) {
verbose(env, "bpf verifier is misconfigured\n"); verbose(env, "bpf verifier is misconfigured\n");
return -EINVAL; return -EFAULT;
} }
if (is_narrower_load && size < target_size) { if (is_narrower_load && size < target_size) {
@ -21038,7 +21038,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
off, size, size_default) * 8; off, size, size_default) * 8;
if (shift && cnt + 1 >= INSN_BUF_SIZE) { if (shift && cnt + 1 >= INSN_BUF_SIZE) {
verbose(env, "bpf verifier narrow ctx load misconfigured\n"); verbose(env, "bpf verifier narrow ctx load misconfigured\n");
return -EINVAL; return -EFAULT;
} }
if (ctx_field_size <= 4) { if (ctx_field_size <= 4) {
if (shift) if (shift)
@ -21803,7 +21803,7 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
cnt = env->ops->gen_ld_abs(insn, insn_buf); cnt = env->ops->gen_ld_abs(insn, insn_buf);
if (cnt == 0 || cnt >= INSN_BUF_SIZE) { if (cnt == 0 || cnt >= INSN_BUF_SIZE) {
verbose(env, "bpf verifier is misconfigured\n"); verbose(env, "bpf verifier is misconfigured\n");
return -EINVAL; return -EFAULT;
} }
new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
@ -22139,7 +22139,7 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
goto patch_map_ops_generic; goto patch_map_ops_generic;
if (cnt <= 0 || cnt >= INSN_BUF_SIZE) { if (cnt <= 0 || cnt >= INSN_BUF_SIZE) {
verbose(env, "bpf verifier is misconfigured\n"); verbose(env, "bpf verifier is misconfigured\n");
return -EINVAL; return -EFAULT;
} }
new_prog = bpf_patch_insn_data(env, i + delta, new_prog = bpf_patch_insn_data(env, i + delta,
@ -22499,7 +22499,7 @@ next_insn:
!map_ptr->ops->map_poke_untrack || !map_ptr->ops->map_poke_untrack ||
!map_ptr->ops->map_poke_run) { !map_ptr->ops->map_poke_run) {
verbose(env, "bpf verifier is misconfigured\n"); verbose(env, "bpf verifier is misconfigured\n");
return -EINVAL; return -EFAULT;
} }
ret = map_ptr->ops->map_poke_track(map_ptr, prog->aux); ret = map_ptr->ops->map_poke_track(map_ptr, prog->aux);