Module Name: src Committed By: mlelstv Date: Mon Apr 10 15:26:57 UTC 2023
Modified Files: src/sys/dev/usb: uvideo.c uvideoreg.h Log Message: Better descriptor parsing. Add sanity check if no default format is found. To generate a diff of this commit: cvs rdiff -u -r1.83 -r1.84 src/sys/dev/usb/uvideo.c cvs rdiff -u -r1.7 -r1.8 src/sys/dev/usb/uvideoreg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/uvideo.c diff -u src/sys/dev/usb/uvideo.c:1.83 src/sys/dev/usb/uvideo.c:1.84 --- src/sys/dev/usb/uvideo.c:1.83 Fri Jul 1 01:06:51 2022 +++ src/sys/dev/usb/uvideo.c Mon Apr 10 15:26:56 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: uvideo.c,v 1.83 2022/07/01 01:06:51 riastradh Exp $ */ +/* $NetBSD: uvideo.c,v 1.84 2023/04/10 15:26:56 mlelstv Exp $ */ /* * Copyright (c) 2008 Patrick Mahoney @@ -42,7 +42,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uvideo.c,v 1.83 2022/07/01 01:06:51 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvideo.c,v 1.84 2023/04/10 15:26:56 mlelstv Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -442,12 +442,8 @@ static void print_vs_format_dv_descripto const uvideo_vs_format_dv_descriptor_t *); #endif /* !UVIDEO_DEBUG */ -#define GET(type, descp, field) \ - (KASSERT((descp)->bLength >= sizeof(type)), \ - ((const type *)(descp))->field) -#define GETP(type, descp, field) \ - (KASSERT((descp)->bLength >= sizeof(type)), \ - &(((const type *)(descp))->field)) +#define GET(type, descp, field) (((const type *)(descp))->field) +#define GETP(type, descp, field) (&(((const type *)(descp))->field)) /* * Given a format descriptor and frame descriptor, copy values common @@ -1312,6 +1308,13 @@ uvideo_stream_free(struct uvideo_stream kmem_free(vs, sizeof(*vs)); } +#define framedesc_size(T, d) ( \ + offsetof(T, uFrameInterval) + \ + ((T *)(d))->bFrameIntervalType \ + ? ((T *)(d))->bFrameIntervalType \ + * sizeof(((T *)(d))->uFrameInterval.discrete) \ + : sizeof(((T *)(d))->uFrameInterval.continuous) \ +) static usbd_status uvideo_stream_init_frame_based_format(struct uvideo_stream *vs, @@ -1342,7 +1345,6 @@ uvideo_stream_init_frame_based_format(st return USBD_INVAL; } subtype = UDESC_VS_FRAME_UNCOMPRESSED; - subtypelen = sizeof(uvideo_vs_frame_uncompressed_descriptor_t); default_index = GET(uvideo_vs_format_uncompressed_descriptor_t, format_desc, bDefaultFrameIndex); @@ -1372,7 +1374,6 @@ uvideo_stream_init_frame_based_format(st return USBD_INVAL; } subtype = UDESC_VS_FRAME_FRAME_BASED; - subtypelen = sizeof(uvideo_frame_frame_based_descriptor_t); default_index = GET(uvideo_format_frame_based_descriptor_t, format_desc, bDefaultFrameIndex); @@ -1386,7 +1387,6 @@ uvideo_stream_init_frame_based_format(st return USBD_INVAL; } subtype = UDESC_VS_FRAME_MJPEG; - subtypelen = sizeof(uvideo_vs_frame_mjpeg_descriptor_t); default_index = GET(uvideo_vs_format_mjpeg_descriptor_t, format_desc, bDefaultFrameIndex); @@ -1398,8 +1398,6 @@ uvideo_stream_init_frame_based_format(st return USBD_INVAL; } - KASSERT(subtypelen >= sizeof(*uvdesc)); - pformat = NULL; SIMPLEQ_FOREACH(pfiter, &vs->vs_pixel_formats, entries) { if (pfiter->pixel_format == pixel_format) { @@ -1432,6 +1430,29 @@ uvideo_stream_init_frame_based_format(st uvdesc = (const uvideo_descriptor_t *)desc; if (uvdesc->bDescriptorSubtype != subtype) break; + + switch (format_desc->bDescriptorSubtype) { + case UDESC_VS_FORMAT_UNCOMPRESSED: + subtypelen = framedesc_size( + const uvideo_vs_frame_uncompressed_descriptor_t, + uvdesc); + break; + case UDESC_VS_FORMAT_MJPEG: + subtypelen = framedesc_size( + const uvideo_vs_frame_mjpeg_descriptor_t, + uvdesc); + break; + case UDESC_VS_FORMAT_FRAME_BASED: + subtypelen = framedesc_size( + const uvideo_frame_frame_based_descriptor_t, + uvdesc); + break; + default: + /* will bail out below */ + subtypelen = uvdesc->bLength; + break; + } + if (uvdesc->bLength < subtypelen) { DPRINTF(("uvideo:" " truncated CS subtype-0x%x descriptor," @@ -1985,7 +2006,10 @@ uvideo_open(void *addr, int flags) return EIO; /* XXX select default format */ + if (vs->vs_default_format == NULL) + return EINVAL; fmt = *vs->vs_default_format; + return uvideo_set_format(addr, &fmt); } Index: src/sys/dev/usb/uvideoreg.h diff -u src/sys/dev/usb/uvideoreg.h:1.7 src/sys/dev/usb/uvideoreg.h:1.8 --- src/sys/dev/usb/uvideoreg.h:1.7 Sat May 14 15:28:59 2022 +++ src/sys/dev/usb/uvideoreg.h Mon Apr 10 15:26:56 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: uvideoreg.h,v 1.7 2022/05/14 15:28:59 riastradh Exp $ */ +/* $NetBSD: uvideoreg.h,v 1.8 2023/04/10 15:26:56 mlelstv Exp $ */ /* * Copyright (c) 2008 Patrick Mahoney @@ -435,8 +435,9 @@ typedef struct { uDWord dwMaxVideoFrameBufferSize; uDWord dwDefaultFrameInterval; uByte bFrameIntervalType; + uvideo_frame_interval_t uFrameInterval; } UPACKED uvideo_vs_frame_uncompressed_descriptor_t; -CTASSERT(sizeof(uvideo_vs_frame_uncompressed_descriptor_t) == 26); + /* Frame based Format and Frame descriptors. This is for generic * frame based payloads not covered by other types (e.g, uncompressed @@ -470,8 +471,9 @@ typedef struct { uDWord dwDefaultFrameInterval; uByte bFrameIntervalType; uDWord dwBytesPerLine; + uvideo_frame_interval_t uFrameInterval; } UPACKED uvideo_frame_frame_based_descriptor_t; -CTASSERT(sizeof(uvideo_frame_frame_based_descriptor_t) == 26); + /* MJPEG format and frame descriptors */ @@ -504,8 +506,9 @@ typedef struct { uDWord dwMaxVideoFrameBufferSize; uDWord dwDefaultFrameInterval; uByte bFrameIntervalType; + uvideo_frame_interval_t uFrameInterval; } UPACKED uvideo_vs_frame_mjpeg_descriptor_t; -CTASSERT(sizeof(uvideo_vs_frame_mjpeg_descriptor_t) == 26); + typedef struct { uByte bLength;