135 lines
4.7 KiB
Diff
135 lines
4.7 KiB
Diff
From: Hui Peng <benquike@gmail.com>
|
|
Date: Thu, 15 Aug 2019 00:31:34 -0400
|
|
Subject: ALSA: usb-audio: Fix a stack buffer overflow bug in check_input_term
|
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-15118
|
|
Origin: https://git.kernel.org/linus/19bce474c45be69a284ecee660aa12d8f1e88f18
|
|
|
|
commit 19bce474c45be69a284ecee660aa12d8f1e88f18 upstream.
|
|
|
|
`check_input_term` recursively calls itself with input from
|
|
device side (e.g., uac_input_terminal_descriptor.bCSourceID)
|
|
as argument (id). In `check_input_term`, if `check_input_term`
|
|
is called with the same `id` argument as the caller, it triggers
|
|
endless recursive call, resulting kernel space stack overflow.
|
|
|
|
This patch fixes the bug by adding a bitmap to `struct mixer_build`
|
|
to keep track of the checked ids and stop the execution if some id
|
|
has been checked (similar to how parse_audio_unit handles unitid
|
|
argument).
|
|
|
|
Reported-by: Hui Peng <benquike@gmail.com>
|
|
Reported-by: Mathias Payer <mathias.payer@nebelwelt.net>
|
|
Signed-off-by: Hui Peng <benquike@gmail.com>
|
|
Cc: <stable@vger.kernel.org>
|
|
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
---
|
|
sound/usb/mixer.c | 35 +++++++++++++++++++++++++++--------
|
|
1 file changed, 27 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
|
|
index 7e1c6c2dc99e..996126a28072 100644
|
|
--- a/sound/usb/mixer.c
|
|
+++ b/sound/usb/mixer.c
|
|
@@ -83,6 +83,7 @@ struct mixer_build {
|
|
unsigned char *buffer;
|
|
unsigned int buflen;
|
|
DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
|
|
+ DECLARE_BITMAP(termbitmap, MAX_ID_ELEMS);
|
|
struct usb_audio_term oterm;
|
|
const struct usbmix_name_map *map;
|
|
const struct usbmix_selector_map *selector_map;
|
|
@@ -788,16 +789,25 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state,
|
|
* parse the source unit recursively until it reaches to a terminal
|
|
* or a branched unit.
|
|
*/
|
|
-static int check_input_term(struct mixer_build *state, int id,
|
|
+static int __check_input_term(struct mixer_build *state, int id,
|
|
struct usb_audio_term *term)
|
|
{
|
|
int protocol = state->mixer->protocol;
|
|
int err;
|
|
void *p1;
|
|
+ unsigned char *hdr;
|
|
|
|
memset(term, 0, sizeof(*term));
|
|
- while ((p1 = find_audio_control_unit(state, id)) != NULL) {
|
|
- unsigned char *hdr = p1;
|
|
+ for (;;) {
|
|
+ /* a loop in the terminal chain? */
|
|
+ if (test_and_set_bit(id, state->termbitmap))
|
|
+ return -EINVAL;
|
|
+
|
|
+ p1 = find_audio_control_unit(state, id);
|
|
+ if (!p1)
|
|
+ break;
|
|
+
|
|
+ hdr = p1;
|
|
term->id = id;
|
|
|
|
if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
|
|
@@ -815,7 +825,7 @@ static int check_input_term(struct mixer_build *state, int id,
|
|
|
|
/* call recursively to verify that the
|
|
* referenced clock entity is valid */
|
|
- err = check_input_term(state, d->bCSourceID, term);
|
|
+ err = __check_input_term(state, d->bCSourceID, term);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
@@ -849,7 +859,7 @@ static int check_input_term(struct mixer_build *state, int id,
|
|
case UAC2_CLOCK_SELECTOR: {
|
|
struct uac_selector_unit_descriptor *d = p1;
|
|
/* call recursively to retrieve the channel info */
|
|
- err = check_input_term(state, d->baSourceID[0], term);
|
|
+ err = __check_input_term(state, d->baSourceID[0], term);
|
|
if (err < 0)
|
|
return err;
|
|
term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
|
|
@@ -912,7 +922,7 @@ static int check_input_term(struct mixer_build *state, int id,
|
|
|
|
/* call recursively to verify that the
|
|
* referenced clock entity is valid */
|
|
- err = check_input_term(state, d->bCSourceID, term);
|
|
+ err = __check_input_term(state, d->bCSourceID, term);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
@@ -963,7 +973,7 @@ static int check_input_term(struct mixer_build *state, int id,
|
|
case UAC3_CLOCK_SELECTOR: {
|
|
struct uac_selector_unit_descriptor *d = p1;
|
|
/* call recursively to retrieve the channel info */
|
|
- err = check_input_term(state, d->baSourceID[0], term);
|
|
+ err = __check_input_term(state, d->baSourceID[0], term);
|
|
if (err < 0)
|
|
return err;
|
|
term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
|
|
@@ -979,7 +989,7 @@ static int check_input_term(struct mixer_build *state, int id,
|
|
return -EINVAL;
|
|
|
|
/* call recursively to retrieve the channel info */
|
|
- err = check_input_term(state, d->baSourceID[0], term);
|
|
+ err = __check_input_term(state, d->baSourceID[0], term);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
@@ -997,6 +1007,15 @@ static int check_input_term(struct mixer_build *state, int id,
|
|
return -ENODEV;
|
|
}
|
|
|
|
+
|
|
+static int check_input_term(struct mixer_build *state, int id,
|
|
+ struct usb_audio_term *term)
|
|
+{
|
|
+ memset(term, 0, sizeof(*term));
|
|
+ memset(state->termbitmap, 0, sizeof(state->termbitmap));
|
|
+ return __check_input_term(state, id, term);
|
|
+}
|
|
+
|
|
/*
|
|
* Feature Unit
|
|
*/
|
|
--
|
|
cgit 1.2-0.3.lf.el7
|
|
|