Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5f59683 authored by Pete Zaitcev's avatar Pete Zaitcev Committed by Greg Kroah-Hartman
Browse files

usb: usbmon: Read text within supplied buffer size



This change fixes buffer overflows and silent data corruption with the
usbmon device driver text file read operations.

Signed-off-by: default avatarFredrik Noring <noring@nocrew.org>
Signed-off-by: default avatarPete Zaitcev <zaitcev@redhat.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 015dbeb2
Loading
Loading
Loading
Loading
+78 −48
Original line number Diff line number Diff line
@@ -85,6 +85,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;

@@ -376,23 +378,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;
@@ -403,24 +418,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;
@@ -440,11 +466,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,