Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3e0e067 authored by Xiaoguang Wang's avatar Xiaoguang Wang Committed by Greg Kroah-Hartman
Browse files

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: default avatarBodo Stroesser <bostroesser@gmail.com>
Signed-off-by: default avatarXiaoguang Wang <xiaoguang.wang@linux.alibaba.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 60b7e4b5
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -1499,6 +1499,7 @@ static struct page *tcmu_try_get_block_page(struct tcmu_dev *udev, uint32_t dbi)
	mutex_lock(&udev->cmdr_lock);
	mutex_lock(&udev->cmdr_lock);
	page = tcmu_get_block_page(udev, dbi);
	page = tcmu_get_block_page(udev, dbi);
	if (likely(page)) {
	if (likely(page)) {
		get_page(page);
		mutex_unlock(&udev->cmdr_lock);
		mutex_unlock(&udev->cmdr_lock);
		return page;
		return page;
	}
	}
@@ -1537,6 +1538,7 @@ static vm_fault_t tcmu_vma_fault(struct vm_fault *vmf)
		/* For the vmalloc()ed cmd area pages */
		/* For the vmalloc()ed cmd area pages */
		addr = (void *)(unsigned long)info->mem[mi].addr + offset;
		addr = (void *)(unsigned long)info->mem[mi].addr + offset;
		page = vmalloc_to_page(addr);
		page = vmalloc_to_page(addr);
		get_page(page);
	} else {
	} else {
		uint32_t dbi;
		uint32_t dbi;


@@ -1547,7 +1549,6 @@ static vm_fault_t tcmu_vma_fault(struct vm_fault *vmf)
			return VM_FAULT_SIGBUS;
			return VM_FAULT_SIGBUS;
	}
	}


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