mirror of
https://github.com/torvalds/linux.git
synced 2026-10-08 11:36:02 +02:00
iommu/tegra241-cmdqv: Reject a vSID wider than the SID_MATCH field
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: 4dc0d12474 ("iommu/tegra241-cmdqv: Add user-space use support")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
61f0d43798
commit
4379610c79
|
|
@ -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) \
|
||||
|
|
@ -1255,7 +1257,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);
|
||||
|
|
@ -1267,7 +1269,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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user