Files
libva-multiplanar/firefox-fourier/0001-rdd-allow-stateless-v4l2-request-api.patch
T
marfrit f91469abe3 Iteration 3 close — F GREEN, A reproduced + diagnosed for iter4
Phase 1 locked F (Firefox RDD sandbox verify-by-patch) and A (frame-11
EINVAL diagnose) running in parallel on a single firefox-fourier build.

Track F: GREEN. Patched Firefox 150.0.1 (firefox-fourier, pkgrel=1.1)
launches on ohm WITHOUT MOZ_DISABLE_RDD_SANDBOX=1 and engages our
libva-v4l2-request backend end-to-end. Three patches needed (Phase 2
identified one and deferred two):
  - Broker policy (SandboxBrokerPolicyFactory.cpp): allow /dev/media*,
    extend cap-filter to admit stateless decoders that lack M2M caps.
  - Seccomp policy (SandboxFilter.cpp): allow ioctl magic byte '|'
    for <linux/media.h> request-API ioctls.
  - Driver (media.c): replace select() with poll() — Mozilla's RDD
    seccomp common policy admits poll/ppoll/epoll_* but not
    select/pselect6. Driver-side fix preferred; smaller surface,
    portable across sandbox policies, and poll() is the modern API.

Track A: REPRODUCES + DIAGNOSED. Frame-11 EINVAL fires deterministically
on a single-slice P-frame (slice_type=0, frame_num=5, post-IDR) — the
exact iter1/iter2 carryover signature, confirming it isn't environmental.
Y2 instrumentation (in v4l2_ioctl_controls) now logs num_controls /
error_idx / per-control id+size on EINVAL. Sizes match kernel UAPI;
error_idx == num_controls is the kernel's "all bad / no specific control"
sentinel — it's a request-level rejection, not a single-field violation.
Fix is iter4's lock; rig + Y2 in place for fast iter4 turnaround.

Build infrastructure introduced: firefox-fourier LXD container on
boltzmann (RK3588 aarch64, persistent, ssh -J boltzmann
builder@firefox-fourier). Upstream Arch x86_64 wasi packages installed
to work around 4-year-stale ALARM versions. PGO generation crashes at
exit (LXC has no display); obj/dist/ tarball used as the deployable
artifact instead of the pacman package.

Phase 6 surprises captured in phase6_iter3_findings.md: malformed
first-cut patch (descriptive vs numeric hunk headers), --enable-v4l2
isn't a Mozilla 150 flag (auto-set on aarch64+GTK), Mozilla 2025 PGP
key rotation, ALARM-stale wasi, onnxruntime missing in ALARM, and the
"no tricks" lesson (revert workarounds first when redirected).

Carries to iter4 substrate: Track A fix is the natural lock; mpv
libplacebo --vo=gpu segfault stays as separate iter4 candidate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 12:56:34 +00:00

114 lines
4.8 KiB
Diff

