From c0f8ef24c1616efd6142aa0cae983174ef8100dd Mon Sep 17 00:00:00 2001
From: Ulrik Sverdrup <ulrik.sverdrup@gmail.com>
Date: Wed, 24 Mar 2010 01:30:10 +0100
Subject: [PATCH] Make impossible to access operating system from Lua scripts

For security reasons, Lua scripts should not be able to read files or
run programs on the host computer; freeciv scenarios should only be
able to influence the state of the game, not the state of the server
process or computer (except through normal scenario events, such as
end of game).

For this reason, we do not load some standard lua libraries that allow
access to files or the operating system. We also disallow loading lua
libraries so that the script cannot go around this restriction.

This is the 2.2 and trunk version (Lua 5.1): we exclude the io
library, os library, and blacklist functions dofile, loadfile.

For Lua 5.1, the list of modules and functions we consider unsafe are:

  "os",
  "io",
  "package",
  "dofile",
  "loadfile",
  "loadlib",
  "module",
  "require"

These are all unavailable by not being loaded or being explicitly blocked.

See gna bug #15624
---
 server/scripting/api.pkg  |   14 ++++++++++++++
 server/scripting/script.c |   28 +++++++++++++++++++++++++++-
 2 files changed, 41 insertions(+), 1 deletions(-)

diff --git a/server/scripting/api.pkg b/server/scripting/api.pkg
index c21e679..2a51daa 100644
--- a/server/scripting/api.pkg
+++ b/server/scripting/api.pkg
@@ -371,6 +371,20 @@ module find {
 }
 
 $[
+
+--
+-- Blacklist unsafe builtin Lua functions
+-- NOTE: This list must be updated with each major Lua version!
+_freeciv_blacklist = {
+  "dofile",
+  "loadfile",
+}
+
+for index, symbol in ipairs(_freeciv_blacklist) do
+  _G[symbol] = nil
+end
+
+
 -- Dump the state of user scalar variables to a Lua code string.
 function _freeciv_state_dump()
   local res = ''
diff --git a/server/scripting/script.c b/server/scripting/script.c
index 64af86e..75d0d44 100644
--- a/server/scripting/script.c
+++ b/server/scripting/script.c
@@ -44,6 +44,20 @@ static char *script_code;
 
 
 /**************************************************************************
+  Lua libraries to load (all default libraries, excluding operating system
+  and library loading modules). See linit.c in Lua 5.1 for the default list.
+**************************************************************************/
+static luaL_Reg script_lualibs[] = {
+  /* Using default libraries excluding: package, io and os */
+  {"", luaopen_base},
+  {LUA_TABLIBNAME, luaopen_table},
+  {LUA_STRLIBNAME, luaopen_string},
+  {LUA_MATHLIBNAME, luaopen_math},
+  {LUA_DBLIBNAME, luaopen_debug},
+  {NULL, NULL}
+};
+
+/**************************************************************************
   Report a lua error.
 **************************************************************************/
 static int script_report(lua_State *L, int status, const char *code)
@@ -378,6 +392,18 @@ static void script_code_save(struct section_file *file)
 }
 
 /**************************************************************************
+  Open lua libraries in the array of library definitions in llib.
+**************************************************************************/
+static void script_openlibs(lua_State *L, const luaL_Reg *llib)
+{
+  for (; llib->func; llib++) {
+    lua_pushcfunction(L, llib->func);
+    lua_pushstring(L, llib->name);
+    lua_call(L, 1, 0);
+  }
+}
+
+/**************************************************************************
   Initialize the scripting state.
 **************************************************************************/
 bool script_init(void)
@@ -388,7 +414,7 @@ bool script_init(void)
       return FALSE;
     }
 
-    luaL_openlibs(state);
+    script_openlibs(state, script_lualibs);
 
     tolua_api_open(state);
 
-- 
1.7.0

