[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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 <astian@e-nautia.com>
Date: Mon, 11 Feb 2020 21:08:51 +0000
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


Reply to: