fix(ncm): prevent HardFault on Linux USB-NCM alt-setting flap (T-312)#6
Merged
Merged
Conversation
Connecting the device to a Linux host hard-faulted during CDC-NCM enumeration. Linux's CDC-NCM driver bounces the data interface (alt=1 -> alt=0 -> alt=1) during bring-up. On the alt=0 edge, ncm_flush_data_paths() freed recv_tinyusb_ntb and set it to NULL while the bulk-OUT transfer was still queued in the DCD. The stale transfer then completed against a NULL owner pointer and netd_xfer_cb() passed NULL to recv_validate_datagram(), which dereferenced ntb->nth before any NULL check -> BusFault -> HardFault (device hang). Fix (primary): in ncm_flush_data_paths(), do not reclaim a buffer whose bulk transfer is still in flight — guard the release of both recv_tinyusb_ntb (ep_out) and xmit_tinyusb_ntb (ep_in) with usbd_edpt_busy(). Ownership stays with the pending transfer, which netd_xfer_cb() reclaims normally on completion. (This fork lacks usbd_edpt_abort(), so the in-flight buffer must not be released.) Fix (defensive): guard netd_xfer_cb() against a NULL recv_tinyusb_ntb and NULL-check ntb inside recv_validate_datagram() before the header deref. Verified on FRDM-RW612: the Linux alt=1/0/1 flap now completes to strict_configured=1; NCM reaches NETIF_READY/DHCP and [ALIVE] heartbeat continues across the flap. No fault, no freeze. (T-312) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ndogj9bsRUroeAvzMMPhYq
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.
Problem
Connecting the FRDM-RW612 to a Linux host hard-faulted the device during CDC-NCM enumeration (device hang).
Root cause
Linux's CDC-NCM driver bounces the data interface alt-setting (
alt=1 → alt=0 → alt=1) during bring-up. On thealt=0edge,ncm_flush_data_paths()freedrecv_tinyusb_ntband set it toNULLwhile the bulk-OUT transfer was still queued in the DCD. The stale transfer then completed,netd_xfer_cb()read the now-NULLowner pointer and passed it torecv_validate_datagram(), which dereferencedntb->nthbefore any NULL check → BusFault → HardFault.Confirmed via non-invasive SWD RTT capture: the log froze at
recv_validate_datagram(00000000, 376)and a halt showedIPSR=003(HardFault). Same interface-toggle race family as the macOS NCM wedge (T-094); on Linux the alt-bounce turns it into a hard crash.Fix
ncm_flush_data_paths(), do not reclaim a buffer whose bulk transfer is still in flight. Guard the release of bothrecv_tinyusb_ntb(ep_out) andxmit_tinyusb_ntb(ep_in) withusbd_edpt_busy(ncm_interface.rhport, ep). Ownership stays with the pending transfer, whichnetd_xfer_cb()reclaims normally on completion. (This fork has nousbd_edpt_abort(), so the in-flight buffer must not be released.)recv_tinyusb_ntbinnetd_xfer_cb(), and NULL-checkntbinsiderecv_validate_datagram()before the header deref.Why it's safe
The TinyUSB device stack is single-threaded via the
tud_taskevent queue;usbd.cclears the endpointbusyflag before invokingnetd_xfer_cb. SET_INTERFACE processing and xfer-completion are serialized, so the busy check is race-free. Skipping the free when busy leaves the buffer owned (no leak, never double-freed); the glue/ready lists only hold already-completed transfers, so freeing those in flush stays safe.Verification (real hardware, FRDM-RW612)
scripts/verify.sh mcuboot→ PASS (build / flash / RTT live / anti-tamper).alt=1/0/1flap now completes tostrict_configured=1; NCM state machine reachesNETIF_READY/DHCP;[ALIVE]heartbeat continues across the flap. No freeze, no fault. The defensive path ("no owning NTB") never triggered — the primary fix alone resolves the race.Fixes T-312.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Ndogj9bsRUroeAvzMMPhYq