[PATCH AUTOSEL 4.14 04/11] scsi: target: tcmu: Fix possible page UAF

From: Sasha Levin
Date: Mon Apr 11 2022 - 21:09:54 EST


From: Xiaoguang Wang <xiaoguang.wang@xxxxxxxxxxxxxxxxx>

[ Upstream commit a6968f7a367f128d120447360734344d5a3d5336 ]

tcmu_try_get_data_page() looks up pages under cmdr_lock, but it does not
take refcount properly and just returns page pointer. When
tcmu_try_get_data_page() returns, the returned page may have been freed by
tcmu_blocks_release().

We need to get_page() under cmdr_lock to avoid concurrent
tcmu_blocks_release().

Link: https://lore.kernel.org/r/20220311132206.24515-1-xiaoguang.wang@xxxxxxxxxxxxxxxxx
Reviewed-by: Bodo Stroesser <bostroesser@xxxxxxxxx>
Signed-off-by: Xiaoguang Wang <xiaoguang.wang@xxxxxxxxxxxxxxxxx>
Signed-off-by: Martin K. Petersen <martin.petersen@xxxxxxxxxx>
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---
drivers/target/target_core_user.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 96601fda47b1..f687481ccfdc 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -1165,6 +1165,7 @@ static struct page *tcmu_try_get_block_page(struct tcmu_dev *udev, uint32_t dbi)
mutex_lock(&udev->cmdr_lock);
page = tcmu_get_block_page(udev, dbi);
if (likely(page)) {
+ get_page(page);
mutex_unlock(&udev->cmdr_lock);
return page;
}
@@ -1233,6 +1234,7 @@ static int tcmu_vma_fault(struct vm_fault *vmf)
/* For the vmalloc()ed cmd area pages */
addr = (void *)(unsigned long)info->mem[mi].addr + offset;
page = vmalloc_to_page(addr);
+ get_page(page);
} else {
uint32_t dbi;

@@ -1243,7 +1245,6 @@ static int tcmu_vma_fault(struct vm_fault *vmf)
return VM_FAULT_NOPAGE;
}

- get_page(page);
vmf->page = page;
return 0;
}
--
2.35.1