proc_read_simdisk() looks at dev->filename without holding dev->lock. A
write to the same file detaches the disk and frees the name under the
lock, so a concurrent reader can copy out freed memory. Copy the name
with the lock held.
Fixes: b6c7e873daf7 ("xtensa: ISS: add host file-based simulated disk")
Cc: <redacted>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
arch/xtensa/platforms/iss/simdisk.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/arch/xtensa/platforms/iss/simdisk.c b/arch/xtensa/platforms/iss/simdisk.c
index a2ddb49c269d..7b115e023de9 100644
--- a/arch/xtensa/platforms/iss/simdisk.c
+++ b/arch/xtensa/platforms/iss/simdisk.c
@@ -238,22 +238,21 @@ static ssize_t proc_read_simdisk(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
struct simdisk *dev = pde_data(file_inode(file));
- const char *s = dev->filename;
- if (s) {
- ssize_t len = strlen(s);
- char *temp = kmalloc(len + 2, GFP_KERNEL);
+ ssize_t len;
+ char *temp;
- if (!temp)
- return -ENOMEM;
+ /* a write sets at most a page, see proc_write_simdisk() */
+ temp = kmalloc(PAGE_SIZE + 2, GFP_KERNEL);
+ if (!temp)
+ return -ENOMEM;
- len = scnprintf(temp, len + 2, "%s\n", s);
- len = simple_read_from_buffer(buf, size, ppos,
- temp, len);
+ spin_lock(&dev->lock);
+ len = scnprintf(temp, PAGE_SIZE + 2, "%s\n", dev->filename ?: "");
+ spin_unlock(&dev->lock);
- kfree(temp);
- return len;
- }
- return simple_read_from_buffer(buf, size, ppos, "\n", 1);
+ len = simple_read_from_buffer(buf, size, ppos, temp, len);
+ kfree(temp);
+ return len;
}
static ssize_t proc_write_simdisk(struct file *file, const char __user *buf,
--
2.53.0