summaryrefslogtreecommitdiffstats
path: root/sound/usb/mixer.c
diff options
context:
space:
mode:
authorHui Peng <benquike@gmail.com>2019-08-15 00:31:34 -0400
committerTakashi Iwai <tiwai@suse.de>2019-08-15 15:48:52 -0400
commit19bce474c45be69a284ecee660aa12d8f1e88f18 (patch)
tree9a58decee9c325aa1dc879780b3bc778d6793e36 /sound/usb/mixer.c
parentdaac07156b330b18eb5071aec4b3ddca1c377f2c (diff)
ALSA: usb-audio: Fix a stack buffer overflow bug in check_input_term
`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>
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r--sound/usb/mixer.c35
1 files changed, 27 insertions, 8 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index ea487378be17..b5927c3d5bc0 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -68,6 +68,7 @@ struct mixer_build {
68 unsigned char *buffer; 68 unsigned char *buffer;
69 unsigned int buflen; 69 unsigned int buflen;
70 DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS); 70 DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
71 DECLARE_BITMAP(termbitmap, MAX_ID_ELEMS);
71 struct usb_audio_term oterm; 72 struct usb_audio_term oterm;
72 const struct usbmix_name_map *map; 73 const struct usbmix_name_map *map;
73 const struct usbmix_selector_map *selector_map; 74 const struct usbmix_selector_map *selector_map;
@@ -775,16 +776,25 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state,
775 * parse the source unit recursively until it reaches to a terminal 776 * parse the source unit recursively until it reaches to a terminal
776 * or a branched unit. 777 * or a branched unit.
777 */ 778 */
778static int check_input_term(struct mixer_build *state, int id, 779static int __check_input_term(struct mixer_build *state, int id,
779 struct usb_audio_term *term) 780 struct usb_audio_term *term)
780{ 781{
781 int protocol = state->mixer->protocol; 782 int protocol = state->mixer->protocol;
782 int err; 783 int err;
783 void *p1; 784 void *p1;
785 unsigned char *hdr;
784 786
785 memset(term, 0, sizeof(*term)); 787 memset(term, 0, sizeof(*term));
786 while ((p1 = find_audio_control_unit(state, id)) != NULL) { 788 for (;;) {
787 unsigned char *hdr = p1; 789 /* a loop in the terminal chain? */
790 if (test_and_set_bit(id, state->termbitmap))
791 return -EINVAL;
792
793 p1 = find_audio_control_unit(state, id);
794 if (!p1)
795 break;
796
797 hdr = p1;
788 term->id = id; 798 term->id = id;
789 799
790 if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { 800 if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
@@ -802,7 +812,7 @@ static int check_input_term(struct mixer_build *state, int id,
802 812
803 /* call recursively to verify that the 813 /* call recursively to verify that the
804 * referenced clock entity is valid */ 814 * referenced clock entity is valid */
805 err = check_input_term(state, d->bCSourceID, term); 815 err = __check_input_term(state, d->bCSourceID, term);
806 if (err < 0) 816 if (err < 0)
807 return err; 817 return err;
808 818
@@ -836,7 +846,7 @@ static int check_input_term(struct mixer_build *state, int id,
836 case UAC2_CLOCK_SELECTOR: { 846 case UAC2_CLOCK_SELECTOR: {
837 struct uac_selector_unit_descriptor *d = p1; 847 struct uac_selector_unit_descriptor *d = p1;
838 /* call recursively to retrieve the channel info */ 848 /* call recursively to retrieve the channel info */
839 err = check_input_term(state, d->baSourceID[0], term); 849 err = __check_input_term(state, d->baSourceID[0], term);
840 if (err < 0) 850 if (err < 0)
841 return err; 851 return err;
842 term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ 852 term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
@@ -899,7 +909,7 @@ static int check_input_term(struct mixer_build *state, int id,
899 909
900 /* call recursively to verify that the 910 /* call recursively to verify that the
901 * referenced clock entity is valid */ 911 * referenced clock entity is valid */
902 err = check_input_term(state, d->bCSourceID, term); 912 err = __check_input_term(state, d->bCSourceID, term);
903 if (err < 0) 913 if (err < 0)
904 return err; 914 return err;
905 915
@@ -950,7 +960,7 @@ static int check_input_term(struct mixer_build *state, int id,
950 case UAC3_CLOCK_SELECTOR: { 960 case UAC3_CLOCK_SELECTOR: {
951 struct uac_selector_unit_descriptor *d = p1; 961 struct uac_selector_unit_descriptor *d = p1;
952 /* call recursively to retrieve the channel info */ 962 /* call recursively to retrieve the channel info */
953 err = check_input_term(state, d->baSourceID[0], term); 963 err = __check_input_term(state, d->baSourceID[0], term);
954 if (err < 0) 964 if (err < 0)
955 return err; 965 return err;
956 term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ 966 term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
@@ -966,7 +976,7 @@ static int check_input_term(struct mixer_build *state, int id,
966 return -EINVAL; 976 return -EINVAL;
967 977
968 /* call recursively to retrieve the channel info */ 978 /* call recursively to retrieve the channel info */
969 err = check_input_term(state, d->baSourceID[0], term); 979 err = __check_input_term(state, d->baSourceID[0], term);
970 if (err < 0) 980 if (err < 0)
971 return err; 981 return err;
972 982
@@ -984,6 +994,15 @@ static int check_input_term(struct mixer_build *state, int id,
984 return -ENODEV; 994 return -ENODEV;
985} 995}
986 996
997
998static int check_input_term(struct mixer_build *state, int id,
999 struct usb_audio_term *term)
1000{
1001 memset(term, 0, sizeof(*term));
1002 memset(state->termbitmap, 0, sizeof(state->termbitmap));
1003 return __check_input_term(state, id, term);
1004}
1005
987/* 1006/*
988 * Feature Unit 1007 * Feature Unit
989 */ 1008 */