Basic protection against Lua os.exit() and posix.exec() (ticket #167)
authorPanu Matilainen <pmatilai@redhat.com>
Mon, 15 Nov 2010 07:36:17 +0000 (09:36 +0200)
committerPanu Matilainen <pmatilai@redhat.com>
Mon, 15 Nov 2010 07:49:14 +0000 (09:49 +0200)
- Track posix.fork() and only allow exit() and exec() if the script
  has forked. There are other questionable items in posix extensions
  too but these are the worst offenders.
- Using Lua registry for tracking forked status might be more Lua-way
  option but this'll do for now.

luaext/lposix.c
luaext/lposix.h
rpmio/rpmlua.c
tests/rpmmacro.at

index 5b26e0c..3b25157 100644 (file)
@@ -42,6 +42,8 @@
 
 #include "modemuncher.c"
 
+static int have_forked = 0;
+
 static const char *filetype(mode_t m)
 {
        if (S_ISREG(m))         return "regular";
@@ -323,7 +325,12 @@ static int Pexec(lua_State *L)                     /** exec(path,[args]) */
 {
        const char *path = luaL_checkstring(L, 1);
        int i,n=lua_gettop(L);
-       char **argv = malloc((n+1)*sizeof(char*));
+       char **argv;
+
+       if (!have_forked)
+           return luaL_error(L, "exec not permitted in this context");
+
+       argv = malloc((n+1)*sizeof(char*));
        if (argv==NULL) return luaL_error(L,"not enough memory");
        argv[0] = (char*)path;
        for (i=1; i<n; i++) argv[i] = (char*)luaL_checkstring(L, i+1);
@@ -335,7 +342,11 @@ static int Pexec(lua_State *L)                     /** exec(path,[args]) */
 
 static int Pfork(lua_State *L)                 /** fork() */
 {
-       return pushresult(L, fork(), NULL);
+       pid_t pid = fork();
+       if (pid == 0) {
+           have_forked = 1;
+       }
+       return pushresult(L, pid, NULL);
 }
 
 
@@ -852,3 +863,27 @@ LUALIB_API int luaopen_posix (lua_State *L)
        lua_settable(L,-3);
        return 1;
 }
+
+/* RPM specific overrides for Lua standard library */
+
+static int exit_override(lua_State *L)
+{
+    if (!have_forked)
+       return luaL_error(L, "exit not permitted in this context");
+
+    exit(luaL_optint(L, 1, EXIT_SUCCESS));
+}
+
+static const luaL_reg os_overrides[] =
+{
+    {"exit",    exit_override},
+    {NULL,      NULL}
+};
+
+int luaopen_rpm_os(lua_State *L)
+{
+    lua_pushvalue(L, LUA_GLOBALSINDEX);
+    luaL_openlib(L, "os", os_overrides, 0);
+    return 0;
+}
+
index e1e819c..1f9afe9 100644 (file)
@@ -2,5 +2,6 @@
 #define LPOSIX_H
 
 int luaopen_posix (lua_State *L);
+int luaopen_rpm_os (lua_State *L);
 
 #endif
index 22a2fc0..a2f70bf 100644 (file)
@@ -53,6 +53,7 @@ rpmlua rpmluaNew()
        {"posix", luaopen_posix},
        {"rex", luaopen_rex},
        {"rpm", luaopen_rpm},
+       {"os",  luaopen_rpm_os},
        {NULL, NULL},
     };
     
index 36e9605..dfec846 100644 (file)
@@ -129,3 +129,16 @@ run rpm \
 [ok
 ])
 AT_CLEANUP
+
+AT_SETUP([lua script exit behavior])
+AT_KEYWORDS([macros lua])
+AT_CHECK([
+run rpm \
+  --eval '%{lua: os.exit()}))}'
+],
+[0],
+[
+],
+[error: lua script failed: [[string "<lua>"]]:1: exit not permitted in this context]
+)
+AT_CLEANUP