aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJann Horn <jannh@google.com>2018-07-06 22:16:33 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-07-07 03:59:35 -0400
commita0341fc1981a950c1e902ab901e98f60e0e243f3 (patch)
tree8a9327399df531520167dc77e6d3d62742735562
parente2a46a48b94d143b7fabd9da7d45eef1a0799986 (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>
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c27
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)
507static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset) 507static 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
536exit: 517 return simple_read_from_buffer(buf, count, offset, lbuf, len);
537 free_page((unsigned long)page);
538 return retval;
539} 518}
540 519
541static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset) 520static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)