diff options
author | Xiaoguang Wang <xiaoguang.wang@linux.alibaba.com> | 2022-03-11 21:22:05 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2022-04-20 09:34:15 +0200 |
commit | b7f3b5d70c834f49f7d87a2f2ed1c6284d9a0322 (patch) | |
tree | 6d5d2885904e258ebd3898b0af36bf2d877ddc58 /drivers | |
parent | 44f95a5aae99afff298491c057acae4d895c9bdd (diff) |
scsi: target: tcmu: Fix possible page UAF
[ 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@linux.alibaba.com
Reviewed-by: Bodo Stroesser <bostroesser@gmail.com>
Signed-off-by: Xiaoguang Wang <xiaoguang.wang@linux.alibaba.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/target/target_core_user.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 9f552f48084c..0ca5ec14d3db 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1821,6 +1821,7 @@ static struct page *tcmu_try_get_data_page(struct tcmu_dev *udev, uint32_t dpi) mutex_lock(&udev->cmdr_lock); page = xa_load(&udev->data_pages, dpi); if (likely(page)) { + get_page(page); mutex_unlock(&udev->cmdr_lock); return page; } @@ -1877,6 +1878,7 @@ static vm_fault_t 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 dpi; @@ -1887,7 +1889,6 @@ static vm_fault_t tcmu_vma_fault(struct vm_fault *vmf) return VM_FAULT_SIGBUS; } - get_page(page); vmf->page = page; return 0; } |