Closed Bug 1387722 Opened 7 years ago Closed 7 years ago

h264 playback on amd64-linux fails

Categories

(Core :: Audio/Video: Playback, defect)

56 Branch
defect
Not set
normal

Tracking

()

RESOLVED WORKSFORME

People

(Reporter: felix-mozilla, Unassigned, NeedInfo)

Details

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0
Build ID: 20170805151832

Steps to reproduce:

Compiled firefox 56 on amd64-linux, went to youtube.
I'm compiling from hg, and I'm building every few days. h264 has worked on my system till about 2 days ago.
To attempt to fix this, I updated my ffmpeg and did a fresh firefox build from scratch. No effect. I'm not sure how to debug this. Advice?



Actual results:

Failed to play h264 videos, webm works.

FWIW, I'm getting these error messages on the console when firefox tries and fails to play a h264 video:

libp11-kit.so.0: cannot open shared object file: No such file or directory
Failed to load module: /usr/lib64/gio/modules/libgiognutls.so
libgvfscommon.so: cannot open shared object file: No such file or directory
Failed to load module: /usr/lib64/gio/modules/libgioremote-volume-monitor.so
libgvfscommon.so: cannot open shared object file: No such file or directory
Failed to load module: /usr/lib64/gio/modules/libgvfsdbus.so
libgconf-2.so.4: cannot open shared object file: No such file or directory
Failed to load module: /usr/lib64/gio/modules/libgsettingsgconfbackend.so

I don't think these are related, maybe it's the failure handling. All these shared libraries are in the system, just not in /usr/lib64. Adding symlinks to /usr/lib64 silences those error messages but does not fix h264 playback.


Expected results:

play h264 videos.
Component: Untriaged → Audio/Video: Playback
Product: Firefox → Core
Summary: h264 linux → h264 playback on amd64-linux fails
I tried to strace firefox to find out what is going on. Here's what I found out.

There appears to be a seccomp based sandboxing layer. Firefox tries to open /opt/firefox64/lib/firefox-56.0/libmozavcodec.so, which sends a SIGSYS, which triggers an intercept to a broker who then passes the file descriptor back.

