mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-05 00:20:32 +00:00
usb: usbmon: Read text within supplied buffer size
commit a5f596830e
upstream.
This change fixes buffer overflows and silent data corruption with the
usbmon device driver text file read operations.
Signed-off-by: Fredrik Noring <noring@nocrew.org>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
b2708e1e30
commit
63f3bac3be
1 changed files with 84 additions and 54 deletions
|
@ -83,6 +83,8 @@ struct mon_reader_text {
|
|||
|
||||
wait_queue_head_t wait;
|
||||
int printf_size;
|
||||
size_t printf_offset;
|
||||
size_t printf_togo;
|
||||
char *printf_buf;
|
||||
struct mutex printf_lock;
|
||||
|
||||
|
@ -374,23 +376,36 @@ static int mon_text_open(struct inode *inode, struct file *file)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* For simplicity, we read one record in one system call and throw out
|
||||
* what does not fit. This means that the following does not work:
|
||||
* dd if=/dbg/usbmon/0t bs=10
|
||||
* Also, we do not allow seeks and do not bother advancing the offset.
|
||||
*/
|
||||
static ssize_t mon_text_copy_to_user(struct mon_reader_text *rp,
|
||||
char __user * const buf, const size_t nbytes)
|
||||
{
|
||||
const size_t togo = min(nbytes, rp->printf_togo);
|
||||
|
||||
if (copy_to_user(buf, &rp->printf_buf[rp->printf_offset], togo))
|
||||
return -EFAULT;
|
||||
rp->printf_togo -= togo;
|
||||
rp->printf_offset += togo;
|
||||
return togo;
|
||||
}
|
||||
|
||||
/* ppos is not advanced since the llseek operation is not permitted. */
|
||||
static ssize_t mon_text_read_t(struct file *file, char __user *buf,
|
||||
size_t nbytes, loff_t *ppos)
|
||||
{
|
||||
struct mon_reader_text *rp = file->private_data;
|
||||
struct mon_event_text *ep;
|
||||
struct mon_text_ptr ptr;
|
||||
ssize_t ret;
|
||||
|
||||
mutex_lock(&rp->printf_lock);
|
||||
|
||||
if (rp->printf_togo == 0) {
|
||||
|
||||
ep = mon_text_read_wait(rp, file);
|
||||
if (IS_ERR(ep))
|
||||
if (IS_ERR(ep)) {
|
||||
mutex_unlock(&rp->printf_lock);
|
||||
return PTR_ERR(ep);
|
||||
mutex_lock(&rp->printf_lock);
|
||||
}
|
||||
ptr.cnt = 0;
|
||||
ptr.pbuf = rp->printf_buf;
|
||||
ptr.limit = rp->printf_size;
|
||||
|
@ -401,24 +416,35 @@ static ssize_t mon_text_read_t(struct file *file, char __user *buf,
|
|||
" %d", ep->length);
|
||||
mon_text_read_data(rp, &ptr, ep);
|
||||
|
||||
if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
|
||||
ptr.cnt = -EFAULT;
|
||||
mutex_unlock(&rp->printf_lock);
|
||||
rp->printf_togo = ptr.cnt;
|
||||
rp->printf_offset = 0;
|
||||
|
||||
kmem_cache_free(rp->e_slab, ep);
|
||||
return ptr.cnt;
|
||||
}
|
||||
|
||||
ret = mon_text_copy_to_user(rp, buf, nbytes);
|
||||
mutex_unlock(&rp->printf_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ppos is not advanced since the llseek operation is not permitted. */
|
||||
static ssize_t mon_text_read_u(struct file *file, char __user *buf,
|
||||
size_t nbytes, loff_t *ppos)
|
||||
{
|
||||
struct mon_reader_text *rp = file->private_data;
|
||||
struct mon_event_text *ep;
|
||||
struct mon_text_ptr ptr;
|
||||
ssize_t ret;
|
||||
|
||||
mutex_lock(&rp->printf_lock);
|
||||
|
||||
if (rp->printf_togo == 0) {
|
||||
|
||||
ep = mon_text_read_wait(rp, file);
|
||||
if (IS_ERR(ep))
|
||||
if (IS_ERR(ep)) {
|
||||
mutex_unlock(&rp->printf_lock);
|
||||
return PTR_ERR(ep);
|
||||
mutex_lock(&rp->printf_lock);
|
||||
}
|
||||
ptr.cnt = 0;
|
||||
ptr.pbuf = rp->printf_buf;
|
||||
ptr.limit = rp->printf_size;
|
||||
|
@ -438,11 +464,15 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf,
|
|||
" %d", ep->length);
|
||||
mon_text_read_data(rp, &ptr, ep);
|
||||
|
||||
if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
|
||||
ptr.cnt = -EFAULT;
|
||||
mutex_unlock(&rp->printf_lock);
|
||||
rp->printf_togo = ptr.cnt;
|
||||
rp->printf_offset = 0;
|
||||
|
||||
kmem_cache_free(rp->e_slab, ep);
|
||||
return ptr.cnt;
|
||||
}
|
||||
|
||||
ret = mon_text_copy_to_user(rp, buf, nbytes);
|
||||
mutex_unlock(&rp->printf_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp,
|
||||
|
|
Loading…
Reference in a new issue