mirror of
https://github.com/torvalds/linux.git
synced 2026-10-14 20:04:03 +02:00
iommu/tegra241-cmdqv: Fix VINTF0 leak on the init-failure path
tegra241_cmdqv_init_structures() allocates VINTF0 with kzalloc_obj(), inits
it, and preallocates its logical VCMDQs. Two of its error paths leak.
When tegra241_cmdqv_init_vintf() fails it returns before VINTF0 reaches the
cmdqv->vintfs[] array, so the devres unwind on probe failure cannot reach
it; free it directly there.
A later VCMDQ preallocation failure instead leaves VINTF0 published, and so
this time the unwind does reach tegra241_cmdqv_remove_vintf(), which then
frees it from vintf->hyp_own. But tegra241_vintf_hw_init() sets that flag
only afterward, from a HW read-back, so the still-uninited VINTF0 reads as
guest-owned and leaks, with mutex_destroy() and ida_destroy() run on fields
it never set up.
Decide ownership from vintf->idx instead, the index assigned when its id is
allocated: idx 0 is the kernel-owned VINTF0, while idx >= 1 marks a guest
VINTF. So the in-kernel free decision in tegra241_cmdqv_remove_vintf() and
tegra241_vintf_free_lvcmdq() now keys on idx too, and hyp_own stays a pure
HW-readback state.
Fixes: 918eb5c856 ("iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV")
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
fb292bfc9b
commit
f40f314447
|
|
@ -716,7 +716,7 @@ static void tegra241_vintf_free_lvcmdq(struct tegra241_vintf *vintf, u16 lidx)
|
|||
dev_dbg(vintf->cmdqv->dev,
|
||||
"%sdeallocated\n", lvcmdq_error_header(vcmdq, header, 64));
|
||||
/* Guest-owned VCMDQ is free-ed with hw_queue by iommufd core */
|
||||
if (vcmdq->vintf->hyp_own)
|
||||
if (!vcmdq->vintf->idx)
|
||||
kfree(vcmdq);
|
||||
}
|
||||
|
||||
|
|
@ -814,7 +814,7 @@ static void tegra241_cmdqv_remove_vintf(struct tegra241_cmdqv *cmdqv, u16 idx)
|
|||
|
||||
dev_dbg(cmdqv->dev, "VINTF%u: deallocated\n", vintf->idx);
|
||||
tegra241_cmdqv_deinit_vintf(cmdqv, idx);
|
||||
if (!vintf->hyp_own) {
|
||||
if (vintf->idx) {
|
||||
mutex_destroy(&vintf->lvcmdq_mutex);
|
||||
ida_destroy(&vintf->sids);
|
||||
/* Guest-owned VINTF is free-ed with viommu by iommufd core */
|
||||
|
|
@ -931,6 +931,12 @@ static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
|
|||
ret = tegra241_cmdqv_init_vintf(cmdqv, 0, vintf);
|
||||
if (ret) {
|
||||
dev_err(cmdqv->dev, "failed to init vintf0: %d\n", ret);
|
||||
/*
|
||||
* tegra241_cmdqv_init_vintf() failed to publish the vintf0 to
|
||||
* cmdqv->vintfs[], so the probe unwind path that goes through
|
||||
* cmdqv->vintfs[] would miss it. Free it here.
|
||||
*/
|
||||
kfree(vintf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user