Skip to content

Commit

Permalink
Introduced LIBUSB_COUNTED_BY macro
Browse files Browse the repository at this point in the history
This will allow catching array overruns with UBSan.

See:
https://people.kernel.org/kees/bounded-flexible-arrays-in-c
  • Loading branch information
seanm committed Apr 20, 2024
1 parent f8a6c41 commit 2e76f30
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 6 deletions.
22 changes: 18 additions & 4 deletions libusb/libusb.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ typedef SSIZE_T ssize_t;
#define LIBUSB_FLEXIBLE_ARRAY 0 /* [0] - non-standard, but usually working code */
#endif /* __STDC_VERSION__ */

/* gcc > 14 and clang > 17 support the counted_by attribute,
* used to indicate the size of struct flexible array members.
* This helps detected buffer overruns.
* See: https://people.kernel.org/kees/bounded-flexible-arrays-in-c */
#if defined __has_attribute
#if __has_attribute(__counted_by__)
#define LIBUSB_COUNTED_BY(member) __attribute__((counted_by(member)))
#else
#define LIBUSB_COUNTED_BY(member)
#endif
#else
#define LIBUSB_COUNTED_BY(member)
#endif

/* 'interface' might be defined as a macro on Windows, so we need to
* undefine it so as not to break the current libusb API, because
* libusb_config_descriptor has an 'interface' member
Expand Down Expand Up @@ -884,7 +898,7 @@ struct libusb_bos_dev_capability_descriptor {
uint8_t bDevCapabilityType;

/** Device Capability data (bLength - 3 bytes) */
uint8_t dev_capability_data[LIBUSB_FLEXIBLE_ARRAY];
uint8_t dev_capability_data[LIBUSB_FLEXIBLE_ARRAY] LIBUSB_COUNTED_BY(bLength - 3);
};

/** \ingroup libusb_desc
Expand All @@ -909,7 +923,7 @@ struct libusb_bos_descriptor {
uint8_t bNumDeviceCaps;

/** bNumDeviceCap Device Capability Descriptors */
struct libusb_bos_dev_capability_descriptor *dev_capability[LIBUSB_FLEXIBLE_ARRAY];
struct libusb_bos_dev_capability_descriptor *dev_capability[LIBUSB_FLEXIBLE_ARRAY] LIBUSB_COUNTED_BY(bNumDeviceCaps);
};

/** \ingroup libusb_desc
Expand Down Expand Up @@ -1031,7 +1045,7 @@ struct libusb_platform_descriptor {
uint8_t PlatformCapabilityUUID[16];

/** Capability data (bLength - 20) */
uint8_t CapabilityData[LIBUSB_FLEXIBLE_ARRAY];
uint8_t CapabilityData[LIBUSB_FLEXIBLE_ARRAY] LIBUSB_COUNTED_BY(bLength - 20);
};

/** \ingroup libusb_asyncio
Expand Down Expand Up @@ -1411,7 +1425,7 @@ struct libusb_transfer {
int num_iso_packets;

/** Isochronous packet descriptors, for isochronous transfers only. */
struct libusb_iso_packet_descriptor iso_packet_desc[LIBUSB_FLEXIBLE_ARRAY];
struct libusb_iso_packet_descriptor iso_packet_desc[LIBUSB_FLEXIBLE_ARRAY] LIBUSB_COUNTED_BY(num_iso_packets);
};

/** \ingroup libusb_misc
Expand Down
4 changes: 2 additions & 2 deletions libusb/libusbi.h
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ struct usbi_interface_descriptor {
struct usbi_string_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wData[LIBUSB_FLEXIBLE_ARRAY];
uint16_t wData[LIBUSB_FLEXIBLE_ARRAY] LIBUSB_COUNTED_BY((bLength - 2) / 2);
} LIBUSB_PACKED;

struct usbi_bos_descriptor {
Expand Down Expand Up @@ -919,7 +919,7 @@ static inline void *usbi_get_transfer_priv(struct usbi_transfer *itransfer)
struct discovered_devs {
size_t len;
size_t capacity;
struct libusb_device *devices[LIBUSB_FLEXIBLE_ARRAY];
struct libusb_device *devices[LIBUSB_FLEXIBLE_ARRAY] LIBUSB_COUNTED_BY(len);
};

struct discovered_devs *discovered_devs_append(
Expand Down

0 comments on commit 2e76f30

Please sign in to comment.