Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'support-bpf_fastcall-patterns-for-calls-to-kfuncs'

Eduard Zingerman says:

====================
support bpf_fastcall patterns for calls to kfuncs

As an extension of [1], allow bpf_fastcall patterns for kfuncs:
- pattern rules are the same as for helpers;
- spill/fill removal is allowed only for kfuncs listed in the
is_fastcall_kfunc_call (under assumption that such kfuncs would
always be members of special_kfunc_list).

Allow bpf_fastcall rewrite for bpf_cast_to_kern_ctx() and
bpf_rdonly_cast() in order to conjure selftests for this feature.

After this patch-set verifier would rewrite the program below:

r2 = 1
*(u64 *)(r10 - 32) = r2
call %[bpf_cast_to_kern_ctx]
r2 = *(u64 *)(r10 - 32)
r0 = r2;"

As follows:

r2 = 1 /* spill/fill at r10[-32] is removed */
r0 = r1 /* replacement for bpf_cast_to_kern_ctx() */
r0 = r2
exit

Also, attribute used by LLVM implementation of the feature had been
changed from no_caller_saved_registers to bpf_fastcall (see [2]).
This patch-set replaces references to nocsr by references to
bpf_fastcall to keep LLVM and Kernel parts in sync.

[1] no_caller_saved_registers attribute for helper calls
https://lore.kernel.org/bpf/20240722233844.1406874-1-eddyz87@gmail.com/
[2] [BPF] introduce __attribute__((bpf_fastcall))
https://github.com/llvm/llvm-project/pull/105417

Changes v2->v3:
- added a patch fixing arch_mask handling in test_loader,
otherwise newly added tests for the feature were skipped
(a fix for regression introduced by a recent commit);
- fixed warning regarding unused 'params' variable;
- applied stylistical fixes suggested by Yonghong;
- added acks from Yonghong;

Changes v1->v2:
- added two patches replacing all mentions of nocsr by bpf_fastcall
(suggested by Andrii);
- removed KF_NOCSR flag (suggested by Yonghong).

v1: https://lore.kernel.org/bpf/20240812234356.2089263-1-eddyz87@gmail.com/
v2: https://lore.kernel.org/bpf/20240817015140.1039351-1-eddyz87@gmail.com/
====================

