diff options
author | Jann Horn <jannh@google.com> | 2018-07-06 22:16:33 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-07-07 03:59:35 -0400 |
commit | a0341fc1981a950c1e902ab901e98f60e0e243f3 (patch) | |
tree | 8a9327399df531520167dc77e6d3d62742735562 /drivers/misc/ibmasm/ibmasmfs.c | |
parent | e2a46a48b94d143b7fabd9da7d45eef1a0799986 (diff) |
ibmasm: don't write out of bounds in read handler
This read handler had a lot of custom logic and wrote outside the bounds of
the provided buffer. This could lead to kernel and userspace memory
corruption. Just use simple_read_from_buffer() with a stack buffer.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/ibmasm/ibmasmfs.c')
-rw-r--r-- | drivers/misc/ibmasm/ibmasmfs.c | 27 |
1 files changed, 3 insertions, 24 deletions
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index e05c3245930a..fa840666bdd1 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c | |||
@@ -507,35 +507,14 @@ static int remote_settings_file_close(struct inode *inode, struct file *file) | |||
507 | static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset) | 507 | static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset) |
508 | { | 508 | { |
509 | void __iomem *address = (void __iomem *)file->private_data; | 509 | void __iomem *address = (void __iomem *)file->private_data; |
510 | unsigned char *page; | ||
511 | int retval; | ||
512 | int len = 0; | 510 | int len = 0; |
513 | unsigned int value; | 511 | unsigned int value; |
514 | 512 | char lbuf[20]; | |
515 | if (*offset < 0) | ||
516 | return -EINVAL; | ||
517 | if (count == 0 || count > 1024) | ||
518 | return 0; | ||
519 | if (*offset != 0) | ||
520 | return 0; | ||
521 | |||
522 | page = (unsigned char *)__get_free_page(GFP_KERNEL); | ||
523 | if (!page) | ||
524 | return -ENOMEM; | ||
525 | 513 | ||
526 | value = readl(address); | 514 | value = readl(address); |
527 | len = sprintf(page, "%d\n", value); | 515 | len = snprintf(lbuf, sizeof(lbuf), "%d\n", value); |
528 | |||
529 | if (copy_to_user(buf, page, len)) { | ||
530 | retval = -EFAULT; | ||
531 | goto exit; | ||
532 | } | ||
533 | *offset += len; | ||
534 | retval = len; | ||
535 | 516 | ||
536 | exit: | 517 | return simple_read_from_buffer(buf, count, offset, lbuf, len); |
537 | free_page((unsigned long)page); | ||
538 | return retval; | ||
539 | } | 518 | } |
540 | 519 | ||
541 | static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset) | 520 | static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset) |