From bced4952ab00e6b2f5065e5f01d307bb842d5bfc Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Fri, 31 Jan 2020 10:11:25 -0800 Subject: [PATCH] iommu: iommu-debug: Fix race with respect to test buffer allocation When the buffer pointed to by test_virt_addr is allocated, there is no synchronization with respect to checking if it is necessary to allocate the buffer. This can lead to various adversarial scenarios, where multiple concurrent allocations of the same buffer can occur, resulting in memory leaks. To avoid these scenarios, make the check and allocation of the buffer atomic with respect to other accesses to test_virt_addr. Change-Id: Ie7e05930042b0bbf4bec0a4f1f5b325970023a5a Signed-off-by: Isaac J. Manjarres --- drivers/iommu/iommu-debug.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index f1024003dac0..6bc2d688e544 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -173,6 +173,7 @@ static LIST_HEAD(iommu_debug_devices); static struct dentry *debugfs_tests_dir; static u32 iters_per_op = 1; static void *test_virt_addr; +static DEFINE_MUTEX(test_virt_addr_lock); struct iommu_debug_device { struct device *dev; @@ -1472,6 +1473,7 @@ static ssize_t iommu_debug_test_virt_addr_read(struct file *file, memset(buf, 0, buf_len); + mutex_lock(&test_virt_addr_lock); if (IS_ERR_OR_NULL(test_virt_addr)) test_virt_addr = kzalloc(SZ_1M, GFP_KERNEL); @@ -1480,6 +1482,7 @@ static ssize_t iommu_debug_test_virt_addr_read(struct file *file, strlcpy(buf, "FAIL\n", buf_len); } else snprintf(buf, buf_len, "0x%pK\n", test_virt_addr); + mutex_unlock(&test_virt_addr_lock); return simple_read_from_buffer(ubuf, count, offset, buf, strlen(buf)); } @@ -1808,11 +1811,17 @@ static ssize_t iommu_debug_dma_map_write(struct file *file, if (kstrtouint(comma2 + 1, 0, &attr)) goto invalid_format; - if (IS_ERR(test_virt_addr)) + mutex_lock(&test_virt_addr_lock); + if (IS_ERR(test_virt_addr)) { + mutex_unlock(&test_virt_addr_lock); goto allocation_failure; + } - if (!test_virt_addr) + if (!test_virt_addr) { + mutex_unlock(&test_virt_addr_lock); goto missing_allocation; + } + mutex_unlock(&test_virt_addr_lock); if (v_addr < test_virt_addr || v_addr + size > test_virt_addr + SZ_1M) goto invalid_addr;