Skip to content

drivers/libusb{0,1}.c: bound rdlens loop by element count, not sizeof - #3550

Open
0x-a6 wants to merge 2 commits into
networkupstools:masterfrom
0x-a6:fix/libusb-rdlens-loop-bounds
Open

drivers/libusb{0,1}.c: bound rdlens loop by element count, not sizeof#3550
0x-a6 wants to merge 2 commits into
networkupstools:masterfrom
0x-a6:fix/libusb-rdlens-loop-bounds

Conversation

@0x-a6

@0x-a6 0x-a6 commented Jul 28, 2026

Copy link
Copy Markdown

nut_libusb_open() iterates the two candidate HID report descriptor lengths:

	int32_t rdlen1, rdlen2, rdlens[2];
	size_t j;
	...
	for (j = 0; j < sizeof(rdlens); j++) {
		rdlen = rdlens[j];

sizeof(rdlens) is the size in bytes (8), not the element count (2), so the loop reads rdlens[2..7] — 24 bytes past the end of the array — and uses that stack garbage as rdlen. The "ran out of candidates" test after the loop (if (j >= sizeof(rdlens))) has the same bug, so it never fires as intended either.

The out-of-range indices are only reached when neither real candidate satisfies the caller — i.e. exactly when a device is in a bad state and both descriptor reads fail, which is when you least want undefined behaviour. Garbage that happens to survive the rdlen sanity checks is then passed to libusb_control_transfer() and on to the HID parser callback, which is where it segfaults.

How it showed up

usbhid-ups segfaulting against an EcoFlow DELTA 3 Plus (3746:ffff) on an NVIDIA Jetson Orin Nano (aarch64, NUT built from v2.8.5) after the device's USB connection had wedged. usbreset on the device cleared the wedge, and the crash went away with it — the descriptor reads then succeeded on the first candidate and the loop never ran past index 0.

Fix

Use SIZEOF_ARRAY() from include/common.h, which both files already include. drivers/libusb0.c carries the identical defect in the same two places and is fixed the same way.

Regression from aba6f43 ("if the tried rdlen did not succeed, fall back to the other value we had in mind" [#3136]), first released in v2.8.5.

Happy to add a NEWS.adoc entry under the 2.8.6 section if you'd like one — I left it out to keep the diff to the fix, since the entry would want this PR's number.

…networkupstools#3136]

nut_libusb_open() iterates the two candidate HID report descriptor lengths:

	int32_t rdlen1, rdlen2, rdlens[2];
	size_t j;
	...
	for (j = 0; j < sizeof(rdlens); j++)

sizeof(rdlens) is 8 (bytes), not 2 (elements), so the loop reads
rdlens[2..7] - 24 bytes past the end of the array - and uses that stack
garbage as rdlen. The "ran out of candidates" check after the loop has
the same bug.

The out-of-range indices are only reached when neither real candidate
satisfies the caller, i.e. exactly when a device is in a bad state and
both descriptor reads fail. Garbage that happens to pass the rdlen sanity
checks is then handed to libusb_control_transfer() and on to the HID
parser callback, which is where it segfaults.

Seen with usbhid-ups against an EcoFlow DELTA 3 Plus (3746:ffff) on an
NVIDIA Jetson Orin Nano whose USB device had wedged; "usbreset" on the
device cleared the wedge and hid the crash.

Use SIZEOF_ARRAY() from common.h, which both files already include.
libusb0.c carries the identical defect and is fixed the same way.

Regression from aba6f43 ("if the tried
'rdlen' did not succeed, fall back to the other value we had in mind"),
first released in v2.8.5.

Signed-off-by: John Grant <john.grant@dronedeploy.com>
@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown

A ZIP file with standard source tarball and another tarball with pre-built docs for commit c736ec5 is temporarily available: NUT-tarballs-PR-3550.zip.

@AppVeyorBot

Copy link
Copy Markdown

Build nut 2.8.5.4994-master completed (commit 616551d00b by @0x-a6)

@jimklimov

Copy link
Copy Markdown
Member

My bad, thanks for the catch and fix! A news entry would be appropriate, perhaps with a new block like - Fix fallout of development in ... seen for some earlier releases. Maybe without reference to specific commit (rather to PR number) to avoid the hassle with nut.dict :)

@jimklimov jimklimov added bug USB impacts-release-2.8.5 Issues reported against NUT release 2.8.5 (maybe vanilla or with minor packaging tweaks) Hardening Ideas and implems to make NUT deployments more robust and secure (relaxed convenience may suffer) labels Jul 28, 2026
@jimklimov jimklimov added this to the 2.8.6 milestone Jul 28, 2026
0x-a6 added a commit to 0x-a6/nut that referenced this pull request Jul 28, 2026
…ools#3550]

Added under a new "Fix fallout of development in NUT v2.8.5" block, as
suggested in review. Refers to the PR rather than the commit that introduced
the regression, so no new nut.dict entries are needed.

Signed-off-by: John Grant <john.grant@dronedeploy.com>
…3550]

Signed-off-by: John Grant <john.grant@dronedeploy.com>
@0x-a6
0x-a6 force-pushed the fix/libusb-rdlens-loop-bounds branch from 875c9df to c736ec5 Compare July 28, 2026 10:36
@0x-a6

0x-a6 commented Jul 28, 2026

Copy link
Copy Markdown
Author

Added to common code, but happy to put it into it's own block.

@jimklimov

Copy link
Copy Markdown
Member

Thanks, ok for now - I've actually added such a block in #3551 so will (hopefully remember to) relocate your entry there after both PRs get merged.

@AppVeyorBot

Copy link
Copy Markdown

Build nut 2.8.5.4995-master completed (commit 49b5e096be by @0x-a6)

@AppVeyorBot

Copy link
Copy Markdown

Build nut 2.8.5.4996-master completed (commit dbb3df6b8d by @0x-a6)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Hardening Ideas and implems to make NUT deployments more robust and secure (relaxed convenience may suffer) impacts-release-2.8.5 Issues reported against NUT release 2.8.5 (maybe vanilla or with minor packaging tweaks) USB

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants