> -----Original Message-----
> From: Intel-wired-lan <[email protected]> On Behalf Of
> Loktionov, Aleksandr
> Sent: Wednesday, June 17, 2026 10:22 PM
> To: Michael Bommarito <[email protected]>; Nguyen, Anthony
> L <[email protected]>; Kitszel, Przemyslaw
> <[email protected]>; Hay, Joshua A <[email protected]>;
> Pavan Kumar Linga <[email protected]>; Andrew Lunn
> <[email protected]>; David S . Miller <[email protected]>; Eric
> Dumazet <[email protected]>; Jakub Kicinski <[email protected]>; Paolo
> Abeni <[email protected]>
> Cc: [email protected]; [email protected]; linux-
> [email protected]
> Subject: Re: [Intel-wired-lan] [PATCH] idpf: bound interrupt-vector register 
> fill
> to the allocated array
> 
> 
> 
> > -----Original Message-----
> > From: Intel-wired-lan <[email protected]> On Behalf
> > Of Michael Bommarito
> > Sent: Wednesday, June 17, 2026 11:58 PM
> > To: Nguyen, Anthony L <[email protected]>; Kitszel,
> > Przemyslaw <[email protected]>; Hay, Joshua A
> > <[email protected]>; Pavan Kumar Linga
> > <[email protected]>; Andrew Lunn <[email protected]>;
> > David S . Miller <[email protected]>; Eric Dumazet
> > <[email protected]>; Jakub Kicinski <[email protected]>; Paolo Abeni
> > <[email protected]>
> > Cc: [email protected]; [email protected]; linux-
> > [email protected]
> > Subject: [Intel-wired-lan] [PATCH] idpf: bound interrupt-vector
> > register fill to the allocated array
> >
> > idpf_get_reg_intr_vecs() fills the caller-allocated reg_vals[] array
> > from the VIRTCHNL2_OP_ALLOC_VECTORS reply in adapter-
> >req_vec_chunks,
> > bounding its inner loop only by the per-chunk num_vectors. The array
> > is sized
> > separately: idpf_intr_reg_init() allocates kzalloc_objs(struct
> > idpf_vec_regs, total_vecs) from caps.num_allocated_vectors and only
> > checks the returned count after the fill. The sum of per-chunk
> > num_vectors is never reconciled against total_vecs, so a reply with a
> > small num_allocated_vectors but chunks summing higher writes past the
> > end of reg_vals[].
> >
> > Impact: a control plane (a PF or hypervisor device model) that returns
> > a VIRTCHNL2_OP_ALLOC_VECTORS reply whose per-chunk num_vectors
> sum
> > exceeds num_allocated_vectors writes struct idpf_vec_regs entries past
> > the end of the reg_vals kmalloc allocation (KASAN slab-out-of-bounds
> > write).
> >
> > Bound the fill loop to the array capacity passed in by the callers,
> > mirroring the sibling idpf_vport_get_q_reg(). The existing num_regs <
> > num_vecs check then rejects an undersized reply without the out-of-
> > bounds write happening first.
> >
> > Fixes: d4d558718266 ("idpf: initialize interrupts and enable vport")
> > Assisted-by: Claude:claude-opus-4-7
> > Signed-off-by: Michael Bommarito <[email protected]>
> > ---
> > The reply originates from the control plane (a PF or hypervisor device
> > model), which is trusted in a standard deployment, so this is a
> > defense-in-depth / robustness fix: it bounds a malformed or internally
> > inconsistent ALLOC_VECTORS reply. It is a genuine trust-boundary
> > crossing only where the guest distrusts the control plane (a
> > confidential VM or an Intel IPU posture) or the control plane is
> > simply buggy. It is not remotely or unprivileged-reachable.
> >
> > Reproduced with a KUnit harness that calls the unmodified
> > idpf_get_reg_intr_vecs() against a crafted req_vec_chunks reply
> > (num_allocated_vectors = 1, four chunks of sixteen vectors) under
> > KASAN:
> > stock reports a slab-out-of-bounds write 0 bytes past a 12-byte
> > kmalloc-16 object and the test fails; the patched build is KASAN-
> > clean; a well-formed 64-vector reply still fills 64 entries on both.
> > The KUnit wiring is repro-only scaffolding, not part of this patch;
> > harness on request.
> >
> >  drivers/net/ethernet/intel/idpf/idpf_dev.c      | 2 +-
> >  drivers/net/ethernet/intel/idpf/idpf_vf_dev.c   | 2 +-
> >  drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 5 +++--
> > drivers/net/ethernet/intel/idpf/idpf_virtchnl.h | 2 +-
> >  4 files changed, 6 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c
> > b/drivers/net/ethernet/intel/idpf/idpf_dev.c
> > index 1a0c71c95ef12..4079a787657f1 100644
> > --- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
> > +++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
> > @@ -87,7 +87,7 @@ static int idpf_intr_reg_init(struct idpf_vport
> > *vport,
> >     if (!reg_vals)
> >             return -ENOMEM;
> >
> > -   num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals);
> > +   num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals,
> > total_vecs);
> >     if (num_regs < num_vecs) {
> >             err = -EINVAL;
> >             goto free_reg_vals;
> > diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> > b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> > index a07d7e808ca9b..6726084f6cfa0 100644
> > --- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> > +++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
> > @@ -86,7 +86,7 @@ static int idpf_vf_intr_reg_init(struct idpf_vport
> > *vport,
> >     if (!reg_vals)
> >             return -ENOMEM;
> >
> > -   num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals);
> > +   num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals,
> > total_vecs);
> >     if (num_regs < num_vecs) {
> >             err = -EINVAL;
> >             goto free_reg_vals;
> > diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
> > b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
> > index be66f9b2e101c..ec7330603ff84 100644
> > --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
> > +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
> > @@ -1318,11 +1318,12 @@ idpf_vport_init_queue_reg_chunks(struct
> > idpf_vport_config *vport_config,
> >   * idpf_get_reg_intr_vecs - Get vector queue register offset
> >   * @adapter: adapter structure to get the vector chunks
> >   * @reg_vals: Register offsets to store in
> > + * @num_vecs: number of entries the @reg_vals array can hold
> >   *
> >   * Return: number of registers that got populated
> >   */
> >  int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
> > -                      struct idpf_vec_regs *reg_vals)
> > +                      struct idpf_vec_regs *reg_vals, int num_vecs)
> >  {
> >     struct virtchnl2_vector_chunks *chunks;
> >     struct idpf_vec_regs reg_val;
> > @@ -1346,7 +1347,7 @@ int idpf_get_reg_intr_vecs(struct idpf_adapter
> > *adapter,
> >             dynctl_reg_spacing = le32_to_cpu(chunk-
> > >dynctl_reg_spacing);
> >             itrn_reg_spacing = le32_to_cpu(chunk->itrn_reg_spacing);
> >
> > -           for (i = 0; i < num_vec; i++) {
> > +           for (i = 0; i < num_vec && num_regs < num_vecs; i++) {
> >                     reg_vals[num_regs].dyn_ctl_reg =
> > reg_val.dyn_ctl_reg;
> >                     reg_vals[num_regs].itrn_reg = reg_val.itrn_reg;
> >                     reg_vals[num_regs].itrn_index_spacing = diff -- git
> > a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
> > b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
> > index 6876e3ed9d1be..9b1c9c86f6eac 100644
> > --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
> > +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
> > @@ -104,7 +104,7 @@ int idpf_vc_core_init(struct idpf_adapter
> > *adapter);  void idpf_vc_core_deinit(struct idpf_adapter *adapter);
> >
> >  int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
> > -                      struct idpf_vec_regs *reg_vals);
> > +                      struct idpf_vec_regs *reg_vals, int num_vecs);
> >  int idpf_queue_reg_init(struct idpf_vport *vport,
> >                     struct idpf_q_vec_rsrc *rsrc,
> >                     struct idpf_queue_id_reg_info *chunks);
> > --
> > 2.53.0
> 
> Reviewed-by: Aleksandr Loktionov <[email protected]>

Tested-by: Samuel Salin <[email protected]>

Reply via email to