Link: https://lore.kernel.org/r/20240822084112.3257995-1-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+192 -102
+3 -3
include/linux/bpf.h
··· 808 808 bool gpl_only; 809 809 bool pkt_access; 810 810 bool might_sleep; 811 - /* set to true if helper follows contract for gcc/llvm 812 - * attribute no_caller_saved_registers: 811 + /* set to true if helper follows contract for llvm 812 + * attribute bpf_fastcall: 813 813 * - void functions do not scratch r0 814 814 * - functions taking N arguments scratch only registers r1-rN 815 815 */ 816 - bool allow_nocsr; 816 + bool allow_fastcall; 817 817 enum bpf_return_type ret_type; 818 818 union { 819 819 struct {
+9 -9
include/linux/bpf_verifier.h
··· 577 577 bool call_with_percpu_alloc_ptr; /* {this,per}_cpu_ptr() with prog percpu alloc */ 578 578 u8 alu_state; /* used in combination with alu_limit */ 579 579 /* true if STX or LDX instruction is a part of a spill/fill 580 - * pattern for a no_caller_saved_registers call. 580 + * pattern for a bpf_fastcall call. 581 581 */ 582 - u8 nocsr_pattern:1; 582 + u8 fastcall_pattern:1; 583 583 /* for CALL instructions, a number of spill/fill pairs in the 584 - * no_caller_saved_registers pattern. 584 + * bpf_fastcall pattern. 585 585 */ 586 - u8 nocsr_spills_num:3; 586 + u8 fastcall_spills_num:3; 587 587 588 588 /* below fields are initialized once */ 589 589 unsigned int orig_idx; /* original instruction index */ ··· 653 653 u32 linfo_idx; /* The idx to the main_prog->aux->linfo */ 654 654 u16 stack_depth; /* max. stack depth used by this function */ 655 655 u16 stack_extra; 656 - /* offsets in range [stack_depth .. nocsr_stack_off) 657 - * are used for no_caller_saved_registers spills and fills. 656 + /* offsets in range [stack_depth .. fastcall_stack_off) 657 + * are used for bpf_fastcall spills and fills. 658 658 */ 659 - s16 nocsr_stack_off; 659 + s16 fastcall_stack_off; 660 660 bool has_tail_call: 1; 661 661 bool tail_call_reachable: 1; 662 662 bool has_ld_abs: 1; ··· 664 664 bool is_async_cb: 1; 665 665 bool is_exception_cb: 1; 666 666 bool args_cached: 1; 667 - /* true if nocsr stack region is used by functions that can't be inlined */ 668 - bool keep_nocsr_stack: 1; 667 + /* true if bpf_fastcall stack region is used by functions that can't be inlined */ 668 + bool keep_fastcall_stack: 1; 669 669 670 670 u8 arg_cnt; 671 671 struct bpf_subprog_arg_info args[MAX_BPF_FUNC_REG_ARGS];
+1 -1
kernel/bpf/helpers.c
··· 158 158 .func = bpf_get_smp_processor_id, 159 159 .gpl_only = false, 160 160 .ret_type = RET_INTEGER, 161 - .allow_nocsr = true, 161 + .allow_fastcall = true, 162 162 }; 163 163 164 164 BPF_CALL_0(bpf_get_numa_node_id)
+108 -73
kernel/bpf/verifier.c
··· 4579 4579 return fls64(reg->umax_value); 4580 4580 } 4581 4581 4582 - /* See comment for mark_nocsr_pattern_for_call() */ 4583 - static void check_nocsr_stack_contract(struct bpf_verifier_env *env, struct bpf_func_state *state, 4584 - int insn_idx, int off) 4582 + /* See comment for mark_fastcall_pattern_for_call() */ 4583 + static void check_fastcall_stack_contract(struct bpf_verifier_env *env, 4584 + struct bpf_func_state *state, int insn_idx, int off) 4585 4585 { 4586 4586 struct bpf_subprog_info *subprog = &env->subprog_info[state->subprogno]; 4587 4587 struct bpf_insn_aux_data *aux = env->insn_aux_data; 4588 4588 int i; 4589 4589 4590 - if (subprog->nocsr_stack_off <= off || aux[insn_idx].nocsr_pattern) 4590 + if (subprog->fastcall_stack_off <= off || aux[insn_idx].fastcall_pattern) 4591 4591 return; 4592 - /* access to the region [max_stack_depth .. nocsr_stack_off) 4593 - * from something that is not a part of the nocsr pattern, 4594 - * disable nocsr rewrites for current subprogram by setting 4595 - * nocsr_stack_off to a value smaller than any possible offset. 4592 + /* access to the region [max_stack_depth .. fastcall_stack_off) 4593 + * from something that is not a part of the fastcall pattern, 4594 + * disable fastcall rewrites for current subprogram by setting 4595 + * fastcall_stack_off to a value smaller than any possible offset. 4596 4596 */ 4597 - subprog->nocsr_stack_off = S16_MIN; 4598 - /* reset nocsr aux flags within subprogram, 4597 + subprog->fastcall_stack_off = S16_MIN; 4598 + /* reset fastcall aux flags within subprogram, 4599 4599 * happens at most once per subprogram 4600 4600 */ 4601 4601 for (i = subprog->start; i < (subprog + 1)->start; ++i) { 4602 - aux[i].nocsr_spills_num = 0; 4603 - aux[i].nocsr_pattern = 0; 4602 + aux[i].fastcall_spills_num = 0; 4603 + aux[i].fastcall_pattern = 0; 4604 4604 } 4605 4605 } 4606 4606 ··· 4652 4652 if (err) 4653 4653 return err; 4654 4654 4655 - check_nocsr_stack_contract(env, state, insn_idx, off); 4655 + check_fastcall_stack_contract(env, state, insn_idx, off); 4656 4656 mark_stack_slot_scratched(env, spi); 4657 4657 if (reg && !(off % BPF_REG_SIZE) && reg->type == SCALAR_VALUE && env->bpf_capable) { 4658 4658 bool reg_value_fits; ··· 4787 4787 return err; 4788 4788 } 4789 4789 4790 - check_nocsr_stack_contract(env, state, insn_idx, min_off); 4790 + check_fastcall_stack_contract(env, state, insn_idx, min_off); 4791 4791 /* Variable offset writes destroy any spilled pointers in range. */ 4792 4792 for (i = min_off; i < max_off; i++) { 4793 4793 u8 new_type, *stype; ··· 4926 4926 reg = &reg_state->stack[spi].spilled_ptr; 4927 4927 4928 4928 mark_stack_slot_scratched(env, spi); 4929 - check_nocsr_stack_contract(env, state, env->insn_idx, off); 4929 + check_fastcall_stack_contract(env, state, env->insn_idx, off); 4930 4930 4931 4931 if (is_spilled_reg(&reg_state->stack[spi])) { 4932 4932 u8 spill_size = 1; ··· 5087 5087 min_off = reg->smin_value + off; 5088 5088 max_off = reg->smax_value + off; 5089 5089 mark_reg_stack_read(env, ptr_state, min_off, max_off + size, dst_regno); 5090 - check_nocsr_stack_contract(env, ptr_state, env->insn_idx, min_off); 5090 + check_fastcall_stack_contract(env, ptr_state, env->insn_idx, min_off); 5091 5091 return 0; 5092 5092 } 5093 5093 ··· 6804 6804 struct bpf_insn_aux_data *aux = &env->insn_aux_data[env->insn_idx]; 6805 6805 int min_valid_off, max_bpf_stack; 6806 6806 6807 - /* If accessing instruction is a spill/fill from nocsr pattern, 6807 + /* If accessing instruction is a spill/fill from bpf_fastcall pattern, 6808 6808 * add room for all caller saved registers below MAX_BPF_STACK. 6809 - * In case if nocsr rewrite won't happen maximal stack depth 6809 + * In case if bpf_fastcall rewrite won't happen maximal stack depth 6810 6810 * would be checked by check_max_stack_depth_subprog(). 6811 6811 */ 6812 6812 max_bpf_stack = MAX_BPF_STACK; 6813 - if (aux->nocsr_pattern) 6813 + if (aux->fastcall_pattern) 6814 6814 max_bpf_stack += CALLER_SAVED_REGS * BPF_REG_SIZE; 6815 6815 6816 6816 if (t == BPF_WRITE || env->allow_uninit_stack) ··· 16118 16118 16119 16119 /* Return a bitmask specifying which caller saved registers are 16120 16120 * clobbered by a call to a helper *as if* this helper follows 16121 - * no_caller_saved_registers contract: 16121 + * bpf_fastcall contract: 16122 16122 * - includes R0 if function is non-void; 16123 16123 * - includes R1-R5 if corresponding parameter has is described 16124 16124 * in the function prototype. 16125 16125 */ 16126 - static u32 helper_nocsr_clobber_mask(const struct bpf_func_proto *fn) 16126 + static u32 helper_fastcall_clobber_mask(const struct bpf_func_proto *fn) 16127 16127 { 16128 - u8 mask; 16128 + u32 mask; 16129 16129 int i; 16130 16130 16131 16131 mask = 0; ··· 16138 16138 } 16139 16139 16140 16140 /* True if do_misc_fixups() replaces calls to helper number 'imm', 16141 - * replacement patch is presumed to follow no_caller_saved_registers contract 16142 - * (see mark_nocsr_pattern_for_call() below). 16141 + * replacement patch is presumed to follow bpf_fastcall contract 16142 + * (see mark_fastcall_pattern_for_call() below). 16143 16143 */ 16144 16144 static bool verifier_inlines_helper_call(struct bpf_verifier_env *env, s32 imm) 16145 16145 { ··· 16153 16153 } 16154 16154 } 16155 16155 16156 - /* GCC and LLVM define a no_caller_saved_registers function attribute. 16156 + /* Same as helper_fastcall_clobber_mask() but for kfuncs, see comment above */ 16157 + static u32 kfunc_fastcall_clobber_mask(struct bpf_kfunc_call_arg_meta *meta) 16158 + { 16159 + u32 vlen, i, mask; 16160 + 16161 + vlen = btf_type_vlen(meta->func_proto); 16162 + mask = 0; 16163 + if (!btf_type_is_void(btf_type_by_id(meta->btf, meta->func_proto->type))) 16164 + mask |= BIT(BPF_REG_0); 16165 + for (i = 0; i < vlen; ++i) 16166 + mask |= BIT(BPF_REG_1 + i); 16167 + return mask; 16168 + } 16169 + 16170 + /* Same as verifier_inlines_helper_call() but for kfuncs, see comment above */ 16171 + static bool is_fastcall_kfunc_call(struct bpf_kfunc_call_arg_meta *meta) 16172 + { 16173 + if (meta->btf == btf_vmlinux) 16174 + return meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] || 16175 + meta->func_id == special_kfunc_list[KF_bpf_rdonly_cast]; 16176 + return false; 16177 + } 16178 + 16179 + /* LLVM define a bpf_fastcall function attribute. 16157 16180 * This attribute means that function scratches only some of 16158 16181 * the caller saved registers defined by ABI. 16159 16182 * For BPF the set of such registers could be defined as follows: ··· 16186 16163 * 16187 16164 * The contract between kernel and clang allows to simultaneously use 16188 16165 * such functions and maintain backwards compatibility with old 16189 - * kernels that don't understand no_caller_saved_registers calls 16190 - * (nocsr for short): 16166 + * kernels that don't understand bpf_fastcall calls: 16191 16167 * 16192 - * - for nocsr calls clang allocates registers as-if relevant r0-r5 16168 + * - for bpf_fastcall calls clang allocates registers as-if relevant r0-r5 16193 16169 * registers are not scratched by the call; 16194 16170 * 16195 - * - as a post-processing step, clang visits each nocsr call and adds 16171 + * - as a post-processing step, clang visits each bpf_fastcall call and adds 16196 16172 * spill/fill for every live r0-r5; 16197 16173 * 16198 16174 * - stack offsets used for the spill/fill are allocated as lowest ··· 16199 16177 * purposes; 16200 16178 * 16201 16179 * - when kernel loads a program, it looks for such patterns 16202 - * (nocsr function surrounded by spills/fills) and checks if 16203 - * spill/fill stack offsets are used exclusively in nocsr patterns; 16180 + * (bpf_fastcall function surrounded by spills/fills) and checks if 16181 + * spill/fill stack offsets are used exclusively in fastcall patterns; 16204 16182 * 16205 16183 * - if so, and if verifier or current JIT inlines the call to the 16206 - * nocsr function (e.g. a helper call), kernel removes unnecessary 16184 + * bpf_fastcall function (e.g. a helper call), kernel removes unnecessary 16207 16185 * spill/fill pairs; 16208 16186 * 16209 16187 * - when old kernel loads a program, presence of spill/fill pairs ··· 16222 16200 * r0 += r2; 16223 16201 * exit; 16224 16202 * 16225 - * The purpose of mark_nocsr_pattern_for_call is to: 16203 + * The purpose of mark_fastcall_pattern_for_call is to: 16226 16204 * - look for such patterns; 16227 - * - mark spill and fill instructions in env->insn_aux_data[*].nocsr_pattern; 16228 - * - mark set env->insn_aux_data[*].nocsr_spills_num for call instruction; 16229 - * - update env->subprog_info[*]->nocsr_stack_off to find an offset 16230 - * at which nocsr spill/fill stack slots start; 16231 - * - update env->subprog_info[*]->keep_nocsr_stack. 16205 + * - mark spill and fill instructions in env->insn_aux_data[*].fastcall_pattern; 16206 + * - mark set env->insn_aux_data[*].fastcall_spills_num for call instruction; 16207 + * - update env->subprog_info[*]->fastcall_stack_off to find an offset 16208 + * at which bpf_fastcall spill/fill stack slots start; 16209 + * - update env->subprog_info[*]->keep_fastcall_stack. 16232 16210 * 16233 - * The .nocsr_pattern and .nocsr_stack_off are used by 16234 - * check_nocsr_stack_contract() to check if every stack access to 16235 - * nocsr spill/fill stack slot originates from spill/fill 16236 - * instructions, members of nocsr patterns. 16211 + * The .fastcall_pattern and .fastcall_stack_off are used by 16212 + * check_fastcall_stack_contract() to check if every stack access to 16213 + * fastcall spill/fill stack slot originates from spill/fill 16214 + * instructions, members of fastcall patterns. 16237 16215 * 16238 - * If such condition holds true for a subprogram, nocsr patterns could 16239 - * be rewritten by remove_nocsr_spills_fills(). 16240 - * Otherwise nocsr patterns are not changed in the subprogram 16216 + * If such condition holds true for a subprogram, fastcall patterns could 16217 + * be rewritten by remove_fastcall_spills_fills(). 16218 + * Otherwise bpf_fastcall patterns are not changed in the subprogram 16241 16219 * (code, presumably, generated by an older clang version). 16242 16220 * 16243 16221 * For example, it is *not* safe to remove spill/fill below: ··· 16250 16228 * r0 += r1; exit; 16251 16229 * exit; 16252 16230 */ 16253 - static void mark_nocsr_pattern_for_call(struct bpf_verifier_env *env, 16254 - struct bpf_subprog_info *subprog, 16255 - int insn_idx, s16 lowest_off) 16231 + static void mark_fastcall_pattern_for_call(struct bpf_verifier_env *env, 16232 + struct bpf_subprog_info *subprog, 16233 + int insn_idx, s16 lowest_off) 16256 16234 { 16257 16235 struct bpf_insn *insns = env->prog->insnsi, *stx, *ldx; 16258 16236 struct bpf_insn *call = &env->prog->insnsi[insn_idx]; ··· 16267 16245 if (get_helper_proto(env, call->imm, &fn) < 0) 16268 16246 /* error would be reported later */ 16269 16247 return; 16270 - clobbered_regs_mask = helper_nocsr_clobber_mask(fn); 16271 - can_be_inlined = fn->allow_nocsr && 16248 + clobbered_regs_mask = helper_fastcall_clobber_mask(fn); 16249 + can_be_inlined = fn->allow_fastcall && 16272 16250 (verifier_inlines_helper_call(env, call->imm) || 16273 16251 bpf_jit_inlines_helper_call(call->imm)); 16252 + } 16253 + 16254 + if (bpf_pseudo_kfunc_call(call)) { 16255 + struct bpf_kfunc_call_arg_meta meta; 16256 + int err; 16257 + 16258 + err = fetch_kfunc_meta(env, call, &meta, NULL); 16259 + if (err < 0) 16260 + /* error would be reported later */ 16261 + return; 16262 + 16263 + clobbered_regs_mask = kfunc_fastcall_clobber_mask(&meta); 16264 + can_be_inlined = is_fastcall_kfunc_call(&meta); 16274 16265 } 16275 16266 16276 16267 if (clobbered_regs_mask == ALL_CALLER_SAVED_REGS) ··· 16324 16289 if (stx->off != off || ldx->off != off) 16325 16290 break; 16326 16291 expected_regs_mask &= ~BIT(stx->src_reg); 16327 - env->insn_aux_data[insn_idx - i].nocsr_pattern = 1; 16328 - env->insn_aux_data[insn_idx + i].nocsr_pattern = 1; 16292 + env->insn_aux_data[insn_idx - i].fastcall_pattern = 1; 16293 + env->insn_aux_data[insn_idx + i].fastcall_pattern = 1; 16329 16294 } 16330 16295 if (i == 1) 16331 16296 return; 16332 16297 16333 - /* Conditionally set 'nocsr_spills_num' to allow forward 16298 + /* Conditionally set 'fastcall_spills_num' to allow forward 16334 16299 * compatibility when more helper functions are marked as 16335 - * nocsr at compile time than current kernel supports, e.g: 16300 + * bpf_fastcall at compile time than current kernel supports, e.g: 16336 16301 * 16337 16302 * 1: *(u64 *)(r10 - 8) = r1 16338 - * 2: call A ;; assume A is nocsr for current kernel 16303 + * 2: call A ;; assume A is bpf_fastcall for current kernel 16339 16304 * 3: r1 = *(u64 *)(r10 - 8) 16340 16305 * 4: *(u64 *)(r10 - 8) = r1 16341 - * 5: call B ;; assume B is not nocsr for current kernel 16306 + * 5: call B ;; assume B is not bpf_fastcall for current kernel 16342 16307 * 6: r1 = *(u64 *)(r10 - 8) 16343 16308 * 16344 - * There is no need to block nocsr rewrite for such program. 16345 - * Set 'nocsr_pattern' for both calls to keep check_nocsr_stack_contract() happy, 16346 - * don't set 'nocsr_spills_num' for call B so that remove_nocsr_spills_fills() 16309 + * There is no need to block bpf_fastcall rewrite for such program. 16310 + * Set 'fastcall_pattern' for both calls to keep check_fastcall_stack_contract() happy, 16311 + * don't set 'fastcall_spills_num' for call B so that remove_fastcall_spills_fills() 16347 16312 * does not remove spill/fill pair {4,6}. 16348 16313 */ 16349 16314 if (can_be_inlined) 16350 - env->insn_aux_data[insn_idx].nocsr_spills_num = i - 1; 16315 + env->insn_aux_data[insn_idx].fastcall_spills_num = i - 1; 16351 16316 else 16352 - subprog->keep_nocsr_stack = 1; 16353 - subprog->nocsr_stack_off = min(subprog->nocsr_stack_off, off); 16317 + subprog->keep_fastcall_stack = 1; 16318 + subprog->fastcall_stack_off = min(subprog->fastcall_stack_off, off); 16354 16319 } 16355 16320 16356 - static int mark_nocsr_patterns(struct bpf_verifier_env *env) 16321 + static int mark_fastcall_patterns(struct bpf_verifier_env *env) 16357 16322 { 16358 16323 struct bpf_subprog_info *subprog = env->subprog_info; 16359 16324 struct bpf_insn *insn; ··· 16370 16335 continue; 16371 16336 lowest_off = min(lowest_off, insn->off); 16372 16337 } 16373 - /* use this offset to find nocsr patterns */ 16338 + /* use this offset to find fastcall patterns */ 16374 16339 for (i = subprog->start; i < (subprog + 1)->start; ++i) { 16375 16340 insn = env->prog->insnsi + i; 16376 16341 if (insn->code != (BPF_JMP | BPF_CALL)) 16377 16342 continue; 16378 - mark_nocsr_pattern_for_call(env, subprog, i, lowest_off); 16343 + mark_fastcall_pattern_for_call(env, subprog, i, lowest_off); 16379 16344 } 16380 16345 } 16381 16346 return 0; ··· 21279 21244 return 0; 21280 21245 } 21281 21246 21282 - /* Remove unnecessary spill/fill pairs, members of nocsr pattern, 21247 + /* Remove unnecessary spill/fill pairs, members of fastcall pattern, 21283 21248 * adjust subprograms stack depth when possible. 21284 21249 */ 21285 - static int remove_nocsr_spills_fills(struct bpf_verifier_env *env) 21250 + static int remove_fastcall_spills_fills(struct bpf_verifier_env *env) 21286 21251 { 21287 21252 struct bpf_subprog_info *subprog = env->subprog_info; 21288 21253 struct bpf_insn_aux_data *aux = env->insn_aux_data; ··· 21293 21258 int i, j; 21294 21259 21295 21260 for (i = 0; i < insn_cnt; i++, insn++) { 21296 - if (aux[i].nocsr_spills_num > 0) { 21297 - spills_num = aux[i].nocsr_spills_num; 21261 + if (aux[i].fastcall_spills_num > 0) { 21262 + spills_num = aux[i].fastcall_spills_num; 21298 21263 /* NOPs would be removed by opt_remove_nops() */ 21299 21264 for (j = 1; j <= spills_num; ++j) { 21300 21265 *(insn - j) = NOP; ··· 21303 21268 modified = true; 21304 21269 } 21305 21270 if ((subprog + 1)->start == i + 1) { 21306 - if (modified && !subprog->keep_nocsr_stack) 21307 - subprog->stack_depth = -subprog->nocsr_stack_off; 21271 + if (modified && !subprog->keep_fastcall_stack) 21272 + subprog->stack_depth = -subprog->fastcall_stack_off; 21308 21273 subprog++; 21309 21274 modified = false; 21310 21275 } ··· 22227 22192 if (ret < 0) 22228 22193 goto skip_full_check; 22229 22194 22230 - ret = mark_nocsr_patterns(env); 22195 + ret = mark_fastcall_patterns(env); 22231 22196 if (ret < 0) 22232 22197 goto skip_full_check; 22233 22198 ··· 22244 22209 * allocate additional slots. 22245 22210 */ 22246 22211 if (ret == 0) 22247 - ret = remove_nocsr_spills_fills(env); 22212 + ret = remove_fastcall_spills_fills(env); 22248 22213 22249 22214 if (ret == 0) 22250 22215 ret = check_max_stack_depth(env);
+2 -2
tools/testing/selftests/bpf/prog_tests/verifier.c
··· 53 53 #include "verifier_movsx.skel.h" 54 54 #include "verifier_netfilter_ctx.skel.h" 55 55 #include "verifier_netfilter_retcode.skel.h" 56 - #include "verifier_nocsr.skel.h" 56 + #include "verifier_bpf_fastcall.skel.h" 57 57 #include "verifier_or_jmp32_k.skel.h" 58 58 #include "verifier_precision.skel.h" 59 59 #include "verifier_prevent_map_lookup.skel.h" ··· 177 177 void test_verifier_movsx(void) { RUN(verifier_movsx); } 178 178 void test_verifier_netfilter_ctx(void) { RUN(verifier_netfilter_ctx); } 179 179 void test_verifier_netfilter_retcode(void) { RUN(verifier_netfilter_retcode); } 180 - void test_verifier_nocsr(void) { RUN(verifier_nocsr); } 180 + void test_verifier_bpf_fastcall(void) { RUN(verifier_bpf_fastcall); } 181 181 void test_verifier_or_jmp32_k(void) { RUN(verifier_or_jmp32_k); } 182 182 void test_verifier_precision(void) { RUN(verifier_precision); } 183 183 void test_verifier_prevent_map_lookup(void) { RUN(verifier_prevent_map_lookup); }
+68 -13
tools/testing/selftests/bpf/progs/verifier_nocsr.c tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
··· 2 2 3 3 #include <linux/bpf.h> 4 4 #include <bpf/bpf_helpers.h> 5 + #include <bpf/bpf_core_read.h> 5 6 #include "../../../include/linux/filter.h" 6 7 #include "bpf_misc.h" 8 + #include <stdbool.h> 9 + #include "bpf_kfuncs.h" 7 10 8 11 SEC("raw_tp") 9 12 __arch_x86_64 ··· 42 39 : __clobber_all); 43 40 } 44 41 45 - /* The logic for detecting and verifying nocsr pattern is the same for 42 + /* The logic for detecting and verifying bpf_fastcall pattern is the same for 46 43 * any arch, however x86 differs from arm64 or riscv64 in a way 47 44 * bpf_get_smp_processor_id is rewritten: 48 45 * - on x86 it is done by verifier ··· 55 52 * 56 53 * It is really desirable to check instruction indexes in the xlated 57 54 * patterns, so add this canary test to check that function rewrite by 58 - * jit is correctly processed by nocsr logic, keep the rest of the 55 + * jit is correctly processed by bpf_fastcall logic, keep the rest of the 59 56 * tests as x86. 60 57 */ 61 58 SEC("raw_tp") ··· 466 463 { 467 464 asm volatile ( 468 465 "r0 = 1;" 469 - "*(u64 *)(r1 - 0) = r0;" /* invalidates nocsr contract for caller: */ 466 + "*(u64 *)(r1 - 0) = r0;" /* invalidates bpf_fastcall contract for caller: */ 470 467 "exit;" /* caller stack at -8 used outside of the pattern */ 471 468 ::: __clobber_all); 472 469 } ··· 483 480 { 484 481 asm volatile ( 485 482 "r1 = 1;" 486 - /* nocsr pattern with stack offset -8 */ 483 + /* bpf_fastcall pattern with stack offset -8 */ 487 484 "*(u64 *)(r10 - 8) = r1;" 488 485 "call %[bpf_get_smp_processor_id];" 489 486 "r1 = *(u64 *)(r10 - 8);" ··· 491 488 "r1 += -8;" 492 489 "r2 = 1;" 493 490 "r3 = 42;" 494 - /* read dst is fp[-8], thus nocsr rewrite not applied */ 491 + /* read dst is fp[-8], thus bpf_fastcall rewrite not applied */ 495 492 "call %[bpf_probe_read_kernel];" 496 493 "exit;" 497 494 : ··· 601 598 __log_level(4) __msg("stack depth 8") 602 599 __xlated("2: r0 = &(void __percpu *)(r0)") 603 600 __success 604 - __naked void helper_call_does_not_prevent_nocsr(void) 601 + __naked void helper_call_does_not_prevent_bpf_fastcall(void) 605 602 { 606 603 asm volatile ( 607 604 "r1 = 1;" ··· 692 689 { 693 690 asm volatile ( 694 691 "r1 = 1;" 695 - /* nocsr stack region at -16, but could be removed */ 692 + /* bpf_fastcall stack region at -16, but could be removed */ 696 693 "*(u64 *)(r10 - 16) = r1;" 697 694 "call %[bpf_get_smp_processor_id];" 698 695 "r1 = *(u64 *)(r10 - 16);" ··· 732 729 { 733 730 asm volatile ( 734 731 "r1 = 42;" 735 - /* nocsr stack region at -16, cannot be removed */ 732 + /* bpf_fastcall stack region at -16, cannot be removed */ 736 733 "*(u64 *)(r10 - 16) = r1;" 737 734 "call %[bpf_get_smp_processor_id];" 738 735 "r1 = *(u64 *)(r10 - 16);" ··· 762 759 __xlated("r0 = &(void __percpu *)(r0)") 763 760 __success 764 761 /* cumulative_stack_depth() stack usage is MAX_BPF_STACK, 765 - * called subprogram uses an additional slot for nocsr spill/fill, 766 - * since nocsr spill/fill could be removed the program still fits 762 + * called subprogram uses an additional slot for bpf_fastcall spill/fill, 763 + * since bpf_fastcall spill/fill could be removed the program still fits 767 764 * in MAX_BPF_STACK and should be accepted. 768 765 */ 769 766 __naked int cumulative_stack_depth(void) ··· 801 798 __xlated("4: r0 = *(u32 *)(r0 +0)") 802 799 __xlated("5: exit") 803 800 __success 804 - __naked int nocsr_max_stack_ok(void) 801 + __naked int bpf_fastcall_max_stack_ok(void) 805 802 { 806 803 asm volatile( 807 804 "r1 = 42;" ··· 823 820 __log_level(4) 824 821 __msg("stack depth 520") 825 822 __failure 826 - __naked int nocsr_max_stack_fail(void) 823 + __naked int bpf_fastcall_max_stack_fail(void) 827 824 { 828 825 asm volatile( 829 826 "r1 = 42;" ··· 831 828 "*(u64 *)(r10 - %[max_bpf_stack_8]) = r1;" 832 829 "call %[bpf_get_smp_processor_id];" 833 830 "r1 = *(u64 *)(r10 - %[max_bpf_stack_8]);" 834 - /* call to prandom blocks nocsr rewrite */ 831 + /* call to prandom blocks bpf_fastcall rewrite */ 835 832 "*(u64 *)(r10 - %[max_bpf_stack_8]) = r1;" 836 833 "call %[bpf_get_prandom_u32];" 837 834 "r1 = *(u64 *)(r10 - %[max_bpf_stack_8]);" ··· 843 840 __imm(bpf_get_prandom_u32) 844 841 : __clobber_all 845 842 ); 843 + } 844 + 845 + SEC("cgroup/getsockname_unix") 846 + __xlated("0: r2 = 1") 847 + /* bpf_cast_to_kern_ctx is replaced by a single assignment */ 848 + __xlated("1: r0 = r1") 849 + __xlated("2: r0 = r2") 850 + __xlated("3: exit") 851 + __success 852 + __naked void kfunc_bpf_cast_to_kern_ctx(void) 853 + { 854 + asm volatile ( 855 + "r2 = 1;" 856 + "*(u64 *)(r10 - 32) = r2;" 857 + "call %[bpf_cast_to_kern_ctx];" 858 + "r2 = *(u64 *)(r10 - 32);" 859 + "r0 = r2;" 860 + "exit;" 861 + : 862 + : __imm(bpf_cast_to_kern_ctx) 863 + : __clobber_all); 864 + } 865 + 866 + SEC("raw_tp") 867 + __xlated("3: r3 = 1") 868 + /* bpf_rdonly_cast is replaced by a single assignment */ 869 + __xlated("4: r0 = r1") 870 + __xlated("5: r0 = r3") 871 + void kfunc_bpf_rdonly_cast(void) 872 + { 873 + asm volatile ( 874 + "r2 = %[btf_id];" 875 + "r3 = 1;" 876 + "*(u64 *)(r10 - 32) = r3;" 877 + "call %[bpf_rdonly_cast];" 878 + "r3 = *(u64 *)(r10 - 32);" 879 + "r0 = r3;" 880 + : 881 + : __imm(bpf_rdonly_cast), 882 + [btf_id]"r"(bpf_core_type_id_kernel(union bpf_attr)) 883 + : __clobber_common); 884 + } 885 + 886 + /* BTF FUNC records are not generated for kfuncs referenced 887 + * from inline assembly. These records are necessary for 888 + * libbpf to link the program. The function below is a hack 889 + * to ensure that BTF FUNC records are generated. 890 + */ 891 + void kfunc_root(void) 892 + { 893 + bpf_cast_to_kern_ctx(0); 894 + bpf_rdonly_cast(0, 0); 846 895 } 847 896 848 897 char _license[] SEC("license") = "GPL";
+1 -1
tools/testing/selftests/bpf/test_loader.c
··· 543 543 } 544 544 } 545 545 546 - spec->arch_mask = arch_mask; 546 + spec->arch_mask = arch_mask ?: -1; 547 547 548 548 if (spec->mode_mask == 0) 549 549 spec->mode_mask = PRIV;