2023-01-06 06:32:03

by Kees Cook

[permalink] [raw]
Subject: [PATCH] media: uvcvideo: Silence memcpy() run-time false positive warnings

The memcpy() in uvc_video_decode_meta() intentionally copies across the
length and flags members and into the trailing buf flexible array.
Split the copy so that the compiler can better reason about (the lack
of) buffer overflows here. Avoid the run-time false positive warning:

memcpy: detected field-spanning write (size 12) of single field "&meta->length" at drivers/media/usb/uvc/uvc_video.c:1355 (size 1)

Additionally fix a typo in the documentation for struct uvc_meta_buf.

Reported-by: [email protected]
Link: https://bugzilla.kernel.org/show_bug.cgi?id=216810
Cc: Laurent Pinchart <[email protected]>
Cc: Mauro Carvalho Chehab <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/media/usb/uvc/uvc_video.c | 4 +++-
include/uapi/linux/uvcvideo.h | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index d2eb9066e4dc..b67347ab4181 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -1352,7 +1352,9 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream,
if (has_scr)
memcpy(stream->clock.last_scr, scr, 6);

- memcpy(&meta->length, mem, length);
+ meta->length = mem[0];
+ meta->flags = mem[1];
+ memcpy(meta->buf, &mem[2], length - 2);
meta_buf->bytesused += length + sizeof(meta->ns) + sizeof(meta->sof);

