Files
marfrit-packages/upstream-submissions/firefox-fourier/bugzilla-1969297-comment.md
T
test0r 7183f16961 upstream-submissions/firefox-fourier: bugzilla 1969297 comment draft
Independent firefox-fourier campaign (RK3399 H.264 stateless via
rkvdec) overlaps significantly with David's HEVC work outlined in
comment #3 — same gfxinfo / FFmpeg / sandbox plumbing. Posting our
findings, including a non-obvious sandbox/libudev interaction
(Mozilla's OpenAtTrap rejects fd-relative openat used by systemd's
chase() inside udev_enumerate_scan_devices), would save duplicate
effort.

Draft is the proposed comment text plus upload notes. Final
submission still needs human review + bugzilla account to post.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 18:14:36 +00:00

5.8 KiB

bugzilla.mozilla.org bug 1969297 — comment draft

Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1969297 Title: Implement hardware decoding of h.265/HEVC with v4l2-stateless Owner: david.turner@raspberrypi.com Status: ASSIGNED, Linux/ARM64, Core :: Audio/Video: Playback

This bug tracks H.265/HEVC stateless. Our work targeted H.264 stateless on Rockchip RK3399 (Pinebook Pro, mainline kernel, rkvdec driver) but the plumbing — gfxinfo fourcc detection, libavcodec hwaccel routing, RDD sandbox carve-out — is identical in shape to what David outlined in comment #3 ("work that needs doing"). Posting findings here in case it saves duplicate effort and to flag a sandbox interaction that any V4L2 stateless implementation will hit.


Comment to post (markdown — Bugzilla renders ``` blocks)

Posting independent findings from a parallel firefox-fourier campaign on Rockchip RK3399 / Pinebook Pro / mainline rkvdec (H.264 stateless). The plumbing is identical to what David described in comment #3 for HEVC, so this should fold into bug 1969297 cleanly once H.265-specific bits are layered on.

Patch series (validated end-to-end, RDD CPU 78% software → 5% hardware on bbb 1080p30 H.264, default RDD sandbox enabled, no env overrides):

  1. widget/gtk/GfxInfo.cpp — recognize V4L2 stateless fourccs S264, S265, VP9F alongside the existing stateful set
  2. dom/media/platforms/ffmpeg/FFmpegLibWrapper — silent av_hwdevice_ctx_create wrapper (suppresses libavutil's stderr spam when the autodetect tries unsupported devices)
  3. dom/media/platforms/ffmpeg/FFmpegVideoDecoder — split V4L2 stateless init (InitV4L2RequestDecoder) from stateful (InitV4L2Decoder), with a two-pass codec-name-first / hw_configs-fallback probe so it works against both legacy (AV_HWDEVICE_TYPE_DRM) and modern (AV_HWDEVICE_TYPE_V4L2REQUEST, value 15 in Kwiboo's fork) FFmpeg vintages
  4. modules/libpref/init/StaticPrefList.yaml — gate behind media.ffmpeg.v4l2-request.enabled (default true)
  5. security/sandbox/linux/{broker/SandboxBrokerPolicyFactory,SandboxFilter}.cpp — RDD sandbox extension: /dev/media* (driver-matched against the existing /dev/video* walk), MEDIA_IOC_* ioctl family '|', plus AddTree on /sys/class, /sys/bus, /sys/dev/char, /sys/devices/platform, /run/udev, /etc/udev/udev.conf, /proc/self, /dev/dma_heap

The series is published on git.reauktion.de/marfrit/marfrit-packages under arch/firefox-fourier/patches/.

The non-obvious finding worth surfacing here: udev_enumerate_scan_devices() returns -EUNATCH (-49) inside RDD's sandbox even with all the broker carve-outs above in place. Mozilla's OpenAtTrap in security/sandbox/linux/SandboxFilter.cpp explicitly rejects fd-relative openat():

if (fd != AT_FDCWD && path[0] != '/') {
  SANDBOX_LOG("unsupported fd-relative openat(%d, \"%s\", 0%o)", fd, path, flags);
  return BlockedSyscallTrap(aArgs, nullptr);  // returns -ENOSYS
}

systemd v255+ uses fd-relative openat() extensively inside its chase() symlink-resolver for TOCTOU safety, and chase() is the spine of udev_enumerate_scan_devices. So libudev fails inside the sandbox no matter how permissive the broker policy is — the calls never reach the broker. Confirmed by bpftrace comparison (sandbox-on vs sandbox-off): full openat("/"), openat("sys"), openat("bus"), openat("..") chase flurry under sandbox-off, zero openat() events under sandbox-on.

Workaround we shipped (in our ffmpeg-v4l2-request fork): a brute-force fallback inside libavutil/hwcontext_v4l2request.c's v4l2request_open_decoder that enumerates /dev/media[0..15] directly via absolute paths plus MEDIA_IOC_DEVICE_INFO and MEDIA_IOC_G_TOPOLOGY, with stat()-based major/minor matching to resolve /dev/videoN paths. The fallback only activates when libudev's scan returns negative. Same approach Chromium uses in media/gpu/v4l2/stateless/ for ChromeOS where the sandbox has the same constraint.

This is a libavcodec-side fix, not a Firefox-side one — so it'd be appropriate either to upstream to FFmpeg (the v4l2_request hwaccel predates wider sandboxed-Linux deployment, so the libudev assumption was reasonable at the time) or carry it as a Firefox-bundled libavcodec patch.

The alternative — teaching Mozilla's broker to handle fd-relative openat() via /proc/self/fd/<fd>/<path> resolution — would close the gap for any future libudev consumer in the sandbox, but has TOCTOU implications I haven't audited; the libavcodec-side bypass felt cheaper to ship.

Validation log on RK3399 / Pinebook Pro / mainline rkvdec, default RDD sandbox, MOZ_LOG=FFmpegLib:5:

V4L2 stateless FFmpeg init successful
Format drm_prime chosen by get_format().
Format drm_prime requires hwaccel h264_v4l2request initialisation.
libudev probe failed (-2), falling back to brute-force /dev/media*
Using V4L2 media driver rkvdec (brute-force) for S264
Reinit context to 1920x1088, pix_fmt: drm_prime

Happy to coordinate / split work / share patches if that helps the HEVC track. None of patches 1-4 above are H.264-specific; 5 is codec-agnostic. The libavcodec libudev-bypass has zero codec coupling.


Notes for upload

  • This is just the comment text. Don't attach the patches — Mozilla prefers Phabricator (D-numbers) for code review. If the H.264 work is upstreamed it should go through Phabricator with David tagged.
  • Suggest emailing David first (david.turner@raspberrypi.com) before pasting in the bug, in case he's already half-implemented something similar — saves a thrash if there's overlap.
  • The /proc/self/fd/ trick mentioned at the end is real (and is how Chromium handles its own broker for some paths). If pursued upstream in Mozilla, see security/sandbox/linux/broker/SandboxBroker.cpp RealPath() + SymlinkPermissions() for the existing precedent.