All of lore.kernel.org
 help / color / mirror / Atom feed
* [bug report] bpf: Inline calls to bpf_loop when callback is known
@ 2022-06-23  8:21 Dan Carpenter
  2022-06-23  9:05 ` Eduard Zingerman
  0 siblings, 1 reply; 3+ messages in thread
From: Dan Carpenter @ 2022-06-23  8:21 UTC (permalink / raw)
  To: eddyz87; +Cc: bpf

Hello Eduard Zingerman,

The patch 1ade23711971: "bpf: Inline calls to bpf_loop when callback
is known" from Jun 21, 2022, leads to the following Smatch static
checker warning:

	kernel/bpf/verifier.c:14420 inline_bpf_loop()
	error: dereferencing freed memory 'env->prog'

kernel/bpf/verifier.c
    14350 static struct bpf_prog *inline_bpf_loop(struct bpf_verifier_env *env,
    14351                                         int position,
    14352                                         s32 stack_base,
    14353                                         u32 callback_subprogno,
    14354                                         u32 *cnt)
    14355 {
    14356         s32 r6_offset = stack_base + 0 * BPF_REG_SIZE;
    14357         s32 r7_offset = stack_base + 1 * BPF_REG_SIZE;
    14358         s32 r8_offset = stack_base + 2 * BPF_REG_SIZE;
    14359         int reg_loop_max = BPF_REG_6;
    14360         int reg_loop_cnt = BPF_REG_7;
    14361         int reg_loop_ctx = BPF_REG_8;
    14362 
    14363         struct bpf_prog *new_prog;
    14364         u32 callback_start;
    14365         u32 call_insn_offset;
    14366         s32 callback_offset;
    14367 
    14368         /* This represents an inlined version of bpf_iter.c:bpf_loop,
    14369          * be careful to modify this code in sync.
    14370          */
    14371         struct bpf_insn insn_buf[] = {
    14372                 /* Return error and jump to the end of the patch if
    14373                  * expected number of iterations is too big.
    14374                  */
    14375                 BPF_JMP_IMM(BPF_JLE, BPF_REG_1, BPF_MAX_LOOPS, 2),
    14376                 BPF_MOV32_IMM(BPF_REG_0, -E2BIG),
    14377                 BPF_JMP_IMM(BPF_JA, 0, 0, 16),
    14378                 /* spill R6, R7, R8 to use these as loop vars */
    14379                 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_6, r6_offset),
    14380                 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_7, r7_offset),
    14381                 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_8, r8_offset),
    14382                 /* initialize loop vars */
    14383                 BPF_MOV64_REG(reg_loop_max, BPF_REG_1),
    14384                 BPF_MOV32_IMM(reg_loop_cnt, 0),
    14385                 BPF_MOV64_REG(reg_loop_ctx, BPF_REG_3),
    14386                 /* loop header,
    14387                  * if reg_loop_cnt >= reg_loop_max skip the loop body
    14388                  */
    14389                 BPF_JMP_REG(BPF_JGE, reg_loop_cnt, reg_loop_max, 5),
    14390                 /* callback call,
    14391                  * correct callback offset would be set after patching
    14392                  */
    14393                 BPF_MOV64_REG(BPF_REG_1, reg_loop_cnt),
    14394                 BPF_MOV64_REG(BPF_REG_2, reg_loop_ctx),
    14395                 BPF_CALL_REL(0),
    14396                 /* increment loop counter */
    14397                 BPF_ALU64_IMM(BPF_ADD, reg_loop_cnt, 1),
    14398                 /* jump to loop header if callback returned 0 */
    14399                 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, -6),
    14400                 /* return value of bpf_loop,
    14401                  * set R0 to the number of iterations
    14402                  */
    14403                 BPF_MOV64_REG(BPF_REG_0, reg_loop_cnt),
    14404                 /* restore original values of R6, R7, R8 */
    14405                 BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, r6_offset),
    14406                 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_10, r7_offset),
    14407                 BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_10, r8_offset),
    14408         };
    14409 
    14410         *cnt = ARRAY_SIZE(insn_buf);
    14411         new_prog = bpf_patch_insn_data(env, position, insn_buf, *cnt);

The bpf_patch_insn_data() function sometimes frees the old "env->prog"
and returns "new_prog".

    14412         if (!new_prog)
    14413                 return new_prog;
    14414 
    14415         /* callback start is known only after patching */
    14416         callback_start = env->subprog_info[callback_subprogno].start;
    14417         /* Note: insn_buf[12] is an offset of BPF_CALL_REL instruction */
    14418         call_insn_offset = position + 12;
    14419         callback_offset = callback_start - call_insn_offset - 1;
--> 14420         env->prog->insnsi[call_insn_offset].imm = callback_offset;

Presumably somewhere there is a "env->prog = new_prog;" but I couldn't
spot it in bpf_patch_insn_data().  But it feels like it would be more
readable to say:

	new_prog->insnsi[call_insn_offset].imm = callback_offset;


    14421 
    14422         return new_prog;
    14423 }

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [bug report] bpf: Inline calls to bpf_loop when callback is known
  2022-06-23  8:21 [bug report] bpf: Inline calls to bpf_loop when callback is known Dan Carpenter
@ 2022-06-23  9:05 ` Eduard Zingerman
  2022-06-23 21:09   ` Alexei Starovoitov
  0 siblings, 1 reply; 3+ messages in thread
From: Eduard Zingerman @ 2022-06-23  9:05 UTC (permalink / raw)
  To: Dan Carpenter, ast; +Cc: bpf

> On Thu, 2022-06-23 at 11:21 +0300, Dan Carpenter wrote:
> Hello Eduard Zingerman,
> 
> The patch 1ade23711971: "bpf: Inline calls to bpf_loop when callback
> is known" from Jun 21, 2022, leads to the following Smatch static
> checker warning:
> 
> 	kernel/bpf/verifier.c:14420 inline_bpf_loop()
> 	error: dereferencing freed memory 'env->prog'
> 
> kernel/bpf/verifier.c
>     14350 static struct bpf_prog *inline_bpf_loop(...)
[...]
>     14411         new_prog = bpf_patch_insn_data(env, position, insn_buf, *cnt);
> 
> The bpf_patch_insn_data() function sometimes frees the old "env->prog"
> and returns "new_prog".
> 
>     14412         if (!new_prog)
>     14413                 return new_prog;
>     14414 
>     14415         /* callback start is known only after patching */
>     14416         callback_start = env->subprog_info[callback_subprogno].start;
>     14417         /* Note: insn_buf[12] is an offset of BPF_CALL_REL instruction */
>     14418         call_insn_offset = position + 12;
>     14419         callback_offset = callback_start - call_insn_offset - 1;
> --> 14420         env->prog->insnsi[call_insn_offset].imm = callback_offset;

Hi Dan,

Thank you for the report, you are correct!

> Presumably somewhere there is a "env->prog = new_prog;"

This assignment is inside `optimize_bpf_loop` right after the call to
`inline_bpf_loop`.

> But it feels like it would be more readable to say:
> 
> 	new_prog->insnsi[call_insn_offset].imm = callback_offset;

Yes, I agree.

Alexei, could you please suggest how should I proceed:
- submit a new patch with a fix, or
- submit a the complete patchset with the fix included?

Thanks,
Eduard

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [bug report] bpf: Inline calls to bpf_loop when callback is known
  2022-06-23  9:05 ` Eduard Zingerman
@ 2022-06-23 21:09   ` Alexei Starovoitov
  0 siblings, 0 replies; 3+ messages in thread
From: Alexei Starovoitov @ 2022-06-23 21:09 UTC (permalink / raw)
  To: Eduard Zingerman; +Cc: Dan Carpenter, Alexei Starovoitov, bpf

On Thu, Jun 23, 2022 at 2:05 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
call_insn_offset - 1;
> > --> 14420         env->prog->insnsi[call_insn_offset].imm = callback_offset;
...
> >
> >       new_prog->insnsi[call_insn_offset].imm = callback_offset;
>
> Yes, I agree.

Good catch. The fix makes sense.

>
> Alexei, could you please suggest how should I proceed:
> - submit a new patch with a fix, or
> - submit a the complete patchset with the fix included?

The patchset already landed (see bpf-next). We don't revert
for cases like this. Please send a follow up patch.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-06-23 21:10 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-23  8:21 [bug report] bpf: Inline calls to bpf_loop when callback is known Dan Carpenter
2022-06-23  9:05 ` Eduard Zingerman
2022-06-23 21:09   ` Alexei Starovoitov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.