uvc_dbg(stream->dev, FRAME,
diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
index 8288137387c0..a9d0a64007ba 100644
--- a/include/uapi/linux/uvcvideo.h
+++ b/include/uapi/linux/uvcvideo.h
@@ -86,7 +86,7 @@ struct uvc_xu_control_query {
* struct. The first two fields are added by the driver, they can be used for
* clock synchronisation. The rest is an exact copy of a UVC payload header.
* Only complete objects with complete buffers are included. Therefore it's
- * always sizeof(meta->ts) + sizeof(meta->sof) + meta->length bytes large.
+ * always sizeof(meta->ns) + sizeof(meta->sof) + meta->length bytes large.
*/
struct uvc_meta_buf {
__u64 ns;
--
2.34.1


2023-01-06 11:56:23

by Ricardo Ribalda

[permalink] [raw]
Subject: Re: [PATCH] media: uvcvideo: Silence memcpy() run-time false positive warnings

Hi Kees

Thanks for the patch

Would it make more sense to replace *mem with a structure/union. Something like:
https://patchwork.linuxtv.org/project/linux-media/patch/[email protected]/

Regards!

On Fri, 6 Jan 2023 at 07:19, Kees Cook <[email protected]> wrote:
>
> The memcpy() in uvc_video_decode_meta() intentionally copies across the
> length and flags members and into the trailing buf flexible array.
> Split the copy so that the compiler can better reason about (the lack
> of) buffer overflows here. Avoid the run-time false positive warning:
>
> memcpy: detected field-spanning write (size 12) of single field "&meta->length" at drivers/media/usb/uvc/uvc_video.c:1355 (size 1)
>
> Additionally fix a typo in the documentation for struct uvc_meta_buf.
>
> Reported-by: [email protected]
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=216810
> Cc: Laurent Pinchart <[email protected]>
> Cc: Mauro Carvalho Chehab <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> drivers/media/usb/uvc/uvc_video.c | 4 +++-
> include/uapi/linux/uvcvideo.h | 2 +-
> 2 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
> index d2eb9066e4dc..b67347ab4181 100644
> --- a/drivers/media/usb/uvc/uvc_video.c
> +++ b/drivers/media/usb/uvc/uvc_video.c
> @@ -1352,7 +1352,9 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream,
> if (has_scr)
> memcpy(stream->clock.last_scr, scr, 6);
>
> - memcpy(&meta->length, mem, length);
> + meta->length = mem[0];
> + meta->flags = mem[1];
> + memcpy(meta->buf, &mem[2], length - 2);
> meta_buf->bytesused += length + sizeof(meta->ns) + sizeof(meta->sof);
>
> uvc_dbg(stream->dev, FRAME,
> diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
> index 8288137387c0..a9d0a64007ba 100644
> --- a/include/uapi/linux/uvcvideo.h
> +++ b/include/uapi/linux/uvcvideo.h
> @@ -86,7 +86,7 @@ struct uvc_xu_control_query {
> * struct. The first two fields are added by the driver, they can be used for
> * clock synchronisation. The rest is an exact copy of a UVC payload header.
> * Only complete objects with complete buffers are included. Therefore it's
> - * always sizeof(meta->ts) + sizeof(meta->sof) + meta->length bytes large.
> + * always sizeof(meta->ns) + sizeof(meta->sof) + meta->length bytes large.
> */
> struct uvc_meta_buf {
> __u64 ns;
> --
> 2.34.1
>


--
Ricardo Ribalda

2023-01-06 20:39:24

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH] media: uvcvideo: Silence memcpy() run-time false positive warnings

On Fri, Jan 06, 2023 at 12:43:44PM +0100, Ricardo Ribalda wrote:
> On Fri, 6 Jan 2023 at 07:19, Kees Cook <[email protected]> wrote:
> >
> > The memcpy() in uvc_video_decode_meta() intentionally copies across the
> > length and flags members and into the trailing buf flexible array.
> > Split the copy so that the compiler can better reason about (the lack
> > of) buffer overflows here. Avoid the run-time false positive warning:
> >
> > memcpy: detected field-spanning write (size 12) of single field "&meta->length" at drivers/media/usb/uvc/uvc_video.c:1355 (size 1)
> >
> > Additionally fix a typo in the documentation for struct uvc_meta_buf.
> >
> > Reported-by: [email protected]
> > Link: https://bugzilla.kernel.org/show_bug.cgi?id=216810
> > Cc: Laurent Pinchart <[email protected]>
> > Cc: Mauro Carvalho Chehab <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Kees Cook <[email protected]>
> > ---
> > drivers/media/usb/uvc/uvc_video.c | 4 +++-
> > include/uapi/linux/uvcvideo.h | 2 +-
> > 2 files changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
> > index d2eb9066e4dc..b67347ab4181 100644
> > --- a/drivers/media/usb/uvc/uvc_video.c
> > +++ b/drivers/media/usb/uvc/uvc_video.c
> > @@ -1352,7 +1352,9 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream,
> > if (has_scr)
> > memcpy(stream->clock.last_scr, scr, 6);
> >
> > - memcpy(&meta->length, mem, length);
> > + meta->length = mem[0];
> > + meta->flags = mem[1];
> > + memcpy(meta->buf, &mem[2], length - 2);
> > meta_buf->bytesused += length + sizeof(meta->ns) + sizeof(meta->sof);
> >
> > uvc_dbg(stream->dev, FRAME,
> > diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
> > index 8288137387c0..a9d0a64007ba 100644
> > --- a/include/uapi/linux/uvcvideo.h
> > +++ b/include/uapi/linux/uvcvideo.h
> > @@ -86,7 +86,7 @@ struct uvc_xu_control_query {
> > * struct. The first two fields are added by the driver, they can be used for
> > * clock synchronisation. The rest is an exact copy of a UVC payload header.
> > * Only complete objects with complete buffers are included. Therefore it's
> > - * always sizeof(meta->ts) + sizeof(meta->sof) + meta->length bytes large.
> > + * always sizeof(meta->ns) + sizeof(meta->sof) + meta->length bytes large.
> > */
> > struct uvc_meta_buf {
> > __u64 ns;
> [...]
>
> Would it make more sense to replace *mem with a structure/union. Something like:
> https://patchwork.linuxtv.org/project/linux-media/patch/[email protected]/

I wasn't sure -- it seemed like this routine was doing the serializing
into a struct already and an additional struct overlay wasn't going to
improve readability. But I can certainly do that if it's preferred!

-Kees

--
Kees Cook

2023-01-07 02:29:19

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH] media: uvcvideo: Silence memcpy() run-time false positive warnings

Hello,

On Fri, Jan 06, 2023 at 12:19:01PM -0800, Kees Cook wrote:
> On Fri, Jan 06, 2023 at 12:43:44PM +0100, Ricardo Ribalda wrote:
> > On Fri, 6 Jan 2023 at 07:19, Kees Cook wrote:
> > >
> > > The memcpy() in uvc_video_decode_meta() intentionally copies across the
> > > length and flags members and into the trailing buf flexible array.
> > > Split the copy so that the compiler can better reason about (the lack
> > > of) buffer overflows here. Avoid the run-time false positive warning:
> > >
> > > memcpy: detected field-spanning write (size 12) of single field "&meta->length" at drivers/media/usb/uvc/uvc_video.c:1355 (size 1)
> > >
> > > Additionally fix a typo in the documentation for struct uvc_meta_buf.
> > >
> > > Reported-by: [email protected]
> > > Link: https://bugzilla.kernel.org/show_bug.cgi?id=216810
> > > Cc: Laurent Pinchart <[email protected]>
> > > Cc: Mauro Carvalho Chehab <[email protected]>
> > > Cc: [email protected]
> > > Signed-off-by: Kees Cook <[email protected]>
> > > ---
> > > drivers/media/usb/uvc/uvc_video.c | 4 +++-
> > > include/uapi/linux/uvcvideo.h | 2 +-
> > > 2 files changed, 4 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
> > > index d2eb9066e4dc..b67347ab4181 100644
> > > --- a/drivers/media/usb/uvc/uvc_video.c
> > > +++ b/drivers/media/usb/uvc/uvc_video.c
> > > @@ -1352,7 +1352,9 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream,
> > > if (has_scr)
> > > memcpy(stream->clock.last_scr, scr, 6);
> > >
> > > - memcpy(&meta->length, mem, length);
> > > + meta->length = mem[0];
> > > + meta->flags = mem[1];
> > > + memcpy(meta->buf, &mem[2], length - 2);
> > > meta_buf->bytesused += length + sizeof(meta->ns) + sizeof(meta->sof);
> > >
> > > uvc_dbg(stream->dev, FRAME,
> > > diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
> > > index 8288137387c0..a9d0a64007ba 100644
> > > --- a/include/uapi/linux/uvcvideo.h
> > > +++ b/include/uapi/linux/uvcvideo.h
> > > @@ -86,7 +86,7 @@ struct uvc_xu_control_query {
> > > * struct. The first two fields are added by the driver, they can be used for
> > > * clock synchronisation. The rest is an exact copy of a UVC payload header.
> > > * Only complete objects with complete buffers are included. Therefore it's
> > > - * always sizeof(meta->ts) + sizeof(meta->sof) + meta->length bytes large.
> > > + * always sizeof(meta->ns) + sizeof(meta->sof) + meta->length bytes large.
> > > */
> > > struct uvc_meta_buf {
> > > __u64 ns;
> > [...]
> >
> > Would it make more sense to replace *mem with a structure/union. Something like:
> > https://patchwork.linuxtv.org/project/linux-media/patch/[email protected]/
>
> I wasn't sure -- it seemed like this routine was doing the serializing
> into a struct already and an additional struct overlay wasn't going to
> improve readability. But I can certainly do that if it's preferred!

I'm not sure to see how using an additional struct or union would help.
We can't use struct assignment as the data may be unaligned, so memcpy()
is required. The issue isn't with the source operand of the memcpy() but
with the destination operand. Ricardo, if I'm missing something, please
submit an alternative patch to explain what you meant.

Reviewed-by: Laurent Pinchart <[email protected]>

--
Regards,

Laurent Pinchart

2023-01-09 10:53:57

by Ricardo Ribalda

[permalink] [raw]
Subject: Re: [PATCH] media: uvcvideo: Silence memcpy() run-time false positive warnings

Hi Laurent

I was thinking about something on the line of the attached patch,

uvc_frame_header->data could also be replaced with a union.

Warning, not tested ;)


On Sat, 7 Jan 2023 at 02:42, Laurent Pinchart
<[email protected]> wrote:
>
> Hello,
>
> On Fri, Jan 06, 2023 at 12:19:01PM -0800, Kees Cook wrote:
> > On Fri, Jan 06, 2023 at 12:43:44PM +0100, Ricardo Ribalda wrote:
> > > On Fri, 6 Jan 2023 at 07:19, Kees Cook wrote:
> > > >
> > > > The memcpy() in uvc_video_decode_meta() intentionally copies across the
> > > > length and flags members and into the trailing buf flexible array.
> > > > Split the copy so that the compiler can better reason about (the lack
> > > > of) buffer overflows here. Avoid the run-time false positive warning:
> > > >
> > > > memcpy: detected field-spanning write (size 12) of single field "&meta->length" at drivers/media/usb/uvc/uvc_video.c:1355 (size 1)
> > > >
> > > > Additionally fix a typo in the documentation for struct uvc_meta_buf.
> > > >
> > > > Reported-by: [email protected]
> > > > Link: https://bugzilla.kernel.org/show_bug.cgi?id=216810
> > > > Cc: Laurent Pinchart <[email protected]>
> > > > Cc: Mauro Carvalho Chehab <[email protected]>
> > > > Cc: [email protected]
> > > > Signed-off-by: Kees Cook <[email protected]>
> > > > ---
> > > > drivers/media/usb/uvc/uvc_video.c | 4 +++-
> > > > include/uapi/linux/uvcvideo.h | 2 +-
> > > > 2 files changed, 4 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
> > > > index d2eb9066e4dc..b67347ab4181 100644
> > > > --- a/drivers/media/usb/uvc/uvc_video.c
> > > > +++ b/drivers/media/usb/uvc/uvc_video.c
> > > > @@ -1352,7 +1352,9 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream,
> > > > if (has_scr)
> > > > memcpy(stream->clock.last_scr, scr, 6);
> > > >
> > > > - memcpy(&meta->length, mem, length);
> > > > + meta->length = mem[0];
> > > > + meta->flags = mem[1];
> > > > + memcpy(meta->buf, &mem[2], length - 2);
> > > > meta_buf->bytesused += length + sizeof(meta->ns) + sizeof(meta->sof);
> > > >
> > > > uvc_dbg(stream->dev, FRAME,
> > > > diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
> > > > index 8288137387c0..a9d0a64007ba 100644
> > > > --- a/include/uapi/linux/uvcvideo.h
> > > > +++ b/include/uapi/linux/uvcvideo.h
> > > > @@ -86,7 +86,7 @@ struct uvc_xu_control_query {
> > > > * struct. The first two fields are added by the driver, they can be used for
> > > > * clock synchronisation. The rest is an exact copy of a UVC payload header.
> > > > * Only complete objects with complete buffers are included. Therefore it's
> > > > - * always sizeof(meta->ts) + sizeof(meta->sof) + meta->length bytes large.
> > > > + * always sizeof(meta->ns) + sizeof(meta->sof) + meta->length bytes large.
> > > > */
> > > > struct uvc_meta_buf {
> > > > __u64 ns;
> > > [...]
> > >
> > > Would it make more sense to replace *mem with a structure/union. Something like:
> > > https://patchwork.linuxtv.org/project/linux-media/patch/[email protected]/
> >
> > I wasn't sure -- it seemed like this routine was doing the serializing
> > into a struct already and an additional struct overlay wasn't going to
> > improve readability. But I can certainly do that if it's preferred!
>
> I'm not sure to see how using an additional struct or union would help.
> We can't use struct assignment as the data may be unaligned, so memcpy()
> is required. The issue isn't with the source operand of the memcpy() but
> with the destination operand. Ricardo, if I'm missing something, please
> submit an alternative patch to explain what you meant.
>
> Reviewed-by: Laurent Pinchart <[email protected]>
>
> --
> Regards,
>
> Laurent Pinchart



--
Ricardo Ribalda


Attachments:
0001-media-uvcvideo-Refactor-uvc_video_decode_meta.patch (4.40 kB)

2023-02-07 22:07:49

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH] media: uvcvideo: Silence memcpy() run-time false positive warnings

On Mon, Jan 09, 2023 at 11:46:00AM +0100, Ricardo Ribalda wrote:
> Hi Laurent
>
> I was thinking about something on the line of the attached patch,
>
> uvc_frame_header->data could also be replaced with a union.
>
> Warning, not tested ;)

...

> +struct uvc_frame_header {
> + u8 length;
> + u8 flags;
> + u8 data[];
> +} __packed;

__packed! (See below)

...

> + pts = (u32 *) header->data;

Ai-ai-ai.
Here is just a yellow flag...

...

> uvc_dbg(stream->dev, FRAME,
> "%s(): t-sys %lluns, SOF %u, len %u, flags 0x%x, PTS %u, STC %u frame SOF %u\n",
> __func__, ktime_to_ns(time), meta->sof, meta->length,
> meta->flags,
> + has_pts ? *pts : 0,

...and here is a red flag. What you need to have is

void *pts;
u32 pts_val;

pts_val = get_unaligned_be32(); // or le32

...use pts_val...

> + has_scr ? scr->scr : 0,
> + has_scr ? scr->frame_sof & 0x7ff : 0);


--
With Best Regards,
Andy Shevchenko



2023-02-22 13:15:06

by Ricardo Ribalda

[permalink] [raw]
Subject: Re: [PATCH] media: uvcvideo: Silence memcpy() run-time false positive warnings

Hi Andy

On Tue, 7 Feb 2023 at 23:07, Andy Shevchenko
<[email protected]> wrote:
>
> On Mon, Jan 09, 2023 at 11:46:00AM +0100, Ricardo Ribalda wrote:
> > Hi Laurent
> >
> > I was thinking about something on the line of the attached patch,
> >
> > uvc_frame_header->data could also be replaced with a union.
> >
> > Warning, not tested ;)
>
> ...
>
> > +struct uvc_frame_header {
> > + u8 length;
> > + u8 flags;
> > + u8 data[];
> > +} __packed;
>
> __packed! (See below)
>
> ...
>
> > + pts = (u32 *) header->data;
>
> Ai-ai-ai.
> Here is just a yellow flag...
>
> ...
>
> > uvc_dbg(stream->dev, FRAME,
> > "%s(): t-sys %lluns, SOF %u, len %u, flags 0x%x, PTS %u, STC %u frame SOF %u\n",
> > __func__, ktime_to_ns(time), meta->sof, meta->length,
> > meta->flags,
> > + has_pts ? *pts : 0,
>
> ...and here is a red flag. What you need to have is

Thanks! you are absolutely right :)

Luckily Laurent merged the original patch not mine.

Regards!

>
> void *pts;
> u32 pts_val;
>
> pts_val = get_unaligned_be32(); // or le32
>
> ...use pts_val...
>
> > + has_scr ? scr->scr : 0,
> > + has_scr ? scr->frame_sof & 0x7ff : 0);
>
>
> --
> With Best Regards,
> Andy Shevchenko
>
>


--
Ricardo Ribalda