From faf3c8b4964fdc3b0c6cf04fa62209d8feb75970 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 4 Aug 2012 18:16:52 +0100 Subject: SUPPLE: If we're on Linux we can lock ourselves down into seccomp mode 1 with some mallopt trickery --- lib/supple/capi.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/supple/sandbox.lua | 10 ++++------ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/lib/supple/capi.c b/lib/supple/capi.c index 97802ec..125a415 100644 --- a/lib/supple/capi.c +++ b/lib/supple/capi.c @@ -21,6 +21,10 @@ #include #include #include +#ifdef linux +#include +#include +#endif /* The API exposed, increment on backward-compatible changes */ #define CAPI_API 1 @@ -254,6 +258,30 @@ supple_capi_lockdown(lua_State *L) } \ } while (0) +#ifdef linux + /* Have a go at ensuring we won't call brk() ready for seccomp() */ + if (rootly && prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 0) { + /* We might be able to enter seccomp mode 1, so carry on */ + /* Disable returning memory to the OS */ + if (mallopt(M_TRIM_THRESHOLD, -1) == 0) { + int saved_errno = errno; + lua_pushliteral(L, "mallopt(M_TRIM_THRESHOLD)"); + lua_pushnumber(L, saved_errno); + return 2; + } + /* Disable allocating memory by mmap() */ + if (mallopt(M_MMAP_MAX, 0) == 0) { + int saved_errno = errno; + lua_pushliteral(L, "mallopt(M_MMAP_MAX)"); + lua_pushnumber(L, saved_errno); + return 2; + } + /* Now allocate/free a big chunk of RAM */ + free(malloc(20 * 1024 * 1024)); + } +#endif + /* Regardless of OS, we'll now try and set off some limits */ + /* Limit the virtual memory arena to 50 megs. * While this might seem a lot, a bare lua5.1 interpreter plus Supple * and deps seems to come to around 28MB VMSZ (although only 2MB res) @@ -281,8 +309,33 @@ supple_capi_lockdown(lua_State *L) lua_pushnumber(L, saved_errno); return 2; } + +#ifdef linux + /* Next, we're going to attempt a seccomp setup */ + if (rootly) { + /* We're fairly well locked down, however with Linux we + * can go one step further and enter 'seccomp mode 1' which + * limits our syscalls to read/write/_exit/sigreturn. + * + * This means that even if the attacker breaks out harder + * than we can imagine, their *ONLY* avenue of attack is + * back along the already open FD to the host app. + */ + if (prctl(PR_SET_SECCOMP, 1, 0, 0, 0) != 0) { + int saved_errno = errno; + lua_pushliteral(L, "prctl(PR_SET_SECCOMP, 1)"); + lua_pushnumber(L, saved_errno); + return 2; + } + } + /* If we reach here and we're rootly, we need to inform the lib + * Not to do the open() test or we get killed + */ + lua_pushstring(L, (rootly ? "OK" : "oknonroot")); +#else lua_pushstring(L, (rootly ? "ok" : "oknonroot")); +#endif lua_pushnumber(L, 0); return 2; } diff --git a/lib/supple/sandbox.lua b/lib/supple/sandbox.lua index 57e5cd3..6a79348 100644 --- a/lib/supple/sandbox.lua +++ b/lib/supple/sandbox.lua @@ -78,7 +78,7 @@ local function run() -- Run the sandbox local result, errno = capi.lockdown() - if result ~= "ok" + if result ~= "ok" and result ~= "OK" -- START_TEST_ONLY and result ~= "oknonroot" -- END_TEST_ONLY @@ -88,9 +88,9 @@ local function run() return errno end --- START_TEST_ONLY - if result ~= "oknonroot" then --- END_TEST_ONLY + if result == "ok" then + -- Note, if result is "OK" then we're pretty hard jailed + -- and cannot even do this test lest we get killed -- Check that we're definitely solidly jailed fh, errno = sio.open("testfile", "rw") if fh then @@ -98,9 +98,7 @@ local function run() luxio.unlink("testfile") return 1 end --- START_TEST_ONLY end --- END_TEST_ONLY -- Prepare a severely limited sandbox local sandbox_globals = { -- cgit v1.2.1