RE: [PATCH v3 09/17] iommufd: Add IOMMU_HWPT_INVALIDATE

From: Liu, Yi L
Date: Mon Jul 31 2023 - 06:07:43 EST


> From: Jason Gunthorpe <jgg@xxxxxxxxxx>
> Sent: Saturday, July 29, 2023 2:03 AM
>
> On Mon, Jul 24, 2023 at 04:03:58AM -0700, Yi Liu wrote:
> > In nested translation, the stage-1 page table is user-managed and used by
> > IOMMU hardware, so update of any present page table entry in the stage-1
> > page table should be followed with an IOTLB invalidation.
> >
> > This adds IOMMU_HWPT_INVALIDATE for stage-1 IOTLB invalidation.
> >
> > Co-developed-by: Nicolin Chen <nicolinc@xxxxxxxxxx>
> > Signed-off-by: Nicolin Chen <nicolinc@xxxxxxxxxx>
> > Signed-off-by: Yi Liu <yi.l.liu@xxxxxxxxx>
> > ---
> > drivers/iommu/iommufd/hw_pagetable.c | 45 +++++++++++++++++++++++++
> > drivers/iommu/iommufd/iommufd_private.h | 9 +++++
> > drivers/iommu/iommufd/main.c | 3 ++
> > include/uapi/linux/iommufd.h | 22 ++++++++++++
> > 4 files changed, 79 insertions(+)
> >
> > diff --git a/drivers/iommu/iommufd/hw_pagetable.c
> b/drivers/iommu/iommufd/hw_pagetable.c
> > index 97e4114226de..9064e6d181b4 100644
> > --- a/drivers/iommu/iommufd/hw_pagetable.c
> > +++ b/drivers/iommu/iommufd/hw_pagetable.c
> > @@ -286,3 +286,48 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)
> > iommufd_put_object(&idev->obj);
> > return rc;
> > }
> > +
> > +int iommufd_hwpt_invalidate(struct iommufd_ucmd *ucmd)
> > +{
> > + struct iommu_hwpt_invalidate *cmd = ucmd->cmd;
> > + struct iommufd_hw_pagetable *hwpt;
> > + u32 user_data_len, klen;
> > + u64 user_ptr;
> > + int rc = 0;
> > +
> > + if (!cmd->data_len || cmd->__reserved)
> > + return -EOPNOTSUPP;
> > +
> > + hwpt = iommufd_get_hwpt(ucmd, cmd->hwpt_id);
> > + if (IS_ERR(hwpt))
> > + return PTR_ERR(hwpt);
> > +
> > + /* Do not allow any kernel-managed hw_pagetable */
> > + if (!hwpt->parent) {
>
> I don't think this is needed because:
>
> > + rc = -EINVAL;
> > + goto out_put_hwpt;
> > + }
> > +
> > + klen = hwpt->domain->ops->cache_invalidate_user_data_len;
> > + if (!hwpt->domain->ops->cache_invalidate_user || !klen) {
> > + rc = -EOPNOTSUPP;
>
> We need to get to a place where the drivers are providing proper ops
> for the domains, so this op should never exist for a paging domain.

Yes.

>
> And return EINVAL here instead.

Sure.

>
> > + goto out_put_hwpt;
> > + }
> > +
> > + /*
> > + * Copy the needed fields before reusing the ucmd buffer, this
> > + * avoids memory allocation in this path.
> > + */
> > + user_ptr = cmd->data_uptr;
> > + user_data_len = cmd->data_len;
>
> Uhh, who checks that klen < the temporary stack struct?

Take vtd as an example. The invalidate structure is struct iommu_hwpt_vtd_s1_invalidate[1].
The klen is sizeof(struct iommu_hwpt_vtd_s1_invalidate)[2]. iommu_hwpt_vtd_s1_invalidate
is also placed in the temporary stack struct (actually it is a union)[1]. So the klen should
be <= temporary stack.

[1] https://lore.kernel.org/linux-iommu/20230724111335.107427-8-yi.l.liu@xxxxxxxxx/
[2] https://lore.kernel.org/linux-iommu/20230724111335.107427-10-yi.l.liu@xxxxxxxxx/

It's not so explicit though. Perhaps worth to have a check like below in this patch?

if (unlikely(klen > sizeof(union ucmd_buffer)))
return -EINVAL;

Regards,
Yi Liu