mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
bpf: Report Policy helper and kfunc errors
Augment selected helper and kfunc allowability failures with Policy reports. These reports explain which requested operation is forbidden and why, without adding path history for non-path-dependent policy checks. Cover unprivileged bpf2bpf and kfunc use, helper program-type restrictions, GPL-only helpers, helper-specific allow callbacks, kfunc allowability, and destructive kfunc capability checks. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://patch.msgid.link/20260815064612.378577-15-memxor@gmail.com Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
This commit is contained in:
committed by
Eduard Zingerman
parent
a8f4278353
commit
ac545b00ca
@@ -22,6 +22,7 @@
|
||||
#define CALL_TYPE_SAFETY "Call Type Safety"
|
||||
#define EXECUTION_CONTEXT_SAFETY "Execution Context Safety"
|
||||
#define PROGRAM_STRUCTURE "Program Structure"
|
||||
#define POLICY "Policy"
|
||||
|
||||
#define BPF_DIAG_TEXT_WIDTH 100
|
||||
#define BPF_DIAG_TEXT_INDENT " "
|
||||
@@ -1211,6 +1212,19 @@ void bpf_diag_program_structure(struct bpf_verifier_env *env, u32 insn_idx,
|
||||
|
||||
diag_suggestion(env, "%s", suggestion);
|
||||
}
|
||||
|
||||
void bpf_diag_policy(struct bpf_verifier_env *env, u32 insn_idx, const char *operation,
|
||||
const char *reason, const char *suggestion)
|
||||
{
|
||||
bpf_diag_header(env, POLICY, "operation is not allowed");
|
||||
diag_reason(env, "The %s is not allowed: %s.", operation, reason);
|
||||
|
||||
diag_section(env, "At");
|
||||
bpf_diag_source(env, insn_idx, "error", "policy check failed for %s", operation);
|
||||
|
||||
diag_suggestion(env, "%s", suggestion);
|
||||
}
|
||||
|
||||
void bpf_diag_invalid_deref(struct bpf_verifier_env *env, u32 insn_idx, int regno,
|
||||
const char *reg_name, const struct bpf_reg_state *reg,
|
||||
enum bpf_diag_invalid_deref_kind kind, s64 offset)
|
||||
|
||||
@@ -92,6 +92,8 @@ void bpf_diag_ctx_underflow(struct bpf_verifier_env *env, u32 insn_idx,
|
||||
void bpf_diag_program_structure(struct bpf_verifier_env *env, u32 insn_idx,
|
||||
const char *problem, const char *suggestion,
|
||||
const char *reason_fmt, ...) __printf(5, 6);
|
||||
void bpf_diag_policy(struct bpf_verifier_env *env, u32 insn_idx, const char *operation,
|
||||
const char *reason, const char *suggestion);
|
||||
void bpf_diag_record_branch(struct bpf_verifier_env *env, u32 insn_idx, bool cond_true);
|
||||
void bpf_diag_mod_begin(struct bpf_verifier_env *env, const struct bpf_reg_state *reg,
|
||||
const struct bpf_reg_state *origin, enum bpf_diag_mod_reason reason);
|
||||
|
||||
+32
-1
@@ -2924,6 +2924,10 @@ static int add_subprogs(struct bpf_verifier_env *env)
|
||||
|
||||
if (!env->bpf_capable) {
|
||||
verbose(env, "loading/calling other bpf or kernel functions are allowed for CAP_BPF and CAP_SYS_ADMIN\n");
|
||||
bpf_diag_policy(
|
||||
env, i, "BPF-to-BPF function call",
|
||||
"loading or calling other BPF functions requires CAP_BPF or CAP_SYS_ADMIN",
|
||||
"Load this program with the required capability, or avoid BPF-to-BPF function calls in unprivileged programs.");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@@ -2976,6 +2980,10 @@ static int add_kfuncs(struct bpf_verifier_env *env)
|
||||
|
||||
if (!env->bpf_capable) {
|
||||
verbose(env, "loading/calling other bpf or kernel functions are allowed for CAP_BPF and CAP_SYS_ADMIN\n");
|
||||
bpf_diag_policy(
|
||||
env, i, "kernel function call",
|
||||
"calling kernel functions requires CAP_BPF or CAP_SYS_ADMIN",
|
||||
"Load this program with the required capability, or avoid kernel function calls in unprivileged programs.");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@@ -10748,17 +10756,31 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
|
||||
if (err) {
|
||||
verbose(env, "program of this type cannot use helper %s#%d\n",
|
||||
func_id_name(func_id), func_id);
|
||||
operation = bpf_diag_fmt(env, "helper %s#%d", func_id_name(func_id), func_id);
|
||||
bpf_diag_policy(
|
||||
env, insn_idx, operation, "this program type does not allow the helper",
|
||||
"Use a helper allowed for this program type, or move the logic to a compatible program type.");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* eBPF programs must be GPL compatible to use GPL-ed functions */
|
||||
if (!env->prog->gpl_compatible && fn->gpl_only) {
|
||||
verbose(env, "cannot call GPL-restricted function from non-GPL compatible program\n");
|
||||
operation = bpf_diag_fmt(env, "helper %s#%d", func_id_name(func_id), func_id);
|
||||
bpf_diag_policy(
|
||||
env, insn_idx, operation,
|
||||
"this helper is restricted to GPL-compatible programs",
|
||||
"Use a GPL-compatible license, or replace the helper with one that is available to non-GPL programs.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fn->allowed && !fn->allowed(env->prog)) {
|
||||
verbose(env, "helper call is not allowed in probe\n");
|
||||
operation = bpf_diag_fmt(env, "helper %s#%d", func_id_name(func_id), func_id);
|
||||
bpf_diag_policy(
|
||||
env, insn_idx, operation,
|
||||
"the helper-specific policy callback rejected this program",
|
||||
"Use the helper only from an allowed attach point or program configuration.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -13643,8 +13665,13 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
|
||||
return 0;
|
||||
|
||||
err = bpf_fetch_kfunc_arg_meta(env, insn->imm, insn->off, &meta);
|
||||
if (err == -EACCES && meta.func_name)
|
||||
if (err == -EACCES && meta.func_name) {
|
||||
verbose(env, "calling kernel function %s is not allowed\n", meta.func_name);
|
||||
operation = bpf_diag_fmt(env, "kfunc %s", meta.func_name);
|
||||
bpf_diag_policy(
|
||||
env, insn_idx, operation, "this program cannot call the kfunc",
|
||||
"Use a kfunc allowed for this program type and attach point, or change the program context.");
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
desc_btf = meta.btf;
|
||||
@@ -13691,6 +13718,10 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
|
||||
|
||||
if (is_kfunc_destructive(&meta) && !capable(CAP_SYS_BOOT)) {
|
||||
verbose(env, "destructive kfunc calls require CAP_SYS_BOOT capability\n");
|
||||
operation = bpf_diag_fmt(env, "destructive kfunc %s", meta.func_name);
|
||||
bpf_diag_policy(
|
||||
env, insn_idx, operation, "destructive kfuncs require CAP_SYS_BOOT",
|
||||
"Load the program with CAP_SYS_BOOT, or avoid destructive kfuncs.");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user