[libpeas] Prevent the accidental escaping of globals with Lua plugins



commit 60cfc58eb64446fd3512f8c36b22a2f0b9968c9d
Author: Garrett Regier <garrettregier gmail com>
Date:   Thu Jan 22 18:54:11 2015 -0800

    Prevent the accidental escaping of globals with Lua plugins
    
    This implements a strict mode which prevents the
    creation of globals, except when using rawset().
    This can be disabled for incompatible code by setting
    __STRICT to false.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=742557

 configure.ac                                       |    1 +
 loaders/lua5.1/Makefile.am                         |   18 ++----
 loaders/lua5.1/peas-lua-internal.c                 |   48 +-------------
 loaders/lua5.1/peas-lua-utils.c                    |   70 +++++++++++++++++++-
 loaders/lua5.1/peas-lua-utils.h                    |    5 ++
 loaders/lua5.1/peas-plugin-loader-lua.c            |    3 +-
 loaders/lua5.1/resources/Makefile.am               |   13 ++++
 .../lua5.1/{ => resources}/peas-lua-compile.lua    |    0
 .../lua5.1/{ => resources}/peas-lua-internal.lua   |    2 +-
 loaders/lua5.1/resources/peas-lua-strict.lua       |   51 ++++++++++++++
 .../lua5.1/{ => resources}/peas-lua.gresource.xml  |    1 +
 .../plugins/extension-lua/extension-lua51.lua      |   21 ++++++
 12 files changed, 172 insertions(+), 61 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 28d145f..e653301 100644
--- a/configure.ac
+++ b/configure.ac
@@ -541,6 +541,7 @@ libpeas/Makefile
 libpeas-gtk/Makefile
 loaders/Makefile
 loaders/lua5.1/Makefile
+loaders/lua5.1/resources/Makefile
 loaders/python/Makefile
 loaders/python3/Makefile
 data/Makefile
diff --git a/loaders/lua5.1/Makefile.am b/loaders/lua5.1/Makefile.am
index 6be90ea..49fe82f 100644
--- a/loaders/lua5.1/Makefile.am
+++ b/loaders/lua5.1/Makefile.am
@@ -1,5 +1,7 @@
 # Lua 5.1 plugin loader
 
+SUBDIRS = resources
+
 loaderdir = $(libdir)/libpeas-1.0/loaders
 
 AM_CPPFLAGS = \
@@ -30,23 +32,15 @@ liblua51loader_la_LIBADD = \
        $(PEAS_LIBS)                            \
        $(LUA51_LIBS)
 
-%.luac: %.lua
-       $(AM_V_GEN) $(LUA51_BIN) $(srcdir)/peas-lua-compile.lua $< $@
-
-all-local: peas-lua-internal.luac
-
-loader_resources_deps = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies 
$(srcdir)/peas-lua.gresource.xml)
-peas-lua-resources.c: $(srcdir)/peas-lua.gresource.xml $(loader_resources_deps)
-       $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --internal --target=$@ --sourcedir=$(srcdir) --generate-source 
$(srcdir)/peas-lua.gresource.xml
+loader_resources_deps = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir)/resources 
--generate-dependencies $(srcdir)/resources/peas-lua.gresource.xml)
+peas-lua-resources.c: $(srcdir)/resources/peas-lua.gresource.xml $(loader_resources_deps)
+       $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --internal --target=$@ --sourcedir=$(srcdir)/resources 
--generate-source $(srcdir)/resources/peas-lua.gresource.xml
 
 EXTRA_DIST = \
-       peas-lua-compile.lua            \
        peas-lua.gresource.xml          \
        $(loader_resources_deps)
 
-CLEANFILES = \
-       peas-lua-internal.luac  \
-       peas-lua-resources.c
+CLEANFILES = peas-lua-resources.c
 
 gcov_sources = $(liblua51loader_la_SOURCES)
 include $(top_srcdir)/Makefile.gcov
