我最近将 18.04 安装更新到 20.04.1,Netflix 无法使用 Firefox(最新 78.0.2)播放其 DRM 内容。当我尝试在 Netflix 网站上播放视频时,我被带到一个错误页面,显示 F7701-1003,并且 Firefox 页面框架顶部出现一个黄色栏,提示插件崩溃。我采取了明显的步骤启用 DRM。
每次插件崩溃后,内核消息日志都包含以下行:
[440489.660558] MainThread[364746]: segfault at 0 ip 00007fb9fed72335 sp 00007fffa457a790 error 6 in libxul.so[7fb9fce9e000+4b5b000]
[440489.660566] Code: 8b 0d f7 80 39 05 48 89 01 c7 04 25 00 00 00 00 47 02 00 00 e8 dc 51 13 fe 48 8d 05 3f c7 d3 03 48 8b 0d d6 80 39 05 48 89 01 <c7> 04 25 00 00 00 00 49 02 00 00 e8 bb 51 13 fe 48 8d 05 50 c7 d3
因此看起来插件崩溃了libxul.so
。为了查看崩溃原因,我安装了 Firefox 调试包,然后使用这个SO答案,在 bash shell 中运行以下命令(其中IP
和MAPOFF
取自内核日志消息):
IP=0x00007fb9fed72335
MAPOFF=0x7fb9fce9e000
ADDR=$(python3 -c "print(hex($IP-$MAPOFF))")
addr2line -j .text -e /usr/lib/firefox/libxul.so $ADDR
输出结果如下:
/build/firefox-k3d8Rk/firefox-78.0.2+build2/obj-x86_64-linux-gnu/dist/include/mozilla/RefPtr.h:67
看看Firefox 源代码在线(我不想安装源包,我怀疑 ubuntu 已经修补了这个文件)实际上没有太大帮助。
我认为这可能是一个seccomp
类似的问题这个。因此我禁用了所有沙盒,并设置了以下环境变量:MOZ_DISABLE_CONTENT_SANDBOX=1 MOZ_DISABLE_GMP_SANDBOX=1
。但这也无济于事。
我尝试gdb
使用以下方法将实例附加到插件容器这些说明。虽然我可以连接到插件容器,但 gdb 从未捕获任何东西,最终插件被终止。我想知道这是否是由于 widevine 插件中的一些反调试功能造成的(即库认为它正在被调试并且故意崩溃)。
然后我strace
记录了 Firefox 实例所有进程的所有系统调用,并找到了插件容器崩溃的位置。以下是相关代码片段:
359684 execve("/usr/lib/firefox/plugin-container", ["/usr/lib/firefox/plugin-container", "/home/user/.mozilla/firefox/Media-Streaming-Sites/gmp-widevinecdm/4.10.1582.2", "359458", "true", "gmplugin"], 0x7f6598fb1000 /* 82 vars */ <unfinished ...>
... snip ...
359684 openat(AT_FDCWD, "/home/user/.mozilla/firefox/Media-Streaming-Sites/gmp-widevinecdm/4.10.1582.2/libwidevinecdm.so", O_RDONLY|O_CLOEXEC) = 15</home/user/.mozilla/firefox/Media-Streaming-Sites/gmp-widevinecdm/4.10.1582.2/libwidevinecdm.so>
359684 read(15</home/user/.mozilla/firefox/Media-Streaming-Sites/gmp-widevinecdm/4.10.1582.2/libwidevinecdm.so>, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0\354\16l\0\0\0\0\0\270\23l\0\0\0\0\0\0\0\0\0@\08\0\n\0@\0(\0'"..., 832) = 832
359684 pread64(15</home/user/.mozilla/firefox/Media-Streaming-Sites/gmp-widevinecdm/4.10.1582.2/libwidevinecdm.so>, "\6\0\0\0\4\0\0\0\354\16l\0\0\0\0\0\354\16l\0\0\0\0\0\354\16l\0\0\0\0\0000\2\0\0\0\0\0\0000\2\0\0"..., 560, 7081708) = 560
359684 fstat(15</home/user/.mozilla/firefox/Media-Streaming-Sites/gmp-widevinecdm/4.10.1582.2/libwidevinecdm.so>, {st_mode=S_IFREG|0600, st_size=7085500, ...}) = 0
359684 pread64(15</home/user/.mozilla/firefox/Media-Streaming-Sites/gmp-widevinecdm/4.10.1582.2/libwidevinecdm.so>, "\6\0\0\0\4\0\0\0\354\16l\0\0\0\0\0\354\16l"..., 560, 7081708) = 560
359684 mmap(NULL, 7082268, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 15</home/user/.mozilla/firefox/Media-Streaming-Sites/gmp-widevinecdm/4.10.1582.2/libwidevinecdm.so>, 0) = -1 EPERM (Operation not permitted)
359684 close(15</home/user/.mozilla/firefox/Media-Streaming-Sites/gmp-widevinecdm/4.10.1582.2/libwidevinecdm.so>) = 0
359684 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
359684 rt_sigaction(SIGSEGV, NULL, {sa_handler=0x7fdf19dbc670, sa_mask=[ILL TRAP ABRT BUS FPE SEGV], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7fdf1db583c0}, 8) = 0
359684 write(7<pipe:[3459405]>, "`\0\0\0001\0\0\0\0\0\0\0MOZ_CRASH(aborting because of MsgProcessingError)\212\0\0\0\34\0\0\0\0\0\0\000359686:\"Chrome_ChildThread\",6\0\0\0X\0\0\0\0\0\0\0/home/user/.mozilla/firefox/Media-Streaming-Sites/gmp-widevinecdm/4.10.1582.2", 201) = 201
359684 close(7<pipe:[3459405]>) = 0
359684 prctl(PR_SET_DUMPABLE, SUID_DUMP_USER) = 0
因此,在 strace 输出中,我们可以看到插件容器进程是359684
。它成功打开了插件库文件,并成功执行了read
和 两个操作pread64
。然后尝试访问mmap
文件,但失败了,不久之后,进程得到了 ,SIGSEGV
代码为SEGV_MAPERR
。然后调用进程的处理程序并写入一条错误消息,表明由于库中的SIGSEGV
而导致崩溃。MsgProcessingError
我怎样才能解决这个问题?
答案1
TLDR;验证插件是否位于具有执行权限的安装座上。
事实证明,配置文件位于具有属性的挂载上。因此,对with的noexec
调用应该会像它一样失败。但是,库使用将其指令加载到内存中,然后执行它们。一旦配置文件(以及插件文件)被移动到具有执行权限的挂载上,流式传输 Netflix 内容就会按预期工作。mmap
PROT_EXEC
EPERM
mmap
虽然我没有明确设置noexec
任何挂载点,但它被隐式添加,因为是带有属性的/home/user/.mozilla
挂载点,允许我的用户进行挂载。该属性隐式添加到挂载点。fstab
user
user
noexec
我猜我得到了一个SEGV_MAPERR
因为代码假设mmap
成功并尝试在请求的映射内存中运行指令。但是,由于失败mmap
,因此该内存实际上并未映射。
这个故事的寓意是,如果 widevine 崩溃了,而你对配置文件位置做了一些奇怪的事情,请确保该库能够执行。如果将 widevine 设置为与 Firefox 二进制文件一起安装的软件包,就可以避免这一切,但可能出于某些法律原因而不这样做。