RE: [Intel-wired-lan] [PATCH] idpf: bound interrupt-vector register fill to the allocated array
From: Salin, Samuel
Date: Thu Jul 16 2026 - 12:34:19 EST
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@xxxxxxxxxx> On Behalf Of
> Loktionov, Aleksandr
> Sent: Wednesday, June 17, 2026 10:22 PM
> To: Michael Bommarito <michael.bommarito@xxxxxxxxx>; Nguyen, Anthony
> L <anthony.l.nguyen@xxxxxxxxx>; Kitszel, Przemyslaw
> <przemyslaw.kitszel@xxxxxxxxx>; Hay, Joshua A <joshua.a.hay@xxxxxxxxx>;
> Pavan Kumar Linga <pavan.kumar.linga@xxxxxxxxx>; Andrew Lunn
> <andrew+netdev@xxxxxxx>; David S . Miller <davem@xxxxxxxxxxxxx>; Eric
> Dumazet <edumazet@xxxxxxxxxx>; Jakub Kicinski <kuba@xxxxxxxxxx>; Paolo
> Abeni <pabeni@xxxxxxxxxx>
> Cc: intel-wired-lan@xxxxxxxxxxxxxxxx; netdev@xxxxxxxxxxxxxxx; linux-
> kernel@xxxxxxxxxxxxxxx
> Subject: Re: [Intel-wired-lan] [PATCH] idpf: bound interrupt-vector register fill
> to the allocated array
>
>
>
> > -----Original Message-----
> > From: Intel-wired-lan <intel-wired-lan-bounces@xxxxxxxxxx> On Behalf
> > Of Michael Bommarito
> > Sent: Wednesday, June 17, 2026 11:58 PM
> > To: Nguyen, Anthony L <anthony.l.nguyen@xxxxxxxxx>; Kitszel,
> > Przemyslaw <przemyslaw.kitszel@xxxxxxxxx>; Hay, Joshua A
> > <joshua.a.hay@xxxxxxxxx>; Pavan Kumar Linga
> > <pavan.kumar.linga@xxxxxxxxx>; Andrew Lunn <andrew+netdev@xxxxxxx>;
> > David S . Miller <davem@xxxxxxxxxxxxx>; Eric Dumazet
> > <edumazet@xxxxxxxxxx>; Jakub Kicinski <kuba@xxxxxxxxxx>; Paolo Abeni
> > <pabeni@xxxxxxxxxx>
> > Cc: intel-wired-lan@xxxxxxxxxxxxxxxx; netdev@xxxxxxxxxxxxxxx; linux-
> > kernel@xxxxxxxxxxxxxxx
> > 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 <michael.bommarito@xxxxxxxxx>
> > ---
> > 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 <aleksandr.loktionov@xxxxxxxxx>
Tested-by: Samuel Salin <Samuel.salin@xxxxxxxxx>