2016-11-02 1 views
3

Donc je cherche à sécuriser la fonction load de Lua pour le chargement de bytecode. À l'heure actuelle, j'ai ceci:Signé bytecode chargement

local nativeload = load 
load = function(chunk, chunkname, mode, ...) 
    if mode == nil then 
    mode = "bt" 
    elseif not (mode == "b" or mode == "t" or mode == "bt") then 
    error("Invalid mode") 
    end 
    local targetenv = [[snip]] 
    if select('#', ...) > 0 then targetenv = ... end 
    if mode == "t" then 
    return nativeload(chunk, chunkname, mode, targetenv) 
    elseif type(chunk) == "string" then 
    if chunk:sub(1,4) == "\27Lua" then 
     local code = chunk:sub(1,-33) 
     if HMAC_SHA256(code, getkey()) == chunk:sub(-32) then 
     return nativeload(code, chunkname, mode, targetenv) 
     else 
     error("Invalid signature") 
     end 
    else 
     return nativeload(chunk, chunkname, mode, targetenv) 
    end 
    elseif type(chunk) == "function" then 
    -- How do I do this?! 
    end 
end 

Et, tandis que le mode texte et des morceaux de chaîne sont assez trivial à manipuler, je ne sais pas comment gérer des morceaux de fonction. Est-ce que je collectionne tout simplement d'une manière ou d'une autre, puis fais les trucs de HMAC et appelle le nativeload avec cette chaîne? Mais ensuite je perds load() gros fichiers (par exemple 2GB) sans que le programme plante (load avec fonction compile le fichier par incréments de 8kbyte, et quand le fichier est presque vide, cela signifie qu'il n'a besoin que de quelques kilo-octets pendant la compilation - tout en chargeant le fichier entier dans une chaîne utiliserait clairement 2 Go de RAM).

Comment est-ce que je ferais ceci?

Répondre

1
local function extract_code(data) 
    local code = data:sub(1,-33) 
    assert(HMAC_SHA256(code, getkey()) == data:sub(-32), "Invalid signature") 
    return code 
end 

local nativeload = load 
load = function(chunk, chunkname, mode, ...) 
    local targetenv = [[snip]] 
    if select('#', ...) ~= 0 then targetenv = ... end 
    local new_chunk 
    if type(chunk) == "string" then 
     new_chunk = chunk:match"^\27Lua" and extract_code(chunk) or chunk 
    elseif type(chunk) == "function" then 
     local buffer = "" 
     repeat 
     local next_part = chunk() or "" 
     buffer = buffer..next_part 
     until next_part == "" or #buffer >= 4 
     if buffer:match"^\27Lua" then -- Bytecode can't be very large, collect it in a string 
     local t = {buffer} 
     while t[#t] ~= "" do t[#t+1] = chunk() or "" end 
     new_chunk = extract_code(table.concat(t)) 
     else       -- Source code can be very large, use a function 
     local function f() 
      f = chunk 
      return buffer 
     end 
     function new_chunk() 
      return f() 
     end 
     end 
    end 
    return nativeload(new_chunk, chunkname, mode, targetenv) 
end 
+0

Hey qu'est-il arrivé à l'optimisation du mode texte? De même, vous n'êtes pas censé utiliser affirmer comme erreur car certaines bibliothèques l'accrochent. – SoniEx2

+0

Pourquoi utiliser O (nlogn) 't [# t + 1]' plutôt que O (n) en gardant une trace de longueur? – SoniEx2

+0

1) "optimisation de mode texte" ne fait presque rien d'utile pour vous. 2) Oui, vous pouvez utiliser d'autres moyens pour générer des erreurs. Mon code est juste une illustration de l'algorithme d'interception de la fonction chunk. –