Lua Sandbox со специальными функциями, которые протекают - PullRequest
4 голосов
/ 22 октября 2011

Я пытаюсь использовать Как мне создать безопасную песочницу Lua? , чтобы создать свою собственную дырявую песочницу.

Я пытаюсь создать песочницу Lua, где некоторые функции Lua могут получить доступ к некоторым другим функциям Lua вне песочницы. Например, я хочу, чтобы в моей песочнице была специальная функция «display», которая может вызывать «print», но также не иметь «print» в песочнице.

Основная проблема заключается в том, что я пытаюсь создать изолированную программную среду в уже большой кодовой базе, поэтому я не могу обнулять функции.

Как это возможно?

Решение должно быть чисто Lua-функцией не по моей вине.

Ответы [ 3 ]

5 голосов
/ 22 октября 2011

Когда вы создаете песочницу, вы делаете это, выбирая функции и значения из большой среды, чтобы создать новую среду песочницы.Вам не нужно ничего уничтожать или «обнулять» в исходной среде.

  1. Создайте свою среду песочницы, выбирая функции и значения cherry
  2. Загрузите скрипт (это компилирует ивозвращает его как функцию для вызова)
  3. Установить среду скрипта в среду песочницы
  4. Выполнить скрипт в песочнице

Итак,

local script = loadstring "display(math.log(2, 3))"
local env = {display = print, math = math, string = string}
setfenv(script, env)
pcall(script)

печатает

0.69314718055995

, тогда как

local script = loadstring "print(math.log(2, 3))"
local env = {display = print, math = math, string = string}
setfenv(script, env)
pcall(script)

завершается с

false   [string "print(math.log(2, 3))"]:1: attempt to call global 'print' (a nil value)
1 голос
/ 22 октября 2011

Нужно ли специально вызывать функцию стандартной библиотеки Lua print?Можете ли вы вместо этого подражать функциональности print?Потому что это был бы самый простой способ.

Однако, если вы хотите иметь обертку вокруг print, есть два способа сделать это: с чистым кодом Lua и с кодом C / C ++.

Чистое решение Lua заключается в следующем.Обратите внимание, что это должно быть сделано перед загрузкой любых внешних скриптов.Сначала откройте стандартную библиотеку Lua с print.Затем запустите этот скрипт Lua:

local internal_print = print

return function(...)
    --Do display logic.
    internal_print(...) --Or whatever else you want.
end

Это вернет функцию «display».Вы можете сохранить его в глобальной переменной с именем display, если хотите, или вызвать что-то еще.

После этого вы можете nil вывести глобальную переменную print, сделав ее практически полностью недоступной.

Если вы хотите сделать это из C / C ++, это очень похоже.Во-первых, как и прежде, вы регистрируете стандартную библиотеку Lua, которая включает print, чтобы вы могли получить функцию для нее.Затем вы используете lua_getglobal(L, "print"), чтобы получить функцию print и поместить ее в стек.Затем вы регистрируете свою функцию C / C ++, используя lua_pushcclosure.Но вы хотите указать одно значение, которое Lua выталкивает из стека во время регистрации.

И теперь ваша зарегистрированная функция находится в стеке, ожидая, когда ее поместят в переменную Lua или запись в глобальной таблице.

Предупреждение: библиотека отладки Lua может выдавать значения вверх и, таким образом, получать функцию print из вашей новой функции.Так что если вы хотите идеальной безопасности, избавьтесь от debug.getupvalue.

0 голосов
/ 22 октября 2011

Создайте свою песочницу (или несколько песочниц, если у каждой из них свои требования) и перемещайте ненадежный код в песочницу по одной части за раз.В моих быстрых тестах Cli, 5.1 и 5.2 будут запускать функции, которые были определены вне песочницы, без изменений.Чтобы использовать пример Дуга, предположим, что display является частью вашего ранее существующего кода, который использует print:

-- 5.1
local function display(...)
  print(...)
end
local script = loadstring "display(math.log(2, 3))"
local env = {display = display, math = math, string = string}
setfenv(script, env)
print(pcall(script))

-- 5.2
local function display(...)
  print(...)
end
local script = loadstring "display(math.log(2, 3))"
local e=_ENV
_ENV={display = display, math = math, string = string}
e.print(e.pcall(script))
_ENV=e

Обратите внимание, что в обоих приведенных выше примерах функция display использует print без изменения этого кода, поскольку вы не были в песочнице, когда создавалась эта функция.

В прошлом я сохранял локальный указатель на среду без песочницы, но не могу воспроизвестиситуация, когда это необходимо в моих быстрых тестах.Если вы можете привести пример, я, возможно, смогу найти обходной путь, для которого не требуется переменная e.Вот пример этого кода с использованием 5.2:

local e=_ENV

for k,v in e.pairs(value) do
-- iterate
end

другой пример, для моего кода таблицы только для чтения, я снова использую e:

function ro_table (t)
  local t = t
  if t then
    return e.setmetatable({}, 
      { __index=t, 
        __newindex= function(_,_,_) e.error ("Attempt to modify read-only table") end, 
      })
  else
    return nil
  end
end
...