Here's what it looks like when it works:

 61676 7194  openat(AT_FDCWD, "/usr/lib64/libavcodec-ffmpeg.so.57", O_RDONLY|O_CLOEXEC) = 257
 61677 7194  --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_errno=EEXIST, si_call_addr=0x7fc218252840, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} ---
 61678 7194  socketpair(AF_UNIX, SOCK_SEQPACKET, 0, [39, 40]) = 0
 61679 7194  sendmsg(36, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\0\0\0\0\0\0\10\0\0\0\0\0\0\0\0\0", iov_len=16}, {iov_base="/usr/lib64/libavcodec-ffmpeg.so."..., iov_len=35}, {iov_base=NULL, iov_len=0}], msg_iovlen=3, msg_control=[{cmsg_len=20, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, cmsg_data=[40]}], msg_controllen=24, msg_flags=0}, MSG_NOSIGNAL <unfinished ...>
 61680 7196  <... recvmsg resumed> {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\0\0\0\0\0\0\10\0\0\0\0\0\0\0\0\0", iov_len=16}, {iov_base="/usr/lib64/libavcodec-ffmpeg.so."..., iov_len=8194}], msg_iovlen=2, msg_control=[{cmsg_len=20, cmsg_level=SOL_SOCKET,cmsg_type=SCM_RIGHTS, cmsg_data=[66]}], msg_controllen=24, msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 51
 61681 7194  <... sendmsg resumed> )           = 51
 61682 7196  openat(AT_FDCWD, "/usr/lib64/libavcodec-ffmpeg.so.57", O_RDONLY|O_NOCTTY|O_CLOEXEC <unfinished ...>
 61683 7194  close(40 <unfinished ...>
 61684 7196  <... openat resumed> )            = 95
 61685 7194  <... close resumed> )             = 0
 61686 7196  sendmsg(66, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\0\0\0\0", iov_len=4}], msg_iovlen=1, msg_control=[{cmsg_len=20, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, cmsg_data=[95]}], msg_controllen=24, msg_flags=0}, MSG_NOSIGNAL <unfinished ...>
 61687 7194  recvmsg(39,  <unfinished ...>
 61688 7196  <... sendmsg resumed> )           = 4
 61689 7194  <... recvmsg resumed> {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\0\0\0\0", iov_len=4}], msg_iovlen=1, msg_control=[{cmsg_len=20, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, cmsg_data=[40]}], msg_controllen=24, msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 4

I put /usr/lib64/libavcodec-ffmpeg.so.57 there so firefox would find it.

lrwxrwxrwx    1 root     root           16 Aug  5 16:13 /usr/lib64/libavcodec-ffmpeg.so.57 -> libavcodec.so.57

We see the original openat, the SIGSYS, sendmsg to query the broker for the file, the broker receives the request, does an openat, and passes the descriptor back.

Now observe what happens if libavcodec has a dependency on libva.so.1:

 62138 7194  openat(AT_FDCWD, "/usr/X11R7/lib64/libva.so.1", O_RDONLY|O_CLOEXEC) = 257
 62139 7194  --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_errno=EEXIST, si_call_addr=0x7fc218252840, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} ---                                                                                   
 62140 7194  socketpair(AF_UNIX, SOCK_SEQPACKET, 0, [39, 40]) = 0
 62141 7194  sendmsg(36, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\0\0\0\0\0\0\10\0\0\0\0\0\0\0\0\0", iov_len=16}, {iov_base="/usr/X11R7/lib64/libva.so.1\0", iov_len=28}, {iov_base=NULL, iov_len=0}], msg_iovlen=3, msg_control=[{cmsg_len=20, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, cmsg_data=[40]}], msg_controllen=24, msg_flags=0}, MSG_NOSIGNAL <unfinished ...>
 62142 7196  <... recvmsg resumed> {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\0\0\0\0\0\0\10\0\0\0\0\0\0\0\0\0", iov_len=16}, {iov_base="/usr/X11R7/lib64/libva.so.1\0", iov_len=8194}], msg_iovlen=2, msg_control=[{cmsg_len=20, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, cmsg_data=[66]}], msg_controllen=24, msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 44
 62143 7194  <... sendmsg resumed> )           = 44
 62144 7196  lstat("/usr",  <unfinished ...>
 62145 7194  close(40 <unfinished ...>
 62146 7196  <... lstat resumed> {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 62147 7194  <... close resumed> )             = 0
 62148 7196  lstat("/usr/X11R7",  <unfinished ...>
 62149 7194  recvmsg(39,  <unfinished ...>
 62150 7196  <... lstat resumed> {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 62151 7216  mprotect(0xefe6901d000, 4096, PROT_READ|PROT_WRITE <unfinished ...>
 62152 7196  lstat("/usr/X11R7/lib64",  <unfinished ...>
 62153 7216  <... mprotect resumed> )          = 0
 62154 7196  <... lstat resumed> {st_mode=S_IFDIR|0755, st_size=49152, ...}) = 0
 62155 7216  mprotect(0xefe6901d000, 4096, PROT_READ|PROT_EXEC <unfinished ...>
 62156 7196  lstat("/usr/X11R7/lib64/libva.so.1",  <unfinished ...>
 62157 7216  <... mprotect resumed> )          = 0
 62158 7196  <... lstat resumed> {st_mode=S_IFLNK|0777, st_size=17, ...}) = 0
 62159 7216  mprotect(0xefe6901d000, 4096, PROT_READ|PROT_WRITE <unfinished ...>
 62160 7196  readlink("/usr/X11R7/lib64/libva.so.1",  <unfinished ...>
 62161 7216  <... mprotect resumed> )          = 0
 62162 7196  <... readlink resumed> "libva.so.1.3904.0", 4095) = 17
 62163 7216  mprotect(0xefe6901d000, 4096, PROT_READ|PROT_EXEC <unfinished ...>
 62164 7196  lstat("/usr/X11R7/lib64/libva.so.1.3904.0",  <unfinished ...>
 62165 7216  <... mprotect resumed> )          = 0
 62166 7196  <... lstat resumed> {st_mode=S_IFREG|0755, st_size=117200, ...}) = 0
 62167 7216  mprotect(0xefe6901d000, 4096, PROT_READ|PROT_WRITE <unfinished ...>
 62168 7196  sendmsg(66, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\363\377\377\377", iov_len=4}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_NOSIGNAL <unfinished ...>
 62169 7216  <... mprotect resumed> )          = 0
 62170 7196  <... sendmsg resumed> )           = 4
 62171 7216  mprotect(0xefe6901d000, 4096, PROT_READ|PROT_EXEC <unfinished ...>
 62172 7196  close(66 <unfinished ...>
 62173 7216  <... mprotect resumed> )          = 0
 62174 7196  <... close resumed> )             = 0
 62175 7194  <... recvmsg resumed> {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\363\377\377\377", iov_len=4}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 4

For some reason, the broker code does not just to an openat. It does a series of lstat and then a readlink. And then, instead of trying to openat the file, which would have worked, it does a "file not found" sendmsg back.

So my guess is that this behavior is deliberate. Maybe there is a whitelist with trusted directory names somewhere, and it does not contain /usr/X11R7/lib64. Where is it?
Building on this, I searched for broker code and a directory whitelist, and here it is:

/src/firefox/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp:

 97   policy->AddPath(rdonly, "/dev/urandom");
 98   policy->AddPath(rdonly, "/proc/cpuinfo");
 99   policy->AddPath(rdonly, "/proc/meminfo");
100   policy->AddDir(rdonly, "/lib");
101   policy->AddDir(rdonly, "/etc");
102   policy->AddDir(rdonly, "/usr/share");
103   policy->AddDir(rdonly, "/usr/local/share");
104   policy->AddDir(rdonly, "/usr/lib");
105   policy->AddDir(rdonly, "/usr/lib32");
106   policy->AddDir(rdonly, "/usr/lib64");
107   policy->AddDir(rdonly, "/usr/X11R7/lib64");          // I just added this, let's see if it works
108   policy->AddDir(rdonly, "/usr/X11R6/lib/X11/fonts");
109   policy->AddDir(rdonly, "/usr/tmp");
110   policy->AddDir(rdonly, "/var/tmp");
111   policy->AddDir(rdonly, "/sys/devices/cpu");
112   policy->AddDir(rdonly, "/sys/devices/system/cpu");
h264 stopped working for me as well after update to 56.0b1 (64-bit) but distributed by Firefox update
I'm guessing it is a sandboxing issue but I can't repro it. Is the issue still affecting nightly?
Flags: needinfo?(felix-mozilla)
Version 	56.0b3
Build ID 	20170815141045

I am able to play h264 now testing with https://www.quirksmode.org/html5/tests/video.html

My distro's openh264 package has updated to 1.7.0 in the meanwhile. I don't know if it could affect it. I'd test downgrading it, but chromium 60 depends on the 1.7.0 version.
Status: UNCONFIRMED → RESOLVED
Closed: 7 years ago
Resolution: --- → WORKSFORME
You need to log in before you can comment on or make changes to this bug.