From 2e9ba9de33fd839f8e64d2b36f440c310eb4fb77 Mon Sep 17 00:00:00 2001 From: Leo Date: Sun, 14 Feb 2021 08:46:45 -0300 Subject: main/libusb: fix handling buggy USB devices See: https://github.com/libusb/libusb/commit/f38f09da98acc63966b65b72029b1f7f81166bef Fixes #12426 --- main/libusb/APKBUILD | 6 +- .../f38f09da98acc63966b65b72029b1f7f81166bef.patch | 217 +++++++++++++++++++++ 2 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 main/libusb/f38f09da98acc63966b65b72029b1f7f81166bef.patch diff --git a/main/libusb/APKBUILD b/main/libusb/APKBUILD index 7c99044dbbe..9489a735059 100644 --- a/main/libusb/APKBUILD +++ b/main/libusb/APKBUILD @@ -2,7 +2,7 @@ pkgname=libusb pkgver=1.0.24 _ver=${pkgver/_/-} -pkgrel=0 +pkgrel=1 pkgdesc="Library that enables userspace access to USB devices" url="https://libusb.info/" arch="all" @@ -11,6 +11,7 @@ subpackages="$pkgname-dev" replaces="libusbx" makedepends="linux-headers" source="https://github.com/libusb/libusb/releases/download/v$pkgver/libusb-$pkgver.tar.bz2 + f38f09da98acc63966b65b72029b1f7f81166bef.patch " build() { @@ -31,4 +32,5 @@ package() { make DESTDIR="$pkgdir" install } -sha512sums="5aea36a530aaa15c6dd656d0ed3ce204522c9946d8d39ffbb290dab4a98cda388a2598da4995123d1032324056090bd429e702459626d3e8d7daeebc4e7ff3dc libusb-1.0.24.tar.bz2" +sha512sums="5aea36a530aaa15c6dd656d0ed3ce204522c9946d8d39ffbb290dab4a98cda388a2598da4995123d1032324056090bd429e702459626d3e8d7daeebc4e7ff3dc libusb-1.0.24.tar.bz2 +fdfc2b02eb996661c75ce01652b623afa4339612c2fc84331187ad55ac93d94abe20f48bf3ec891138ebdb8703a29e8b45643518e896f298562f93a5749e014c f38f09da98acc63966b65b72029b1f7f81166bef.patch" diff --git a/main/libusb/f38f09da98acc63966b65b72029b1f7f81166bef.patch b/main/libusb/f38f09da98acc63966b65b72029b1f7f81166bef.patch new file mode 100644 index 00000000000..94395318c57 --- /dev/null +++ b/main/libusb/f38f09da98acc63966b65b72029b1f7f81166bef.patch @@ -0,0 +1,217 @@ +From f38f09da98acc63966b65b72029b1f7f81166bef Mon Sep 17 00:00:00 2001 +From: Chris Dickens +Date: Mon, 8 Feb 2021 11:56:13 -0800 +Subject: [PATCH] linux_usbfs: Gracefully handle buggy devices with a + configuration 0 + +The USB spec states that a configuration value of 0 is reserved and is +used to indicate the device in not configured (e.g. is in the address +state). Unfortunately some devices do exist that violate this and use 0 +as the bConfigurationValue of the configuration descriptor. + +Improve how the Linux backend handles such non-conformant devices by +adding special handling around the configuration value 0. Most devices +will not require this special handling, but for those that do there is +no way to distinguish between the device being unconfigured and using +configuration 0. + +Closes #850 + +Signed-off-by: Chris Dickens +--- + libusb/os/linux_usbfs.c | 94 ++++++++++++++++++++++++++--------------- + libusb/version_nano.h | 2 +- + 2 files changed, 60 insertions(+), 36 deletions(-) + +diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c +index ebf8cfed..3a1894cf 100644 +--- a/libusb/os/linux_usbfs.c ++++ b/libusb/os/linux_usbfs.c +@@ -128,7 +128,7 @@ struct linux_device_priv { + void *descriptors; + size_t descriptors_len; + struct config_descriptor *config_descriptors; +- uint8_t active_config; /* cache val for !sysfs_available */ ++ int active_config; /* cache val for !sysfs_available */ + }; + + struct linux_device_handle_priv { +@@ -169,6 +169,21 @@ struct linux_transfer_priv { + int iso_packet_offset; + }; + ++static int dev_has_config0(struct libusb_device *dev) ++{ ++ struct linux_device_priv *priv = usbi_get_device_priv(dev); ++ struct config_descriptor *config; ++ uint8_t idx; ++ ++ for (idx = 0; idx < dev->device_descriptor.bNumConfigurations; idx++) { ++ config = &priv->config_descriptors[idx]; ++ if (config->desc->bConfigurationValue == 0) ++ return 1; ++ } ++ ++ return 0; ++} ++ + static int get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent) + { + struct libusb_context *ctx = DEVICE_CTX(dev); +@@ -574,22 +589,12 @@ static int sysfs_scan_device(struct libusb_context *ctx, const char *devname) + } + + /* read the bConfigurationValue for a device */ +-static int sysfs_get_active_config(struct libusb_device *dev, uint8_t *config) ++static int sysfs_get_active_config(struct libusb_device *dev, int *config) + { + struct linux_device_priv *priv = usbi_get_device_priv(dev); +- int ret, tmp; +- +- ret = read_sysfs_attr(DEVICE_CTX(dev), priv->sysfs_dir, "bConfigurationValue", +- UINT8_MAX, &tmp); +- if (ret < 0) +- return ret; + +- if (tmp == -1) +- tmp = 0; /* unconfigured */ +- +- *config = (uint8_t)tmp; +- +- return 0; ++ return read_sysfs_attr(DEVICE_CTX(dev), priv->sysfs_dir, "bConfigurationValue", ++ UINT8_MAX, config); + } + + int linux_get_device_address(struct libusb_context *ctx, int detached, +@@ -765,6 +770,9 @@ static int parse_config_descriptors(struct libusb_device *dev) + } + } + ++ if (config_desc->bConfigurationValue == 0) ++ usbi_warn(ctx, "device has configuration 0"); ++ + priv->config_descriptors[idx].desc = config_desc; + priv->config_descriptors[idx].actual_len = config_len; + +@@ -798,7 +806,7 @@ static int op_get_active_config_descriptor(struct libusb_device *dev, + { + struct linux_device_priv *priv = usbi_get_device_priv(dev); + void *config_desc; +- uint8_t active_config; ++ int active_config; + int r; + + if (priv->sysfs_dir) { +@@ -810,12 +818,12 @@ static int op_get_active_config_descriptor(struct libusb_device *dev, + active_config = priv->active_config; + } + +- if (active_config == 0) { ++ if (active_config == -1) { + usbi_err(DEVICE_CTX(dev), "device unconfigured"); + return LIBUSB_ERROR_NOT_FOUND; + } + +- r = op_get_config_descriptor_by_value(dev, active_config, &config_desc); ++ r = op_get_config_descriptor_by_value(dev, (uint8_t)active_config, &config_desc); + if (r < 0) + return r; + +@@ -863,17 +871,26 @@ static int usbfs_get_active_config(struct libusb_device *dev, int fd) + + /* we hit this error path frequently with buggy devices :( */ + usbi_warn(DEVICE_CTX(dev), "get configuration failed, errno=%d", errno); ++ ++ /* assume the current configuration is the first one if we have ++ * the configuration descriptors, otherwise treat the device ++ * as unconfigured. */ ++ if (priv->config_descriptors) ++ priv->active_config = (int)priv->config_descriptors[0].desc->bConfigurationValue; ++ else ++ priv->active_config = -1; + } else if (active_config == 0) { +- /* some buggy devices have a configuration 0, but we're +- * reaching into the corner of a corner case here, so let's +- * not support buggy devices in these circumstances. +- * stick to the specs: a configuration value of 0 means +- * unconfigured. */ +- usbi_warn(DEVICE_CTX(dev), "active cfg 0? assuming unconfigured device"); ++ if (dev_has_config0(dev)) { ++ /* some buggy devices have a configuration 0, but we're ++ * reaching into the corner of a corner case here. */ ++ priv->active_config = 0; ++ } else { ++ priv->active_config = -1; ++ } ++ } else { ++ priv->active_config = (int)active_config; + } + +- priv->active_config = active_config; +- + return LIBUSB_SUCCESS; + } + +@@ -1004,9 +1021,9 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, + usbi_warn(ctx, "Missing rw usbfs access; cannot determine " + "active configuration descriptor"); + if (priv->config_descriptors) +- priv->active_config = priv->config_descriptors[0].desc->bConfigurationValue; ++ priv->active_config = (int)priv->config_descriptors[0].desc->bConfigurationValue; + else +- priv->active_config = 0; /* No config dt */ ++ priv->active_config = -1; /* No config dt */ + + return LIBUSB_SUCCESS; + } +@@ -1428,22 +1445,27 @@ static int op_get_configuration(struct libusb_device_handle *handle, + uint8_t *config) + { + struct linux_device_priv *priv = usbi_get_device_priv(handle->dev); ++ int active_config; + int r; + + if (priv->sysfs_dir) { +- r = sysfs_get_active_config(handle->dev, config); ++ r = sysfs_get_active_config(handle->dev, &active_config); + } else { + struct linux_device_handle_priv *hpriv = usbi_get_device_handle_priv(handle); + + r = usbfs_get_active_config(handle->dev, hpriv->fd); + if (r == LIBUSB_SUCCESS) +- *config = priv->active_config; ++ active_config = priv->active_config; + } + if (r < 0) + return r; + +- if (*config == 0) +- usbi_err(HANDLE_CTX(handle), "device unconfigured"); ++ if (active_config == -1) { ++ usbi_warn(HANDLE_CTX(handle), "device unconfigured"); ++ active_config = 0; ++ } ++ ++ *config = (uint8_t)active_config; + + return 0; + } +@@ -1467,11 +1489,13 @@ static int op_set_configuration(struct libusb_device_handle *handle, int config) + return LIBUSB_ERROR_OTHER; + } + +- if (config == -1) +- config = 0; ++ /* if necessary, update our cached active config descriptor */ ++ if (!priv->sysfs_dir) { ++ if (config == 0 && !dev_has_config0(handle->dev)) ++ config = -1; + +- /* update our cached active config descriptor */ +- priv->active_config = (uint8_t)config; ++ priv->active_config = config; ++ } + + return LIBUSB_SUCCESS; + } -- cgit v1.2.3