2011-10-22 13 views
4

私はHow can I create a secure Lua sandbox?を使用して、自分自身のリーキーなサンドボックスを構築しようとしています。Luaサンドボックスにはリークする特別な機能があります

一部のLua関数がサンドボックス外の他のいくつかのLua関数にアクセスできるLuaサンドボックスを作成しようとしています。たとえば、私は自分のサンドボックスに "print"を呼び出すことができるが、サンドボックスには "print"を持たない特別な "表示"機能を持たせたい。

主な問題は、すでに大きなコードベース内にサンドボックスを構築しようとしているため、機能を排除できないということです。

これはどのように可能ですか?

解決策は、鉱山の欠陥がないため、純粋なLua関数でなければなりません。

答えて

5

サンドボックスを作成するときは、大規模な環境の関数と値を選択して新しいサンドボックス環境を作成します。あなたは、元の環境で何かを破壊したり、「除外する」必要はありません。

  1. 桜狩りの機能により、あなたのサンドボックス環境を作成し、
  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) 
+0

これは私が望むものに近いようです。私はそれを試して、それが私が必要とする方法で動作するかどうかを見ていきます。 –

1

具体的には、Lua標準ライブラリprintを呼び出す必要がありますか?代わりにprintの機能をエミュレートできますか?それが最も簡単な方法だろうから。

しかし、printのラッパーを使用したい場合は、純粋なLuaコードとC/C++コードの2つの方法があります。

純粋なLua溶液は以下の通りです。これは、外部スクリプトをロードする前に行う必要があることに注意してください。まず、printを持つLua標準ライブラリを開きます。次に、このLuaスクリプトを実行します。

local internal_print = print 

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

これは「表示」機能を返します。あなたが好きな場合は、displayというグローバル変数に格納するか、別のものを呼び出すことができます。

その後、グローバル変数printからnilを入力すると、ほとんど完全にアクセスできなくなります。

C/C++からやりたい場合は、非常に似ています。まず、前と同様に、関数を得るために、printを含むLua標準ライブラリを登録します。次にlua_getglobal(L, "print")を使用してprint関数を取得し、スタックにプッシュします。次に、lua_pushcclosureを使用してC/C++関数を登録します。しかし、登録時にLuaがスタックからポップする1つの上位値を指定したいとします。

これで、登録された関数がスタック上にあり、Lua変数またはグローバルテーブルエントリにプッシュされるのを待っています。

警告: Luaデバッグライブラリは新しい値からprint関数を呼び出すことができます。あなたが完璧なセキュリティを望むなら、debug.getupvalueを取り除く。

+0

「プリント」への唯一の簡単な例でした概念を説明してください。また、直接アクセスするコードが大量であるため、古い「印刷物」を除外することはできません。 –

0

で失敗するのに対し、一度に1つずつ。私のクイッククイックテストでは、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 

注:Dougの例を使用するには、displayprintを使用して、あなたの既存のコードの一部であると仮定この関数が作成されたときのサンドボックス内の

以前は、サンドボックス環境ではない場所へのポインタを格納していましたが、クイッククイックテストで必要な状況を再現することはできません。例を考え出すことができたら、おそらく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 
関連する問題