diff --git a/loaders/lua5.1/peas-lua-internal.c b/loaders/lua5.1/peas-lua-internal.c
index 23d2d6b..531bb17 100644
--- a/loaders/lua5.1/peas-lua-internal.c
+++ b/loaders/lua5.1/peas-lua-internal.c
@@ -25,10 +25,7 @@
 
 #include "peas-lua-internal.h"
 
-#include <gio/gio.h>
-
 #include <lauxlib.h>
-#include <lualib.h>
 
 #include "peas-lua-utils.h"
 
@@ -60,54 +57,15 @@ failed_fn (lua_State *L)
 gboolean
 peas_lua_internal_setup (lua_State *L)
 {
-  GBytes *internal_lua;
-  const gchar *code;
-  gsize code_len;
-
-  /* We don't use the byte-compiled Lua source
-   * because glib-compile-resources cannot output
-   * depends for generated files.
-   *
-   * There are also concerns that the bytecode is
-   * not stable enough between different Lua versions.
-   *
-   * https://bugzilla.gnome.org/show_bug.cgi?id=673101
-   */
-  internal_lua = g_resources_lookup_data ("/org/gnome/libpeas/loaders/"
-                                          "lua5.1/internal.lua",
-                                          G_RESOURCE_LOOKUP_FLAGS_NONE,
-                                          NULL);
-  g_return_val_if_fail (internal_lua != NULL, FALSE);
-
-  code = g_bytes_get_data (internal_lua, &code_len);
-
-  /* Filenames are prefixed with '@' */
-  if (luaL_loadbuffer (L, code, code_len, "@peas-lua-internal.lua") != 0)
-    {
-      g_warning ("Failed to load internal Lua code: %s",
-                 lua_tostring (L, -1));
-
-      /* Pop error */
-      lua_pop (L, 1);
-      g_bytes_unref (internal_lua);
-      return FALSE;
-    }
-
-  g_bytes_unref (internal_lua);
-
-  if (!peas_lua_utils_call (L, 0, 1))
+  if (!peas_lua_utils_load_resource (L, "internal.lua", 0, 1))
     {
-      g_warning ("Failed to run internal Lua code: %s",
-                 lua_tostring (L, -1));
-
-      /* Pop error */
-      lua_pop (L, 1);
+      /* Already warned */
       return FALSE;
     }
 
   if (!lua_istable (L, -1))
     {
-      g_warning ("Invalid result from internal Lua code: %s",
+      g_warning ("Invalid result from 'internal.lua' resource: %s",
                  lua_tostring (L, -1));
 
       /* Pop result */
diff --git a/loaders/lua5.1/peas-lua-utils.c b/loaders/lua5.1/peas-lua-utils.c
index 76f7a9c..f22499a 100644
--- a/loaders/lua5.1/peas-lua-utils.c
+++ b/loaders/lua5.1/peas-lua-utils.c
@@ -25,10 +25,9 @@
 
 #include "peas-lua-utils.h"
 
-#include <string.h>
+#include <gio/gio.h>
 
 #include <lauxlib.h>
-#include <lualib.h>
 
 
 gboolean
@@ -175,3 +174,70 @@ peas_lua_utils_call (lua_State *L,
   lua_remove (L, -1 - (success ? n_results : 1));
   return success;
 }
+
+gboolean
+peas_lua_utils_load_resource (lua_State   *L,
+                              const gchar *name,
+                              guint        n_args,
+                              guint        n_results)
+{
+  gchar *resource_path;
+  GBytes *lua_resource;
+  const gchar *code;
+  gsize code_len;
+  gchar *lua_filename;
+
+  /* We don't use the byte-compiled Lua source
+   * because glib-compile-resources cannot output
+   * depends for generated files.
+   *
+   * There are also concerns that the bytecode is
+   * not stable enough between different Lua versions.
+   *
+   * https://bugzilla.gnome.org/show_bug.cgi?id=673101
+   */
+  resource_path = g_strconcat ("/org/gnome/libpeas/loaders/lua5.1/",
+                               name, NULL);
+  lua_resource = g_resources_lookup_data (resource_path,
+                                          G_RESOURCE_LOOKUP_FLAGS_NONE,
+                                          NULL);
+  g_free (resource_path);
+
+  if (lua_resource == NULL)
+    {
+      g_warning ("Failed to find '%s' resource", name);
+      return FALSE;
+    }
+
+  code = g_bytes_get_data (lua_resource, &code_len);
+
+  /* Filenames are prefixed with '@' */
+  lua_filename = g_strconcat ("@peas-lua-", name, NULL);
+
+  if (luaL_loadbuffer (L, code, code_len, lua_filename) != 0)
+    {
+      g_warning ("Failed to load '%s' resource: %s",
+                 name, lua_tostring (L, -1));
+
+      /* Pop error */
+      lua_pop (L, 1);
+      g_free (lua_filename);
+      g_bytes_unref (lua_resource);
+      return FALSE;
+    }
+
+  g_free (lua_filename);
+  g_bytes_unref (lua_resource);
+
+  if (!peas_lua_utils_call (L, n_args, n_results))
+    {
+      g_warning ("Failed to run '%s' resource: %s",
+                 name, lua_tostring (L, -1));
+
+      /* Pop error */
+      lua_pop (L, 1);
+      return FALSE;
+    }
+
+  return TRUE;
+}
diff --git a/loaders/lua5.1/peas-lua-utils.h b/loaders/lua5.1/peas-lua-utils.h
index 29069be..091f87d 100644
--- a/loaders/lua5.1/peas-lua-utils.h
+++ b/loaders/lua5.1/peas-lua-utils.h
@@ -40,6 +40,11 @@ gboolean peas_lua_utils_call          (lua_State   *L,
                                        guint        n_args,
                                        guint        n_results);
 
+gboolean peas_lua_utils_load_resource (lua_State   *L,
+                                       const gchar *name,
+                                       guint        n_args,
+                                       guint        n_results);
+
 G_END_DECLS
 
 #endif /* __PEAS_LUA_UTILS_H__ */
diff --git a/loaders/lua5.1/peas-plugin-loader-lua.c b/loaders/lua5.1/peas-plugin-loader-lua.c
index 32c6418..ef07be3 100644
--- a/loaders/lua5.1/peas-plugin-loader-lua.c
+++ b/loaders/lua5.1/peas-plugin-loader-lua.c
@@ -285,7 +285,8 @@ peas_plugin_loader_lua_initialize (PeasPluginLoader *loader)
 
   luaL_openlibs (L);
 
-  if (!peas_lua_utils_require (L, "lgi") ||
+  if (!peas_lua_utils_load_resource (L, "strict.lua", 0, 0) ||
+      !peas_lua_utils_require (L, "lgi") ||
       !peas_lua_utils_check_version (L,
                                      LGI_MAJOR_VERSION,
                                      LGI_MINOR_VERSION,
diff --git a/loaders/lua5.1/resources/Makefile.am b/loaders/lua5.1/resources/Makefile.am
new file mode 100644
index 0000000..710581e
--- /dev/null
+++ b/loaders/lua5.1/resources/Makefile.am
@@ -0,0 +1,13 @@
+LUAC_FILES =                           \
+       peas-lua-internal.luac          \
+       peas-lua-strict.luac
+
+
+%.luac: %.lua
+       $(AM_V_GEN) $(LUA51_BIN) $(srcdir)/peas-lua-compile.lua $< $@
+
+all-local: $(LUAC_FILES)
+
+CLEANFILES = \
+       $(LUAC_FILES)
+
diff --git a/loaders/lua5.1/peas-lua-compile.lua b/loaders/lua5.1/resources/peas-lua-compile.lua
similarity index 100%
rename from loaders/lua5.1/peas-lua-compile.lua
rename to loaders/lua5.1/resources/peas-lua-compile.lua
diff --git a/loaders/lua5.1/peas-lua-internal.lua b/loaders/lua5.1/resources/peas-lua-internal.lua
similarity index 99%
rename from loaders/lua5.1/peas-lua-internal.lua
rename to loaders/lua5.1/resources/peas-lua-internal.lua
index 8f4e60d..f70904d 100644
--- a/loaders/lua5.1/peas-lua-internal.lua
+++ b/loaders/lua5.1/resources/peas-lua-internal.lua
@@ -159,4 +159,4 @@ end
 
 return Hooks.new()
 
--- ex:set ts=4 et sw=4 ai:
+-- ex:ts=4:et:
diff --git a/loaders/lua5.1/resources/peas-lua-strict.lua b/loaders/lua5.1/resources/peas-lua-strict.lua
new file mode 100644
index 0000000..d3458b9
--- /dev/null
+++ b/loaders/lua5.1/resources/peas-lua-strict.lua
@@ -0,0 +1,51 @@
+--
+--  Copyright (C) 2015 - Garrett Regier
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU Library General Public License as published by
+-- the Free Software Foundation; either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU Library General Public License for more details.
+--
+-- You should have received a copy of the GNU Library General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 51 Franklin Street, Fifth Floor,
+-- Boston, MA 02110-1301, USA.
+--
+-- Modified version of: http://metalua.luaforge.net/src/lib/strict.lua.html
+
+__STRICT = true
+
+local mt = getmetatable(_G)
+if mt == nil then
+    mt = {}
+    setmetatable(_G, mt)
+end
+
+function mt:__newindex(name, value)
+    if __STRICT then
+        local what = debug.getinfo(2, 'S').what
+
+        if what ~= 'C' then
+            error("Attempted to create global variable '" ..
+                  tostring(name) .. "'", 2)
+        end
+    end
+
+    rawset(self, name, value)
+end
+
+function mt:__index(name)
+    if not __STRICT or debug.getinfo(2, 'S').what == 'C' then
+        return rawget(self, name)
+    end
+
+    error("Attempted to access nonexistent " ..
+          "global variable '" .. tostring(name) .. "'", 2)
+end
+
+-- ex:ts=4:et:
diff --git a/loaders/lua5.1/peas-lua.gresource.xml b/loaders/lua5.1/resources/peas-lua.gresource.xml
similarity index 77%
rename from loaders/lua5.1/peas-lua.gresource.xml
rename to loaders/lua5.1/resources/peas-lua.gresource.xml
index 2eaf9cb..c8d43a0 100644
--- a/loaders/lua5.1/peas-lua.gresource.xml
+++ b/loaders/lua5.1/resources/peas-lua.gresource.xml
@@ -2,5 +2,6 @@
 <gresources>
   <gresource prefix="/org/gnome/libpeas/loaders/lua5.1">
     <file alias="internal.lua">peas-lua-internal.lua</file>
+    <file alias="strict.lua">peas-lua-strict.lua</file>
   </gresource>
 </gresources>
diff --git a/tests/libpeas/plugins/extension-lua/extension-lua51.lua 
b/tests/libpeas/plugins/extension-lua/extension-lua51.lua
index a0162fe..89cdf2d 100644
--- a/tests/libpeas/plugins/extension-lua/extension-lua51.lua
+++ b/tests/libpeas/plugins/extension-lua/extension-lua51.lua
@@ -80,6 +80,27 @@ function ExtensionLuaPlugin:do_call_multi_args(in_, inout)
     return inout, in_
 end
 
+-- Test strict mode
+local UNIQUE = {}
+
+local function assert_error(success, result)
+    assert(not success, result)
+end
+
+assert_error(pcall(function() _G[UNIQUE] = true end))
+assert(pcall(function()
+    rawset(_G, UNIQUE, true)
+    assert(_G[UNIQUE] == true)
+    _G[UNIQUE] = nil
+end))
+assert_error(pcall(function() _G[UNIQUE] = true end))
+assert(pcall(function()
+    __STRICT = false
+    _G[UNIQUE] = true
+    _G[UNIQUE] = nil
+    __STRICT = true
+end))
+
 return { ExtensionLuaPlugin }
 
 -- ex:set ts=4 et sw=4 ai:


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