From: Markus Fritsche <fritsche.markus@gmail.com>
Date: 2026-05-05
Subject: [PATCH] sandbox/linux: allow V4L2 stateless request-API decoders in RDD
Firefox's RDD process sandbox blocks hardware video decode for V4L2
stateless decoders (hantro G1/G2 on RK35xx, cedrus on Allwinner, etc.).
Three distinct gates close the door:
1. Broker policy: AddV4l2Dependencies() filters /dev/video* by VIDEO_M2M /
VIDEO_M2M_MPLANE capability. Stateless decoders advertise
CAPTURE_MPLANE + OUTPUT_MPLANE + STREAMING but typically not M2M,
so /dev/video1 (the hantro device) is silently dropped.
2. Broker policy: GetRDDPolicy() never references /dev/media*. The
V4L2 request API (MEDIA_REQUEST_IOC_QUEUE et al), required for
stateless decode, lives on /dev/media* nodes that the broker
won't open from RDD.
3. Seccomp policy: RDDSandboxPolicy::EvaluateSyscall's ioctl handler
allowlists ioctl magic byte 'V' (V4L2) but not '|' (linux/media.h).
Even after broker permits the open, the kernel ioctl path is
filtered, returning ENOSYS to userspace and causing libva to
abandon decode. (Empirically confirmed iter3 Phase 7:
"Unable to allocate media request: Function not implemented".)
Tested: libva-v4l2-request-fourier on PineTab2 (RK3568, hantro G1)
playing bbb_1080p30 H.264 in Firefox 150 without
MOZ_DISABLE_RDD_SANDBOX=1.
---
--- a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
+++ b/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
@@ -901,8 +901,16 @@
}
if ((cap.device_caps & V4L2_CAP_VIDEO_M2M) ||
- (cap.device_caps & V4L2_CAP_VIDEO_M2M_MPLANE)) {
- // This is an M2M device (i.e. not a webcam), so allow access
+ (cap.device_caps & V4L2_CAP_VIDEO_M2M_MPLANE) ||
+ // V4L2 stateless decoders (hantro G1/G2 on Rockchip, cedrus on
+ // Allwinner, etc.) report CAPTURE_MPLANE + OUTPUT_MPLANE +
+ // STREAMING but do not set the M2M caps. They use the request API
+ // via /dev/media* (see AddV4l2RequestApiDependencies below).
+ ((cap.device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE) &&
+ (cap.device_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE) &&
+ (cap.device_caps & V4L2_CAP_STREAMING))) {
+ // This is an M2M or stateless decode device (i.e. not a webcam),
+ // so allow access
policy->AddPath(rdwr, path.get());
}
@@ -913,6 +921,32 @@
// FFmpeg V4L2 needs to list /dev to find V4L2 devices.
policy->AddPath(rdonly, "/dev");
}
+
+// V4L2 stateless decoders submit per-frame decode requests via the
+// media-controller framework on /dev/media* nodes (ioctls in the
+// MEDIA_REQUEST_IOC_* family, magic byte '|', defined in <linux/media.h>).
+// These are required alongside /dev/video* for any request-API decoder.
+// We allow rdwr access to all /dev/media* nodes; the kernel's
+// media-controller layer enforces device-level access control.
+// This mirrors the model AddV4l2Dependencies uses for /dev/video*.
+static void AddV4l2RequestApiDependencies(SandboxBroker::Policy* policy) {
+ DIR* dir = opendir("/dev");
+ if (!dir) {
+ SANDBOX_LOG("Couldn't list /dev for media-controller nodes");
+ return;
+ }
+
+ struct dirent* dir_entry;
+ while ((dir_entry = readdir(dir))) {
+ if (strncmp(dir_entry->d_name, "media", 5)) {
+ continue;
+ }
+ nsCString path = "/dev/"_ns;
+ path += nsDependentCString(dir_entry->d_name);
+ policy->AddPath(rdwr, path.get());
+ }
+ closedir(dir);
+}
#endif // MOZ_ENABLE_V4L2
/* static */ UniquePtr<SandboxBroker::Policy>
@@ -979,6 +1013,7 @@
#ifdef MOZ_ENABLE_V4L2
AddV4l2Dependencies(policy.get());
+ AddV4l2RequestApiDependencies(policy.get());
#endif // MOZ_ENABLE_V4L2
// Bug 1903688: NVIDIA Tegra hardware decoding from Linux4Tegra
--- a/security/sandbox/linux/SandboxFilter.cpp
+++ b/security/sandbox/linux/SandboxFilter.cpp
@@ -2067,6 +2067,11 @@
// Type 'V' for V4L2, used for hw accelerated decode
static constexpr unsigned long kVideoType =
static_cast<unsigned long>('V') << _IOC_TYPESHIFT;
+ // Type '|' for the V4L2 request API on /dev/media* nodes
+ // (MEDIA_REQUEST_IOC_QUEUE et al, defined in <linux/media.h>).
+ // Required by V4L2 stateless decoders such as hantro/cedrus/sun*.
+ static constexpr unsigned long kMediaType =
+ static_cast<unsigned long>('|') << _IOC_TYPESHIFT;
#endif
// nvidia non-tegra uses some ioctls from this range (but not actual
// fbdev ioctls; nvidia uses values >= 200 for the NR field
@@ -2088,6 +2093,7 @@
.ElseIf(shifted_type == kDmaBufType, Allow())
#ifdef MOZ_ENABLE_V4L2
.ElseIf(shifted_type == kVideoType, Allow())
+ .ElseIf(shifted_type == kMediaType, Allow())
#endif
// NVIDIA decoder from Linux4Tegra, this is specific to Tegra ARM64 SoC
#if defined(__aarch64__)