linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Németh Márton" <nm127@freemail.hu>
To: Mauro Carvalho Chehab <mchehab@infradead.org>,
	Guennadi Liakhovetski <g.liakhovetski@gmx.de>,
	V4L Mailing List <linux-media@vger.kernel.org>
Cc: LKML <linux-kernel@vger.kernel.org>
Subject: [PATCH] v4l2: handle multiplication overflow
Date: Thu, 22 Dec 2011 10:42:58 +0100	[thread overview]
Message-ID: <4EF2FBA2.5070802@freemail.hu> (raw)

From: Márton Németh <nm127@freemail.hu>

When a V4L2 ioctl is executed the memory provided by the caller in user space
is copied to the kernel space in video_usercopy() function. To find out
how many bytes has to be copied the check_array_args() helper function is used.

This patch adds a check for multiplication overflow. Without this check the
multiplication may overflow resulting array_size to be zero. This means that
later on uninitialized value can trigger NULL pointer exception.

The overflow happens because ctrls->count is an __u32 multiplied by a constant
coming from sizeof() operator. Multiplication result of two 32bit value may
be a 64bit value, thus overflow can happen. Similarly buf->length is an __u32
multiplied by a constant coming from sizeof() operator.

The chosen error value is -ENOMEM because we are just about to allocate
kernel memory to copy data from userspace. We cannot even store the required
number of bytes in the variable of size_t type.

To trigger the error from user space use the v4l-test 0.19 [1] or essentially
the following code fragment:

	struct v4l2_ext_controls controls;
	memset(&controls, 0, sizeof(controls));
	controls.ctrl_class = V4L2_CTRL_CLASS_USER;
	controls.count = 0x40000000;
	controls.controls = NULL;
	ret = ioctl(f, VIDIOC_G_EXT_CTRLS, &controls);


References:
[1] v4l-test: Test environment for Video For Linux Two (V4L2) API
    http://v4l-test.sourceforge.net/

Signed-off-by: Márton Németh <nm127@freemail.hu>
---

I'm a little bit in doubt whether this is the correct way to check for the
multiplication overflow. In case of x86 architecture the MUL insruction [2]
can be used to multiply EAX with an other 32bit register, and the 64bit result
is placed to EDX:EAX. In case of EDX != 0 the carry and overflow flags are set.

This means that executing the MUL instruction on x86 already provides information
whether the result fits to 32bit or not. I might use __u64 as a result of the
multiplication and check whether the upper 32bit is still zero but the optimal
would be to check for the carry or the overflow flag.

Still, there could be a special case when the constant from sizeof() operator is
a power of 2, in this case the compiler might optimize the multiplication using
a shift left. In this case something else is needed.

I couldn't really find information about the number of bits for size_t on
different architectures. If size_t happens to be at least 64bit on some architecture
then this overflow will not happen at all and the array_size will contain the
correct value.

What do you think?

References:
[2] Intel 80386 Reference Programmer's Manual
    MUL -- Unsigned Multiplication of AL or AX
    http://www.scs.stanford.edu/nyu/04fa/lab/i386/MUL.htm

---
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index e1da8fc..e239be8 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -2200,6 +2200,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
 			    void * __user *user_ptr, void ***kernel_ptr)
 {
 	int ret = 0;
+	size_t size;

 	switch (cmd) {
 	case VIDIOC_QUERYBUF:
@@ -2214,8 +2215,15 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
 			}
 			*user_ptr = (void __user *)buf->m.planes;
 			*kernel_ptr = (void *)&buf->m.planes;
-			*array_size = sizeof(struct v4l2_plane) * buf->length;
-			ret = 1;
+			size = sizeof(struct v4l2_plane) * buf->length;
+			if (unlikely(size < buf->length)) {
+				/* *array_size overflowed at multiplication */
+				*array_size = 0;
+				ret = -ENOMEM;
+			} else {
+				*array_size = size;
+				ret = 1;
+			}
 		}
 		break;
 	}
@@ -2228,9 +2236,15 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
 		if (ctrls->count != 0) {
 			*user_ptr = (void __user *)ctrls->controls;
 			*kernel_ptr = (void *)&ctrls->controls;
-			*array_size = sizeof(struct v4l2_ext_control)
-				    * ctrls->count;
-			ret = 1;
+			size = sizeof(struct v4l2_ext_control) * ctrls->count;
+			if (unlikely(size < ctrls->count)) {
+				/* *array_size overflowed at multiplication */
+				*array_size = 0;
+				ret = -ENOMEM;
+			} else {
+				*array_size = size;
+				ret = 1;
+			}
 		}
 		break;
 	}

             reply	other threads:[~2011-12-22 10:19 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-12-22  9:42 Németh Márton [this message]
2012-01-23 18:04 ` [PATCH] v4l2: handle multiplication overflow Mauro Carvalho Chehab
2012-01-24  6:16   ` Németh Márton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4EF2FBA2.5070802@freemail.hu \
    --to=nm127@freemail.hu \
    --cc=g.liakhovetski@gmx.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).