On Sat, 17 Aug 2019 06:32:07 +0200, Hui Peng wrote:
`uac_mixer_unit_get_channels` calls `uac_mixer_unit_bmControls` to get pointer to bmControls field. The current implementation of `uac_mixer_unit_get_channels` does properly check the size of uac_mixer_unit_descriptor descriptor and may allow OOB access in `uac_mixer_unit_bmControls`.
Reported-by: Hui Peng benquike@gmail.com Reported-by: Mathias Payer mathias.payer@nebelwelt.net Signed-off-by: Hui Peng benquike@gmail.com
Ah a good catch.
One easier fix in this case would be to get the offset from uac_mixer_unit_bmControls(), e.g.
/* calculate the offset of bmControls field */ size_t bmc_offset = uac_mixer_unit_bmControls(NULL, protocol) - NULL; .... if (desc->bLength < bmc_offset) return 0;
thanks,
Takashi
sound/usb/mixer.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index b5927c3d5bc0..00e6274a63c3 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -738,28 +738,39 @@ static int get_cluster_channels_v3(struct mixer_build *state, unsigned int clust static int uac_mixer_unit_get_channels(struct mixer_build *state, struct uac_mixer_unit_descriptor *desc) {
- int mu_channels;
- int mu_channels = 0; void *c;
if (desc->bLength < sizeof(*desc))
return -EINVAL;
if (!desc->bNrInPins) return -EINVAL;
if (desc->bLength < sizeof(*desc) + desc->bNrInPins)
return -EINVAL;
switch (state->mixer->protocol) { case UAC_VERSION_1:
// limit derived from uac_mixer_unit_bmControls
if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 4)
return 0;
mu_channels = uac_mixer_unit_bNrChannels(desc);
break;
- case UAC_VERSION_2:
- default:
if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 1)
// limit derived from uac_mixer_unit_bmControls
if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 6) return 0; /* no bmControls -> skip */
mu_channels = uac_mixer_unit_bNrChannels(desc); break; case UAC_VERSION_3:
// limit derived from uac_mixer_unit_bmControls
if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 2)
return 0; /* no bmControls -> skip */
mu_channels = get_cluster_channels_v3(state, uac3_mixer_unit_wClusterDescrID(desc)); break;
default:
break;
}
if (!mu_channels)
-- 2.22.1