Skip to content

UVC camera compat & stability hardening (v0.0.7.3→v0.0.7.8): transfer-buffers property, negotiation diagnostics, quirk seam, camera-compat docs - #16

Merged
andrescera merged 11 commits into
mainfrom
feat/uvc-camera-compat-stability
Jul 4, 2026
Merged

UVC camera compat & stability hardening (v0.0.7.3→v0.0.7.8): transfer-buffers property, negotiation diagnostics, quirk seam, camera-compat docs#16
andrescera merged 11 commits into
mainfrom
feat/uvc-camera-compat-stability

Conversation

@andrescera

Copy link
Copy Markdown
Member

Summary

This PR lands the culmination of the uvc-camera-compat-stability hardening plan: it adopts a substantially hardened CeraLive/libuvc fork and adds a set of opt-in, off-by-default plugin knobs and diagnostics for UVC camera compatibility.

No default-behavior change. Every new knob is sentinel-off; existing DJI/UVC setups negotiate byte-identically when nothing is set.

What this does

  • libuvc fork hardening backports (A1–A14). Ports individually-audited robustness fixes from upstream libuvc, pupil-labs, and saki4510t sources into the CeraLive fork — flaky stream starts (alt-setting retry), silent no-frame starts, teardown hangs (bounded uvc_stream_stop), metadata-buffer leaks, degenerate/broken frame-descriptor repair, zero/corrupt/oversized payload guards, and composite-device VC-header dwClockFrequency preservation. Fixes were extracted individually rather than merging any fork wholesale, each behind a mandatory per-fix equivalence audit.
  • New opt-in transfer-buffers property. USB transfer-buffer count hint, mirroring the existing max-payload contract exactly: sentinel 0 = library default (no device write), nonzero clamped to [2, 100], applied right before uvc_start_streaming() on both initial start() and every reconnect re-arm (reconnect-idempotent), read-back logged. Fork-only; a no-op with one warning on the LIBUVC_USE_FORK=OFF upstream-fallback build (feature-guarded via HAVE_UVC_TRANSFER_BUFFERS).
  • Negotiation-failure descriptor-inventory diagnostics. When caps negotiation fails, the element now logs exactly what formats/resolutions the unsupported camera actually offered, instead of a bare failure.
  • vid:pid quirk seam with QUIRK_DOUBLE_PROBE as the first behavior — table + lookup + logging, empty by default (no entries enabled), so it's a pure seam with zero runtime effect until a quirk is deliberately added.
  • docs/notes/camera-compat.md — mechanism-per-family compatibility matrix, field-triage guide, and fork provenance table.

Fork pin

The fork is now pinned at ceralive-v0.0.7.8 (71588dbc23c5204e07c575c3b2ae6ac7ee9bf90d), up from ceralive-v0.0.7.2 / eae7f49 before this work. The fork is public and already released/tagged on https://github.com/CeraLive/libuvc.git; CI's fork-guard clones it with no credentials.

⚠️ Important callout: 5 emergency UAF hotfix rounds (v0.0.7.4 → v0.0.7.8)

After the initial v0.0.7.3 release, an adversarial code-quality review of the new bounded uvc_stream_stop() (A5) teardown path caught a use-after-free chain reachable when a stop-timeout leaves an event/handler thread alive during teardown. Five narrowly-scoped hotfix rounds were required:

Tag Fix
v0.0.7.4 Quarantine strmh on the A5 stop-timeout path in uvc_stream_close.
v0.0.7.5 Quarantine devh in uvc_close so a late LIBUSB_TRANSFER_COMPLETED callback deref of strmh->devh->is_isight is lifetime-safe.
v0.0.7.6 Quarantine uvc_context so uvc_exit skips libusb_exit/free while a stop-timeout event thread still runs on ctx->usb_ctx.
v0.0.7.7 Gate uvc_close's last-device handler-thread kill/join on !has_quarantined_device.
v0.0.7.8 uvc_exit iterates ctx->open_devices with DL_FOREACH_SAFE (safe against uvc_close freeing the current node).

Full per-round detail: libuvch264src/docs/notes/camera-compat.md and the fork's own CHANGELOG.ceralive.md.

CI fix included in this PR

The 5 hotfix commits bumped FORK_SHA in scripts/build-libuvc.sh but the fork ADR's primary pin block was never advanced past v0.0.7.2, so the fork-guard CI job (scripts/check-libuvc-fork.sh) would report PIN DRIFT (build 71588db ≠ ADR eae7f49). This PR adds one docs(libuvc) commit that syncs the ADR's authoritative pin to v0.0.7.8 and documents the hotfix chain — all prior v0.0.7.2/v0.0.7.3 records preserved verbatim as historical provenance.

