diff options
author | Dan Carpenter <error27@gmail.com> | 2010-11-17 00:20:15 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-12-20 11:11:15 -0500 |
commit | 250f7a5f62a08985af5cf7728ae7ba9edbfdc0a9 (patch) | |
tree | 0aa3cbc24524efbb1fc9f29608a44e20b68c1d06 /drivers/media/IR/lirc_dev.c | |
parent | 5c769a68beaee924e1dc90bf06e1b087b1d46237 (diff) |
[media] lirc_dev: fixes in lirc_dev_fop_read()
This makes several changes but they're in one function and sort of
related:
"buf" was leaked on error. The leak if we try to read an invalid
length is the main concern because it could be triggered over and
over.
If the copy_to_user() failed, then the original code returned the
number of bytes remaining. read() is supposed to be the opposite way,
where we return the number of bytes copied. I changed it to just return
-EFAULT on errors.
Also I changed the debug output from "-EFAULT" to just "<fail>" because
it isn't -EFAULT necessarily. And since we go though that path if the
length is invalid now, there was another debug print that I removed.
Signed-off-by: Dan Carpenter <error27@gmail.com>
Reviewed-by: Jarod Wilson <jarod@redhat.com>
Acked-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/IR/lirc_dev.c')
-rw-r--r-- | drivers/media/IR/lirc_dev.c | 25 |
1 files changed, 15 insertions, 10 deletions
diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c index 8ab9d87f3a46..756656e17bdd 100644 --- a/drivers/media/IR/lirc_dev.c +++ b/drivers/media/IR/lirc_dev.c | |||
@@ -647,18 +647,18 @@ ssize_t lirc_dev_fop_read(struct file *file, | |||
647 | if (!buf) | 647 | if (!buf) |
648 | return -ENOMEM; | 648 | return -ENOMEM; |
649 | 649 | ||
650 | if (mutex_lock_interruptible(&ir->irctl_lock)) | 650 | if (mutex_lock_interruptible(&ir->irctl_lock)) { |
651 | return -ERESTARTSYS; | 651 | ret = -ERESTARTSYS; |
652 | goto out_unlocked; | ||
653 | } | ||
652 | if (!ir->attached) { | 654 | if (!ir->attached) { |
653 | mutex_unlock(&ir->irctl_lock); | 655 | ret = -ENODEV; |
654 | return -ENODEV; | 656 | goto out_locked; |
655 | } | 657 | } |
656 | 658 | ||
657 | if (length % ir->chunk_size) { | 659 | if (length % ir->chunk_size) { |
658 | dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n", | 660 | ret = -EINVAL; |
659 | ir->d.name, ir->d.minor); | 661 | goto out_locked; |
660 | mutex_unlock(&ir->irctl_lock); | ||
661 | return -EINVAL; | ||
662 | } | 662 | } |
663 | 663 | ||
664 | /* | 664 | /* |
@@ -709,18 +709,23 @@ ssize_t lirc_dev_fop_read(struct file *file, | |||
709 | lirc_buffer_read(ir->buf, buf); | 709 | lirc_buffer_read(ir->buf, buf); |
710 | ret = copy_to_user((void *)buffer+written, buf, | 710 | ret = copy_to_user((void *)buffer+written, buf, |
711 | ir->buf->chunk_size); | 711 | ir->buf->chunk_size); |
712 | written += ir->buf->chunk_size; | 712 | if (!ret) |
713 | written += ir->buf->chunk_size; | ||
714 | else | ||
715 | ret = -EFAULT; | ||
713 | } | 716 | } |
714 | } | 717 | } |
715 | 718 | ||
716 | remove_wait_queue(&ir->buf->wait_poll, &wait); | 719 | remove_wait_queue(&ir->buf->wait_poll, &wait); |
717 | set_current_state(TASK_RUNNING); | 720 | set_current_state(TASK_RUNNING); |
721 | |||
722 | out_locked: | ||
718 | mutex_unlock(&ir->irctl_lock); | 723 | mutex_unlock(&ir->irctl_lock); |
719 | 724 | ||
720 | out_unlocked: | 725 | out_unlocked: |
721 | kfree(buf); | 726 | kfree(buf); |
722 | dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", | 727 | dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", |
723 | ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret); | 728 | ir->d.name, ir->d.minor, ret ? "<fail>" : "<ok>", ret); |
724 | 729 | ||
725 | return ret ? ret : written; | 730 | return ret ? ret : written; |
726 | } | 731 | } |