Skip to content

v1.0.0-alpha.2.1 — defensive-hardening

Pre-release
Pre-release

Choose a tag to compare

@netrunner01 netrunner01 released this 19 May 16:01

v1.0.0-alpha.2.1 — defensive-hardening

Released: May 19, 2026
Tag: v1.0.0-alpha.2.1
Upstream base: crazii/USBDDOS at b1308fb + PR crazii#31 + PR crazii#32 carried as fork-side commits

Type of release

Defensive-hardening release. Two functional patch series targeting USB enumeration freezes and OHCI DMA-structure page-crossing risks. Both patch series are also open as PRs against upstream crazii/USBDDOS (PR crazii#31 and PR crazii#32 in this fork's release set) and are carried as fork-side commits in the alpha.2.1 binaries until they merge upstream.

This is NOT a housekeeping release. Alpha.2 was housekeeping. Alpha.2.1 is not. There are real code changes in:

  • USBDDOS/usb.c — descriptor parser hardening
  • USBDDOS/HCD/ohci.c — no-page-crossing DMA allocation
  • USBDDOS/usballoc.c — pool arena no-page-crossing
  • USBDDOS/DPMI/dpmi_dj2.c — linear-address-space NCPB check fix

What's new

Gap I (PR crazii#31) — graceful-skip hardening for unsupported device classes

Four edits in USBDDOS/usb.c plus one new constant in USBDDOS/usb.h:

  • Improved no-driver-found log surfaces the full bDeviceClass/bDeviceSubClass/bDeviceProtocol triplet plus a human-readable class name (audio, wireless, miscellaneous(IAD), vendor, etc.):

    • Was: No driver found at port: 0 for device (class 01), skip
    • Now: No driver found at port: 0 for device (class 01/01/04 audio), skip
  • Explicit Interface Association Descriptor recognition (USB_DT_INTERFACE_ASSOCIATION = 0x0B) in the descriptor walker, with informational _LOG of firstIf/count/funcClass. No semantic change — USBDDOS continues to bind class drivers at device level, not function level, and does NOT use IAD's bFunctionClass for driver lookup.

  • bNumInterfaces > 32 cap mirroring Linux's USB_QUIRK_HONOR_BNUMINTERFACES defensive pattern. The cap value is persisted to pConfigList[].bNumInterfaces so subsequent malloc and memset operate on the same size (regression guard against heap buffer overrun).

  • Zero-length descriptor defensive break: if (len == 0) break; in the walker loop. Without this, a malformed device emitting any descriptor with bLength = 0 causes a hard infinite loop on i = i + len. Strong candidate fix for the tester's KT133A+NEC+mixed-class-hub freeze.

Gap H (PR crazii#32) — no-page-crossing enforcement for OHCI DMA structures

Three coordinated changes:

  • USBDDOS/HCD/ohci.c: apply the DPMI_DMAMalloc → DPMI_DMAMallocNCPB macro override at the top of the file, mirroring the pattern EHCI has used since its bring-up (ehci.c:25-30). OHCI's HCData allocation is the highest-risk site: it embeds the 256-byte HCCA plus 8 static EDs (~548 bytes total) and a plain DPMI_DMAMalloc could place it straddling a 4KB page boundary, silently breaking DMA for either the HCCA or the static EDs.

  • USBDDOS/HCD/ohci.c: add DEBUG-build defense-in-depth assertions at the HCCA register-write site verifying the produced allocation actually fits within a single physical page.

  • USBDDOS/usballoc.c: switch pool-arena allocations (both the on-demand USBALLOC_GetMemory path and the USBALLOC_Init pre-allocation path) from DPMI_DMAMalloc to DPMI_DMAMallocNCPB. Variable-size paths stay on plain DMAMalloc because transfer buffers may legitimately exceed a page (OHCI § 3.1.1.1 supports buffers spanning one page boundary via the TD's CBP/BE mechanism).

Bug fixed in the same commit: DPMI_DMAMallocNCPB in dpmi_dj2.c (DJGPP build path) was checking page boundaries in C-pointer-relative space rather than linear-address space. Under HDPMI32 with a non-page-aligned XMS mapping base — observed XMS lbase 002e1c00 (offset 0xC00 within its page) on QEMU — C-pointer "pages" and linear "pages" live on different grids offset by (DPMI_DSBase & 0xFFF). An allocation that NCPB previously declared page-contained in C-pointer space could still straddle a linear page boundary, which is what the hardware sees for DMA. The fix translates via DPMI_DSBase before the boundary test.

The Watcom/Borland path (dpmi_bc.cpp:991) was already correct — it uses DPMI_PTR2L(ptr) to get the linear address before the check, so only the DJGPP build was affected. EHCI was latently exposed to the same bug since its bring-up but evidently has not been hit in practice because its DMA structures (QH 96B, QTD 32B, iTD 64B) are small enough that the probability of crossing a linear-page boundary is much lower than for OHCI's 548-byte HCData.

Recommended upgrade triggers

  • Hit the unsupported-class enumeration freeze. Typical: USB audio, Bluetooth dongle, or wireless-USB device behind a hub alongside HID devices. Specifically reported on KT133A + NEC µPD720101 + 4-port hub with USB microphone (class 0x01), BT dongle (class 0xE0), and two composite HID devices.
  • Suspect OHCI DMA corruption on a DJGPP build using HDPMI32. XMS heap linear base may not be page-aligned, exposing the latent NCPB bug fixed in this release.
  • Running alpha.1 or alpha.2 without observed symptoms: upgrade is optional but recommended.

Real-hardware verification status

The alpha label is retained for this release.

Both patch series were verified in QEMU (OHCI + usb-audio enumeration, mixed-class kbd + audio scenario across two OHCI controllers) and via a native-Linux unit test exercising the descriptor parser against synthetic descriptors (5 cases: audio with CSINTERFACE chain, IAD composite, bNumInterfaces=200 cap, malformed zero-length descriptor, interface overrun — all pass).

Real-hardware report against the original tester's KT133A+NEC configuration is still pending. If you can test on real silicon and file a report, please open an issue at Netrunner01/USBDDOS/issues.

The "alpha" label means real-hardware verification on the silicon the patches target is still pending — it does NOT mean the code is unstable or broken. Promotion to beta or v1.0.0 still requires at least one independent real-hardware test report per patched gap.

Build provenance

All four binaries in usbddos-v1.0.0-alpha.2.1-bundle.zip were built from the release-branch tip at commit 810b58b on a Linux x86_64 sandbox with DJGPP gcc 12.2.0 and Open Watcom v2.0 beta. DJGPP binaries embed the build-ID string 810b58b, DJGPP. Watcom binaries are bit-stable across rebuilds at the same commit.

Binary Toolchain Mode Size
USBDDOS.EXE Open Watcom v2 release 65,402
USBDDOS-DEBUG.EXE Open Watcom v2 DEBUG 95,348
USBDDOSP.EXE DJGPP 12.2.0 release 208,384
USBDDOSP-DEBUG.EXE DJGPP 12.2.0 DEBUG 368,295

All four builds compile clean with the project's existing -Werror -Wconversion -Wsign-compare -pedantic-errors flag set.

Notes

  • No CWSDPMI / HDPMI32 host preference change recommended. The NCPB fix is in the DJGPP build path (USBDDOSP.EXE). The Watcom build (USBDDOS.EXE) was never affected.
  • QEMU regression test coverage: 7-test ladder still passes 7/7, plus an 8th test case (OHCI + usb-audio with HDPMI32 capturing the graceful-skip log line) passes.
  • After PRs crazii#31 and crazii#32 merge upstream, a future alpha.3 release will cut from that new upstream tip (mirroring the alpha.1 → alpha.2 cycle).

License

GPL-2.0. See COPYING inside the release bundle. Source for these binaries is at this tag.