كيفية تنفيذ ملف LUA غير الموثوق به في بيئته الخاصة من C API

StackOverflow https://stackoverflow.com/questions/3444312

  •  27-09-2019
  •  | 
  •  

سؤال

أريد تنفيذ ملف .lua غير الموثوق به في بيئته الخاصة بالاتصال lua_setfenv () بحيث لا يمكن أن يؤثر على أي من الكود الخاص بي.

على الرغم من أن الوثائق الخاصة بهذه الوظيفة تشرح فقط كيفية استدعاء وظيفة ، وليس كيفية تنفيذ ملف.

حاليا لتشغيل الملف الذي أستخدمه:

int error = luaL_loadfile(mState, path.c_str()) || lua_pcall(mState, 0, 0, 0);

هل يجب أن أسمي وظيفة LUA "dofile" من C API مع lua_setfenv, ، أم أن هناك طريقة أكثر أناقة للقيام بذلك؟

هل كانت مفيدة؟

المحلول

انظر المناقشة في ويكي مستخدم LUA من Sandboxing, والموضوع الأكثر عمومية أمن السيناريو. هناك عدد من المشكلات الدقيقة وليس الدقيقة مع هذا النوع من الأشياء. يمكن القيام بذلك ، ولكن الحماية من الكود مثل for i=1,1e39 do end يتطلب أكثر من مجرد تقييد الوظائف المتاحة لصندوق الرمل.

تتمثل التقنية العامة في إنشاء بيئة وظيفية لصندوق الرمل الذي يحتوي على قائمة بيضاء من الوظائف المسموح بها فيه. في بعض الحالات ، قد تكون هذه القائمة فارغة ، ولكن السماح للمستخدم بإمكانية الوصول إليها pairs(), ، على سبيل المثال ، من المؤكد أنه غير ضار. تحتوي صفحة Sandbox على قائمة بوظائف النظام التي تم تقسيمها بسبب سلامتها كمرجع مفيد لبناء مثل هذه القائمة البيضاء.

ثم تستخدم lua_setfenv() لتطبيق بيئة الوظيفة على البرنامج النصي للمستخدم الذي قمت بتحميله (ولكن لم تنفذه بعد) lua_loadfile() أو lua_loadstring() حسب الاقتضاء. مع البيئة المرفقة ، يمكنك تنفيذها مع lua_pcall() والأصدقاء. قبل التنفيذ ، قام بعض الأشخاص بمسح رمز Bytecode المحمّل للعمليات التي لا يريدون السماح بها. يمكن استخدامها لمنع الحلقات أو الكتابة إلى المتغيرات العالمية.

ملاحظة واحدة أخرى هي أن وظائف التحميل ستحمل عمومًا إما نص Bytecode أو LUA. اتضح أنه أكثر أمانًا إذا لم تسمح مطلقًا بتعبير باقعي مسبقًا ، حيث تم تحديد عدد من الطرق لجعل سوء التصرف VM أن كل شيء يعتمد على الصياغة اليدوية غير الصالحة. نظرًا لأن ملفات Bytecode تبدأ بتسلسل بايت محدد جيدًا ليس نصًا عاديًا ، فكل ما عليك فعله هو قراءة البرنامج النصي في المخزن المؤقت lua_loadstring() إذا لم يكن bytecode.

كان هناك قدر لا بأس به من النقاش في LUA-L قائمة البريدية على مر السنين من هذا النوع من الأشياء ، لذلك من المحتمل أيضًا أن يكون هناك البحث مفيدًا.

نصائح أخرى

بالمناسبة ، هذا ما انتهى بي الأمر:

/* Loads, compiles and executes an unstrusted file. */
bool Lua::RunUntrustedFile(const string& path)
{
    if(luaL_loadfile(mState, path.c_str()))
    {
        ErrorLog(lua_tostring(mState, 1));
        Pop(1);
        return false;
    }

    Lua::SetMaximumInstructions(100000000);
    lua_newtable(mState);
    lua_setglobal(mState, "upload");
    ASSERT(Lua::GetStackSize() == 1);
    lua_getglobal(mState, "upload");
    ASSERT_ALWAYS(lua_setfenv(mState, 1) != 0);
    ASSERT(Lua::GetStackSize() == 1);

    if(lua_pcall(mState, 0, 0, 0))
    {
        Lua::ClearMaximumInstructions();
        ErrorLog(lua_tostring(mState, -1));
        Pop(1);
        return false;
    }

    ASSERT(Lua::GetStackSize() == 0);
    Lua::ClearMaximumInstructions();

    return true;
}

"وظائف الدعم:

static void Pop(int elements = 1) { lua_pop(mState, elements); }

/* Sets a maximum number of instructions before throwing an error */
static void SetMaximumInstructions(int count) {
    lua_sethook(mState, &Lua::MaximumInstructionsReached, LUA_MASKCOUNT, count);
}
static void ClearMaximumInstructions() {
    lua_sethook(mState, &Lua::MaximumInstructionsReached, 0, 0);
}

static void MaximumInstructionsReached(lua_State *, lua_Debug *)
{
    Error("The maximum number of instructions has been reached");
}

static int GetStackSize() { return lua_gettop(mState); }

luaL_loadfile() سيتم تحميل الجزء ، ثم اتصل lua_setfenv() لتعيين جدول البيئة ، ثم اتصل lua_pcall() لتنفيذ قطعة. انظر الإجابة الحديثة التي قدمها القاضي مايجاردن في استدعاء وظائف لوا من .lua استخدام المقابض؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top