f91469abe3
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>
114 lines
4.8 KiB
Diff
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__)
|