hid: don't raise on control PDUs a peer may legitimately send - #979
Open
rajathpi wants to merge 1 commit into
Open
hid: don't raise on control PDUs a peer may legitimately send#979rajathpi wants to merge 1 commit into
rajathpi wants to merge 1 commit into
Conversation
Handshake result codes 0x05..0x0D are reserved by the HID Profile 1.1 specification (3.1.2.1, Table 3.2), but `Message.Handshake` was a plain `enum.IntEnum` naming only 0x00..0x04, 0x0E and 0x0F. Receiving a reserved code raised `ValueError`, and no handshake event was emitted. Make it a `utils.OpenIntEnum`, as already used for protocol enums elsewhere in the codebase. An empty control PDU, and a GET_REPORT or SET_REPORT shorter than the report-ID-carrying format Bumble implements, raised `IndexError` while indexing the PDU. Empty PDUs are now dropped, and a short GET/SET_REPORT is answered with ERR_INVALID_PARAMETER. `ClassicChannel.on_sdu` calls the channel sink without a try/except, so these exceptions propagate out of the L2CAP receive path. The transport layer logs them and discards the PDU, which leaves a requesting peer waiting for a handshake that is never sent. Adds tests/hid_test.py; hid.py had no test coverage before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
Collaborator
|
FYI, we are going to refactor HID soon. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Four control PDUs that a remote peer can send cause
bumble/hid.pyto raise out of the L2CAP receive path.ClassicChannel.on_sducalls the channelsinkwithout atry/except, so the exception escapes into the transport's receive loop. On real transports it is caught and logged one layer up (transport/common.py,transport/usb.py), so nothing crashes — but the PDU is discarded and, for the report requests, the mandatory HANDSHAKE response is never sent, leaving the requesting peer waiting.0x05–0x0D(toHost)ValueError, noEVENT_HANDSHAKEemittedHostorDevice)IndexErrorIndexError, no handshake replyIndexError, no handshake replyResult codes
0x05–0x0Dare reserved by the HID Profile 1.1 specification (3.1.2.1, Table 3.2), so a peer can legitimately send one — butMessage.Handshakewas a plainenum.IntEnumnaming only0x00–0x04,0x0Eand0x0F.How
Message.Handshakebecomes autils.OpenIntEnum. That is the idiom already used for protocol enums throughout the codebase (~160 other uses), and it keeps.nameworking for unnamed values.ERR_INVALID_PARAMETER, per 3.1.2.1 ("If [the device] detects a field with a value that is out of range or inappropriate for the request, then an ERR_INVALID_PARAMETER result code shall be returned").The length check is
len(pdu) < (4 if buffer_flag else 2), matching Table 3.4: HIDP header, report ID, then a 2-octet little-endian buffer size only when the Size bit is set. Note the report ID is conditional in the spec, but Bumble's API always carries one (GetReportMessage.__bytes__,get_report_cb(report_id, ...)), so a shorter PDU cannot be dispatched to the application callback without an API change.No behaviour change for well-formed PDUs, and the no-callback-registered path still answers
ERR_UNSUPPORTED_REQUESTexactly as before.Tests
Adds
tests/hid_test.py—hid.pyhad no test coverage. The tests drive the PDUs across a real L2CAP channel between twoTwoDevicespeers rather than callingon_ctrl_pdudirectly, and the empty-PDU case installs a loop exception handler, since that failure surfaces on the event loop rather than at the call site.16 of the 18 tests fail on
mainand pass with this change. The 2 that pass either way are the deliberate no-regression checks (a defined handshake code, and a well-formed GET_REPORT round trip).Full suite: 994 passed. The 6
android-netsimfailures are pre-existing and environmental (grpcionot installed).black -S --check,ruff check,ruff check --select Iandmypyare clean on both files.Note
#815 reworks this file and reaches the same conclusion about
OpenIntEnumfor these enums. This change is deliberately small and non-breaking so it can land onmainindependently; it should be trivially absorbed if that refactor lands.🤖 Generated with Claude Code