Re: [PATCH 5/5] drivers/s390/cio: ensure the copied buf is NULL terminated

From: Bui Quang Minh
Date: Tue Apr 23 2024 - 10:47:02 EST


On 4/23/24 13:50, Heiko Carstens wrote:
On Mon, Apr 22, 2024 at 11:41:40PM +0700, Bui Quang Minh wrote:
Currently, we allocate a lbuf-sized kernel buffer and copy lbuf from
userspace to that buffer. Later, we use scanf on this buffer but we don't
ensure that the string is terminated inside the buffer, this can lead to
OOB read when using scanf. Fix this issue by allocating 1 more byte to at
the end of buffer and write NULL terminator to the end of buffer after
userspace copying.

Fixes: a4f17cc72671 ("s390/cio: add CRW inject functionality")
Signed-off-by: Bui Quang Minh <minhquangbui99@xxxxxxxxx>
---
drivers/s390/cio/cio_inject.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/s390/cio/cio_inject.c b/drivers/s390/cio/cio_inject.c
index 8613fa937237..9b69fbf49f60 100644
--- a/drivers/s390/cio/cio_inject.c
+++ b/drivers/s390/cio/cio_inject.c
@@ -95,10 +95,11 @@ static ssize_t crw_inject_write(struct file *file, const char __user *buf,
return -EINVAL;
}
- buffer = vmemdup_user(buf, lbuf);
+ buffer = vmemdup_user(buf, lbuf + 1);
if (IS_ERR(buffer))
return -ENOMEM;
+ buffer[lbuf] = '\0';

This would read one byte too much from user space, and could potentially
fault.

Why isn't this simply memdup_user_nul() like all others, which would do the
right thing?

Thanks for your review. It's my mistake, I blindly follow the pattern in rvu_debugfs

static ssize_t rvu_dbg_qsize_write(struct file *filp,
const char __user *buffer, size_t count,
loff_t *ppos, int blktype)
{
cmd_buf = memdup_user(buffer, count + 1);
if (IS_ERR(cmd_buf))
return -ENOMEM;

cmd_buf[count] = '\0';
}

I will send a patch to fix this too.

For this case, as the original code uses vmemdup_user, which internally uses kvmalloc not kmalloc, so I try to keep the original behavior. And vmemdup_user does not have the counterpart vmemdup_user_nul. I can kvmalloc(lbuf + 1), then copy_to_user(lbuf) and set buffer[lbuf] = '\0' or do you think I should create vmemdup_user_nul?

Thanks,
Quang Minh.