On Mon, Mar 3, 2025 at 4:32 PM Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx> wrote: > > +u64 bpf_check_timed_may_goto(struct bpf_timed_may_goto *p) > +{ > + u64 time = ktime_get_mono_fast_ns(); > + > + /* > + * Populate the timestamp for this stack frame, and refresh count. > + */ > + if (!p->timestamp) { > + p->timestamp = time; > + return BPF_MAX_TIMED_LOOPS; > + } > + /* > + * Check if we've exhausted our time slice, and zero count. > + */ > + if (time - p->timestamp >= (NSEC_PER_SEC / 4)) > + return 0; > + /* > + * Refresh the count for the stack frame. > + */ I converted the comments back to single line comments. > + return BPF_MAX_TIMED_LOOPS; > +} > + > /* for configs without MMU or 32-bit */ > __weak const struct bpf_map_ops arena_map_ops; > __weak u64 bpf_arena_get_user_vm_start(struct bpf_arena *arena) > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index 22c4edc8695c..f3e95d471fa3 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -21572,7 +21572,50 @@ static int do_misc_fixups(struct bpf_verifier_env *env) > goto next_insn; > } > > - if (is_may_goto_insn(insn)) { > + if (is_may_goto_insn(insn) && bpf_jit_supports_timed_may_goto()) { > + int stack_off_cnt = -stack_depth - 16; > + > + /* > + * Two 8 byte slots, depth-16 stores the count, and > + * depth-8 stores the start timestamp of the loop. > + * > + * The starting value of count is BPF_MAX_TIMED_LOOPS > + * (0xffff). Every iteration loads it and subs it by 1, > + * until the value becomes 0 in AX (thus, 1 in stack), > + * after which we call arch_bpf_timed_may_goto, which > + * either sets AX to 0xffff to keep looping, or to 0 > + * upon timeout. AX is then stored into the stack. In > + * the next iteration, we either see 0 and break out, or > + * continue iterating until the next time value is 0 > + * after subtraction, rinse and repeat. > + */ > + stack_depth_extra = 16; > + insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_AX, BPF_REG_10, stack_off_cnt); > + if (insn->off >= 0) > + insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off + 5); > + else > + insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off - 1); > + insn_buf[2] = BPF_ALU64_IMM(BPF_SUB, BPF_REG_AX, 1); > + insn_buf[3] = BPF_JMP_IMM(BPF_JNE, BPF_REG_AX, 0, 2); > + /* > + * AX is used as an argument to pass in stack_off_cnt > + * (to add to r10/fp), and also as the return value of > + * the call to arch_bpf_timed_may_goto. > + */ > + insn_buf[4] = BPF_MOV64_IMM(BPF_REG_AX, stack_off_cnt); > + insn_buf[5] = BPF_EMIT_CALL(arch_bpf_timed_may_goto); > + insn_buf[6] = BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_AX, stack_off_cnt); > + cnt = 7; > + > + new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); > + if (!new_prog) > + return -ENOMEM; > + > + delta += cnt - 1; > + env->prog = prog = new_prog; > + insn = new_prog->insnsi + i + delta; > + goto next_insn; > + } else if (is_may_goto_insn(insn)) { > int stack_off = -stack_depth - 8; > > stack_depth_extra = 8; > @@ -22113,23 +22156,34 @@ static int do_misc_fixups(struct bpf_verifier_env *env) > > env->prog->aux->stack_depth = subprogs[0].stack_depth; > for (i = 0; i < env->subprog_cnt; i++) { > + int delta = bpf_jit_supports_timed_may_goto() ? 2 : 1; > int subprog_start = subprogs[i].start; > int stack_slots = subprogs[i].stack_extra / 8; > + int slots = delta, cnt = 0; > > if (!stack_slots) > continue; > - if (stack_slots > 1) { > + /* > + * We need two slots in case timed may_goto is supported. > + */ > + if (stack_slots > slots) { > verbose(env, "verifier bug: stack_slots supports may_goto only\n"); > return -EFAULT; > } > > - /* Add ST insn to subprog prologue to init extra stack */ > - insn_buf[0] = BPF_ST_MEM(BPF_DW, BPF_REG_FP, > - -subprogs[i].stack_depth, BPF_MAX_LOOPS); and here added stack_depth = subprogs[i].stack_depth; to reduce copy paste in below lines... > + if (bpf_jit_supports_timed_may_goto()) { > + insn_buf[cnt++] = BPF_ST_MEM(BPF_DW, BPF_REG_FP, -subprogs[i].stack_depth, > + BPF_MAX_TIMED_LOOPS); > + insn_buf[cnt++] = BPF_ST_MEM(BPF_DW, BPF_REG_FP, -subprogs[i].stack_depth + 8, 0); > + } else { > + /* Add ST insn to subprog prologue to init extra stack */ > + insn_buf[cnt++] = BPF_ST_MEM(BPF_DW, BPF_REG_FP, -subprogs[i].stack_depth, > + BPF_MAX_LOOPS); > + } and applied.