mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
Merge branch 'follow-ups-for-verifier-errors-set'
Kumar Kartikeya Dwivedi says:
====================
Follow ups for verifier errors set
Some follow up changes based on comments from Eduard, Sashiko, and BPF
CI Bot. See commits for details.
Patches 1-4 of v3 were applied to bpf-next. This is the remainder,
rebased on the current bpf-next/master.
Changelog:
----------
v3 -> v4
v3: https://lore.kernel.org/bpf/20260924170646.2366016-1-memxor@gmail.com
* Drop v3 patches 1-4, which are already applied.
* Rebase on the current bpf-next/master.
* State in the Program Structure patch that CO-RE relocations stay where
c26e97721b put them and only func_info and line_info validation
moves ahead of the layout checks. (Alexei)
v2 -> v3
v2: https://lore.kernel.org/bpf/20260924092941.3174809-1-memxor@gmail.com
* Rebase on bpf-next/master, which now applies CO-RE relocations before
subprogram discovery, and only move func_info and line_info validation
ahead of the layout checks.
* Drop the truncated final LD_IMM64 relocation guard and its test, as
bpf_check() now rejects that form up front and core_reloc_raw covers it.
v1 -> v2
v1: https://lore.kernel.org/bpf/20260816015746.2632990-1-memxor@gmail.com
* Drop v1 patches 3, 5-7, 11, and 13-14 because they are already present
in bpf-next.
* Use instruction-neutral wording for variable-offset stack accesses
rather than inferring an atomic operation from value_regno == -1. (Eduard)
* Update the variable-offset assertions and cover the retained
uninitialized stack-read diagnostic through the existing CAP_PERFMON-less
read inside the allocated stack. (BPF CI)
* Keep v1 patch 4 unchanged after confirming that the write filter is
reachable for lineage-preserving ALU operations with unchanged
diagnostic snapshots; only its spill arm is impossible. Say so in the
commit message. (Eduard)
* Consider active critical sections only for sleepable programs and let
non-sleepable programs reach the existing no-active-context fallback
instead of adding an early branch. A non-sleepable program can still
hold RCU, preempt, IRQ, or lock state, so the fallback alone would
keep blaming the region. Keep the "non-sleepable prog" description.
(Eduard, BPF CI)
* Select the helper and global-function suggestions by cause, matching
the kfunc site. (BPF CI)
* Split the kfunc coverage into a non-sleepable program case and a
sleepable program inside an RCU read-side critical section. (Eduard)
* Scan subprogram properties with nested loops and drop the partial
recursive-edge details together with their assertion. (Eduard)
* Reject CO-RE relocations targeting a truncated final LD_IMM64 before
applying them, since BTF validation now runs before the subprogram
layout check, and add raw CO-RE coverage for the rejection. Add the
Fixes tag. (BPF CI)
* Rebase on the current bpf-next/master and let the new property scan
also set the callx marker that check_subprogs() collects upstream.
====================
Link: https://patch.msgid.link/20260926133048.2962553-1-memxor@gmail.com
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
commit
7d2fa34fd3
|
|
@ -393,7 +393,7 @@ subprog_jt(int t, struct bpf_verifier_env *env)
|
|||
if (!subprog->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",
|
||||
env, t, "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);
|
||||
|
|
|
|||
|
|
@ -3107,6 +3107,34 @@ static int add_kfuncs(struct bpf_verifier_env *env)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void find_subprog_properties(struct bpf_verifier_env *env)
|
||||
{
|
||||
struct bpf_subprog_info *subprog = env->subprog_info;
|
||||
struct bpf_insn *insn = env->prog->insnsi;
|
||||
int cur_subprog;
|
||||
|
||||
for (cur_subprog = 0; cur_subprog < env->subprog_cnt; cur_subprog++) {
|
||||
int i;
|
||||
|
||||
for (i = subprog[cur_subprog].start;
|
||||
i < subprog[cur_subprog + 1].start; i++) {
|
||||
u8 code = insn[i].code;
|
||||
|
||||
if (code == (BPF_JMP | BPF_CALL) &&
|
||||
insn[i].src_reg == 0 &&
|
||||
insn[i].imm == BPF_FUNC_tail_call) {
|
||||
subprog[cur_subprog].has_tail_call = true;
|
||||
subprog[cur_subprog].tail_call_reachable = true;
|
||||
}
|
||||
if (BPF_CLASS(code) == BPF_LD &&
|
||||
(BPF_MODE(code) == BPF_ABS || BPF_MODE(code) == BPF_IND))
|
||||
subprog[cur_subprog].has_ld_abs = true;
|
||||
if (bpf_is_callx(&insn[i]))
|
||||
env->has_callx = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int check_subprogs(struct bpf_verifier_env *env)
|
||||
{
|
||||
int i, subprog_start, subprog_end, off, cur_subprog = 0;
|
||||
|
|
@ -3120,17 +3148,6 @@ static int check_subprogs(struct bpf_verifier_env *env)
|
|||
for (i = 0; i < insn_cnt; i++) {
|
||||
u8 code = insn[i].code;
|
||||
|
||||
if (code == (BPF_JMP | BPF_CALL) &&
|
||||
insn[i].src_reg == 0 &&
|
||||
insn[i].imm == BPF_FUNC_tail_call) {
|
||||
subprog[cur_subprog].has_tail_call = true;
|
||||
subprog[cur_subprog].tail_call_reachable = true;
|
||||
}
|
||||
if (BPF_CLASS(code) == BPF_LD &&
|
||||
(BPF_MODE(code) == BPF_ABS || BPF_MODE(code) == BPF_IND))
|
||||
subprog[cur_subprog].has_ld_abs = true;
|
||||
if (bpf_is_callx(&insn[i]))
|
||||
env->has_callx = true;
|
||||
if (BPF_CLASS(code) != BPF_JMP && BPF_CLASS(code) != BPF_JMP32)
|
||||
goto next;
|
||||
if (BPF_OP(code) == BPF_CALL)
|
||||
|
|
@ -3154,9 +3171,10 @@ static int check_subprogs(struct bpf_verifier_env *env)
|
|||
}
|
||||
next:
|
||||
if (i == subprog_end - 1) {
|
||||
/* to avoid fall-through from one subprog into another
|
||||
/*
|
||||
* To avoid fall-through from one subprog into another,
|
||||
* the last insn of the subprog should be either exit
|
||||
* or unconditional jump back or bpf_throw call
|
||||
* or unconditional jump back or bpf_throw call.
|
||||
*/
|
||||
if (code != (BPF_JMP | BPF_EXIT) &&
|
||||
code != (BPF_JMP32 | BPF_JA) &&
|
||||
|
|
@ -22511,17 +22529,19 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
|
|||
if (ret < 0)
|
||||
goto skip_full_check;
|
||||
|
||||
/* Discover all subprograms before validating their layout and BTF. */
|
||||
/* Discover all subprograms and collect the properties needed by BTF validation. */
|
||||
ret = add_subprogs(env);
|
||||
if (ret < 0)
|
||||
goto skip_full_check;
|
||||
|
||||
ret = check_subprogs(env);
|
||||
find_subprog_properties(env);
|
||||
|
||||
/* Validate BTF before reporting subprogram layout errors. */
|
||||
ret = bpf_check_btf_info(env, attr, uattr);
|
||||
if (ret < 0)
|
||||
goto skip_full_check;
|
||||
|
||||
/* Validate BTF against the complete subprogram layout. */
|
||||
ret = bpf_check_btf_info(env, attr, uattr);
|
||||
ret = check_subprogs(env);
|
||||
if (ret < 0)
|
||||
goto skip_full_check;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#include "bpf_experimental.h"
|
||||
|
||||
extern int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void *unsafe_ptr__ign, u64 flags) __weak __ksym;
|
||||
extern void bpf_rcu_read_lock(void) __ksym;
|
||||
extern void bpf_rcu_read_unlock(void) __ksym;
|
||||
|
||||
SEC("?tc")
|
||||
__failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_preempt_disable-ed region")
|
||||
|
|
@ -179,6 +181,30 @@ int preempt_sleepable_kfunc(void *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SEC("?fentry/" SYS_PREFIX "sys_getpgid")
|
||||
__failure __msg("program must be sleepable to call sleepable kfunc bpf_copy_from_user_str")
|
||||
__msg("cannot be used in non-sleepable program")
|
||||
int non_sleepable_kfunc(void *ctx)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
bpf_copy_from_user_str(&data, sizeof(data), NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
|
||||
__failure __msg("kernel func bpf_copy_from_user_str is sleepable within rcu_read_lock region")
|
||||
__msg("cannot be used in RCU read lock region")
|
||||
int sleepable_kfunc_in_rcu(void *ctx)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
bpf_rcu_read_lock();
|
||||
bpf_copy_from_user_str(&data, sizeof(data), NULL, 0);
|
||||
bpf_rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __noinline preempt_global_subprog(void)
|
||||
{
|
||||
preempt_balance_subprog();
|
||||
|
|
|
|||
|
|
@ -56,6 +56,46 @@ __naked void out_of_range_jump2(void)
|
|||
" ::: __clobber_all);
|
||||
}
|
||||
|
||||
static __naked __noinline __used int cross_subprog_target(void)
|
||||
{
|
||||
asm volatile (" \
|
||||
r0 = 0; \
|
||||
exit; \
|
||||
" ::: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("socket")
|
||||
__description("jump across subprogram boundary")
|
||||
__failure __msg("jump out of range from insn 1")
|
||||
__msg("jump_across_subprog_boundary @ verifier_cfg.c")
|
||||
__naked void jump_across_subprog_boundary(void)
|
||||
{
|
||||
asm volatile (" \
|
||||
call cross_subprog_target; \
|
||||
goto +1; \
|
||||
exit; \
|
||||
" ::: __clobber_all);
|
||||
}
|
||||
|
||||
static __naked __noinline __used int fallthrough_subprog(void)
|
||||
{
|
||||
asm volatile (" \
|
||||
r0 = 0; \
|
||||
" ::: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("socket")
|
||||
__description("subprogram fallthrough")
|
||||
__failure __msg("last insn is not an exit or jmp")
|
||||
__msg("fallthrough_subprog @ verifier_cfg.c")
|
||||
__naked void subprog_fallthrough(void)
|
||||
{
|
||||
asm volatile (" \
|
||||
call fallthrough_subprog; \
|
||||
exit; \
|
||||
" ::: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("socket")
|
||||
__description("invalid DW LDSX instruction in diagnostics")
|
||||
__failure __msg("BUG_ldx_99")
|
||||
|
|
|
|||
|
|
@ -101,9 +101,11 @@ __naked void jump_table_terminal_gotox_subprog(void)
|
|||
*/
|
||||
SEC("socket")
|
||||
__failure __msg("no jump tables found for subprog starting at 0")
|
||||
__msg(">>> 1 | (0d) gotox r0")
|
||||
__naked void jump_table_no_jump_table(void)
|
||||
{
|
||||
asm volatile (" \
|
||||
r0 = 0; \
|
||||
.8byte %[gotox_r0]; \
|
||||
r0 = 1; \
|
||||
exit; \
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user