]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 11 Nov 2019 09:43:51 +0000 (10:43 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 11 Nov 2019 09:43:51 +0000 (10:43 +0100)
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
sched-fair-fix-low-cpu-usage-with-high-throttling-by-removing-expiration-of-cpu-local-slices.patch
sched-fair-fix-wunused-but-set-variable-warnings.patch
usbip-fix-vhci_urb_enqueue-urb-null-transfer-buffer-error-path.patch
usbip-implement-sg-support-to-vhci-hcd-and-stub-driver.patch

13 files changed:
queue-4.19/alsa-usb-audio-clean-up-check_input_term.patch [new file with mode: 0644]
queue-4.19/alsa-usb-audio-fix-copy-paste-error-in-the-validator.patch [new file with mode: 0644]
queue-4.19/alsa-usb-audio-fix-possible-null-dereference-at-create_yamaha_midi_quirk.patch [new file with mode: 0644]
queue-4.19/alsa-usb-audio-more-validations-of-descriptor-units.patch [new file with mode: 0644]
queue-4.19/alsa-usb-audio-remove-some-dead-code.patch [new file with mode: 0644]
queue-4.19/alsa-usb-audio-remove-superfluous-blength-checks.patch [new file with mode: 0644]
queue-4.19/alsa-usb-audio-simplify-parse_audio_unit.patch [new file with mode: 0644]
queue-4.19/alsa-usb-audio-unify-the-release-of-usb_mixer_elem_info-objects.patch [new file with mode: 0644]
queue-4.19/sched-fair-fix-low-cpu-usage-with-high-throttling-by-removing-expiration-of-cpu-local-slices.patch [new file with mode: 0644]
queue-4.19/sched-fair-fix-wunused-but-set-variable-warnings.patch [new file with mode: 0644]
queue-4.19/series
queue-4.19/usbip-fix-vhci_urb_enqueue-urb-null-transfer-buffer-error-path.patch [new file with mode: 0644]
queue-4.19/usbip-implement-sg-support-to-vhci-hcd-and-stub-driver.patch [new file with mode: 0644]

diff --git a/queue-4.19/alsa-usb-audio-clean-up-check_input_term.patch b/queue-4.19/alsa-usb-audio-clean-up-check_input_term.patch
new file mode 100644 (file)
index 0000000..bcd9569
--- /dev/null
@@ -0,0 +1,477 @@
+From e0ccdef92653f8867e2d1667facfd3c23699f540 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Fri, 23 Aug 2019 12:38:07 +0200
+Subject: ALSA: usb-audio: Clean up check_input_term()
+
+From: Takashi Iwai <tiwai@suse.de>
+
+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 <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/mixer.c |  407 ++++++++++++++++++++++++++++--------------------------
+ 1 file changed, 212 insertions(+), 195 deletions(-)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -773,224 +773,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;
+@@ -2731,7 +2749,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-4.19/alsa-usb-audio-fix-copy-paste-error-in-the-validator.patch b/queue-4.19/alsa-usb-audio-fix-copy-paste-error-in-the-validator.patch
new file mode 100644 (file)
index 0000000..bc931ea
--- /dev/null
@@ -0,0 +1,35 @@
+From ba8bf0967a154796be15c4983603aad0b05c3138 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 22 Oct 2019 17:45:14 +0200
+Subject: ALSA: usb-audio: Fix copy&paste error in the validator
+
+From: Takashi Iwai <tiwai@suse.de>
+
+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 <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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-4.19/alsa-usb-audio-fix-possible-null-dereference-at-create_yamaha_midi_quirk.patch b/queue-4.19/alsa-usb-audio-fix-possible-null-dereference-at-create_yamaha_midi_quirk.patch
new file mode 100644 (file)
index 0000000..0020da7
--- /dev/null
@@ -0,0 +1,35 @@
+From 60849562a5db4a1eee2160167e4dce4590d3eafe Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+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 <tiwai@suse.de>
+
+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 <dan.carpenter@oracle.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/quirks.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -259,8 +259,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-4.19/alsa-usb-audio-more-validations-of-descriptor-units.patch b/queue-4.19/alsa-usb-audio-more-validations-of-descriptor-units.patch
new file mode 100644 (file)
index 0000000..1293295
--- /dev/null
@@ -0,0 +1,533 @@
+From 57f8770620e9b51c61089751f0b5ad3dbe376ff2 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 20 Aug 2019 17:17:09 +0200
+Subject: ALSA: usb-audio: More validations of descriptor units
+
+From: Takashi Iwai <tiwai@suse.de>
+
+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 <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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-usbmidi-lib-objs := midi.o
+--- a/sound/usb/helper.h
++++ b/sound/usb/helper.h
+@@ -30,4 +30,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
+@@ -800,6 +800,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;
+@@ -2794,6 +2796,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:
+@@ -3164,6 +3171,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
+@@ -259,6 +259,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
+@@ -637,16 +637,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;
+@@ -657,7 +655,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;
+@@ -665,8 +663,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;
+       }
+@@ -741,7 +740,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);
+@@ -777,7 +776,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))
+@@ -786,7 +785,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;
+@@ -1012,14 +1012,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 <linux/init.h>
++#include <linux/usb.h>
++#include <linux/usb/audio.h>
++#include <linux/usb/audio-v2.h>
++#include <linux/usb/audio-v3.h>
++#include <linux/usb/midi.h>
++#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-4.19/alsa-usb-audio-remove-some-dead-code.patch b/queue-4.19/alsa-usb-audio-remove-some-dead-code.patch
new file mode 100644 (file)
index 0000000..20c78f7
--- /dev/null
@@ -0,0 +1,32 @@
+From b39e077fcb283dd96dd251a3abeba585402c61fe Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Mon, 26 Aug 2019 16:45:50 +0300
+Subject: ALSA: usb-audio: remove some dead code
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+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 <dan.carpenter@oracle.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/mixer.c |    1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -2670,7 +2670,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-4.19/alsa-usb-audio-remove-superfluous-blength-checks.patch b/queue-4.19/alsa-usb-audio-remove-superfluous-blength-checks.patch
new file mode 100644 (file)
index 0000000..f4481b0
--- /dev/null
@@ -0,0 +1,238 @@
+From b8e4f1fdfa422398c2d6c47bfb7d1feb3046d70a Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Thu, 22 Aug 2019 09:25:27 +0200
+Subject: ALSA: usb-audio: Remove superfluous bLength checks
+
+From: Takashi Iwai <tiwai@suse.de>
+
+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 <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -52,39 +52,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
+@@ -755,13 +755,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:
+@@ -1796,13 +1789,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.
+@@ -1861,62 +1847,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 */
+@@ -2120,15 +2064,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);
+@@ -2390,18 +2330,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)
+@@ -2656,13 +2585,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)
+@@ -3168,8 +3090,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;
+@@ -3181,8 +3101,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;
+@@ -3208,8 +3126,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-4.19/alsa-usb-audio-simplify-parse_audio_unit.patch b/queue-4.19/alsa-usb-audio-simplify-parse_audio_unit.patch
new file mode 100644 (file)
index 0000000..a8a8752
--- /dev/null
@@ -0,0 +1,125 @@
+From 68e9fde245591d18200f8a9054cac22339437adb Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Thu, 15 Aug 2019 16:30:39 +0200
+Subject: ALSA: usb-audio: Simplify parse_audio_unit()
+
+From: Takashi Iwai <tiwai@suse.de>
+
+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 <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/mixer.c |   95 ++++++++++++++++++++++--------------------------------
+ 1 file changed, 39 insertions(+), 56 deletions(-)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -2801,62 +2801,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-4.19/alsa-usb-audio-unify-the-release-of-usb_mixer_elem_info-objects.patch b/queue-4.19/alsa-usb-audio-unify-the-release-of-usb_mixer_elem_info-objects.patch
new file mode 100644 (file)
index 0000000..72d2165
--- /dev/null
@@ -0,0 +1,161 @@
+From 52c3e317a857091fd746e15179a637f32be4d337 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+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 <tiwai@suse.de>
+
+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 <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/mixer.c |   48 ++++++++++++++++++++++++++++--------------------
+ 1 file changed, 28 insertions(+), 20 deletions(-)
+
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -1041,10 +1041,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;
+ }
+@@ -1567,7 +1572,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)
+@@ -1600,7 +1605,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;
+@@ -1770,7 +1775,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,
+@@ -1823,7 +1828,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;
+       }
+@@ -2089,7 +2094,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;
+@@ -2487,7 +2492,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;
+@@ -2625,7 +2630,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) {
+@@ -2697,10 +2702,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++) {
+@@ -2708,11 +2713,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);
+@@ -2726,10 +2728,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;
+@@ -2776,6 +2776,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-4.19/sched-fair-fix-low-cpu-usage-with-high-throttling-by-removing-expiration-of-cpu-local-slices.patch b/queue-4.19/sched-fair-fix-low-cpu-usage-with-high-throttling-by-removing-expiration-of-cpu-local-slices.patch
new file mode 100644 (file)
index 0000000..bedc7e3
--- /dev/null
@@ -0,0 +1,341 @@
+From de53fd7aedb100f03e5d2231cfce0e4993282425 Mon Sep 17 00:00:00 2001
+From: Dave Chiluk <chiluk+linux@indeed.com>
+Date: Tue, 23 Jul 2019 11:44:26 -0500
+Subject: sched/fair: Fix low cpu usage with high throttling by removing expiration of cpu-local slices
+
+From: Dave Chiluk <chiluk+linux@indeed.com>
+
+commit de53fd7aedb100f03e5d2231cfce0e4993282425 upstream.
+
+It has been observed, that highly-threaded, non-cpu-bound applications
+running under cpu.cfs_quota_us constraints can hit a high percentage of
+periods throttled while simultaneously not consuming the allocated
+amount of quota. This use case is typical of user-interactive non-cpu
+bound applications, such as those running in kubernetes or mesos when
+run on multiple cpu cores.
+
+This has been root caused to cpu-local run queue being allocated per cpu
+bandwidth slices, and then not fully using that slice within the period.
+At which point the slice and quota expires. This expiration of unused
+slice results in applications not being able to utilize the quota for
+which they are allocated.
+
+The non-expiration of per-cpu slices was recently fixed by
+'commit 512ac999d275 ("sched/fair: Fix bandwidth timer clock drift
+condition")'. Prior to that it appears that this had been broken since
+at least 'commit 51f2176d74ac ("sched/fair: Fix unlocked reads of some
+cfs_b->quota/period")' which was introduced in v3.16-rc1 in 2014. That
+added the following conditional which resulted in slices never being
+expired.
+
+if (cfs_rq->runtime_expires != cfs_b->runtime_expires) {
+       /* extend local deadline, drift is bounded above by 2 ticks */
+       cfs_rq->runtime_expires += TICK_NSEC;
+
+Because this was broken for nearly 5 years, and has recently been fixed
+and is now being noticed by many users running kubernetes
+(https://github.com/kubernetes/kubernetes/issues/67577) it is my opinion
+that the mechanisms around expiring runtime should be removed
+altogether.
+
+This allows quota already allocated to per-cpu run-queues to live longer
+than the period boundary. This allows threads on runqueues that do not
+use much CPU to continue to use their remaining slice over a longer
+period of time than cpu.cfs_period_us. However, this helps prevent the
+above condition of hitting throttling while also not fully utilizing
+your cpu quota.
+
+This theoretically allows a machine to use slightly more than its
+allotted quota in some periods. This overflow would be bounded by the
+remaining quota left on each per-cpu runqueueu. This is typically no
+more than min_cfs_rq_runtime=1ms per cpu. For CPU bound tasks this will
+change nothing, as they should theoretically fully utilize all of their
+quota in each period. For user-interactive tasks as described above this
+provides a much better user/application experience as their cpu
+utilization will more closely match the amount they requested when they
+hit throttling. This means that cpu limits no longer strictly apply per
+period for non-cpu bound applications, but that they are still accurate
+over longer timeframes.
+
+This greatly improves performance of high-thread-count, non-cpu bound
+applications with low cfs_quota_us allocation on high-core-count
+machines. In the case of an artificial testcase (10ms/100ms of quota on
+80 CPU machine), this commit resulted in almost 30x performance
+improvement, while still maintaining correct cpu quota restrictions.
+That testcase is available at https://github.com/indeedeng/fibtest.
+
+Fixes: 512ac999d275 ("sched/fair: Fix bandwidth timer clock drift condition")
+Signed-off-by: Dave Chiluk <chiluk+linux@indeed.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Phil Auld <pauld@redhat.com>
+Reviewed-by: Ben Segall <bsegall@google.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: John Hammond <jhammond@indeed.com>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Cc: Kyle Anderson <kwa@yelp.com>
+Cc: Gabriel Munos <gmunoz@netflix.com>
+Cc: Peter Oskolkov <posk@posk.io>
+Cc: Cong Wang <xiyou.wangcong@gmail.com>
+Cc: Brendan Gregg <bgregg@netflix.com>
+Link: https://lkml.kernel.org/r/1563900266-19734-2-git-send-email-chiluk+linux@indeed.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ Documentation/scheduler/sched-bwc.txt |   45 +++++++++++++++++++++
+ kernel/sched/fair.c                   |   72 +++-------------------------------
+ kernel/sched/sched.h                  |    4 -
+ 3 files changed, 52 insertions(+), 69 deletions(-)
+
+--- a/Documentation/scheduler/sched-bwc.txt
++++ b/Documentation/scheduler/sched-bwc.txt
+@@ -90,6 +90,51 @@ There are two ways in which a group may
+ In case b) above, even though the child may have runtime remaining it will not
+ be allowed to until the parent's runtime is refreshed.
++CFS Bandwidth Quota Caveats
++---------------------------
++Once a slice is assigned to a cpu it does not expire.  However all but 1ms of
++the slice may be returned to the global pool if all threads on that cpu become
++unrunnable. This is configured at compile time by the min_cfs_rq_runtime
++variable. This is a performance tweak that helps prevent added contention on
++the global lock.
++
++The fact that cpu-local slices do not expire results in some interesting corner
++cases that should be understood.
++
++For cgroup cpu constrained applications that are cpu limited this is a
++relatively moot point because they will naturally consume the entirety of their
++quota as well as the entirety of each cpu-local slice in each period. As a
++result it is expected that nr_periods roughly equal nr_throttled, and that
++cpuacct.usage will increase roughly equal to cfs_quota_us in each period.
++
++For highly-threaded, non-cpu bound applications this non-expiration nuance
++allows applications to briefly burst past their quota limits by the amount of
++unused slice on each cpu that the task group is running on (typically at most
++1ms per cpu or as defined by min_cfs_rq_runtime).  This slight burst only
++applies if quota had been assigned to a cpu and then not fully used or returned
++in previous periods. This burst amount will not be transferred between cores.
++As a result, this mechanism still strictly limits the task group to quota
++average usage, albeit over a longer time window than a single period.  This
++also limits the burst ability to no more than 1ms per cpu.  This provides
++better more predictable user experience for highly threaded applications with
++small quota limits on high core count machines. It also eliminates the
++propensity to throttle these applications while simultanously using less than
++quota amounts of cpu. Another way to say this, is that by allowing the unused
++portion of a slice to remain valid across periods we have decreased the
++possibility of wastefully expiring quota on cpu-local silos that don't need a
++full slice's amount of cpu time.
++
++The interaction between cpu-bound and non-cpu-bound-interactive applications
++should also be considered, especially when single core usage hits 100%. If you
++gave each of these applications half of a cpu-core and they both got scheduled
++on the same CPU it is theoretically possible that the non-cpu bound application
++will use up to 1ms additional quota in some periods, thereby preventing the
++cpu-bound application from fully using its quota by that same amount. In these
++instances it will be up to the CFS algorithm (see sched-design-CFS.rst) to
++decide which application is chosen to run, as they will both be runnable and
++have remaining quota. This runtime discrepancy will be made up in the following
++periods when the interactive application idles.
++
+ Examples
+ --------
+ 1. Limit a group to 1 CPU worth of runtime.
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -4320,8 +4320,6 @@ void __refill_cfs_bandwidth_runtime(stru
+       now = sched_clock_cpu(smp_processor_id());
+       cfs_b->runtime = cfs_b->quota;
+-      cfs_b->runtime_expires = now + ktime_to_ns(cfs_b->period);
+-      cfs_b->expires_seq++;
+ }
+ static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg)
+@@ -4343,8 +4341,7 @@ static int assign_cfs_rq_runtime(struct
+ {
+       struct task_group *tg = cfs_rq->tg;
+       struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(tg);
+-      u64 amount = 0, min_amount, expires;
+-      int expires_seq;
++      u64 amount = 0, min_amount;
+       /* note: this is a positive sum as runtime_remaining <= 0 */
+       min_amount = sched_cfs_bandwidth_slice() - cfs_rq->runtime_remaining;
+@@ -4361,61 +4358,17 @@ static int assign_cfs_rq_runtime(struct
+                       cfs_b->idle = 0;
+               }
+       }
+-      expires_seq = cfs_b->expires_seq;
+-      expires = cfs_b->runtime_expires;
+       raw_spin_unlock(&cfs_b->lock);
+       cfs_rq->runtime_remaining += amount;
+-      /*
+-       * we may have advanced our local expiration to account for allowed
+-       * spread between our sched_clock and the one on which runtime was
+-       * issued.
+-       */
+-      if (cfs_rq->expires_seq != expires_seq) {
+-              cfs_rq->expires_seq = expires_seq;
+-              cfs_rq->runtime_expires = expires;
+-      }
+       return cfs_rq->runtime_remaining > 0;
+ }
+-/*
+- * Note: This depends on the synchronization provided by sched_clock and the
+- * fact that rq->clock snapshots this value.
+- */
+-static void expire_cfs_rq_runtime(struct cfs_rq *cfs_rq)
+-{
+-      struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg);
+-
+-      /* if the deadline is ahead of our clock, nothing to do */
+-      if (likely((s64)(rq_clock(rq_of(cfs_rq)) - cfs_rq->runtime_expires) < 0))
+-              return;
+-
+-      if (cfs_rq->runtime_remaining < 0)
+-              return;
+-
+-      /*
+-       * If the local deadline has passed we have to consider the
+-       * possibility that our sched_clock is 'fast' and the global deadline
+-       * has not truly expired.
+-       *
+-       * Fortunately we can check determine whether this the case by checking
+-       * whether the global deadline(cfs_b->expires_seq) has advanced.
+-       */
+-      if (cfs_rq->expires_seq == cfs_b->expires_seq) {
+-              /* extend local deadline, drift is bounded above by 2 ticks */
+-              cfs_rq->runtime_expires += TICK_NSEC;
+-      } else {
+-              /* global deadline is ahead, expiration has passed */
+-              cfs_rq->runtime_remaining = 0;
+-      }
+-}
+-
+ static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec)
+ {
+       /* dock delta_exec before expiring quota (as it could span periods) */
+       cfs_rq->runtime_remaining -= delta_exec;
+-      expire_cfs_rq_runtime(cfs_rq);
+       if (likely(cfs_rq->runtime_remaining > 0))
+               return;
+@@ -4600,8 +4553,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cf
+               resched_curr(rq);
+ }
+-static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b,
+-              u64 remaining, u64 expires)
++static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b, u64 remaining)
+ {
+       struct cfs_rq *cfs_rq;
+       u64 runtime;
+@@ -4626,7 +4578,6 @@ static u64 distribute_cfs_runtime(struct
+               remaining -= runtime;
+               cfs_rq->runtime_remaining += runtime;
+-              cfs_rq->runtime_expires = expires;
+               /* we check whether we're throttled above */
+               if (cfs_rq->runtime_remaining > 0)
+@@ -4651,7 +4602,7 @@ next:
+  */
+ static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun)
+ {
+-      u64 runtime, runtime_expires;
++      u64 runtime;
+       int throttled;
+       /* no need to continue the timer with no bandwidth constraint */
+@@ -4679,8 +4630,6 @@ static int do_sched_cfs_period_timer(str
+       /* account preceding periods in which throttling occurred */
+       cfs_b->nr_throttled += overrun;
+-      runtime_expires = cfs_b->runtime_expires;
+-
+       /*
+        * This check is repeated as we are holding onto the new bandwidth while
+        * we unthrottle. This can potentially race with an unthrottled group
+@@ -4693,8 +4642,7 @@ static int do_sched_cfs_period_timer(str
+               cfs_b->distribute_running = 1;
+               raw_spin_unlock(&cfs_b->lock);
+               /* we can't nest cfs_b->lock while distributing bandwidth */
+-              runtime = distribute_cfs_runtime(cfs_b, runtime,
+-                                               runtime_expires);
++              runtime = distribute_cfs_runtime(cfs_b, runtime);
+               raw_spin_lock(&cfs_b->lock);
+               cfs_b->distribute_running = 0;
+@@ -4771,8 +4719,7 @@ static void __return_cfs_rq_runtime(stru
+               return;
+       raw_spin_lock(&cfs_b->lock);
+-      if (cfs_b->quota != RUNTIME_INF &&
+-          cfs_rq->runtime_expires == cfs_b->runtime_expires) {
++      if (cfs_b->quota != RUNTIME_INF) {
+               cfs_b->runtime += slack_runtime;
+               /* we are under rq->lock, defer unthrottling using a timer */
+@@ -4804,7 +4751,6 @@ static __always_inline void return_cfs_r
+ static void do_sched_cfs_slack_timer(struct cfs_bandwidth *cfs_b)
+ {
+       u64 runtime = 0, slice = sched_cfs_bandwidth_slice();
+-      u64 expires;
+       /* confirm we're still not at a refresh boundary */
+       raw_spin_lock(&cfs_b->lock);
+@@ -4821,7 +4767,6 @@ static void do_sched_cfs_slack_timer(str
+       if (cfs_b->quota != RUNTIME_INF && cfs_b->runtime > slice)
+               runtime = cfs_b->runtime;
+-      expires = cfs_b->runtime_expires;
+       if (runtime)
+               cfs_b->distribute_running = 1;
+@@ -4830,11 +4775,10 @@ static void do_sched_cfs_slack_timer(str
+       if (!runtime)
+               return;
+-      runtime = distribute_cfs_runtime(cfs_b, runtime, expires);
++      runtime = distribute_cfs_runtime(cfs_b, runtime);
+       raw_spin_lock(&cfs_b->lock);
+-      if (expires == cfs_b->runtime_expires)
+-              cfs_b->runtime -= min(runtime, cfs_b->runtime);
++      cfs_b->runtime -= min(runtime, cfs_b->runtime);
+       cfs_b->distribute_running = 0;
+       raw_spin_unlock(&cfs_b->lock);
+ }
+@@ -4989,8 +4933,6 @@ void start_cfs_bandwidth(struct cfs_band
+       cfs_b->period_active = 1;
+       overrun = hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period);
+-      cfs_b->runtime_expires += (overrun + 1) * ktime_to_ns(cfs_b->period);
+-      cfs_b->expires_seq++;
+       hrtimer_start_expires(&cfs_b->period_timer, HRTIMER_MODE_ABS_PINNED);
+ }
+--- a/kernel/sched/sched.h
++++ b/kernel/sched/sched.h
+@@ -334,8 +334,6 @@ struct cfs_bandwidth {
+       u64                     quota;
+       u64                     runtime;
+       s64                     hierarchical_quota;
+-      u64                     runtime_expires;
+-      int                     expires_seq;
+       short                   idle;
+       short                   period_active;
+@@ -555,8 +553,6 @@ struct cfs_rq {
+ #ifdef CONFIG_CFS_BANDWIDTH
+       int                     runtime_enabled;
+-      int                     expires_seq;
+-      u64                     runtime_expires;
+       s64                     runtime_remaining;
+       u64                     throttled_clock;
diff --git a/queue-4.19/sched-fair-fix-wunused-but-set-variable-warnings.patch b/queue-4.19/sched-fair-fix-wunused-but-set-variable-warnings.patch
new file mode 100644 (file)
index 0000000..89b448c
--- /dev/null
@@ -0,0 +1,87 @@
+From 763a9ec06c409dcde2a761aac4bb83ff3938e0b3 Mon Sep 17 00:00:00 2001
+From: Qian Cai <cai@lca.pw>
+Date: Tue, 20 Aug 2019 14:40:55 -0400
+Subject: sched/fair: Fix -Wunused-but-set-variable warnings
+
+From: Qian Cai <cai@lca.pw>
+
+commit 763a9ec06c409dcde2a761aac4bb83ff3938e0b3 upstream.
+
+Commit:
+
+   de53fd7aedb1 ("sched/fair: Fix low cpu usage with high throttling by removing expiration of cpu-local slices")
+
+introduced a few compilation warnings:
+
+  kernel/sched/fair.c: In function '__refill_cfs_bandwidth_runtime':
+  kernel/sched/fair.c:4365:6: warning: variable 'now' set but not used [-Wunused-but-set-variable]
+  kernel/sched/fair.c: In function 'start_cfs_bandwidth':
+  kernel/sched/fair.c:4992:6: warning: variable 'overrun' set but not used [-Wunused-but-set-variable]
+
+Also, __refill_cfs_bandwidth_runtime() does no longer update the
+expiration time, so fix the comments accordingly.
+
+Signed-off-by: Qian Cai <cai@lca.pw>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Ben Segall <bsegall@google.com>
+Reviewed-by: Dave Chiluk <chiluk+linux@indeed.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: pauld@redhat.com
+Fixes: de53fd7aedb1 ("sched/fair: Fix low cpu usage with high throttling by removing expiration of cpu-local slices")
+Link: https://lkml.kernel.org/r/1566326455-8038-1-git-send-email-cai@lca.pw
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ kernel/sched/fair.c |   19 ++++++-------------
+ 1 file changed, 6 insertions(+), 13 deletions(-)
+
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -4305,21 +4305,16 @@ static inline u64 sched_cfs_bandwidth_sl
+ }
+ /*
+- * Replenish runtime according to assigned quota and update expiration time.
+- * We use sched_clock_cpu directly instead of rq->clock to avoid adding
+- * additional synchronization around rq->lock.
++ * Replenish runtime according to assigned quota. We use sched_clock_cpu
++ * directly instead of rq->clock to avoid adding additional synchronization
++ * around rq->lock.
+  *
+  * requires cfs_b->lock
+  */
+ void __refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b)
+ {
+-      u64 now;
+-
+-      if (cfs_b->quota == RUNTIME_INF)
+-              return;
+-
+-      now = sched_clock_cpu(smp_processor_id());
+-      cfs_b->runtime = cfs_b->quota;
++      if (cfs_b->quota != RUNTIME_INF)
++              cfs_b->runtime = cfs_b->quota;
+ }
+ static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg)
+@@ -4924,15 +4919,13 @@ static void init_cfs_rq_runtime(struct c
+ void start_cfs_bandwidth(struct cfs_bandwidth *cfs_b)
+ {
+-      u64 overrun;
+-
+       lockdep_assert_held(&cfs_b->lock);
+       if (cfs_b->period_active)
+               return;
+       cfs_b->period_active = 1;
+-      overrun = hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period);
++      hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period);
+       hrtimer_start_expires(&cfs_b->period_timer, HRTIMER_MODE_ABS_PINNED);
+ }
index 7cb91da85e8922f20cb8b3b7988cc7c2e713ec61..7badd22a47753ca8d7d1d9681bac946c77572580 100644 (file)
@@ -54,3 +54,15 @@ configfs_register_group-shouldn-t-be-and-isn-t-called-in-rmdirable-parts.patch
 configfs-new-object-reprsenting-tree-fragments.patch
 configfs-provide-exclusion-between-io-and-removals.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
+sched-fair-fix-low-cpu-usage-with-high-throttling-by-removing-expiration-of-cpu-local-slices.patch
+sched-fair-fix-wunused-but-set-variable-warnings.patch
+usbip-fix-vhci_urb_enqueue-urb-null-transfer-buffer-error-path.patch
+usbip-implement-sg-support-to-vhci-hcd-and-stub-driver.patch
diff --git a/queue-4.19/usbip-fix-vhci_urb_enqueue-urb-null-transfer-buffer-error-path.patch b/queue-4.19/usbip-fix-vhci_urb_enqueue-urb-null-transfer-buffer-error-path.patch
new file mode 100644 (file)
index 0000000..526fbd9
--- /dev/null
@@ -0,0 +1,34 @@
+From 2c904963b1dd2acd4bc785b6c72e10a6283c2081 Mon Sep 17 00:00:00 2001
+From: Shuah Khan <shuah@kernel.org>
+Date: Thu, 24 Jan 2019 14:46:42 -0700
+Subject: usbip: Fix vhci_urb_enqueue() URB null transfer buffer error path
+
+From: Shuah Khan <shuah@kernel.org>
+
+commit 2c904963b1dd2acd4bc785b6c72e10a6283c2081 upstream.
+
+Fix vhci_urb_enqueue() to print debug msg and return error instead of
+failing with BUG_ON.
+
+Signed-off-by: Shuah Khan <shuah@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/usbip/vhci_hcd.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/usbip/vhci_hcd.c
++++ b/drivers/usb/usbip/vhci_hcd.c
+@@ -702,8 +702,10 @@ static int vhci_urb_enqueue(struct usb_h
+       }
+       vdev = &vhci_hcd->vdev[portnum-1];
+-      /* patch to usb_sg_init() is in 2.5.60 */
+-      BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
++      if (!urb->transfer_buffer && urb->transfer_buffer_length) {
++              dev_dbg(dev, "Null URB transfer buffer\n");
++              return -EINVAL;
++      }
+       spin_lock_irqsave(&vhci->lock, flags);
diff --git a/queue-4.19/usbip-implement-sg-support-to-vhci-hcd-and-stub-driver.patch b/queue-4.19/usbip-implement-sg-support-to-vhci-hcd-and-stub-driver.patch
new file mode 100644 (file)
index 0000000..59052e8
--- /dev/null
@@ -0,0 +1,949 @@
+From ea44d190764b4422af4d1c29eaeb9e69e353b406 Mon Sep 17 00:00:00 2001
+From: Suwan Kim <suwan.kim027@gmail.com>
+Date: Wed, 28 Aug 2019 12:27:41 +0900
+Subject: usbip: Implement SG support to vhci-hcd and stub driver
+
+From: Suwan Kim <suwan.kim027@gmail.com>
+
+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<N>. 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<N> iflag=direct of=/dev/null bs=1G count=1
+Write - dd if=<my file path> iflag=direct of=/dev/sd<N> bs=1G count=1
+
+Signed-off-by: Suwan Kim <suwan.kim027@gmail.com>
+Acked-by: Shuah khan <skhan@linuxfoundation.org>
+Link: https://lore.kernel.org/r/20190828032741.12234-1-suwan.kim027@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/string.h>
+ #include <linux/module.h>
+ #include <linux/device.h>
++#include <linux/scatterlist.h>
+ #include "usbip_common.h"
+ #include "stub.h"
+@@ -283,13 +284,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;
+@@ -316,25 +353,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 <linux/kthread.h>
+ #include <linux/usb.h>
+ #include <linux/usb/hcd.h>
++#include <linux/scatterlist.h>
+ #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 <linux/kthread.h>
+ #include <linux/socket.h>
++#include <linux/scatterlist.h>
+ #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
+@@ -702,7 +702,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;
+       }
+@@ -1148,6 +1149,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 <linux/kthread.h>
+ #include <linux/slab.h>
++#include <linux/scatterlist.h>
+ #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)