Scope boundaries

No XU-based Logitech H.264, no GoPro non-UVC mode, no capture-card handling, no upstream-fallback (patches/) changes, no force_usb_release()-before-uvc_close() reintroduction, and no sibling-repo changes. Real-hardware validation remains a separate follow-up (the full ctest suite is mock-backed and hardware-independent).

Verification

Full evidence trail (fresh-clone builds, real ctest runs incl. TSan/ASan, fork CI checks, per-fix equivalence audits) exists under .omo/evidence/task-*.md/.txt in this repo — gitignored, so not part of the PR diff, but available for review context on request.


Ultraworked with Sisyphus

andrescera and others added 11 commits July 2, 2026 21:30
The main test_transfer_buffers target's three ON-path cases (applied,
clamped, reconnect_reapply) asserted the fork-only uvc_set_transfer_buffers()
effect unconditionally. The file already defined TB_API_AVAILABLE for exactly
this purpose but never used it, so a real -DLIBUVC_USE_FORK=OFF full-suite run
(first exercised by the todo-13 integration gate) failed those three cases:
with the fork API absent the element correctly warns and no-ops, so no setter
call is made. Activate the guard so each case asserts the fork ON behavior when
TB_API_AVAILABLE and the warn-and-no-op behavior otherwise; the max-payload
reconnect re-arm (not fork-gated) stays asserted on both paths. No product code
changed; the OFF no-op remains covered by test_transfer_buffers_off_noop.
…or late-callback UAF)

Round 1 (v0.0.7.4, dfba86f) quarantined the stream handle but uvc_close() still
freed strmh->devh, so a late LIBUSB_TRANSFER_COMPLETED callback dereferencing
strmh->devh->is_isight in _uvc_process_payload was a use-after-free on the freed
device handle. v0.0.7.5 (a1949ae) propagates the quarantine to the device handle:
uvc_close() intentionally leaks devh when a stream was quarantined, so the late
deref lands on live memory. Bounded-wait preserved; common path still frees both.

Only FORK_SHA + its comment change. UPSTREAM_SHA and patches/ untouched.
Gate re-run against the build-libuvc.sh clone of a1949ae: ASan 148/148, plain
93/93, CVE oob+null + usb_teardown + pts/frame(+tsan) all Passed; plugin .so and
test_cve_2026_1991 resolve libuvc.so.0 -> pinned install (RUNPATH).
…x for handler-thread/libusb_exit race)

FORK_SHA a1949ae -> 3ede00e (tag ceralive-v0.0.7.6). Round 3 quarantines the
uvc_context on the stop-timeout path: uvc_exit() now leaks the context (skips
libusb_exit + free) and uvc_open_internal() skips a duplicate event-handler
thread while a still-running _uvc_handle_events loops on ctx->usb_ctx after a
quarantining uvc_close(). Fixes a UAF/race on the libusb context on every
plugin stop() after a quarantine, and a double handler thread on reconnect.

Re-gated against the build-libuvc.sh clone of 3ede00e (fresh dirs): ASan
148/148, plain 93/93; cve_2026_1991 oob+null, usb_teardown(+asan),
pts_thread_safety(+tsan), frame_throughput(+tsan), reconnect_* all Passed;
real plugin .so + test_cve_2026_1991 resolve libuvc.so.0 => the pinned install.
UPSTREAM_SHA + patches/ untouched.
The 5 emergency hotfix rounds (v0.0.7.4->v0.0.7.8) bumped FORK_SHA in
scripts/build-libuvc.sh but the fork ADR's primary pin block was never
advanced past v0.0.7.2, so scripts/check-libuvc-fork.sh (the CI
fork-guard) reported PIN DRIFT: build 71588db != ADR eae7f49.

Add an authoritative CURRENT PIN callout at the top of the Fork URL
section (71588db / ceralive-v0.0.7.8) so the guard's first-GIT_TAG /
first-Tag-HEAD-SHA reads agree with the build pin, and add a v0.0.7.8
addendum documenting the UAF/lifetime hotfix chain. All prior v0.0.7.2
and v0.0.7.3 records are preserved verbatim as historical provenance.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@andrescera
andrescera merged commit 5883bb3 into main Jul 4, 2026
5 checks passed
@andrescera
andrescera deleted the feat/uvc-camera-compat-stability branch July 4, 2026 00:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant