From: Greg Kroah-Hartman Date: Mon, 11 Nov 2019 09:44:09 +0000 (+0100) Subject: 5.3-stable patches X-Git-Tag: v4.4.201~28 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0e626424553f51ff0842a5f9cd0a596a8651cb4d;p=thirdparty%2Fkernel%2Fstable-queue.git 5.3-stable patches added patches: alsa-usb-audio-clean-up-check_input_term.patch alsa-usb-audio-fix-copy-paste-error-in-the-validator.patch alsa-usb-audio-fix-possible-null-dereference-at-create_yamaha_midi_quirk.patch alsa-usb-audio-more-validations-of-descriptor-units.patch alsa-usb-audio-remove-some-dead-code.patch alsa-usb-audio-remove-superfluous-blength-checks.patch alsa-usb-audio-simplify-parse_audio_unit.patch alsa-usb-audio-unify-the-release-of-usb_mixer_elem_info-objects.patch usbip-implement-sg-support-to-vhci-hcd-and-stub-driver.patch --- diff --git a/queue-5.3/alsa-usb-audio-clean-up-check_input_term.patch b/queue-5.3/alsa-usb-audio-clean-up-check_input_term.patch new file mode 100644 index 00000000000..e80db253946 --- /dev/null +++ b/queue-5.3/alsa-usb-audio-clean-up-check_input_term.patch @@ -0,0 +1,477 @@ +From e0ccdef92653f8867e2d1667facfd3c23699f540 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 23 Aug 2019 12:38:07 +0200 +Subject: ALSA: usb-audio: Clean up check_input_term() + +From: Takashi Iwai + +commit e0ccdef92653f8867e2d1667facfd3c23699f540 upstream. + +The primary changes in this patch are cleanups of __check_input_term() +and move to a non-nested switch-case block by evaluating the pair of +UAC version and the unit type, as we've done for parse_audio_unit(). +Also each parser is split into the function for readability. + +Now, a slight behavior change by this cleanup is the handling of +processing and extension units. Formerly we've dealt with them +differently between UAC1/2 and UAC3; the latter returns an error if no +input sources are available, while the former continues to parse. + +In this patch, unify the behavior in all cases: when input sources are +available, it parses recursively, then override the type and the id, +as well as channel information if not provided yet. + +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/usb/mixer.c | 407 ++++++++++++++++++++++++++++-------------------------- + 1 file changed, 212 insertions(+), 195 deletions(-) + +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -758,224 +758,242 @@ static int uac_mixer_unit_get_channels(s + } + + /* +- * parse the source unit recursively until it reaches to a terminal +- * or a branched unit. ++ * Parse Input Terminal Unit + */ + static int __check_input_term(struct mixer_build *state, int id, +- struct usb_audio_term *term) ++ struct usb_audio_term *term); ++ ++static int parse_term_uac1_iterm_unit(struct mixer_build *state, ++ struct usb_audio_term *term, ++ void *p1, int id) ++{ ++ struct uac_input_terminal_descriptor *d = p1; ++ ++ term->type = le16_to_cpu(d->wTerminalType); ++ term->channels = d->bNrChannels; ++ term->chconfig = le16_to_cpu(d->wChannelConfig); ++ term->name = d->iTerminal; ++ return 0; ++} ++ ++static int parse_term_uac2_iterm_unit(struct mixer_build *state, ++ struct usb_audio_term *term, ++ void *p1, int id) + { +- int protocol = state->mixer->protocol; ++ struct uac2_input_terminal_descriptor *d = p1; + int err; +- void *p1; +- unsigned char *hdr; + +- memset(term, 0, sizeof(*term)); +- for (;;) { +- /* a loop in the terminal chain? */ +- if (test_and_set_bit(id, state->termbitmap)) +- return -EINVAL; ++ /* call recursively to verify the referenced clock entity */ ++ err = __check_input_term(state, d->bCSourceID, term); ++ if (err < 0) ++ return err; + +- p1 = find_audio_control_unit(state, id); +- if (!p1) +- break; +- if (!snd_usb_validate_audio_desc(p1, protocol)) +- break; /* bad descriptor */ ++ /* save input term properties after recursion, ++ * to ensure they are not overriden by the recursion calls ++ */ ++ term->id = id; ++ term->type = le16_to_cpu(d->wTerminalType); ++ term->channels = d->bNrChannels; ++ term->chconfig = le32_to_cpu(d->bmChannelConfig); ++ term->name = d->iTerminal; ++ return 0; ++} + +- hdr = p1; +- term->id = id; ++static int parse_term_uac3_iterm_unit(struct mixer_build *state, ++ struct usb_audio_term *term, ++ void *p1, int id) ++{ ++ struct uac3_input_terminal_descriptor *d = p1; ++ int err; + +- if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { +- switch (hdr[2]) { +- case UAC_INPUT_TERMINAL: +- if (protocol == UAC_VERSION_1) { +- struct uac_input_terminal_descriptor *d = p1; +- +- term->type = le16_to_cpu(d->wTerminalType); +- term->channels = d->bNrChannels; +- term->chconfig = le16_to_cpu(d->wChannelConfig); +- term->name = d->iTerminal; +- } else { /* UAC_VERSION_2 */ +- struct uac2_input_terminal_descriptor *d = p1; +- +- /* call recursively to verify that the +- * referenced clock entity is valid */ +- err = __check_input_term(state, d->bCSourceID, term); +- if (err < 0) +- return err; +- +- /* save input term properties after recursion, +- * to ensure they are not overriden by the +- * recursion calls */ +- term->id = id; +- term->type = le16_to_cpu(d->wTerminalType); +- term->channels = d->bNrChannels; +- term->chconfig = le32_to_cpu(d->bmChannelConfig); +- term->name = d->iTerminal; +- } +- return 0; +- case UAC_FEATURE_UNIT: { +- /* the header is the same for v1 and v2 */ +- struct uac_feature_unit_descriptor *d = p1; ++ /* call recursively to verify the referenced clock entity */ ++ err = __check_input_term(state, d->bCSourceID, term); ++ if (err < 0) ++ return err; + +- id = d->bSourceID; +- break; /* continue to parse */ +- } +- case UAC_MIXER_UNIT: { +- struct uac_mixer_unit_descriptor *d = p1; ++ /* save input term properties after recursion, ++ * to ensure they are not overriden by the recursion calls ++ */ ++ term->id = id; ++ term->type = le16_to_cpu(d->wTerminalType); + +- term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ +- term->channels = uac_mixer_unit_bNrChannels(d); +- term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol); +- term->name = uac_mixer_unit_iMixer(d); +- return 0; +- } +- case UAC_SELECTOR_UNIT: +- 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); +- if (err < 0) +- return err; +- term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ +- term->id = id; +- term->name = uac_selector_unit_iSelector(d); +- return 0; +- } +- case UAC1_PROCESSING_UNIT: +- /* UAC2_EFFECT_UNIT */ +- if (protocol == UAC_VERSION_1) +- term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ +- else /* UAC_VERSION_2 */ +- term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */ +- /* fall through */ +- case UAC1_EXTENSION_UNIT: +- /* UAC2_PROCESSING_UNIT_V2 */ +- if (protocol == UAC_VERSION_1 && !term->type) +- term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ +- else if (protocol == UAC_VERSION_2 && !term->type) +- term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ +- /* fall through */ +- case UAC2_EXTENSION_UNIT_V2: { +- struct uac_processing_unit_descriptor *d = p1; +- +- if (protocol == UAC_VERSION_2 && +- hdr[2] == UAC2_EFFECT_UNIT) { +- /* UAC2/UAC1 unit IDs overlap here in an +- * uncompatible way. Ignore this unit for now. +- */ +- return 0; +- } ++ err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID)); ++ if (err < 0) ++ return err; ++ term->channels = err; + +- if (d->bNrInPins) { +- id = d->baSourceID[0]; +- break; /* continue to parse */ +- } +- if (!term->type) +- term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ ++ /* REVISIT: UAC3 IT doesn't have channels cfg */ ++ term->chconfig = 0; + +- term->channels = uac_processing_unit_bNrChannels(d); +- term->chconfig = uac_processing_unit_wChannelConfig(d, protocol); +- term->name = uac_processing_unit_iProcessing(d, protocol); +- return 0; +- } +- case UAC2_CLOCK_SOURCE: { +- struct uac_clock_source_descriptor *d = p1; ++ term->name = le16_to_cpu(d->wTerminalDescrStr); ++ return 0; ++} + +- term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ +- term->id = id; +- term->name = d->iClockSource; +- return 0; +- } +- default: +- return -ENODEV; +- } +- } else { /* UAC_VERSION_3 */ +- switch (hdr[2]) { +- case UAC_INPUT_TERMINAL: { +- struct uac3_input_terminal_descriptor *d = p1; +- +- /* call recursively to verify that the +- * referenced clock entity is valid */ +- err = __check_input_term(state, d->bCSourceID, term); +- if (err < 0) +- return err; +- +- /* save input term properties after recursion, +- * to ensure they are not overriden by the +- * recursion calls */ +- term->id = id; +- term->type = le16_to_cpu(d->wTerminalType); +- +- err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID)); +- if (err < 0) +- return err; +- term->channels = err; ++static int parse_term_mixer_unit(struct mixer_build *state, ++ struct usb_audio_term *term, ++ void *p1, int id) ++{ ++ struct uac_mixer_unit_descriptor *d = p1; ++ int protocol = state->mixer->protocol; ++ int err; + +- /* REVISIT: UAC3 IT doesn't have channels cfg */ +- term->chconfig = 0; ++ err = uac_mixer_unit_get_channels(state, d); ++ if (err <= 0) ++ return err; + +- term->name = le16_to_cpu(d->wTerminalDescrStr); +- return 0; +- } +- case UAC3_FEATURE_UNIT: { +- struct uac3_feature_unit_descriptor *d = p1; ++ term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ ++ term->channels = err; ++ if (protocol != UAC_VERSION_3) { ++ term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol); ++ term->name = uac_mixer_unit_iMixer(d); ++ } ++ return 0; ++} + +- id = d->bSourceID; +- break; /* continue to parse */ +- } +- case UAC3_CLOCK_SOURCE: { +- struct uac3_clock_source_descriptor *d = p1; ++static int parse_term_selector_unit(struct mixer_build *state, ++ struct usb_audio_term *term, ++ void *p1, int id) ++{ ++ struct uac_selector_unit_descriptor *d = p1; ++ int err; + +- term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ +- term->id = id; +- term->name = le16_to_cpu(d->wClockSourceStr); +- return 0; +- } +- case UAC3_MIXER_UNIT: { +- struct uac_mixer_unit_descriptor *d = p1; ++ /* call recursively to retrieve the channel info */ ++ err = __check_input_term(state, d->baSourceID[0], term); ++ if (err < 0) ++ return err; ++ term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ ++ term->id = id; ++ if (state->mixer->protocol != UAC_VERSION_3) ++ term->name = uac_selector_unit_iSelector(d); ++ return 0; ++} + +- err = uac_mixer_unit_get_channels(state, d); +- if (err <= 0) +- return err; ++static int parse_term_proc_unit(struct mixer_build *state, ++ struct usb_audio_term *term, ++ void *p1, int id, int vtype) ++{ ++ struct uac_processing_unit_descriptor *d = p1; ++ int protocol = state->mixer->protocol; ++ int err; + +- term->channels = err; +- term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ ++ if (d->bNrInPins) { ++ /* call recursively to retrieve the channel info */ ++ err = __check_input_term(state, d->baSourceID[0], term); ++ if (err < 0) ++ return err; ++ } + +- return 0; +- } +- case UAC3_SELECTOR_UNIT: +- 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); +- if (err < 0) +- return err; +- term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ +- term->id = id; +- term->name = 0; /* TODO: UAC3 Class-specific strings */ ++ term->type = vtype << 16; /* virtual type */ ++ term->id = id; + +- return 0; +- } +- case UAC3_PROCESSING_UNIT: { +- struct uac_processing_unit_descriptor *d = p1; ++ if (protocol == UAC_VERSION_3) ++ return 0; + +- if (!d->bNrInPins) +- return -EINVAL; ++ if (!term->channels) { ++ term->channels = uac_processing_unit_bNrChannels(d); ++ term->chconfig = uac_processing_unit_wChannelConfig(d, protocol); ++ } ++ term->name = uac_processing_unit_iProcessing(d, protocol); ++ return 0; ++} ++ ++static int parse_term_uac2_clock_source(struct mixer_build *state, ++ struct usb_audio_term *term, ++ void *p1, int id) ++{ ++ struct uac_clock_source_descriptor *d = p1; ++ ++ term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ ++ term->id = id; ++ term->name = d->iClockSource; ++ return 0; ++} + +- /* call recursively to retrieve the channel info */ +- err = __check_input_term(state, d->baSourceID[0], term); +- if (err < 0) +- return err; +- +- term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ +- term->id = id; +- term->name = 0; /* TODO: UAC3 Class-specific strings */ ++static int parse_term_uac3_clock_source(struct mixer_build *state, ++ struct usb_audio_term *term, ++ void *p1, int id) ++{ ++ struct uac3_clock_source_descriptor *d = p1; ++ ++ term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ ++ term->id = id; ++ term->name = le16_to_cpu(d->wClockSourceStr); ++ return 0; ++} + +- return 0; +- } +- default: +- return -ENODEV; +- } ++#define PTYPE(a, b) ((a) << 8 | (b)) ++ ++/* ++ * 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, ++ struct usb_audio_term *term) ++{ ++ int protocol = state->mixer->protocol; ++ void *p1; ++ unsigned char *hdr; ++ ++ 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; ++ if (!snd_usb_validate_audio_desc(p1, protocol)) ++ break; /* bad descriptor */ ++ ++ hdr = p1; ++ term->id = id; ++ ++ switch (PTYPE(protocol, hdr[2])) { ++ case PTYPE(UAC_VERSION_1, UAC_FEATURE_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC_FEATURE_UNIT): ++ case PTYPE(UAC_VERSION_3, UAC3_FEATURE_UNIT): { ++ /* the header is the same for all versions */ ++ struct uac_feature_unit_descriptor *d = p1; ++ ++ id = d->bSourceID; ++ break; /* continue to parse */ ++ } ++ case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL): ++ return parse_term_uac1_iterm_unit(state, term, p1, id); ++ case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL): ++ return parse_term_uac2_iterm_unit(state, term, p1, id); ++ case PTYPE(UAC_VERSION_3, UAC_INPUT_TERMINAL): ++ return parse_term_uac3_iterm_unit(state, term, p1, id); ++ case PTYPE(UAC_VERSION_1, UAC_MIXER_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC_MIXER_UNIT): ++ case PTYPE(UAC_VERSION_3, UAC3_MIXER_UNIT): ++ return parse_term_mixer_unit(state, term, p1, id); ++ case PTYPE(UAC_VERSION_1, UAC_SELECTOR_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC_SELECTOR_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SELECTOR): ++ case PTYPE(UAC_VERSION_3, UAC3_SELECTOR_UNIT): ++ case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SELECTOR): ++ return parse_term_selector_unit(state, term, p1, id); ++ case PTYPE(UAC_VERSION_1, UAC1_PROCESSING_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2): ++ case PTYPE(UAC_VERSION_3, UAC3_PROCESSING_UNIT): ++ return parse_term_proc_unit(state, term, p1, id, ++ UAC3_PROCESSING_UNIT); ++ case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT): ++ case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT): ++ return parse_term_proc_unit(state, term, p1, id, ++ UAC3_EFFECT_UNIT); ++ case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2): ++ case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT): ++ return parse_term_proc_unit(state, term, p1, id, ++ UAC3_EXTENSION_UNIT); ++ case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SOURCE): ++ return parse_term_uac2_clock_source(state, term, p1, id); ++ case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SOURCE): ++ return parse_term_uac3_clock_source(state, term, p1, id); ++ default: ++ return -ENODEV; + } + } + return -ENODEV; +@@ -2712,7 +2730,6 @@ static int parse_audio_unit(struct mixer + return 0; /* skip invalid unit */ + } + +-#define PTYPE(a, b) ((a) << 8 | (b)) + switch (PTYPE(protocol, p1[2])) { + case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL): + case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL): diff --git a/queue-5.3/alsa-usb-audio-fix-copy-paste-error-in-the-validator.patch b/queue-5.3/alsa-usb-audio-fix-copy-paste-error-in-the-validator.patch new file mode 100644 index 00000000000..bc931ea9141 --- /dev/null +++ b/queue-5.3/alsa-usb-audio-fix-copy-paste-error-in-the-validator.patch @@ -0,0 +1,35 @@ +From ba8bf0967a154796be15c4983603aad0b05c3138 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 22 Oct 2019 17:45:14 +0200 +Subject: ALSA: usb-audio: Fix copy&paste error in the validator + +From: Takashi Iwai + +commit ba8bf0967a154796be15c4983603aad0b05c3138 upstream. + +The recently introduced USB-audio descriptor validator had a stupid +copy&paste error that may lead to an unexpected overlook of too short +descriptors for processing and extension units. It's likely the cause +of the report triggered by syzkaller fuzzer. Let's fix it. + +Fixes: 57f8770620e9 ("ALSA: usb-audio: More validations of descriptor units") +Reported-by: syzbot+0620f79a1978b1133fd7@syzkaller.appspotmail.com +Link: https://lore.kernel.org/r/s5hsgnkdbsl.wl-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/usb/validate.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/usb/validate.c ++++ b/sound/usb/validate.c +@@ -75,7 +75,7 @@ static bool validate_processing_unit(con + + if (d->bLength < sizeof(*d)) + return false; +- len = d->bLength < sizeof(*d) + d->bNrInPins; ++ len = sizeof(*d) + d->bNrInPins; + if (d->bLength < len) + return false; + switch (v->protocol) { diff --git a/queue-5.3/alsa-usb-audio-fix-possible-null-dereference-at-create_yamaha_midi_quirk.patch b/queue-5.3/alsa-usb-audio-fix-possible-null-dereference-at-create_yamaha_midi_quirk.patch new file mode 100644 index 00000000000..83bdb81dcf7 --- /dev/null +++ b/queue-5.3/alsa-usb-audio-fix-possible-null-dereference-at-create_yamaha_midi_quirk.patch @@ -0,0 +1,35 @@ +From 60849562a5db4a1eee2160167e4dce4590d3eafe Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 26 Aug 2019 13:55:21 +0200 +Subject: ALSA: usb-audio: Fix possible NULL dereference at create_yamaha_midi_quirk() + +From: Takashi Iwai + +commit 60849562a5db4a1eee2160167e4dce4590d3eafe upstream. + +The previous addition of descriptor validation may lead to a NULL +dereference at create_yamaha_midi_quirk() when either injd or outjd is +NULL. Add proper non-NULL checks. + +Fixes: 57f8770620e9 ("ALSA: usb-audio: More validations of descriptor units") +Reported-by: Dan Carpenter +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/usb/quirks.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -248,8 +248,8 @@ static int create_yamaha_midi_quirk(stru + NULL, USB_MS_MIDI_OUT_JACK); + if (!injd && !outjd) + return -ENODEV; +- if (!snd_usb_validate_midi_desc(injd) || +- !snd_usb_validate_midi_desc(outjd)) ++ if (!(injd && snd_usb_validate_midi_desc(injd)) || ++ !(outjd && snd_usb_validate_midi_desc(outjd))) + return -ENODEV; + if (injd && (injd->bLength < 5 || + (injd->bJackType != USB_MS_EMBEDDED && diff --git a/queue-5.3/alsa-usb-audio-more-validations-of-descriptor-units.patch b/queue-5.3/alsa-usb-audio-more-validations-of-descriptor-units.patch new file mode 100644 index 00000000000..0203e6e1918 --- /dev/null +++ b/queue-5.3/alsa-usb-audio-more-validations-of-descriptor-units.patch @@ -0,0 +1,533 @@ +From 57f8770620e9b51c61089751f0b5ad3dbe376ff2 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 20 Aug 2019 17:17:09 +0200 +Subject: ALSA: usb-audio: More validations of descriptor units + +From: Takashi Iwai + +commit 57f8770620e9b51c61089751f0b5ad3dbe376ff2 upstream. + +Introduce a new helper to validate each audio descriptor unit before +and check the unit before actually accessing it. This should harden +against the OOB access cases with malformed descriptors that have been +recently frequently reported by fuzzers. + +The existing descriptor checks are still kept although they become +superfluous after this patch. They'll be cleaned up eventually +later. + +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/usb/Makefile | 3 + sound/usb/helper.h | 4 + sound/usb/mixer.c | 10 + + sound/usb/power.c | 2 + sound/usb/quirks.c | 3 + sound/usb/stream.c | 25 +-- + sound/usb/validate.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 366 insertions(+), 13 deletions(-) + +--- a/sound/usb/Makefile ++++ b/sound/usb/Makefile +@@ -16,7 +16,8 @@ snd-usb-audio-objs := card.o \ + power.o \ + proc.o \ + quirks.o \ +- stream.o ++ stream.o \ ++ validate.o + + snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o + +--- a/sound/usb/helper.h ++++ b/sound/usb/helper.h +@@ -31,4 +31,8 @@ static inline int snd_usb_ctrl_intf(stru + return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber; + } + ++/* in validate.c */ ++bool snd_usb_validate_audio_desc(void *p, int protocol); ++bool snd_usb_validate_midi_desc(void *p); ++ + #endif /* __USBAUDIO_HELPER_H */ +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -785,6 +785,8 @@ static int __check_input_term(struct mix + p1 = find_audio_control_unit(state, id); + if (!p1) + break; ++ if (!snd_usb_validate_audio_desc(p1, protocol)) ++ break; /* bad descriptor */ + + hdr = p1; + term->id = id; +@@ -2775,6 +2777,11 @@ static int parse_audio_unit(struct mixer + return -EINVAL; + } + ++ if (!snd_usb_validate_audio_desc(p1, protocol)) { ++ usb_audio_dbg(state->chip, "invalid unit %d\n", unitid); ++ return 0; /* skip invalid unit */ ++ } ++ + if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { + switch (p1[2]) { + case UAC_INPUT_TERMINAL: +@@ -3145,6 +3152,9 @@ static int snd_usb_mixer_controls(struct + while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, + mixer->hostif->extralen, + p, UAC_OUTPUT_TERMINAL)) != NULL) { ++ if (!snd_usb_validate_audio_desc(p, mixer->protocol)) ++ continue; /* skip invalid descriptor */ ++ + if (mixer->protocol == UAC_VERSION_1) { + struct uac1_output_terminal_descriptor *desc = p; + +--- a/sound/usb/power.c ++++ b/sound/usb/power.c +@@ -31,6 +31,8 @@ snd_usb_find_power_domain(struct usb_hos + struct uac3_power_domain_descriptor *pd_desc = p; + int i; + ++ if (!snd_usb_validate_audio_desc(p, UAC_VERSION_3)) ++ continue; + for (i = 0; i < pd_desc->bNrEntities; i++) { + if (pd_desc->baEntityID[i] == id) { + pd->pd_id = pd_desc->bPowerDomainID; +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -248,6 +248,9 @@ static int create_yamaha_midi_quirk(stru + NULL, USB_MS_MIDI_OUT_JACK); + if (!injd && !outjd) + return -ENODEV; ++ if (!snd_usb_validate_midi_desc(injd) || ++ !snd_usb_validate_midi_desc(outjd)) ++ return -ENODEV; + if (injd && (injd->bLength < 5 || + (injd->bJackType != USB_MS_EMBEDDED && + injd->bJackType != USB_MS_EXTERNAL))) +--- a/sound/usb/stream.c ++++ b/sound/usb/stream.c +@@ -627,16 +627,14 @@ static int parse_uac_endpoint_attributes + */ + static void * + snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, +- int terminal_id, bool uac23) ++ int terminal_id, int protocol) + { + struct uac2_input_terminal_descriptor *term = NULL; +- size_t minlen = uac23 ? sizeof(struct uac2_input_terminal_descriptor) : +- sizeof(struct uac_input_terminal_descriptor); + + while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + term, UAC_INPUT_TERMINAL))) { +- if (term->bLength < minlen) ++ if (!snd_usb_validate_audio_desc(term, protocol)) + continue; + if (term->bTerminalID == terminal_id) + return term; +@@ -647,7 +645,7 @@ snd_usb_find_input_terminal_descriptor(s + + static void * + snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, +- int terminal_id) ++ int terminal_id, int protocol) + { + /* OK to use with both UAC2 and UAC3 */ + struct uac2_output_terminal_descriptor *term = NULL; +@@ -655,8 +653,9 @@ snd_usb_find_output_terminal_descriptor( + while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + term, UAC_OUTPUT_TERMINAL))) { +- if (term->bLength >= sizeof(*term) && +- term->bTerminalID == terminal_id) ++ if (!snd_usb_validate_audio_desc(term, protocol)) ++ continue; ++ if (term->bTerminalID == terminal_id) + return term; + } + +@@ -731,7 +730,7 @@ snd_usb_get_audioformat_uac12(struct snd + + iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink, +- false); ++ protocol); + if (iterm) { + num_channels = iterm->bNrChannels; + chconfig = le16_to_cpu(iterm->wChannelConfig); +@@ -767,7 +766,7 @@ snd_usb_get_audioformat_uac12(struct snd + */ + input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink, +- true); ++ protocol); + if (input_term) { + clock = input_term->bCSourceID; + if (!chconfig && (num_channels == input_term->bNrChannels)) +@@ -776,7 +775,8 @@ snd_usb_get_audioformat_uac12(struct snd + } + + output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, +- as->bTerminalLink); ++ as->bTerminalLink, ++ protocol); + if (output_term) { + clock = output_term->bCSourceID; + goto found_clock; +@@ -1002,14 +1002,15 @@ snd_usb_get_audioformat_uac3(struct snd_ + */ + input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink, +- true); ++ UAC_VERSION_3); + if (input_term) { + clock = input_term->bCSourceID; + goto found_clock; + } + + output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, +- as->bTerminalLink); ++ as->bTerminalLink, ++ UAC_VERSION_3); + if (output_term) { + clock = output_term->bCSourceID; + goto found_clock; +--- /dev/null ++++ b/sound/usb/validate.c +@@ -0,0 +1,332 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// ++// Validation of USB-audio class descriptors ++// ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "usbaudio.h" ++#include "helper.h" ++ ++struct usb_desc_validator { ++ unsigned char protocol; ++ unsigned char type; ++ bool (*func)(const void *p, const struct usb_desc_validator *v); ++ size_t size; ++}; ++ ++#define UAC_VERSION_ALL (unsigned char)(-1) ++ ++/* UAC1 only */ ++static bool validate_uac1_header(const void *p, ++ const struct usb_desc_validator *v) ++{ ++ const struct uac1_ac_header_descriptor *d = p; ++ ++ return d->bLength >= sizeof(*d) && ++ d->bLength >= sizeof(*d) + d->bInCollection; ++} ++ ++/* for mixer unit; covering all UACs */ ++static bool validate_mixer_unit(const void *p, ++ const struct usb_desc_validator *v) ++{ ++ const struct uac_mixer_unit_descriptor *d = p; ++ size_t len; ++ ++ if (d->bLength < sizeof(*d) || !d->bNrInPins) ++ return false; ++ len = sizeof(*d) + d->bNrInPins; ++ /* We can't determine the bitmap size only from this unit descriptor, ++ * so just check with the remaining length. ++ * The actual bitmap is checked at mixer unit parser. ++ */ ++ switch (v->protocol) { ++ case UAC_VERSION_1: ++ default: ++ len += 2 + 1; /* wChannelConfig, iChannelNames */ ++ /* bmControls[n*m] */ ++ len += 1; /* iMixer */ ++ break; ++ case UAC_VERSION_2: ++ len += 4 + 1; /* bmChannelConfig, iChannelNames */ ++ /* bmMixerControls[n*m] */ ++ len += 1 + 1; /* bmControls, iMixer */ ++ break; ++ case UAC_VERSION_3: ++ len += 2; /* wClusterDescrID */ ++ /* bmMixerControls[n*m] */ ++ break; ++ } ++ return d->bLength >= len; ++} ++ ++/* both for processing and extension units; covering all UACs */ ++static bool validate_processing_unit(const void *p, ++ const struct usb_desc_validator *v) ++{ ++ const struct uac_processing_unit_descriptor *d = p; ++ const unsigned char *hdr = p; ++ size_t len, m; ++ ++ if (d->bLength < sizeof(*d)) ++ return false; ++ len = d->bLength < sizeof(*d) + d->bNrInPins; ++ if (d->bLength < len) ++ return false; ++ switch (v->protocol) { ++ case UAC_VERSION_1: ++ default: ++ /* bNrChannels, wChannelConfig, iChannelNames, bControlSize */ ++ len += 1 + 2 + 1 + 1; ++ if (d->bLength < len) /* bControlSize */ ++ return false; ++ m = hdr[len]; ++ len += 1 + m + 1; /* bControlSize, bmControls, iProcessing */ ++ break; ++ case UAC_VERSION_2: ++ /* bNrChannels, bmChannelConfig, iChannelNames */ ++ len += 1 + 4 + 1; ++ if (v->type == UAC2_PROCESSING_UNIT_V2) ++ len += 2; /* bmControls -- 2 bytes for PU */ ++ else ++ len += 1; /* bmControls -- 1 byte for EU */ ++ len += 1; /* iProcessing */ ++ break; ++ case UAC_VERSION_3: ++ /* wProcessingDescrStr, bmControls */ ++ len += 2 + 4; ++ break; ++ } ++ if (d->bLength < len) ++ return false; ++ ++ switch (v->protocol) { ++ case UAC_VERSION_1: ++ default: ++ if (v->type == UAC1_EXTENSION_UNIT) ++ return true; /* OK */ ++ switch (d->wProcessType) { ++ case UAC_PROCESS_UP_DOWNMIX: ++ case UAC_PROCESS_DOLBY_PROLOGIC: ++ if (d->bLength < len + 1) /* bNrModes */ ++ return false; ++ m = hdr[len]; ++ len += 1 + m * 2; /* bNrModes, waModes(n) */ ++ break; ++ default: ++ break; ++ } ++ break; ++ case UAC_VERSION_2: ++ if (v->type == UAC2_EXTENSION_UNIT_V2) ++ return true; /* OK */ ++ switch (d->wProcessType) { ++ case UAC2_PROCESS_UP_DOWNMIX: ++ case UAC2_PROCESS_DOLBY_PROLOCIC: /* SiC! */ ++ if (d->bLength < len + 1) /* bNrModes */ ++ return false; ++ m = hdr[len]; ++ len += 1 + m * 4; /* bNrModes, daModes(n) */ ++ break; ++ default: ++ break; ++ } ++ break; ++ case UAC_VERSION_3: ++ if (v->type == UAC3_EXTENSION_UNIT) { ++ len += 2; /* wClusterDescrID */ ++ break; ++ } ++ switch (d->wProcessType) { ++ case UAC3_PROCESS_UP_DOWNMIX: ++ if (d->bLength < len + 1) /* bNrModes */ ++ return false; ++ m = hdr[len]; ++ len += 1 + m * 2; /* bNrModes, waClusterDescrID(n) */ ++ break; ++ case UAC3_PROCESS_MULTI_FUNCTION: ++ len += 2 + 4; /* wClusterDescrID, bmAlgorighms */ ++ break; ++ default: ++ break; ++ } ++ break; ++ } ++ if (d->bLength < len) ++ return false; ++ ++ return true; ++} ++ ++/* both for selector and clock selector units; covering all UACs */ ++static bool validate_selector_unit(const void *p, ++ const struct usb_desc_validator *v) ++{ ++ const struct uac_selector_unit_descriptor *d = p; ++ size_t len; ++ ++ if (d->bLength < sizeof(*d)) ++ return false; ++ len = sizeof(*d) + d->bNrInPins; ++ switch (v->protocol) { ++ case UAC_VERSION_1: ++ default: ++ len += 1; /* iSelector */ ++ break; ++ case UAC_VERSION_2: ++ len += 1 + 1; /* bmControls, iSelector */ ++ break; ++ case UAC_VERSION_3: ++ len += 4 + 2; /* bmControls, wSelectorDescrStr */ ++ break; ++ } ++ return d->bLength >= len; ++} ++ ++static bool validate_uac1_feature_unit(const void *p, ++ const struct usb_desc_validator *v) ++{ ++ const struct uac_feature_unit_descriptor *d = p; ++ ++ if (d->bLength < sizeof(*d) || !d->bControlSize) ++ return false; ++ /* at least bmaControls(0) for master channel + iFeature */ ++ return d->bLength >= sizeof(*d) + d->bControlSize + 1; ++} ++ ++static bool validate_uac2_feature_unit(const void *p, ++ const struct usb_desc_validator *v) ++{ ++ const struct uac2_feature_unit_descriptor *d = p; ++ ++ if (d->bLength < sizeof(*d)) ++ return false; ++ /* at least bmaControls(0) for master channel + iFeature */ ++ return d->bLength >= sizeof(*d) + 4 + 1; ++} ++ ++static bool validate_uac3_feature_unit(const void *p, ++ const struct usb_desc_validator *v) ++{ ++ const struct uac3_feature_unit_descriptor *d = p; ++ ++ if (d->bLength < sizeof(*d)) ++ return false; ++ /* at least bmaControls(0) for master channel + wFeatureDescrStr */ ++ return d->bLength >= sizeof(*d) + 4 + 2; ++} ++ ++static bool validate_midi_out_jack(const void *p, ++ const struct usb_desc_validator *v) ++{ ++ const struct usb_midi_out_jack_descriptor *d = p; ++ ++ return d->bLength >= sizeof(*d) && ++ d->bLength >= sizeof(*d) + d->bNrInputPins * 2; ++} ++ ++#define FIXED(p, t, s) { .protocol = (p), .type = (t), .size = sizeof(s) } ++#define FUNC(p, t, f) { .protocol = (p), .type = (t), .func = (f) } ++ ++static struct usb_desc_validator audio_validators[] = { ++ /* UAC1 */ ++ FUNC(UAC_VERSION_1, UAC_HEADER, validate_uac1_header), ++ FIXED(UAC_VERSION_1, UAC_INPUT_TERMINAL, ++ struct uac_input_terminal_descriptor), ++ FIXED(UAC_VERSION_1, UAC_OUTPUT_TERMINAL, ++ struct uac1_output_terminal_descriptor), ++ FUNC(UAC_VERSION_1, UAC_MIXER_UNIT, validate_mixer_unit), ++ FUNC(UAC_VERSION_1, UAC_SELECTOR_UNIT, validate_selector_unit), ++ FUNC(UAC_VERSION_1, UAC_FEATURE_UNIT, validate_uac1_feature_unit), ++ FUNC(UAC_VERSION_1, UAC1_PROCESSING_UNIT, validate_processing_unit), ++ FUNC(UAC_VERSION_1, UAC1_EXTENSION_UNIT, validate_processing_unit), ++ ++ /* UAC2 */ ++ FIXED(UAC_VERSION_2, UAC_HEADER, struct uac2_ac_header_descriptor), ++ FIXED(UAC_VERSION_2, UAC_INPUT_TERMINAL, ++ struct uac2_input_terminal_descriptor), ++ FIXED(UAC_VERSION_2, UAC_OUTPUT_TERMINAL, ++ struct uac2_output_terminal_descriptor), ++ FUNC(UAC_VERSION_2, UAC_MIXER_UNIT, validate_mixer_unit), ++ FUNC(UAC_VERSION_2, UAC_SELECTOR_UNIT, validate_selector_unit), ++ FUNC(UAC_VERSION_2, UAC_FEATURE_UNIT, validate_uac2_feature_unit), ++ /* UAC_VERSION_2, UAC2_EFFECT_UNIT: not implemented yet */ ++ FUNC(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2, validate_processing_unit), ++ FUNC(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2, validate_processing_unit), ++ FIXED(UAC_VERSION_2, UAC2_CLOCK_SOURCE, ++ struct uac_clock_source_descriptor), ++ FUNC(UAC_VERSION_2, UAC2_CLOCK_SELECTOR, validate_selector_unit), ++ FIXED(UAC_VERSION_2, UAC2_CLOCK_MULTIPLIER, ++ struct uac_clock_multiplier_descriptor), ++ /* UAC_VERSION_2, UAC2_SAMPLE_RATE_CONVERTER: not implemented yet */ ++ ++ /* UAC3 */ ++ FIXED(UAC_VERSION_2, UAC_HEADER, struct uac3_ac_header_descriptor), ++ FIXED(UAC_VERSION_3, UAC_INPUT_TERMINAL, ++ struct uac3_input_terminal_descriptor), ++ FIXED(UAC_VERSION_3, UAC_OUTPUT_TERMINAL, ++ struct uac3_output_terminal_descriptor), ++ /* UAC_VERSION_3, UAC3_EXTENDED_TERMINAL: not implemented yet */ ++ FUNC(UAC_VERSION_3, UAC3_MIXER_UNIT, validate_mixer_unit), ++ FUNC(UAC_VERSION_3, UAC3_SELECTOR_UNIT, validate_selector_unit), ++ FUNC(UAC_VERSION_3, UAC_FEATURE_UNIT, validate_uac3_feature_unit), ++ /* UAC_VERSION_3, UAC3_EFFECT_UNIT: not implemented yet */ ++ FUNC(UAC_VERSION_3, UAC3_PROCESSING_UNIT, validate_processing_unit), ++ FUNC(UAC_VERSION_3, UAC3_EXTENSION_UNIT, validate_processing_unit), ++ FIXED(UAC_VERSION_3, UAC3_CLOCK_SOURCE, ++ struct uac3_clock_source_descriptor), ++ FUNC(UAC_VERSION_3, UAC3_CLOCK_SELECTOR, validate_selector_unit), ++ FIXED(UAC_VERSION_3, UAC3_CLOCK_MULTIPLIER, ++ struct uac3_clock_multiplier_descriptor), ++ /* UAC_VERSION_3, UAC3_SAMPLE_RATE_CONVERTER: not implemented yet */ ++ /* UAC_VERSION_3, UAC3_CONNECTORS: not implemented yet */ ++ { } /* terminator */ ++}; ++ ++static struct usb_desc_validator midi_validators[] = { ++ FIXED(UAC_VERSION_ALL, USB_MS_HEADER, ++ struct usb_ms_header_descriptor), ++ FIXED(UAC_VERSION_ALL, USB_MS_MIDI_IN_JACK, ++ struct usb_midi_in_jack_descriptor), ++ FUNC(UAC_VERSION_ALL, USB_MS_MIDI_OUT_JACK, ++ validate_midi_out_jack), ++ { } /* terminator */ ++}; ++ ++ ++/* Validate the given unit descriptor, return true if it's OK */ ++static bool validate_desc(unsigned char *hdr, int protocol, ++ const struct usb_desc_validator *v) ++{ ++ if (hdr[1] != USB_DT_CS_INTERFACE) ++ return true; /* don't care */ ++ ++ for (; v->type; v++) { ++ if (v->type == hdr[2] && ++ (v->protocol == UAC_VERSION_ALL || ++ v->protocol == protocol)) { ++ if (v->func) ++ return v->func(hdr, v); ++ /* check for the fixed size */ ++ return hdr[0] >= v->size; ++ } ++ } ++ ++ return true; /* not matching, skip validation */ ++} ++ ++bool snd_usb_validate_audio_desc(void *p, int protocol) ++{ ++ return validate_desc(p, protocol, audio_validators); ++} ++ ++bool snd_usb_validate_midi_desc(void *p) ++{ ++ return validate_desc(p, UAC_VERSION_1, midi_validators); ++} ++ diff --git a/queue-5.3/alsa-usb-audio-remove-some-dead-code.patch b/queue-5.3/alsa-usb-audio-remove-some-dead-code.patch new file mode 100644 index 00000000000..7256cfeb449 --- /dev/null +++ b/queue-5.3/alsa-usb-audio-remove-some-dead-code.patch @@ -0,0 +1,32 @@ +From b39e077fcb283dd96dd251a3abeba585402c61fe Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Mon, 26 Aug 2019 16:45:50 +0300 +Subject: ALSA: usb-audio: remove some dead code + +From: Dan Carpenter + +commit b39e077fcb283dd96dd251a3abeba585402c61fe upstream. + +We recently cleaned up the error handling in commit 52c3e317a857 ("ALSA: +usb-audio: Unify the release of usb_mixer_elem_info objects") but +accidentally left this stray return. + +Fixes: 52c3e317a857 ("ALSA: usb-audio: Unify the release of usb_mixer_elem_info objects") +Signed-off-by: Dan Carpenter +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/usb/mixer.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -2651,7 +2651,6 @@ static int parse_audio_selector_unit(str + usb_audio_err(state->chip, "cannot malloc kcontrol\n"); + err = -ENOMEM; + goto error_name; +- return -ENOMEM; + } + kctl->private_value = (unsigned long)namelist; + kctl->private_free = usb_mixer_selector_elem_free; diff --git a/queue-5.3/alsa-usb-audio-remove-superfluous-blength-checks.patch b/queue-5.3/alsa-usb-audio-remove-superfluous-blength-checks.patch new file mode 100644 index 00000000000..762e28010fb --- /dev/null +++ b/queue-5.3/alsa-usb-audio-remove-superfluous-blength-checks.patch @@ -0,0 +1,238 @@ +From b8e4f1fdfa422398c2d6c47bfb7d1feb3046d70a Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 22 Aug 2019 09:25:27 +0200 +Subject: ALSA: usb-audio: Remove superfluous bLength checks + +From: Takashi Iwai + +commit b8e4f1fdfa422398c2d6c47bfb7d1feb3046d70a upstream. + +Now that we got the more comprehensive validation code for USB-audio +descriptors, the check of overflow in each descriptor unit parser +became superfluous. Drop some of the obvious cases. + +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/usb/clock.c | 14 +++------ + sound/usb/mixer.c | 84 ------------------------------------------------------ + 2 files changed, 6 insertions(+), 92 deletions(-) + +--- a/sound/usb/clock.c ++++ b/sound/usb/clock.c +@@ -38,39 +38,37 @@ static void *find_uac_clock_desc(struct + static bool validate_clock_source_v2(void *p, int id) + { + struct uac_clock_source_descriptor *cs = p; +- return cs->bLength == sizeof(*cs) && cs->bClockID == id; ++ return cs->bClockID == id; + } + + static bool validate_clock_source_v3(void *p, int id) + { + struct uac3_clock_source_descriptor *cs = p; +- return cs->bLength == sizeof(*cs) && cs->bClockID == id; ++ return cs->bClockID == id; + } + + static bool validate_clock_selector_v2(void *p, int id) + { + struct uac_clock_selector_descriptor *cs = p; +- return cs->bLength >= sizeof(*cs) && cs->bClockID == id && +- cs->bLength == 7 + cs->bNrInPins; ++ return cs->bClockID == id; + } + + static bool validate_clock_selector_v3(void *p, int id) + { + struct uac3_clock_selector_descriptor *cs = p; +- return cs->bLength >= sizeof(*cs) && cs->bClockID == id && +- cs->bLength == 11 + cs->bNrInPins; ++ return cs->bClockID == id; + } + + static bool validate_clock_multiplier_v2(void *p, int id) + { + struct uac_clock_multiplier_descriptor *cs = p; +- return cs->bLength == sizeof(*cs) && cs->bClockID == id; ++ return cs->bClockID == id; + } + + static bool validate_clock_multiplier_v3(void *p, int id) + { + struct uac3_clock_multiplier_descriptor *cs = p; +- return cs->bLength == sizeof(*cs) && cs->bClockID == id; ++ return cs->bClockID == id; + } + + #define DEFINE_FIND_HELPER(name, obj, validator, type) \ +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -740,13 +740,6 @@ static int uac_mixer_unit_get_channels(s + { + int mu_channels; + +- 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: + case UAC_VERSION_2: +@@ -1781,13 +1774,6 @@ static int parse_clock_source_unit(struc + if (state->mixer->protocol != UAC_VERSION_2) + return -EINVAL; + +- if (hdr->bLength != sizeof(*hdr)) { +- usb_audio_dbg(state->chip, +- "Bogus clock source descriptor length of %d, ignoring.\n", +- hdr->bLength); +- return 0; +- } +- + /* + * The only property of this unit we are interested in is the + * clock source validity. If that isn't readable, just bail out. +@@ -1846,62 +1832,20 @@ static int parse_audio_feature_unit(stru + __u8 *bmaControls; + + if (state->mixer->protocol == UAC_VERSION_1) { +- if (hdr->bLength < 7) { +- usb_audio_err(state->chip, +- "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", +- unitid); +- return -EINVAL; +- } + csize = hdr->bControlSize; +- if (!csize) { +- usb_audio_dbg(state->chip, +- "unit %u: invalid bControlSize == 0\n", +- unitid); +- return -EINVAL; +- } + channels = (hdr->bLength - 7) / csize - 1; + bmaControls = hdr->bmaControls; +- if (hdr->bLength < 7 + csize) { +- usb_audio_err(state->chip, +- "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", +- unitid); +- return -EINVAL; +- } + } else if (state->mixer->protocol == UAC_VERSION_2) { + struct uac2_feature_unit_descriptor *ftr = _ftr; +- if (hdr->bLength < 6) { +- usb_audio_err(state->chip, +- "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", +- unitid); +- return -EINVAL; +- } + csize = 4; + channels = (hdr->bLength - 6) / 4 - 1; + bmaControls = ftr->bmaControls; +- if (hdr->bLength < 6 + csize) { +- usb_audio_err(state->chip, +- "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", +- unitid); +- return -EINVAL; +- } + } else { /* UAC_VERSION_3 */ + struct uac3_feature_unit_descriptor *ftr = _ftr; + +- if (hdr->bLength < 7) { +- usb_audio_err(state->chip, +- "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n", +- unitid); +- return -EINVAL; +- } + csize = 4; + channels = (ftr->bLength - 7) / 4 - 1; + bmaControls = ftr->bmaControls; +- if (hdr->bLength < 7 + csize) { +- usb_audio_err(state->chip, +- "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n", +- unitid); +- return -EINVAL; +- } + } + + /* parse the source unit */ +@@ -2101,15 +2045,11 @@ static int parse_audio_input_terminal(st + + if (state->mixer->protocol == UAC_VERSION_2) { + struct uac2_input_terminal_descriptor *d_v2 = raw_desc; +- if (d_v2->bLength < sizeof(*d_v2)) +- return -EINVAL; + control = UAC2_TE_CONNECTOR; + term_id = d_v2->bTerminalID; + bmctls = le16_to_cpu(d_v2->bmControls); + } else if (state->mixer->protocol == UAC_VERSION_3) { + struct uac3_input_terminal_descriptor *d_v3 = raw_desc; +- if (d_v3->bLength < sizeof(*d_v3)) +- return -EINVAL; + control = UAC3_TE_INSERTION; + term_id = d_v3->bTerminalID; + bmctls = le32_to_cpu(d_v3->bmControls); +@@ -2371,18 +2311,7 @@ static int build_audio_procunit(struct m + const char *name = extension_unit ? + "Extension Unit" : "Processing Unit"; + +- if (desc->bLength < 13) { +- usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid); +- return -EINVAL; +- } +- + num_ins = desc->bNrInPins; +- if (desc->bLength < 13 + num_ins || +- desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) { +- usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid); +- return -EINVAL; +- } +- + for (i = 0; i < num_ins; i++) { + err = parse_audio_unit(state, desc->baSourceID[i]); + if (err < 0) +@@ -2637,13 +2566,6 @@ static int parse_audio_selector_unit(str + const struct usbmix_name_map *map; + char **namelist; + +- if (desc->bLength < 5 || !desc->bNrInPins || +- desc->bLength < 5 + desc->bNrInPins) { +- usb_audio_err(state->chip, +- "invalid SELECTOR UNIT descriptor %d\n", unitid); +- return -EINVAL; +- } +- + for (i = 0; i < desc->bNrInPins; i++) { + err = parse_audio_unit(state, desc->baSourceID[i]); + if (err < 0) +@@ -3149,8 +3071,6 @@ static int snd_usb_mixer_controls(struct + if (mixer->protocol == UAC_VERSION_1) { + struct uac1_output_terminal_descriptor *desc = p; + +- if (desc->bLength < sizeof(*desc)) +- continue; /* invalid descriptor? */ + /* mark terminal ID as visited */ + set_bit(desc->bTerminalID, state.unitbitmap); + state.oterm.id = desc->bTerminalID; +@@ -3162,8 +3082,6 @@ static int snd_usb_mixer_controls(struct + } else if (mixer->protocol == UAC_VERSION_2) { + struct uac2_output_terminal_descriptor *desc = p; + +- if (desc->bLength < sizeof(*desc)) +- continue; /* invalid descriptor? */ + /* mark terminal ID as visited */ + set_bit(desc->bTerminalID, state.unitbitmap); + state.oterm.id = desc->bTerminalID; +@@ -3189,8 +3107,6 @@ static int snd_usb_mixer_controls(struct + } else { /* UAC_VERSION_3 */ + struct uac3_output_terminal_descriptor *desc = p; + +- if (desc->bLength < sizeof(*desc)) +- continue; /* invalid descriptor? */ + /* mark terminal ID as visited */ + set_bit(desc->bTerminalID, state.unitbitmap); + state.oterm.id = desc->bTerminalID; diff --git a/queue-5.3/alsa-usb-audio-simplify-parse_audio_unit.patch b/queue-5.3/alsa-usb-audio-simplify-parse_audio_unit.patch new file mode 100644 index 00000000000..04c55ac0958 --- /dev/null +++ b/queue-5.3/alsa-usb-audio-simplify-parse_audio_unit.patch @@ -0,0 +1,125 @@ +From 68e9fde245591d18200f8a9054cac22339437adb Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 15 Aug 2019 16:30:39 +0200 +Subject: ALSA: usb-audio: Simplify parse_audio_unit() + +From: Takashi Iwai + +commit 68e9fde245591d18200f8a9054cac22339437adb upstream. + +Minor code refactoring by combining the UAC version and the type in +the switch-case flow, so that we reduce the indentation and +redundancy. One good bonus is that the duplicated definition of the +same type value (e.g. UAC2_EFFECT_UNIT) can be handled more cleanly. + +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/usb/mixer.c | 95 ++++++++++++++++++++++-------------------------------- + 1 file changed, 39 insertions(+), 56 deletions(-) + +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -2782,62 +2782,45 @@ static int parse_audio_unit(struct mixer + return 0; /* skip invalid unit */ + } + +- if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { +- switch (p1[2]) { +- case UAC_INPUT_TERMINAL: +- return parse_audio_input_terminal(state, unitid, p1); +- case UAC_MIXER_UNIT: +- return parse_audio_mixer_unit(state, unitid, p1); +- case UAC2_CLOCK_SOURCE: +- return parse_clock_source_unit(state, unitid, p1); +- case UAC_SELECTOR_UNIT: +- case UAC2_CLOCK_SELECTOR: +- return parse_audio_selector_unit(state, unitid, p1); +- case UAC_FEATURE_UNIT: +- return parse_audio_feature_unit(state, unitid, p1); +- case UAC1_PROCESSING_UNIT: +- /* UAC2_EFFECT_UNIT has the same value */ +- if (protocol == UAC_VERSION_1) +- return parse_audio_processing_unit(state, unitid, p1); +- else +- return 0; /* FIXME - effect units not implemented yet */ +- case UAC1_EXTENSION_UNIT: +- /* UAC2_PROCESSING_UNIT_V2 has the same value */ +- if (protocol == UAC_VERSION_1) +- return parse_audio_extension_unit(state, unitid, p1); +- else /* UAC_VERSION_2 */ +- return parse_audio_processing_unit(state, unitid, p1); +- case UAC2_EXTENSION_UNIT_V2: +- return parse_audio_extension_unit(state, unitid, p1); +- default: +- usb_audio_err(state->chip, +- "unit %u: unexpected type 0x%02x\n", unitid, p1[2]); +- return -EINVAL; +- } +- } else { /* UAC_VERSION_3 */ +- switch (p1[2]) { +- case UAC_INPUT_TERMINAL: +- return parse_audio_input_terminal(state, unitid, p1); +- case UAC3_MIXER_UNIT: +- return parse_audio_mixer_unit(state, unitid, p1); +- case UAC3_CLOCK_SOURCE: +- return parse_clock_source_unit(state, unitid, p1); +- case UAC3_SELECTOR_UNIT: +- case UAC3_CLOCK_SELECTOR: +- return parse_audio_selector_unit(state, unitid, p1); +- case UAC3_FEATURE_UNIT: +- return parse_audio_feature_unit(state, unitid, p1); +- case UAC3_EFFECT_UNIT: +- return 0; /* FIXME - effect units not implemented yet */ +- case UAC3_PROCESSING_UNIT: +- return parse_audio_processing_unit(state, unitid, p1); +- case UAC3_EXTENSION_UNIT: +- return parse_audio_extension_unit(state, unitid, p1); +- default: +- usb_audio_err(state->chip, +- "unit %u: unexpected type 0x%02x\n", unitid, p1[2]); +- return -EINVAL; +- } ++#define PTYPE(a, b) ((a) << 8 | (b)) ++ switch (PTYPE(protocol, p1[2])) { ++ case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL): ++ case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL): ++ case PTYPE(UAC_VERSION_3, UAC_INPUT_TERMINAL): ++ return parse_audio_input_terminal(state, unitid, p1); ++ case PTYPE(UAC_VERSION_1, UAC_MIXER_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC_MIXER_UNIT): ++ case PTYPE(UAC_VERSION_3, UAC3_MIXER_UNIT): ++ return parse_audio_mixer_unit(state, unitid, p1); ++ case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SOURCE): ++ case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SOURCE): ++ return parse_clock_source_unit(state, unitid, p1); ++ case PTYPE(UAC_VERSION_1, UAC_SELECTOR_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC_SELECTOR_UNIT): ++ case PTYPE(UAC_VERSION_3, UAC3_SELECTOR_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SELECTOR): ++ case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SELECTOR): ++ return parse_audio_selector_unit(state, unitid, p1); ++ case PTYPE(UAC_VERSION_1, UAC_FEATURE_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC_FEATURE_UNIT): ++ case PTYPE(UAC_VERSION_3, UAC3_FEATURE_UNIT): ++ return parse_audio_feature_unit(state, unitid, p1); ++ case PTYPE(UAC_VERSION_1, UAC1_PROCESSING_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2): ++ case PTYPE(UAC_VERSION_3, UAC3_PROCESSING_UNIT): ++ return parse_audio_processing_unit(state, unitid, p1); ++ case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT): ++ case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2): ++ case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT): ++ return parse_audio_extension_unit(state, unitid, p1); ++ case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT): ++ case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT): ++ return 0; /* FIXME - effect units not implemented yet */ ++ default: ++ usb_audio_err(state->chip, ++ "unit %u: unexpected type 0x%02x\n", ++ unitid, p1[2]); ++ return -EINVAL; + } + } + diff --git a/queue-5.3/alsa-usb-audio-unify-the-release-of-usb_mixer_elem_info-objects.patch b/queue-5.3/alsa-usb-audio-unify-the-release-of-usb_mixer_elem_info-objects.patch new file mode 100644 index 00000000000..23a6625a935 --- /dev/null +++ b/queue-5.3/alsa-usb-audio-unify-the-release-of-usb_mixer_elem_info-objects.patch @@ -0,0 +1,161 @@ +From 52c3e317a857091fd746e15179a637f32be4d337 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 22 Aug 2019 08:23:10 +0200 +Subject: ALSA: usb-audio: Unify the release of usb_mixer_elem_info objects + +From: Takashi Iwai + +commit 52c3e317a857091fd746e15179a637f32be4d337 upstream. + +Instead of the direct kfree() calls, introduce a new local helper to +release the usb_mixer_elem_info object. This will be extended to do +more than a single kfree() in the later patches. + +Also, use the standard goto instead of multiple calls in +parse_audio_selector_unit() error paths. + +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/usb/mixer.c | 48 ++++++++++++++++++++++++++++-------------------- + 1 file changed, 28 insertions(+), 20 deletions(-) + +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -1026,10 +1026,15 @@ static struct usb_feature_control_info a + { UAC2_FU_PHASE_INVERTER, "Phase Inverter Control", USB_MIXER_BOOLEAN, -1 }, + }; + ++static void usb_mixer_elem_info_free(struct usb_mixer_elem_info *cval) ++{ ++ kfree(cval); ++} ++ + /* private_free callback */ + void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl) + { +- kfree(kctl->private_data); ++ usb_mixer_elem_info_free(kctl->private_data); + kctl->private_data = NULL; + } + +@@ -1552,7 +1557,7 @@ static void __build_feature_ctl(struct u + + ctl_info = get_feature_control_info(control); + if (!ctl_info) { +- kfree(cval); ++ usb_mixer_elem_info_free(cval); + return; + } + if (mixer->protocol == UAC_VERSION_1) +@@ -1585,7 +1590,7 @@ static void __build_feature_ctl(struct u + + if (!kctl) { + usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); +- kfree(cval); ++ usb_mixer_elem_info_free(cval); + return; + } + kctl->private_free = snd_usb_mixer_elem_free; +@@ -1755,7 +1760,7 @@ static void build_connector_control(stru + kctl = snd_ctl_new1(&usb_connector_ctl_ro, cval); + if (!kctl) { + usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); +- kfree(cval); ++ usb_mixer_elem_info_free(cval); + return; + } + get_connector_control_name(mixer, term, is_input, kctl->id.name, +@@ -1808,7 +1813,7 @@ static int parse_clock_source_unit(struc + kctl = snd_ctl_new1(&usb_bool_master_control_ctl_ro, cval); + + if (!kctl) { +- kfree(cval); ++ usb_mixer_elem_info_free(cval); + return -ENOMEM; + } + +@@ -2070,7 +2075,7 @@ static void build_mixer_unit_ctl(struct + kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); + if (!kctl) { + usb_audio_err(state->chip, "cannot malloc kcontrol\n"); +- kfree(cval); ++ usb_mixer_elem_info_free(cval); + return; + } + kctl->private_free = snd_usb_mixer_elem_free; +@@ -2468,7 +2473,7 @@ static int build_audio_procunit(struct m + + kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); + if (!kctl) { +- kfree(cval); ++ usb_mixer_elem_info_free(cval); + return -ENOMEM; + } + kctl->private_free = snd_usb_mixer_elem_free; +@@ -2606,7 +2611,7 @@ static void usb_mixer_selector_elem_free + if (kctl->private_data) { + struct usb_mixer_elem_info *cval = kctl->private_data; + num_ins = cval->max; +- kfree(cval); ++ usb_mixer_elem_info_free(cval); + kctl->private_data = NULL; + } + if (kctl->private_value) { +@@ -2678,10 +2683,10 @@ static int parse_audio_selector_unit(str + break; + } + +- namelist = kmalloc_array(desc->bNrInPins, sizeof(char *), GFP_KERNEL); ++ namelist = kcalloc(desc->bNrInPins, sizeof(char *), GFP_KERNEL); + if (!namelist) { +- kfree(cval); +- return -ENOMEM; ++ err = -ENOMEM; ++ goto error_cval; + } + #define MAX_ITEM_NAME_LEN 64 + for (i = 0; i < desc->bNrInPins; i++) { +@@ -2689,11 +2694,8 @@ static int parse_audio_selector_unit(str + len = 0; + namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL); + if (!namelist[i]) { +- while (i--) +- kfree(namelist[i]); +- kfree(namelist); +- kfree(cval); +- return -ENOMEM; ++ err = -ENOMEM; ++ goto error_name; + } + len = check_mapped_selector_name(state, unitid, i, namelist[i], + MAX_ITEM_NAME_LEN); +@@ -2707,10 +2709,8 @@ static int parse_audio_selector_unit(str + kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval); + if (! kctl) { + usb_audio_err(state->chip, "cannot malloc kcontrol\n"); +- for (i = 0; i < desc->bNrInPins; i++) +- kfree(namelist[i]); +- kfree(namelist); +- kfree(cval); ++ err = -ENOMEM; ++ goto error_name; + return -ENOMEM; + } + kctl->private_value = (unsigned long)namelist; +@@ -2757,6 +2757,14 @@ static int parse_audio_selector_unit(str + usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n", + cval->head.id, kctl->id.name, desc->bNrInPins); + return snd_usb_mixer_add_control(&cval->head, kctl); ++ ++ error_name: ++ for (i = 0; i < desc->bNrInPins; i++) ++ kfree(namelist[i]); ++ kfree(namelist); ++ error_cval: ++ usb_mixer_elem_info_free(cval); ++ return err; + } + + /* diff --git a/queue-5.3/series b/queue-5.3/series index 7e3dc8be3c7..9cf6cf37d66 100644 --- a/queue-5.3/series +++ b/queue-5.3/series @@ -79,3 +79,12 @@ can-dev-add-missing-of_node_put-after-calling-of_get_child_by_name.patch can-mcba_usb-fix-use-after-free-on-disconnect.patch can-peak_usb-fix-slab-info-leak.patch configfs-fix-a-deadlock-in-configfs_symlink.patch +alsa-usb-audio-more-validations-of-descriptor-units.patch +alsa-usb-audio-simplify-parse_audio_unit.patch +alsa-usb-audio-unify-the-release-of-usb_mixer_elem_info-objects.patch +alsa-usb-audio-remove-superfluous-blength-checks.patch +alsa-usb-audio-clean-up-check_input_term.patch +alsa-usb-audio-fix-possible-null-dereference-at-create_yamaha_midi_quirk.patch +alsa-usb-audio-remove-some-dead-code.patch +alsa-usb-audio-fix-copy-paste-error-in-the-validator.patch +usbip-implement-sg-support-to-vhci-hcd-and-stub-driver.patch diff --git a/queue-5.3/usbip-implement-sg-support-to-vhci-hcd-and-stub-driver.patch b/queue-5.3/usbip-implement-sg-support-to-vhci-hcd-and-stub-driver.patch new file mode 100644 index 00000000000..aba84d5ed22 --- /dev/null +++ b/queue-5.3/usbip-implement-sg-support-to-vhci-hcd-and-stub-driver.patch @@ -0,0 +1,949 @@ +From ea44d190764b4422af4d1c29eaeb9e69e353b406 Mon Sep 17 00:00:00 2001 +From: Suwan Kim +Date: Wed, 28 Aug 2019 12:27:41 +0900 +Subject: usbip: Implement SG support to vhci-hcd and stub driver + +From: Suwan Kim + +commit ea44d190764b4422af4d1c29eaeb9e69e353b406 upstream. + +There are bugs on vhci with usb 3.0 storage device. In USB, each SG +list entry buffer should be divisible by the bulk max packet size. +But with native SG support, this problem doesn't matter because the +SG buffer is treated as contiguous buffer. But without native SG +support, USB storage driver breaks SG list into several URBs and the +error occurs because of a buffer size of URB that cannot be divided +by the bulk max packet size. The error situation is as follows. + +When USB Storage driver requests 31.5 KB data and has SG list which +has 3584 bytes buffer followed by 7 4096 bytes buffer for some +reason. USB Storage driver splits this SG list into several URBs +because VHCI doesn't support SG and sends them separately. So the +first URB buffer size is 3584 bytes. When receiving data from device, +USB 3.0 device sends data packet of 1024 bytes size because the max +packet size of BULK pipe is 1024 bytes. So device sends 4096 bytes. +But the first URB buffer has only 3584 bytes buffer size. So host +controller terminates the transfer even though there is more data to +receive. So, vhci needs to support SG transfer to prevent this error. + +In this patch, vhci supports SG regardless of whether the server's +host controller supports SG or not, because stub driver splits SG +list into several URBs if the server's host controller doesn't +support SG. + +To support SG, vhci sets URB_DMA_MAP_SG flag in urb->transfer_flags +if URB has SG list and this flag will tell stub driver to use SG +list. After receiving urb from stub driver, vhci clear URB_DMA_MAP_SG +flag to avoid unnecessary DMA unmapping in HCD. + +vhci sends each SG list entry to stub driver. Then, stub driver sees +the total length of the buffer and allocates SG table and pages +according to the total buffer length calling sgl_alloc(). After stub +driver receives completed URB, it again sends each SG list entry to +vhci. + +If the server's host controller doesn't support SG, stub driver +breaks a single SG request into several URBs and submits them to +the server's host controller. When all the split URBs are completed, +stub driver reassembles the URBs into a single return command and +sends it to vhci. + +Moreover, in the situation where vhci supports SG, but stub driver +does not, or vice versa, usbip works normally. Because there is no +protocol modification, there is no problem in communication between +server and client even if the one has a kernel without SG support. + +In the case of vhci supports SG and stub driver doesn't, because +vhci sends only the total length of the buffer to stub driver as +it did before the patch applied, stub driver only needs to allocate +the required length of buffers using only kmalloc() regardless of +whether vhci supports SG or not. But stub driver has to allocate +buffer with kmalloc() as much as the total length of SG buffer which +is quite huge when vhci sends SG request, so it has overhead in +buffer allocation in this situation. + +If stub driver needs to send data buffer to vhci because of IN pipe, +stub driver also sends only total length of buffer as metadata and +then sends real data as vhci does. Then vhci receive data from stub +driver and store it to the corresponding buffer of SG list entry. + +And for the case of stub driver supports SG and vhci doesn't, since +the USB storage driver checks that vhci doesn't support SG and sends +the request to stub driver by splitting the SG list into multiple +URBs, stub driver allocates a buffer for each URB with kmalloc() as +it did before this patch. + +* Test environment + +Test uses two difference machines and two different kernel version +to make mismatch situation between the client and the server where +vhci supports SG, but stub driver does not, or vice versa. All tests +are conducted in both full SG support that both vhci and stub support +SG and half SG support that is the mismatch situation. Test kernel +version is 5.3-rc6 with commit "usb: add a HCD_DMA flag instead of +guestimating DMA capabilities" to avoid unnecessary DMA mapping and +unmapping. + + - Test kernel version + - 5.3-rc6 with SG support + - 5.1.20-200.fc29.x86_64 without SG support + +* SG support test + + - Test devices + - Super-speed storage device - SanDisk Ultra USB 3.0 + - High-speed storage device - SMI corporation USB 2.0 flash drive + + - Test description + +Test read and write operation of mass storage device that uses the +BULK transfer. In test, the client reads and writes files whose size +is over 1G and it works normally. + +* Regression test + + - Test devices + - Super-speed device - Logitech Brio webcam + - High-speed device - Logitech C920 HD Pro webcam + - Full-speed device - Logitech bluetooth mouse + - Britz BR-Orion speaker + - Low-speed device - Logitech wired mouse + + - Test description + +Moving and click test for mouse. To test the webcam, use gnome-cheese. +To test the speaker, play music and video on the client. All works +normally. + +* VUDC compatibility test + +VUDC also works well with this patch. Tests are done with two USB +gadget created by CONFIGFS USB gadget. Both use the BULK pipe. + + 1. Serial gadget + 2. Mass storage gadget + + - Serial gadget test + +Serial gadget on the host sends and receives data using cat command +on the /dev/ttyGS. The client uses minicom to communicate with +the serial gadget. + + - Mass storage gadget test + +After connecting the gadget with vhci, use "dd" to test read and +write operation on the client side. + +Read - dd if=/dev/sd iflag=direct of=/dev/null bs=1G count=1 +Write - dd if= iflag=direct of=/dev/sd bs=1G count=1 + +Signed-off-by: Suwan Kim +Acked-by: Shuah khan +Link: https://lore.kernel.org/r/20190828032741.12234-1-suwan.kim027@gmail.com +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/usbip/stub.h | 7 + + drivers/usb/usbip/stub_main.c | 57 ++++++++--- + drivers/usb/usbip/stub_rx.c | 202 +++++++++++++++++++++++++++------------ + drivers/usb/usbip/stub_tx.c | 99 ++++++++++++++----- + drivers/usb/usbip/usbip_common.c | 59 +++++++---- + drivers/usb/usbip/vhci_hcd.c | 12 ++ + drivers/usb/usbip/vhci_rx.c | 3 + drivers/usb/usbip/vhci_tx.c | 66 ++++++++++-- + 8 files changed, 379 insertions(+), 126 deletions(-) + +--- a/drivers/usb/usbip/stub.h ++++ b/drivers/usb/usbip/stub.h +@@ -52,7 +52,11 @@ struct stub_priv { + unsigned long seqnum; + struct list_head list; + struct stub_device *sdev; +- struct urb *urb; ++ struct urb **urbs; ++ struct scatterlist *sgl; ++ int num_urbs; ++ int completed_urbs; ++ int urb_status; + + int unlinking; + }; +@@ -86,6 +90,7 @@ extern struct usb_device_driver stub_dri + struct bus_id_priv *get_busid_priv(const char *busid); + void put_busid_priv(struct bus_id_priv *bid); + int del_match_busid(char *busid); ++void stub_free_priv_and_urb(struct stub_priv *priv); + void stub_device_cleanup_urbs(struct stub_device *sdev); + + /* stub_rx.c */ +--- a/drivers/usb/usbip/stub_main.c ++++ b/drivers/usb/usbip/stub_main.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + #include "usbip_common.h" + #include "stub.h" +@@ -281,13 +282,49 @@ static struct stub_priv *stub_priv_pop_f + struct stub_priv *priv, *tmp; + + list_for_each_entry_safe(priv, tmp, listhead, list) { +- list_del(&priv->list); ++ list_del_init(&priv->list); + return priv; + } + + return NULL; + } + ++void stub_free_priv_and_urb(struct stub_priv *priv) ++{ ++ struct urb *urb; ++ int i; ++ ++ for (i = 0; i < priv->num_urbs; i++) { ++ urb = priv->urbs[i]; ++ ++ if (!urb) ++ return; ++ ++ kfree(urb->setup_packet); ++ urb->setup_packet = NULL; ++ ++ ++ if (urb->transfer_buffer && !priv->sgl) { ++ kfree(urb->transfer_buffer); ++ urb->transfer_buffer = NULL; ++ } ++ ++ if (urb->num_sgs) { ++ sgl_free(urb->sg); ++ urb->sg = NULL; ++ urb->num_sgs = 0; ++ } ++ ++ usb_free_urb(urb); ++ } ++ if (!list_empty(&priv->list)) ++ list_del(&priv->list); ++ if (priv->sgl) ++ sgl_free(priv->sgl); ++ kfree(priv->urbs); ++ kmem_cache_free(stub_priv_cache, priv); ++} ++ + static struct stub_priv *stub_priv_pop(struct stub_device *sdev) + { + unsigned long flags; +@@ -314,25 +351,15 @@ done: + void stub_device_cleanup_urbs(struct stub_device *sdev) + { + struct stub_priv *priv; +- struct urb *urb; ++ int i; + + dev_dbg(&sdev->udev->dev, "Stub device cleaning up urbs\n"); + + while ((priv = stub_priv_pop(sdev))) { +- urb = priv->urb; +- dev_dbg(&sdev->udev->dev, "free urb seqnum %lu\n", +- priv->seqnum); +- usb_kill_urb(urb); +- +- kmem_cache_free(stub_priv_cache, priv); ++ for (i = 0; i < priv->num_urbs; i++) ++ usb_kill_urb(priv->urbs[i]); + +- kfree(urb->transfer_buffer); +- urb->transfer_buffer = NULL; +- +- kfree(urb->setup_packet); +- urb->setup_packet = NULL; +- +- usb_free_urb(urb); ++ stub_free_priv_and_urb(priv); + } + } + +--- a/drivers/usb/usbip/stub_rx.c ++++ b/drivers/usb/usbip/stub_rx.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + #include "usbip_common.h" + #include "stub.h" +@@ -201,7 +202,7 @@ static void tweak_special_requests(struc + static int stub_recv_cmd_unlink(struct stub_device *sdev, + struct usbip_header *pdu) + { +- int ret; ++ int ret, i; + unsigned long flags; + struct stub_priv *priv; + +@@ -246,12 +247,14 @@ static int stub_recv_cmd_unlink(struct s + * so a driver in a client host will know the failure + * of the unlink request ? + */ +- ret = usb_unlink_urb(priv->urb); +- if (ret != -EINPROGRESS) +- dev_err(&priv->urb->dev->dev, +- "failed to unlink a urb # %lu, ret %d\n", +- priv->seqnum, ret); +- ++ for (i = priv->completed_urbs; i < priv->num_urbs; i++) { ++ ret = usb_unlink_urb(priv->urbs[i]); ++ if (ret != -EINPROGRESS) ++ dev_err(&priv->urbs[i]->dev->dev, ++ "failed to unlink %d/%d urb of seqnum %lu, ret %d\n", ++ i + 1, priv->num_urbs, ++ priv->seqnum, ret); ++ } + return 0; + } + +@@ -433,14 +436,36 @@ static void masking_bogus_flags(struct u + urb->transfer_flags &= allowed; + } + ++static int stub_recv_xbuff(struct usbip_device *ud, struct stub_priv *priv) ++{ ++ int ret; ++ int i; ++ ++ for (i = 0; i < priv->num_urbs; i++) { ++ ret = usbip_recv_xbuff(ud, priv->urbs[i]); ++ if (ret < 0) ++ break; ++ } ++ ++ return ret; ++} ++ + static void stub_recv_cmd_submit(struct stub_device *sdev, + struct usbip_header *pdu) + { +- int ret; + struct stub_priv *priv; + struct usbip_device *ud = &sdev->ud; + struct usb_device *udev = sdev->udev; ++ struct scatterlist *sgl = NULL, *sg; ++ void *buffer = NULL; ++ unsigned long long buf_len; ++ int nents; ++ int num_urbs = 1; + int pipe = get_pipe(sdev, pdu); ++ int use_sg = pdu->u.cmd_submit.transfer_flags & URB_DMA_MAP_SG; ++ int support_sg = 1; ++ int np = 0; ++ int ret, i; + + if (pipe == -1) + return; +@@ -449,76 +474,139 @@ static void stub_recv_cmd_submit(struct + if (!priv) + return; + +- /* setup a urb */ +- if (usb_pipeisoc(pipe)) +- priv->urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets, +- GFP_KERNEL); +- else +- priv->urb = usb_alloc_urb(0, GFP_KERNEL); ++ buf_len = (unsigned long long)pdu->u.cmd_submit.transfer_buffer_length; + +- if (!priv->urb) { +- usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); +- return; ++ /* allocate urb transfer buffer, if needed */ ++ if (buf_len) { ++ if (use_sg) { ++ sgl = sgl_alloc(buf_len, GFP_KERNEL, &nents); ++ if (!sgl) ++ goto err_malloc; ++ } else { ++ buffer = kzalloc(buf_len, GFP_KERNEL); ++ if (!buffer) ++ goto err_malloc; ++ } + } + +- /* allocate urb transfer buffer, if needed */ +- if (pdu->u.cmd_submit.transfer_buffer_length > 0) { +- priv->urb->transfer_buffer = +- kzalloc(pdu->u.cmd_submit.transfer_buffer_length, +- GFP_KERNEL); +- if (!priv->urb->transfer_buffer) { ++ /* Check if the server's HCD supports SG */ ++ if (use_sg && !udev->bus->sg_tablesize) { ++ /* ++ * If the server's HCD doesn't support SG, break a single SG ++ * request into several URBs and map each SG list entry to ++ * corresponding URB buffer. The previously allocated SG ++ * list is stored in priv->sgl (If the server's HCD support SG, ++ * SG list is stored only in urb->sg) and it is used as an ++ * indicator that the server split single SG request into ++ * several URBs. Later, priv->sgl is used by stub_complete() and ++ * stub_send_ret_submit() to reassemble the divied URBs. ++ */ ++ support_sg = 0; ++ num_urbs = nents; ++ priv->completed_urbs = 0; ++ pdu->u.cmd_submit.transfer_flags &= ~URB_DMA_MAP_SG; ++ } ++ ++ /* allocate urb array */ ++ priv->num_urbs = num_urbs; ++ priv->urbs = kmalloc_array(num_urbs, sizeof(*priv->urbs), GFP_KERNEL); ++ if (!priv->urbs) ++ goto err_urbs; ++ ++ /* setup a urb */ ++ if (support_sg) { ++ if (usb_pipeisoc(pipe)) ++ np = pdu->u.cmd_submit.number_of_packets; ++ ++ priv->urbs[0] = usb_alloc_urb(np, GFP_KERNEL); ++ if (!priv->urbs[0]) ++ goto err_urb; ++ ++ if (buf_len) { ++ if (use_sg) { ++ priv->urbs[0]->sg = sgl; ++ priv->urbs[0]->num_sgs = nents; ++ priv->urbs[0]->transfer_buffer = NULL; ++ } else { ++ priv->urbs[0]->transfer_buffer = buffer; ++ } ++ } ++ ++ /* copy urb setup packet */ ++ priv->urbs[0]->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, ++ 8, GFP_KERNEL); ++ if (!priv->urbs[0]->setup_packet) { + usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); + return; + } +- } + +- /* copy urb setup packet */ +- priv->urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8, +- GFP_KERNEL); +- if (!priv->urb->setup_packet) { +- dev_err(&udev->dev, "allocate setup_packet\n"); +- usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); +- return; ++ usbip_pack_pdu(pdu, priv->urbs[0], USBIP_CMD_SUBMIT, 0); ++ } else { ++ for_each_sg(sgl, sg, nents, i) { ++ priv->urbs[i] = usb_alloc_urb(0, GFP_KERNEL); ++ /* The URBs which is previously allocated will be freed ++ * in stub_device_cleanup_urbs() if error occurs. ++ */ ++ if (!priv->urbs[i]) ++ goto err_urb; ++ ++ usbip_pack_pdu(pdu, priv->urbs[i], USBIP_CMD_SUBMIT, 0); ++ priv->urbs[i]->transfer_buffer = sg_virt(sg); ++ priv->urbs[i]->transfer_buffer_length = sg->length; ++ } ++ priv->sgl = sgl; + } + +- /* set other members from the base header of pdu */ +- priv->urb->context = (void *) priv; +- priv->urb->dev = udev; +- priv->urb->pipe = pipe; +- priv->urb->complete = stub_complete; ++ for (i = 0; i < num_urbs; i++) { ++ /* set other members from the base header of pdu */ ++ priv->urbs[i]->context = (void *) priv; ++ priv->urbs[i]->dev = udev; ++ priv->urbs[i]->pipe = pipe; ++ priv->urbs[i]->complete = stub_complete; + +- usbip_pack_pdu(pdu, priv->urb, USBIP_CMD_SUBMIT, 0); ++ /* no need to submit an intercepted request, but harmless? */ ++ tweak_special_requests(priv->urbs[i]); + ++ masking_bogus_flags(priv->urbs[i]); ++ } + +- if (usbip_recv_xbuff(ud, priv->urb) < 0) ++ if (stub_recv_xbuff(ud, priv) < 0) + return; + +- if (usbip_recv_iso(ud, priv->urb) < 0) ++ if (usbip_recv_iso(ud, priv->urbs[0]) < 0) + return; + +- /* no need to submit an intercepted request, but harmless? */ +- tweak_special_requests(priv->urb); +- +- masking_bogus_flags(priv->urb); + /* urb is now ready to submit */ +- ret = usb_submit_urb(priv->urb, GFP_KERNEL); +- +- if (ret == 0) +- usbip_dbg_stub_rx("submit urb ok, seqnum %u\n", +- pdu->base.seqnum); +- else { +- dev_err(&udev->dev, "submit_urb error, %d\n", ret); +- usbip_dump_header(pdu); +- usbip_dump_urb(priv->urb); ++ for (i = 0; i < priv->num_urbs; i++) { ++ ret = usb_submit_urb(priv->urbs[i], GFP_KERNEL); + +- /* +- * Pessimistic. +- * This connection will be discarded. +- */ +- usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT); ++ if (ret == 0) ++ usbip_dbg_stub_rx("submit urb ok, seqnum %u\n", ++ pdu->base.seqnum); ++ else { ++ dev_err(&udev->dev, "submit_urb error, %d\n", ret); ++ usbip_dump_header(pdu); ++ usbip_dump_urb(priv->urbs[i]); ++ ++ /* ++ * Pessimistic. ++ * This connection will be discarded. ++ */ ++ usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT); ++ break; ++ } + } + + usbip_dbg_stub_rx("Leave\n"); ++ return; ++ ++err_urb: ++ kfree(priv->urbs); ++err_urbs: ++ kfree(buffer); ++ sgl_free(sgl); ++err_malloc: ++ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); + } + + /* recv a pdu */ +--- a/drivers/usb/usbip/stub_tx.c ++++ b/drivers/usb/usbip/stub_tx.c +@@ -5,25 +5,11 @@ + + #include + #include ++#include + + #include "usbip_common.h" + #include "stub.h" + +-static void stub_free_priv_and_urb(struct stub_priv *priv) +-{ +- struct urb *urb = priv->urb; +- +- kfree(urb->setup_packet); +- urb->setup_packet = NULL; +- +- kfree(urb->transfer_buffer); +- urb->transfer_buffer = NULL; +- +- list_del(&priv->list); +- kmem_cache_free(stub_priv_cache, priv); +- usb_free_urb(urb); +-} +- + /* be in spin_lock_irqsave(&sdev->priv_lock, flags) */ + void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum, + __u32 status) +@@ -85,6 +71,22 @@ void stub_complete(struct urb *urb) + break; + } + ++ /* ++ * If the server breaks single SG request into the several URBs, the ++ * URBs must be reassembled before sending completed URB to the vhci. ++ * Don't wake up the tx thread until all the URBs are completed. ++ */ ++ if (priv->sgl) { ++ priv->completed_urbs++; ++ ++ /* Only save the first error status */ ++ if (urb->status && !priv->urb_status) ++ priv->urb_status = urb->status; ++ ++ if (priv->completed_urbs < priv->num_urbs) ++ return; ++ } ++ + /* link a urb to the queue of tx. */ + spin_lock_irqsave(&sdev->priv_lock, flags); + if (sdev->ud.tcp_socket == NULL) { +@@ -156,18 +158,22 @@ static int stub_send_ret_submit(struct s + size_t total_size = 0; + + while ((priv = dequeue_from_priv_tx(sdev)) != NULL) { +- int ret; +- struct urb *urb = priv->urb; ++ struct urb *urb = priv->urbs[0]; + struct usbip_header pdu_header; + struct usbip_iso_packet_descriptor *iso_buffer = NULL; + struct kvec *iov = NULL; ++ struct scatterlist *sg; ++ u32 actual_length = 0; + int iovnum = 0; ++ int ret; ++ int i; + + txsize = 0; + memset(&pdu_header, 0, sizeof(pdu_header)); + memset(&msg, 0, sizeof(msg)); + +- if (urb->actual_length > 0 && !urb->transfer_buffer) { ++ if (urb->actual_length > 0 && !urb->transfer_buffer && ++ !urb->num_sgs) { + dev_err(&sdev->udev->dev, + "urb: actual_length %d transfer_buffer null\n", + urb->actual_length); +@@ -176,6 +182,11 @@ static int stub_send_ret_submit(struct s + + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + iovnum = 2 + urb->number_of_packets; ++ else if (usb_pipein(urb->pipe) && urb->actual_length > 0 && ++ urb->num_sgs) ++ iovnum = 1 + urb->num_sgs; ++ else if (usb_pipein(urb->pipe) && priv->sgl) ++ iovnum = 1 + priv->num_urbs; + else + iovnum = 2; + +@@ -192,6 +203,15 @@ static int stub_send_ret_submit(struct s + setup_ret_submit_pdu(&pdu_header, urb); + usbip_dbg_stub_tx("setup txdata seqnum: %d\n", + pdu_header.base.seqnum); ++ ++ if (priv->sgl) { ++ for (i = 0; i < priv->num_urbs; i++) ++ actual_length += priv->urbs[i]->actual_length; ++ ++ pdu_header.u.ret_submit.status = priv->urb_status; ++ pdu_header.u.ret_submit.actual_length = actual_length; ++ } ++ + usbip_header_correct_endian(&pdu_header, 1); + + iov[iovnum].iov_base = &pdu_header; +@@ -200,12 +220,47 @@ static int stub_send_ret_submit(struct s + txsize += sizeof(pdu_header); + + /* 2. setup transfer buffer */ +- if (usb_pipein(urb->pipe) && ++ if (usb_pipein(urb->pipe) && priv->sgl) { ++ /* If the server split a single SG request into several ++ * URBs because the server's HCD doesn't support SG, ++ * reassemble the split URB buffers into a single ++ * return command. ++ */ ++ for (i = 0; i < priv->num_urbs; i++) { ++ iov[iovnum].iov_base = ++ priv->urbs[i]->transfer_buffer; ++ iov[iovnum].iov_len = ++ priv->urbs[i]->actual_length; ++ iovnum++; ++ } ++ txsize += actual_length; ++ } else if (usb_pipein(urb->pipe) && + usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS && + urb->actual_length > 0) { +- iov[iovnum].iov_base = urb->transfer_buffer; +- iov[iovnum].iov_len = urb->actual_length; +- iovnum++; ++ if (urb->num_sgs) { ++ unsigned int copy = urb->actual_length; ++ int size; ++ ++ for_each_sg(urb->sg, sg, urb->num_sgs, i) { ++ if (copy == 0) ++ break; ++ ++ if (copy < sg->length) ++ size = copy; ++ else ++ size = sg->length; ++ ++ iov[iovnum].iov_base = sg_virt(sg); ++ iov[iovnum].iov_len = size; ++ ++ iovnum++; ++ copy -= size; ++ } ++ } else { ++ iov[iovnum].iov_base = urb->transfer_buffer; ++ iov[iovnum].iov_len = urb->actual_length; ++ iovnum++; ++ } + txsize += urb->actual_length; + } else if (usb_pipein(urb->pipe) && + usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { +--- a/drivers/usb/usbip/usbip_common.c ++++ b/drivers/usb/usbip/usbip_common.c +@@ -680,8 +680,12 @@ EXPORT_SYMBOL_GPL(usbip_pad_iso); + /* some members of urb must be substituted before. */ + int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) + { +- int ret; ++ struct scatterlist *sg; ++ int ret = 0; ++ int recv; + int size; ++ int copy; ++ int i; + + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) { + /* the direction of urb must be OUT. */ +@@ -701,29 +705,48 @@ int usbip_recv_xbuff(struct usbip_device + if (!(size > 0)) + return 0; + +- if (size > urb->transfer_buffer_length) { ++ if (size > urb->transfer_buffer_length) + /* should not happen, probably malicious packet */ +- if (ud->side == USBIP_STUB) { +- usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); +- return 0; +- } else { +- usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); +- return -EPIPE; +- } +- } ++ goto error; ++ ++ if (urb->num_sgs) { ++ copy = size; ++ for_each_sg(urb->sg, sg, urb->num_sgs, i) { ++ int recv_size; ++ ++ if (copy < sg->length) ++ recv_size = copy; ++ else ++ recv_size = sg->length; ++ ++ recv = usbip_recv(ud->tcp_socket, sg_virt(sg), ++ recv_size); + +- ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size); +- if (ret != size) { +- dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret); +- if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) { +- usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); +- } else { +- usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); +- return -EPIPE; ++ if (recv != recv_size) ++ goto error; ++ ++ copy -= recv; ++ ret += recv; + } ++ ++ if (ret != size) ++ goto error; ++ } else { ++ ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size); ++ if (ret != size) ++ goto error; + } + + return ret; ++ ++error: ++ dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret); ++ if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) ++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); ++ else ++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); ++ ++ return -EPIPE; + } + EXPORT_SYMBOL_GPL(usbip_recv_xbuff); + +--- a/drivers/usb/usbip/vhci_hcd.c ++++ b/drivers/usb/usbip/vhci_hcd.c +@@ -697,7 +697,8 @@ static int vhci_urb_enqueue(struct usb_h + } + vdev = &vhci_hcd->vdev[portnum-1]; + +- if (!urb->transfer_buffer && urb->transfer_buffer_length) { ++ if (!urb->transfer_buffer && !urb->num_sgs && ++ urb->transfer_buffer_length) { + dev_dbg(dev, "Null URB transfer buffer\n"); + return -EINVAL; + } +@@ -1143,6 +1144,15 @@ static int vhci_setup(struct usb_hcd *hc + hcd->speed = HCD_USB3; + hcd->self.root_hub->speed = USB_SPEED_SUPER; + } ++ ++ /* ++ * Support SG. ++ * sg_tablesize is an arbitrary value to alleviate memory pressure ++ * on the host. ++ */ ++ hcd->self.sg_tablesize = 32; ++ hcd->self.no_sg_constraint = 1; ++ + return 0; + } + +--- a/drivers/usb/usbip/vhci_rx.c ++++ b/drivers/usb/usbip/vhci_rx.c +@@ -90,6 +90,9 @@ static void vhci_recv_ret_submit(struct + if (usbip_dbg_flag_vhci_rx) + usbip_dump_urb(urb); + ++ if (urb->num_sgs) ++ urb->transfer_flags &= ~URB_DMA_MAP_SG; ++ + usbip_dbg_vhci_rx("now giveback urb %u\n", pdu->base.seqnum); + + spin_lock_irqsave(&vhci->lock, flags); +--- a/drivers/usb/usbip/vhci_tx.c ++++ b/drivers/usb/usbip/vhci_tx.c +@@ -5,6 +5,7 @@ + + #include + #include ++#include + + #include "usbip_common.h" + #include "vhci.h" +@@ -50,19 +51,23 @@ static struct vhci_priv *dequeue_from_pr + + static int vhci_send_cmd_submit(struct vhci_device *vdev) + { ++ struct usbip_iso_packet_descriptor *iso_buffer = NULL; + struct vhci_priv *priv = NULL; ++ struct scatterlist *sg; + + struct msghdr msg; +- struct kvec iov[3]; ++ struct kvec *iov; + size_t txsize; + + size_t total_size = 0; ++ int iovnum; ++ int err = -ENOMEM; ++ int i; + + while ((priv = dequeue_from_priv_tx(vdev)) != NULL) { + int ret; + struct urb *urb = priv->urb; + struct usbip_header pdu_header; +- struct usbip_iso_packet_descriptor *iso_buffer = NULL; + + txsize = 0; + memset(&pdu_header, 0, sizeof(pdu_header)); +@@ -72,18 +77,45 @@ static int vhci_send_cmd_submit(struct v + usbip_dbg_vhci_tx("setup txdata urb seqnum %lu\n", + priv->seqnum); + ++ if (urb->num_sgs && usb_pipeout(urb->pipe)) ++ iovnum = 2 + urb->num_sgs; ++ else ++ iovnum = 3; ++ ++ iov = kcalloc(iovnum, sizeof(*iov), GFP_KERNEL); ++ if (!iov) { ++ usbip_event_add(&vdev->ud, SDEV_EVENT_ERROR_MALLOC); ++ return -ENOMEM; ++ } ++ ++ if (urb->num_sgs) ++ urb->transfer_flags |= URB_DMA_MAP_SG; ++ + /* 1. setup usbip_header */ + setup_cmd_submit_pdu(&pdu_header, urb); + usbip_header_correct_endian(&pdu_header, 1); ++ iovnum = 0; + +- iov[0].iov_base = &pdu_header; +- iov[0].iov_len = sizeof(pdu_header); ++ iov[iovnum].iov_base = &pdu_header; ++ iov[iovnum].iov_len = sizeof(pdu_header); + txsize += sizeof(pdu_header); ++ iovnum++; + + /* 2. setup transfer buffer */ + if (!usb_pipein(urb->pipe) && urb->transfer_buffer_length > 0) { +- iov[1].iov_base = urb->transfer_buffer; +- iov[1].iov_len = urb->transfer_buffer_length; ++ if (urb->num_sgs && ++ !usb_endpoint_xfer_isoc(&urb->ep->desc)) { ++ for_each_sg(urb->sg, sg, urb->num_sgs, i) { ++ iov[iovnum].iov_base = sg_virt(sg); ++ iov[iovnum].iov_len = sg->length; ++ iovnum++; ++ } ++ } else { ++ iov[iovnum].iov_base = urb->transfer_buffer; ++ iov[iovnum].iov_len = ++ urb->transfer_buffer_length; ++ iovnum++; ++ } + txsize += urb->transfer_buffer_length; + } + +@@ -95,23 +127,26 @@ static int vhci_send_cmd_submit(struct v + if (!iso_buffer) { + usbip_event_add(&vdev->ud, + SDEV_EVENT_ERROR_MALLOC); +- return -1; ++ goto err_iso_buffer; + } + +- iov[2].iov_base = iso_buffer; +- iov[2].iov_len = len; ++ iov[iovnum].iov_base = iso_buffer; ++ iov[iovnum].iov_len = len; ++ iovnum++; + txsize += len; + } + +- ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 3, txsize); ++ ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, iovnum, ++ txsize); + if (ret != txsize) { + pr_err("sendmsg failed!, ret=%d for %zd\n", ret, + txsize); +- kfree(iso_buffer); + usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP); +- return -1; ++ err = -EPIPE; ++ goto err_tx; + } + ++ kfree(iov); + kfree(iso_buffer); + usbip_dbg_vhci_tx("send txdata\n"); + +@@ -119,6 +154,13 @@ static int vhci_send_cmd_submit(struct v + } + + return total_size; ++ ++err_tx: ++ kfree(iso_buffer); ++err_iso_buffer: ++ kfree(iov); ++ ++ return err; + } + + static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)