Bug#950816: mpv: unintended code execution vulnerability
Package: mpv Version: 0.32.0-1 Severity: grave Tags: security fixed-upstream Justification: user security hole Dear Maintainer, If Lua scripts are enabled (they are by default) and configured for use (Debian doesn't seem to have any active by default) mpv could end up loading unintended code (lua scripts/bytecode and/or shared objects) from the current working directory. The following upstream commit supposedly fixes this: https://github.com/mpv-player/mpv/commit/cce7062a8a6b6a3b3666aea3ff86db879cba67b6 Excerpt from the commit message: lua: fix highly security relevant arbitrary code execution bug It appears Lua's package paths try to load .lua files from the current working directory. Not only that, but also shared libraries. [...] In mpv's case, this is so security relevant, because mpv is normally used from the command line, and you will most likely actually change into your media directory or whatever with the shell, and play a file from there. No, you don't want to load a (probably downloaded) shared library from this directory if a script try to load a system lib with the same name or so. I'm not sure why LUA_PATH_DEFAULT in luaconf.h (both upstream and the Debian version) put "./?.lua" at the end, but in any case, trying to load a module that doesn't exist nicely lists all package paths in order, and confirms it tries to load files from the working directory first (anyone can try this). Even if it didn't, this would be problematic at best. Note that scripts are not sandboxed. They're allowed to load system libraries, which is also why we want to keep the non-idiotic parts of the package paths. [...] mpv in default configuration (i.e. no external scripts) is probably not affected. All builtin scripts only "require" preloaded modules, which, in a stroke of genius by the Lua developers, are highest priority in the load order. Otherwise, enjoy your semi-remote code execution bug. [...] Cheers. -- System Information: Debian Release: bullseye/sid APT prefers unstable-debug APT policy: (500, 'unstable-debug'), (500, 'unstable'), (500, 'testing'), (500, 'stable') Architecture: amd64 (x86_64) Kernel: Linux 4.19.0-6-amd64 (SMP w/4 CPU cores) Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8), LANGUAGE=en_GB:en (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system) LSM: AppArmor: enabled Versions of packages mpv depends on: ii libarchive13 3.4.0-1+b1 ii libasound21.2.1.2-2 ii libass9 1:0.14.0-2 ii libavcodec58 7:4.2.2-1 ii libavdevice58 7:4.2.2-1 ii libavfilter7 7:4.2.2-1 ii libavformat58 7:4.2.2-1 ii libavutil56 7:4.2.2-1 ii libbluray21:1.1.2-2 ii libc6 2.29-9 ii libcaca0 0.99.beta19-2.1 ii libcdio-cdda2 10.2+2.0.0-1+b1 ii libcdio-paranoia2 10.2+2.0.0-1+b1 ii libcdio18 2.0.0-2 ii libdrm2 2.4.100-4 ii libdvdnav46.0.1-1+b1 ii libegl1 1.3.0-7 ii libgbm1 19.3.3-1 ii libgl11.3.0-7 ii libjack-jackd2-0 [libjack-0.125] 1.9.12~dfsg-2+b1 ii libjpeg62-turbo 1:1.5.2-2+b1 ii liblcms2-22.9-4 ii liblua5.2-0 5.2.4-1.1+b3 ii libpulse0 13.0-4 ii librubberband21.8.2-1 ii libsdl2-2.0-0 2.0.10+dfsg1-1 ii libsmbclient 2:4.11.5+dfsg-1 ii libsndio7.0 1.5.0-3 ii libswresample37:4.2.2-1 ii libswscale5 7:4.2.2-1 ii libuchardet0 0.0.6-3 ii libva-drm22.6.1-1 ii libva-wayland22.6.1-1 ii libva-x11-2 2.6.1-1 ii libva22.6.1-1 ii libvdpau1 1.3-1 ii libwayland-client01.17.0-1+b1 ii libwayland-cursor01.17.0-1+b1 ii libwayland-egl1 1.17.0-1+b1 ii libx11-6 2:1.6.8-1 ii libxext6 2:1.3.3-1+b2 ii libxinerama1 2:1.1.4-2 ii libxkbcommon0 0.9.1-1 ii libxrandr22:1.5.1-1 ii libxss1 1:1.2.3-1 ii libxv12:1.0.11-1 ii zlib1g1:1.2.11.dfsg-1.1 Versions of packages mpv recommends: ii xdg-utils 1.1.3-1 ii youtube-dl 2020.01.24-0.1 mpv suggests no packages. -- no debconf information
Bug#950816: mpv: unintended code execution vulnerability
Control: tags -1 + patch Control: found -1 mpv/0.29.1-1 FYI, the patch below works for me. Also, I think the version in stable is also affected. The code differs slightly so the patch will need a little tweak. Cheers. -- >From 937749b545407aa68b1d15ea5e19a6c23d62da42 Mon Sep 17 00:00:00 2001 From: astian Date: Mon, 11 Feb 2020 21:08:51 + Subject: [PATCH] lua: fix unintended code execution vulnerability Backport of upstream commit cce7062a8a6b6a3b3666aea3ff86db879cba67b6 ("lua: fix highly security relevant arbitrary code execution") to release 0.32.0. Note: Before release 0.32.0, it used to be that mpv-related scripts directories where added to Lua's module-loaders search path. This behaviour was dropped in 0.32.0 (bc1c024ae032). Later, a similar but stricter behaviour was introduced (see da38caff9c0b and b86bfc907f9c). The original commit on which this patch is based depended on the new behaviour. This backport retains the 0.32.0 behaviour; all it does is filter out relative paths from "package.path" and "package.cpath" for all Lua scripts. --- player/lua.c | 34 ++ 1 file changed, 34 insertions(+) diff --git a/player/lua.c b/player/lua.c index 6423861..172ab4e 100644 --- a/player/lua.c +++ b/player/lua.c @@ -273,6 +273,36 @@ static int load_scripts(lua_State *L) return 0; } +static void fuck_lua(lua_State *L, const char *search_path) +{ +void *tmp = talloc_new(NULL); + +lua_getglobal(L, "package"); // package +lua_getfield(L, -1, search_path); // package search_path +bstr path = bstr0(lua_tostring(L, -1)); +char *newpath = talloc_strdup(tmp, ""); + +// Unbelievable but true: Lua loads .lua files AND dynamic libraries from +// the working directory. This is highly security relevant. +// Lua scripts are still supposed to load globally installed libraries, so +// try to get by by filtering out any relative paths. +while (path.len) { +bstr item; +bstr_split_tok(path, ";", &item, &path); +if (bstr_startswith0(item, "/")) { +newpath = talloc_asprintf_append(newpath, "%s%.*s", + newpath[0] ? ";" : "", + BSTR_P(item)); +} +} + +lua_pushstring(L, newpath); // package search_path newpath +lua_setfield(L, -3, search_path); // package search_path +lua_pop(L, 2); // - + +talloc_free(tmp); +} + static int run_lua(lua_State *L) { struct script_ctx *ctx = lua_touserdata(L, -1); @@ -326,6 +356,10 @@ static int run_lua(lua_State *L) assert(lua_gettop(L) == 0); +fuck_lua(L, "path"); +fuck_lua(L, "cpath"); +assert(lua_gettop(L) == 0); + // run this under an error handler that can do backtraces lua_pushcfunction(L, error_handler); // errf lua_pushcfunction(L, load_scripts); // errf fn -- 2.25.0