2012-07-01 10 views
5

Sto imparando da "Programmazione in Lua" di Roberto Ierusalimschy, e ho trovato che nel libro, l'esempio di Sandboxing utilizza la funzione setfenv() per modificare l'ambiente di una determinata funzione, ma in lua 5.2 questo la funzione non è più disponibile.Sandboxing in Lua 5.2

Ho provato a caricare alcuni valori da un file (un file di configurazione) in un campo in una tabella, ma, in lua 5.2 non posso usare setfenv (quindi posso caricare i valori nell'ambiente specificato). Dopo aver letto alcuni articoli su LUA 5.2 ho trovato che ogni funzione può avere (o non) un sopravvalutare chiamato _ENV che serve come l'ambiente, così, ho provato il codice seguente:

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 

Sostituzione _ENV nel 'sandbox' la funzione funziona bene (non può accedere ai campi regolari), ma, quando viene eseguito il "codice", sembra che ignori che ho sostituito _ENV, ma può ancora accedere ai campi regolari (stampa, file di caricamento, dofile, ecc.).

Leggendo un po 'di più, ho trovato che lua 5.2 fornisce una funzione per questo scopo, questa funzione è loadin(env, chunk), che esegue il blocco dato nell'ambiente specificato, ma, quando provo ad aggiungere questa funzione al mio codice, il la funzione non esiste (non è presente nel campo globale _G).

Qualche aiuto sarà apprezzato.

risposta

7

Quando si assegna a _ENV dall'interno sandbox, non sei sovrascrivere l'ambiente globale - tu sei la sostituzione della _ENV sopravvalutare del codice attualmente in esecuzione. L'aggiunta di chiamate a print(_ENV) può aiutarti a comprendere meglio le identità delle tabelle coinvolte.

Ad esempio:

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 

La funzione loadin era presente in alcune versioni preliminari di Lua 5.2 ma è stato rimosso prima del rilascio finale. Invece, il Lua 5.2 load and loadfile functions prende un argomento env. È anche possibile modificare _ENV di un'altra funzione utilizzando debug.setupvalue.

+1

Grazie! La soluzione è stata facile. Penso che questo approccio per cambiare l'ambiente in 'load' e' loadfile' sia migliore, perché 'setfenv' è stato usato principalmente nel codice caricato quindi ... Grazie! Ho sandboxed come previsto. –

+0

@Miles Quando print_env() è definito, non riceve il valore globale _ENV come valore? Quindi, come viene modificato quando print_env() viene chiamato all'interno di sandbox()? –

+1

@ Gli upvalues ​​di TiagoCosta sono variabili locali esterne. '_ENV' in questo caso è locale per il blocco; l'assegnazione a '_ENV' influisce sulla variabile locale chunk, che è un valore up condiviso per entrambe le chiusure. – Miles