From 484d0b5f4b9ce1cf58121a4c59271385c5b3ff8a Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 28 Aug 2019 13:37:05 +0200 Subject: [PATCH] ALSA: usb-audio: Fix a stack buffer overflow bug in check_input_term (CVE-2019-15118) --- debian/changelog | 2 + ...fer-overflow-bug-in-check_input_term.patch | 134 ++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 137 insertions(+) create mode 100644 debian/patches/bugfix/all/ALSA-usb-audio-Fix-a-stack-buffer-overflow-bug-in-check_input_term.patch diff --git a/debian/changelog b/debian/changelog index 50fc45c5b..0133893bb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,8 @@ linux (4.19.67-3) UNRELEASED; urgency=medium [ Romain Perier ] * ALSA: usb-audio: Fix an OOB bug in parse_audio_mixer_unit (CVE-2019-15117) + * ALSA: usb-audio: Fix a stack buffer overflow bug in check_input_term + (CVE-2019-15118) -- Romain Perier Wed, 28 Aug 2019 13:28:09 +0200 diff --git a/debian/patches/bugfix/all/ALSA-usb-audio-Fix-a-stack-buffer-overflow-bug-in-check_input_term.patch b/debian/patches/bugfix/all/ALSA-usb-audio-Fix-a-stack-buffer-overflow-bug-in-check_input_term.patch new file mode 100644 index 000000000..4f7a8deb9 --- /dev/null +++ b/debian/patches/bugfix/all/ALSA-usb-audio-Fix-a-stack-buffer-overflow-bug-in-check_input_term.patch @@ -0,0 +1,134 @@ +From: Hui Peng +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 +Reported-by: Mathias Payer +Signed-off-by: Hui Peng +Cc: +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + 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 + diff --git a/debian/patches/series b/debian/patches/series index 65e6a8fc2..5c987a19b 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -163,6 +163,7 @@ debian/i386-686-pae-pci-set-pci-nobios-by-default.patch debian/ntfs-mark-it-as-broken.patch bugfix/all/netfilter-conntrack-use-consistent-ct-id-hash-calcul.patch bugfix/all/ALSA-usb-audio-Fix-an-OOB-bug-in-parse_audio_mixer_unit.patch +bugfix/all/ALSA-usb-audio-Fix-a-stack-buffer-overflow-bug-in-check_input_term.patch # Fix exported symbol versions bugfix/all/module-disable-matching-missing-version-crc.patch