Sandboxing в Lua 5.2

Уча се от „Програмиране в Lua“ от Roberto Ierusalimschy и открих, че в книгата примерът за Sandboxing използва функцията setfenv() за промяна на средата на дадена функция, но в lua 5.2 тази функция вече не е налична.

Опитах се да заредя някои стойности от файл (конфигурационен файл) в поле в таблица, но в lua 5.2 не мога да използвам setfenv (за да мога да заредя стойностите в дадената среда). След като прочетох някои статии за lua 5.2, открих, че всяка функция може да има (или не) повишена стойност, наречена _ENV, която служи като среда, така че опитах следния код:

function sandbox(sb_func, sb_env)
    if not sb_func then return nil, "sandbox function not valid" end
    sb_orig_env = _ENV
    _ENV = sb_env -- yes, replaces the global _ENV
    pcall_res, message = pcall( sb_func )
    local modified_env = _ENV -- gets the environment that was used in the pcall( sb_func )
    _ENV = sb_orig_env
    return true, modified_env
end

function readFile(filename)
    code = loadfile(filename)
    res, table = sandbox(code, {})
    if res then
        --[[ Use table (modified_env) ]]--
    else
        print("Code not valid")
end

Замяната на _ENV във функцията „sandbox“ работи добре (няма достъп до обикновените полета), но когато „кодът“ се изпълни, изглежда, че той игнорира, че съм заменил _ENV, той все още има достъп до обикновените полета (print, loadfile, dofile и т.н.).

Като прочетох малко повече, открих, че lua 5.2 предоставя функция за тази цел, тази функция е loadin(env, chunk), която изпълнява даденото парче в дадената среда, но когато се опитам да добавя тази функция към моя код, функцията не съществува (не присъства в глобалното поле _G).

Малко помощ ще бъде оценена.


person Daniel Rivas    schedule 01.07.2012    source източник


Отговори (1)


Когато присвоявате на _ENV от sandbox, вие не заменяте глобалната среда – вие замествате _ENV upvalue на текущо изпълнявания код. Добавянето на повиквания към print(_ENV) може да ви помогне да разберете по-добре идентичността на включените таблици.

Например:

function print_env()
  print(_ENV)
end

function sandbox()
  print(_ENV) -- prints: "table: 0x100100610"
  -- need to keep access to a few globals:
  _ENV = { print = print, print_env = print_env, debug = debug, load = load }
  print(_ENV) -- prints: "table: 0x100105140"
  print_env() -- prints: "table: 0x100105140"
  local code1 = load('print(_ENV)')
  code1()     -- prints: "table: 0x100100610"
  debug.setupvalue(code1, 1, _ENV) -- set our modified env
  code1()     -- prints: "table: 0x100105140"
  local code2 = load('print(_ENV)', nil, nil, _ENV) -- pass 'env' arg
  code2()     -- prints: "table: 0x100105140"
end

Функцията loadin присъстваше в някои предварителни версии на Lua 5.2, но беше премахната преди окончателното издание. Вместо това load и loadfile функциите на Lua 5.2 приемат аргумент env . Можете също така да промените _ENV на друга функция, като използвате debug.setupvalue .

person Miles    schedule 01.07.2012
comment
Благодаря! Решението беше лесно. Мисля, че този подход за промяна на средата в load и loadfile е по-добър, защото setfenv се използва предимно в зареден код, така че... Благодаря! Извърших пясъчник според очакванията. - person Daniel Rivas; 01.07.2012
comment
@Miles Когато print_env() е дефиниран, не получава ли глобалния _ENV като upvalue? И така, как се променя, когато print_env() се извика в sandbox()? - person Tiago Costa; 25.07.2013
comment
@TiagoCosta upvalues ​​са външни локални променливи. _ENV в този случай е локален за парчето; присвояването на _ENV засяга тази локална променлива на част, която е споделена upvalue за двете затваряния. - person Miles; 26.07.2013