mooa

Lua + lubev + sandboxing
git clone https://code.literati.org/mooa.git
Log | Files | Refs | README | LICENSE

commit cff8d71d56b256c5770d0f6c56f4abad3953fb24
parent 0017c88b88cefa6bfa11f1055afa3a28723c3997
Author: Sean Lynch <seanl@literati.org>
Date:   Tue, 23 Feb 2016 21:15:07 -0800

Trying to restart project

Diffstat:
Acapnproto.c | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ajson.c | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmooa.c | 23++++-------------------
Msocket.c | 31++++++++++++++++---------------
Awhitelist | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 329 insertions(+), 34 deletions(-)

diff --git a/capnproto.c b/capnproto.c @@ -0,0 +1,153 @@ +#include <endian.h> + +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> + + +#define PTR_TYPE(X) ((X) & 0x3) +#define STRUCT_OFFSET ((X) >> 2 & 0x3fffffff) +#define STRUCT_DATA_WORDS ((X) >> 32 & 0xffff) +#define STRUCT_PTR_WORDS ((X) >> 48 & 0xffff) + + +typedef struct { + size_t words; + uint64_t data[]; +} capnp_segment_t; + + +static capnp_segment_t *capnp_segment_new(lua_State *L, size_t words) { + capnp_segment_t *segment = lua_newuserdata(L, words * 8 + sizeof (capnp_segment_t)); + segment->words = words; + luaL_getmetatable(L, "capnp_segment"); + lua_setmetatable(L, -2); + return segment; +} + + +static int capnp_read_msg(lua_State *L, FILE *stream) { + uint32_t num_segs, seg_lens[64]; + + fread(&num_segs, sizeof num_segs, 1, stream); + num_segs = le32toh(num_segs) + 1; + + if (num_segs > 64) { + luaL_error(L, "Cannot read message with more than 64 segments."); + } + + fread(seg_lens, sizeof seg_lens[0], num_segs); + lua_pushtable(L); + + // One hopes that this will get optimized out entirely on + // little-endian machines + for (int i = 0; i < num_segs; i++) { + uint32_t words = le32toh(seg_lens[i]); + capnp_segment_t *segment = capnp_segment_new(L, words); + fread(segment->data, sizeof segment->data[0], words, stream); + lua_rawseti(L, -2, i); + } + + // Now we should extract the root struct +} + + +/* + * Expects the message at -2 and the segment at -1 + */ +static int capnp_parse_ptr(lua_State *L, uint64_t ptr) { + // Push the return value + lua_pushtable(L); + lua_setfield(L, -3, "message"); + + switch (PTR_TYPE(ptr)) { + case 0: // struct + // It's in this segment, so save that + lua_pushvalue(L, -2); + lua_setfield(L, -2, "segment"); + + // Compute offset + lua_pushinteger(L, STRUCT_OFFSET(ptr) + offset + 1); + lua_setfield(L, -2, "offset"); + lua_pushinteger(L, STRUCT_DATA_WORDS(ptr)); + lua_setfield(L, -2, "data_words"); + lua_pushinteger(L, STRUCT_PTR_WORDS(ptr)); + lua_setfield(L, -2, "pointer_words"); + + luaL_getmetatable(L, "capnp_struct"); + lua_setmetatable(L, -2); + break; + case 1: // list + break; + case 2: // far + break; + case 3: // other + break; + } + + return 1; +} + + +/* + * message, segment, offset, data_words, pointer_words + */ +static int capnp_struct_get_ptr(lua_State *L) { + int index = luaL_checkinteger(lua_State *L, 2); + + if (index < 0) { + luaL_error(L, "index must not be negative"); + } + + lua_getfield(L, 1, "segment"); + capnp_segment_t *segment = luaL_checkudata(L, -1, "capnp_segment"); + lua_getfield(L, 1, "offset"); + int offset = luaL_checkinteger(L, -1); + lua_getfield(L, 1, "data_words"); + int data_words = luaL_checkinteger(L, -1); + lua_getfield(L, 1, "pointer_words"); + int pointer_words = luaL_checkinteger(L, -1); + lua_pop(L, 3); + + if (offset < 0 || data_words < 0 || pointer_words < 0) { + luaL_error(L, "offset, data_words, and pointer_words must all be >= 0"); + } + + int pointer_start = offset + data_words; + + if (pointer_start + pointer_words > segment->size) { + luaL_error(L, "struct goes past end of segment"); + } + + if (index > pointer_words) { + luaL_error(L, "pointer index is greater than the number of pointers") + } + + uint64_t ptr = le64toh(segment->data[pointer_start + index]); + + // All types have a "message" field, so copy it from the input + lua_getfield(L, 1, "message"); + + capnp_parse_ptr(L, ptr); +} + + +int capnp_open(lua_State *L) { + static luaL_Reg module_functions[] = { + {NULL, NULL} + }; + + static luaL_Reg capnp_methods[] = { + {NULL, NULL} + }; + + luaL_newmetatable(L, "mooa_capnp"); + // Set the method table on the metatable as __index + luaL_newlib(L, capnp_methods); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); + + // Create the module + luaL_newlib(L, module_functions); + return 1; +} diff --git a/json.c b/json.c @@ -0,0 +1,88 @@ +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> + +#include <yajl/yajl_parse.h> +#include <yajl/yajl_gen.h> + + +typedef struct { + lua_State *L; + enum {none, in_map, in_array} state; +} context_t; + + +static int parse_cb(context_t *ctx) { + switch (ctx->state) { + case none: + break; + case in_map: + lua_settable(ctx->L, -3); + break; + case in_array: + lua_rawseti(ctx->L, -2, luaL_getn(ctx->L, -2) + 1); + break; + default: + luaL_error(ctx->L, "Unexpected state %d", ctx->state); + } + + return 1; +} + + +static int parse_null(context_t *ctx) { + lua_pushnil(ctx->L); + return parse_cb(ctx); +} + + +static int parse_boolean(context_t *ctx, int boolVal) { + lua_pushboolean(L, boolVal); + return parse_cb(ctx); +} + + +static int parse_integer(context_t *ctx, long long integerVal) { + lua_pushinteger(ctx->L, integerVal); + return parse_cb(ctx); +} + + +static int parse_float(context_t *ctx, double doubleVal) { + lua_pushnumber(ctx->L, doubleVal); + return parse_cb(ctx); +} + + +static int parse_string(context_t *ctx, const unsigned char *stringVal, + size_t stringLen) { + lua_pushlstring(ctx->L, stringVal, stringLen); + return parse_cb(ctx); +} + + +static int parse_start_map(context_t *ctx) { + lua_pushtable(ctx->L); + return 1; +} + + +static int parse_map_key(context_t *ctx, const unsigned char *key, + size_t keyLen) { + lua_pushlstring(ctx->L, ) +} + + +static yajl_callbacks callbacks = { + parse_null, + parse_boolean, + parse_integer, + parse_float, + NULL, + parse_string, + parse_start_map, + parse_map_key, + parse_end_map, + parse_start_array, + parse_end_array +}; diff --git a/mooa.c b/mooa.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include <stdlib.h> #include <stdio.h> #include <getopt.h> @@ -90,6 +88,7 @@ static void mooa_state_makesafe(lua_State *L) { lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); } + static int get_syscall_nr(const char *name) { int result = seccomp_syscall_resolve_name(name); if (result == __NR_SCMP_ERROR) { @@ -98,6 +97,7 @@ static int get_syscall_nr(const char *name) { return result; } + static void install_seccomp_filter(const char *syscalls[]) { scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_TRACE(1)); if (!ctx) { @@ -113,6 +113,7 @@ static void install_seccomp_filter(const char *syscalls[]) { check(seccomp_load(ctx)); } + static int mooa_panic(lua_State *L) { const char *message = lua_tostring(L, -1); lua_Debug ar; @@ -155,21 +156,6 @@ static lua_State *mooa_state_new(void) { } -static void drop_root_privs(void) { - check(setegid(65534)); - check(seteuid(65534)); -} - - -static void mooa_chroot(const char *new_root) { - check(seteuid(0)); - check(setegid(0)); - check(chroot(new_root)); - check(chdir("/")); - drop_root_privs(); -} - - int main(void) { lua_State *L; const char *whitelist[] = { @@ -196,8 +182,7 @@ int main(void) { return 1; } - /* mooa_chroot("./chroot"); */ - /* install_seccomp_filter(whitelist); */ + install_seccomp_filter(whitelist); mooa_task_spawn(L); diff --git a/socket.c b/socket.c @@ -46,7 +46,7 @@ static int mooa_socket_finalize(lua_State *L) { static void mooa_makeaddr(lua_State *L, struct sockaddr_in *sa, - const char *address, int port) { + const char *address, uint16_t port) { memset(sa, 0, sizeof(*sa)); /* TODO: ipv6 */ @@ -59,7 +59,8 @@ static void mooa_makeaddr(lua_State *L, struct sockaddr_in *sa, } -static int mooa_socket_accept_cb(lua_State *L) { +static int mooa_socket_accept_cb(lua_State *L, int status, lua_KContext ctx) { +#pragma unused(status, ctx) mooa_socket_t *sock = lua_touserdata(L, 1); int fd = accept(sock->socket, NULL, NULL); if (fd < 0) { @@ -95,7 +96,7 @@ static int mooa_socket_bind(lua_State *L) { luaL_checknumber(L, 3); sock = lua_touserdata(L, 1); - mooa_makeaddr(L, &sa, lua_tostring(L, 2), lua_tointeger(L, 3)); + mooa_makeaddr(L, &sa, lua_tostring(L, 2), (uint16_t)lua_tointeger(L, 3)); if (bind(sock->socket, (struct sockaddr *)&sa, sizeof(sa)) != 0) { return luaL_error(L, "Unable to bind (errno %d)", errno); } @@ -126,7 +127,7 @@ static int mooa_socket_connect(lua_State *L) { luaL_checknumber(L, 3); sock = lua_touserdata(L, 1); - mooa_makeaddr(L, &sa, lua_tostring(L, 2), lua_tointeger(L, 3)); + mooa_makeaddr(L, &sa, lua_tostring(L, 2), (uint16_t)lua_tointeger(L, 3)); if (connect(sock->socket, (struct sockaddr *)&sa, sizeof(sa)) != 0 && errno != EINPROGRESS) { return luaL_error(L, "Unable to connect (errno %d)", errno); @@ -145,7 +146,7 @@ static int mooa_socket_listen(lua_State *L) { luaL_checknumber(L, 2); sock = lua_touserdata(L, 1); - backlog = lua_tointeger(L, 2); + backlog = (int)lua_tointeger(L, 2); if (listen(sock->socket, backlog) != 0) { return luaL_error(L, "Unable to listen (errno %d)", errno); @@ -155,10 +156,11 @@ static int mooa_socket_listen(lua_State *L) { } -static int mooa_socket_read_cb(lua_State *L) { +static int mooa_socket_read_cb(lua_State *L, int status, lua_KContext ctx) { +#pragma unused(status, ctx) luaL_Buffer buf; mooa_socket_t *sock = lua_touserdata(L, 1); - int size = lua_tointeger(L, 2); + size_t size = (size_t)lua_tointeger(L, 2); char *data = luaL_buffinitsize(L, &buf, size); ssize_t nread = read(sock->socket, data, size); if (nread < 0) { @@ -167,7 +169,7 @@ static int mooa_socket_read_cb(lua_State *L) { } return luaL_error(L, "Unable to read from socket (errno %d)", errno); } else { - luaL_pushresultsize(&buf, nread); + luaL_pushresultsize(&buf, (size_t)nread); return 1; } } @@ -185,23 +187,22 @@ static int mooa_socket_read(lua_State *L) { } -static int mooa_socket_write_cb(lua_State *L) { +static int mooa_socket_write_cb(lua_State *L, int status, lua_KContext ctx) { +#pragma unused(status) size_t len; ssize_t nsent; - int offset; const char *data; mooa_socket_t *sock = lua_touserdata(L, 1); - lua_getctx(L, &offset); data = lua_tolstring(L, 2, &len); - nsent = write(sock->socket, &data[offset], len - offset); + nsent = write(sock->socket, &data[ctx], len - (uintptr_t)ctx); if (nsent < 0) { /* error */ return luaL_error(L, "Error writing to socket"); } - offset += nsent; - if (offset < len) { - return lua_yieldk(L, 0, offset, mooa_socket_write_cb); + ctx += nsent; + if ((size_t)ctx < len) { + return lua_yieldk(L, 0, ctx, mooa_socket_write_cb); } return 0; diff --git a/whitelist b/whitelist @@ -0,0 +1,68 @@ +access +arch_prctl +brk +chdir +chmod +clock_getres +clock_gettime +close +connect +dup +dup2 +execve +exit +exit_group +faccessat +fadvise64 +fcntl +fstat +futex +getcwd +getdents +getegid +geteuid +getgid +getpgrp +getpid +getppid +getresgid +getresuid +getrlimit +getrusage +gettid +gettimeofday +getuid +getxattr +ioctl +lseek +lstat +madvise +mkdir +mmap +mprotect +mremap +munmap +open +openat +pipe +pipe2 +read +readlink +rmdir +rt_sigaction +rt_sigprocmask +rt_sigreturn +set_robust_list +set_tid_address +setpgid +setrlimit +socket +stat +statfs +tgkill +umask +uname +unlink +utimensat +wait4 +write