All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eduard Zingerman <eddyz87@gmail.com>
To: bpf@vger.kernel.org, ast@kernel.org, andrii@kernel.org
Cc: daniel@iogearbox.net, martin.lau@linux.dev, kernel-team@fb.com,
	 yonghong.song@linux.dev,
	Alexei Starovoitov <alexei.starovoitov@gmail.com>
Subject: Re: [PATCH bpf-next v1 2/2] bpf: use realloc in bpf_patch_insn_data
Date: Wed, 06 Aug 2025 16:54:12 -0700	[thread overview]
Message-ID: <28f5fbaa5703e1ba2f4bb1648962aeb045f7b985.camel@gmail.com> (raw)
In-Reply-To: <4ad7e189907669e140553fba42759e97c691bfa0.camel@gmail.com>

On Wed, 2025-08-06 at 16:04 -0700, Eduard Zingerman wrote:
> On Wed, 2025-08-06 at 13:09 -0700, Eduard Zingerman wrote:
>
> [...]
>
> > @@ -20712,22 +20711,19 @@ static void adjust_insn_aux_data(struct bpf_verifier_env *env,
> >  	 * (cnt == 1) is taken or not. There is no guarantee INSN at OFF is the
> >  	 * original insn at old prog.
> >  	 */
> > -	old_data[off].zext_dst = insn_has_def32(insn + off + cnt - 1);
> > +	data[off].zext_dst = insn_has_def32(insn + off + cnt - 1);
> >
> >  	if (cnt == 1)
> >  		return;
> >  	prog_len = new_prog->len;
> >
> > -	memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
> > -	memcpy(new_data + off + cnt - 1, old_data + off,
> > -	       sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
> > +	memmove(data + off + cnt - 1, data + off,
> > +		sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
> >  	for (i = off; i < off + cnt - 1; i++) {
> >  		/* Expand insni[off]'s seen count to the patched range. */
> > -		new_data[i].seen = old_seen;
> > -		new_data[i].zext_dst = insn_has_def32(insn + i);
> > +		data[i].seen = old_seen;
> > +		data[i].zext_dst = insn_has_def32(insn + i);
> >  	}
> > -	env->insn_aux_data = new_data;
> > -	vfree(old_data);
> >  }
>
> veristat-meta job failed on the CI [1] because the following piece is missing:
>
>   @@ -20719,6 +20719,7 @@ static void adjust_insn_aux_data(struct bpf_verifier_env *env,
>
>           memmove(data + off + cnt - 1, data + off,
>                   sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
>   +       memset(data + off, 0, sizeof(struct bpf_insn_aux_data) * (cnt - 1));
>           for (i = off; i < off + cnt - 1; i++) {
>                   /* Expand insni[off]'s seen count to the patched range. */
>                   data[i].seen = old_seen;
>
> I'm trying to figure out if I can add a selftest for this.
>
> [1] https://github.com/kernel-patches/bpf/actions/runs/16787563163/job/47542309875
>
> [...]

The error reported by verifier is "verifier bug: error during ctx access conversion (0)",
signaled from convert_ctx_accesses(). The rewrite is attempted because
`env->insn_aux_data[i + delta].ptr_type` is set to 12 (PTR_TO_SOCK_COMMON).
The instruction for which rewrite is attempted is a load or store
instruction introduced as a result of inline_bpf_loop() call.
It has a wrong offset for bpf_sock_convert_ctx_access() rewrite,
hence rewrite attempt is unsuccessful and the above mentioned error is reported.
`env->insn_aux_data[i + delta].ptr_type` is set for the instruction in question
because of missing memset(0). It is a value of the insn_aux_data inherited
from an instruction occurring at a small offset after bpf_loop call.

Here is a similar reproducer, but for PTR_TO_CTX (== 2):

  struct { ... } map0 SEC(".maps"); // any valid map definition
  struct { ... } map1 SEC(".maps");
  struct { ... } map2 SEC(".maps");
  
  SEC("xdp")
  __success
  __naked void bug1(void)
  {
          asm volatile ("                                 \
          r0 = %[map0] ll;       /* 0 */                  \
          r0 = %[map1] ll;       /* 2 */                  \
          r1 = 1;                /* 4 */                  \
          r2 = dummy ll;         /* 5 */                  \
          r3 = 0;                /* 7 */                  \
          r4 = 0;                /* 8 */                  \
          call %[bpf_loop];      /* 9 */                  \
          r0 = 0;                /* 10 */                 \
          r0 = 0;                /* 11 */                 \
          r0 = %[map2] ll;       /* 12 */                 \
          exit;                                           \
  "       :
          : __imm(bpf_loop),
            __imm_addr(map0),
            __imm_addr(map1),
            __imm_addr(map2)
          : __clobber_all);
  }

Instruction `call %[bpf_loop]` is replaced by a sequence:

  9:  if r1 <= 0x800000 goto pc+2
  10: w0 = -7
  11: goto pc+16
  12: *(u64 *)(r10 -24) = r6
  ...

Note the store at offset (12). Because of the missing memset(0) it
inherits insn_aux_data fields from original instruction #12: `r0 = %[map2] ll`.
`struct bpf_insn_aux_data` is defined as follows:

   struct bpf_insn_aux_data {
         union {
                 enum bpf_reg_type ptr_type;
				 ...
                 struct {
                         u32 map_index;          /* index into used_maps[] */
                         ...
                 };
				 ...
         };
   }

Here fields .ptr_type and .map_index have same offset.
The example above forces convert_ctx_accesses() to interpret .map_index as a .ptr_type.
The .map_index at offset 12 happens to be 2, which corresponds to PTR_TO_CTX.
convert_ctx_accesses() attempts to rewrite `12: *(u64 *)(r10 -24) = r6` and fails.

All in all, I think this test is fragile, so I'll post v2 w/o a selftest.

      reply	other threads:[~2025-08-06 23:54 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-06 20:09 [PATCH bpf-next v1 1/2] bpf: removed unused 'env' parameter from is_reg64 and insn_has_def32 Eduard Zingerman
2025-08-06 20:09 ` [PATCH bpf-next v1 2/2] bpf: use realloc in bpf_patch_insn_data Eduard Zingerman
2025-08-06 23:04   ` Eduard Zingerman
2025-08-06 23:54     ` Eduard Zingerman [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=28f5fbaa5703e1ba2f4bb1648962aeb045f7b985.camel@gmail.com \
    --to=eddyz87@gmail.com \
    --cc=alexei.starovoitov@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=kernel-team@fb.com \
    --cc=martin.lau@linux.dev \
    --cc=yonghong.song@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.