[PATCH v1 07/11] iommu/tegra241-cmdqv: Reject a vSID wider than the SID_MATCH field
Nicolin Chen
nicolinc at nvidia.com
Thu Jul 2 22:31:33 PDT 2026
tegra241_vintf_init_vsid() programs the guest-provided vSID into SID_MATCH,
whose VIRT_SID field spans bits [20:1] with bit 0 as the match-enable flag.
The HW therefore matches only a 20-bit Stream ID.
The bound check rejects only virt_sid > UINT_MAX, which admits a value far
wider than the field. The write "virt_sid << 1 | 0x1" then drops every bit
above 20: a virt_sid of 0x80000000 lands as SID_MATCH = 0x1, a valid match
on vSID 0, so the entry aliases the wrong Stream ID. Because vdev->virt_id
is guest-controlled, a VMM can trigger it.
Validate virt_sid against the field width with FIELD_MAX(), and program the
register with FIELD_PREP() so the value and the field stay consistent.
Fixes: 4dc0d12474f9 ("iommu/tegra241-cmdqv: Add user-space use support")
Cc: stable at vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
---
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
index fbf7ecf043a8c..812cc500b4a1e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
+++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
@@ -56,6 +56,8 @@
#define VINTF_ENABLED BIT(0)
#define TEGRA241_VINTF_SID_MATCH(s) (0x0040 + 0x4*(s))
+#define VINTF_SID_MATCH_VIRT_SID GENMASK(20, 1)
+#define VINTF_SID_MATCH_ENABLE BIT(0)
#define TEGRA241_VINTF_SID_REPLACE(s) (0x0080 + 0x4*(s))
#define TEGRA241_VINTF_LVCMDQ_ERR_MAP_64(m) \
@@ -1244,7 +1246,7 @@ static int tegra241_vintf_init_vsid(struct iommufd_vdevice *vdev)
u64 virt_sid = vdev->virt_id;
int sidx;
- if (virt_sid > UINT_MAX)
+ if (virt_sid > FIELD_MAX(VINTF_SID_MATCH_VIRT_SID))
return -EINVAL;
WARN_ON_ONCE(master->num_streams != 1);
@@ -1256,7 +1258,9 @@ static int tegra241_vintf_init_vsid(struct iommufd_vdevice *vdev)
return sidx;
writel(stream->id, REG_VINTF(vintf, SID_REPLACE(sidx)));
- writel(virt_sid << 1 | 0x1, REG_VINTF(vintf, SID_MATCH(sidx)));
+ writel(FIELD_PREP(VINTF_SID_MATCH_VIRT_SID, virt_sid) |
+ VINTF_SID_MATCH_ENABLE,
+ REG_VINTF(vintf, SID_MATCH(sidx)));
dev_dbg(vintf->cmdqv->dev,
"VINTF%u: allocated SID_REPLACE%d for pSID=%x, vSID=%x\n",
vintf->idx, sidx, stream->id, (u32)virt_sid);
--
2.43.0
More information about the linux-arm-kernel
mailing list