> -----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]>
