diff --git a/docs/changes.txt b/docs/changes.txt index de374ae..fd19ff4 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -174,3 +174,4 @@ v0.8.1 * winws2: fix loopback large packets processing (up to 64K) * zapret-lib, zapret-antidpi: use numeric indexes in http dissects +* nfqws2: move ctx from lightuserdata to userdata. prevents crashes on specific ARM cpus diff --git a/nfq2/desync.c b/nfq2/desync.c index e8a86d7..ddaf856 100644 --- a/nfq2/desync.c +++ b/nfq2/desync.c @@ -753,7 +753,6 @@ static uint8_t desync( struct func_list *func; int ref_arg = LUA_NOREF, status; bool b, b_cutoff_all, b_unwanted_payload; - t_lua_desync_context ctx = { .magic = 0, .dp = dp, .ctrack = ctrack, .dis = dis, .cancel = false, .incoming = bIncoming }; const char *sDirection = bIncoming ? "in" : "out"; struct packet_range *range; size_t l; @@ -782,13 +781,19 @@ static uint8_t desync( if (LIST_FIRST(&dp->lua_desync)) { + params.desync_ctx->dp = dp; + params.desync_ctx->ctrack = ctrack; + params.desync_ctx->dis = dis; + params.desync_ctx->cancel = false; + params.desync_ctx->incoming = bIncoming; + b_cutoff_all = b_unwanted_payload = true; - ctx.func_n = 1; + params.desync_ctx->func_n = 1; LIST_FOREACH(func, &dp->lua_desync, next) { - ctx.func = func->func; - desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance)); - ctx.instance = instance; + params.desync_ctx->func = func->func; + desync_instance(func->func, dp->n, params.desync_ctx->func_n, instance, sizeof(instance)); + params.desync_ctx->instance = instance; range = bIncoming ? &func->range_in : &func->range_out; if (b_unwanted_payload) @@ -796,7 +801,7 @@ static uint8_t desync( if (b_cutoff_all) { - if (lua_instance_cutoff_check(params.L, &ctx, bIncoming)) + if (lua_instance_cutoff_check(params.L, params.desync_ctx, bIncoming)) DLOG("* lua '%s' : voluntary cutoff\n", instance); else if (check_pos_cutoff(pos, range)) { @@ -814,7 +819,7 @@ static uint8_t desync( else b_cutoff_all = false; } - ctx.func_n++; + params.desync_ctx->func_n++; } if (b_cutoff_all) { @@ -867,14 +872,14 @@ static uint8_t desync( } ref_arg = luaL_ref(params.L, LUA_REGISTRYINDEX); - ctx.func_n = 1; + params.desync_ctx->func_n = 1; LIST_FOREACH(func, &dp->lua_desync, next) { - ctx.func = func->func; - desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance)); - ctx.instance = instance; + params.desync_ctx->func = func->func; + desync_instance(func->func, dp->n, params.desync_ctx->func_n, instance, sizeof(instance)); + params.desync_ctx->instance = instance; - if (!lua_instance_cutoff_check(params.L, &ctx, bIncoming)) + if (!lua_instance_cutoff_check(params.L, params.desync_ctx, bIncoming)) { range = bIncoming ? &func->range_in : &func->range_out; if (check_pos_range(pos, range)) @@ -897,19 +902,16 @@ static uint8_t desync( DLOG_ERR("desync function '%s' does not exist\n", func->func); goto err; } - lua_pushlightuserdata(params.L, &ctx); + lua_rawgeti(params.L, LUA_REGISTRYINDEX, params.ref_desync_ctx); lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg); lua_pushf_args(params.L, &func->args, -1, true); lua_pushf_str(params.L, "func", func->func); - lua_pushf_int(params.L, "func_n", ctx.func_n); + lua_pushf_int(params.L, "func_n", params.desync_ctx->func_n); lua_pushf_str(params.L, "func_instance", instance); - - // lua should not store and access ctx outside of this call - // if this happens make our best to prevent access to bad memory - // this is not crash-proof but better than nothing - ctx.magic = MAGIC_CTX; // mark struct as valid + // prevent use of desync ctx object outside of function call + params.desync_ctx->valid = true; status = lua_pcall(params.L, 2, LUA_MULTRET, 0); - ctx.magic = 0; // mark struct as invalid + params.desync_ctx->valid = false; if (status) { @@ -939,8 +941,8 @@ static uint8_t desync( range->upper_cutoff ? '<' : '-', range->to.mode, range->to.pos); } - if (ctx.cancel) break; - ctx.func_n++; + if (params.desync_ctx->cancel) break; + params.desync_ctx->func_n++; } } diff --git a/nfq2/lua.c b/nfq2/lua.c index 1925a77..e3dd96e 100644 --- a/nfq2/lua.c +++ b/nfq2/lua.c @@ -769,20 +769,42 @@ static int luacall_clock_gettime(lua_State *L) LUA_STACK_GUARD_RETURN(L,2) } +static void lua_mt_init_desync_ctx(lua_State *L) +{ + luaL_newmetatable(L, "desync_ctx"); + lua_pop(L, 1); +} static t_lua_desync_context *lua_desync_ctx(lua_State *L) { - if (lua_isnil(L,1)) - luaL_error(L, "missing ctx"); - if (!lua_islightuserdata(L,1)) - luaL_error(L, "bad ctx - invalid data type"); - - t_lua_desync_context *ctx = lua_touserdata(L,1); - // ensure it's really ctx. LUA could pass us any lightuserdata pointer - if (ctx->magic!=MAGIC_CTX) - luaL_error(L, "bad ctx - magic bytes invalid"); - + if (lua_isnil(L,1)) luaL_error(L, "missing ctx"); + t_lua_desync_context *ctx = (t_lua_desync_context *)luaL_checkudata(L, 1, "desync_ctx"); + if (!ctx->valid) luaL_error(L, "ctx is invalid"); return ctx; } +static void lua_desync_ctx_create(lua_State *L) +{ + if (!params.ref_desync_ctx) + { + LUA_STACK_GUARD_ENTER(L) + + params.desync_ctx = (t_lua_desync_context *)lua_newuserdata(L, sizeof(t_lua_desync_context)); + memset(params.desync_ctx, 0, sizeof(t_lua_desync_context)); + luaL_getmetatable(L, "desync_ctx"); + lua_setmetatable(L, -2); + params.ref_desync_ctx = luaL_ref(params.L, LUA_REGISTRYINDEX); + + LUA_STACK_GUARD_LEAVE(L,0) + } +} +static void lua_desync_ctx_destroy(lua_State *L) +{ + if (params.ref_desync_ctx) + { + luaL_unref(L, LUA_REGISTRYINDEX, params.ref_desync_ctx); + params.ref_desync_ctx = 0; + params.desync_ctx = NULL; + } +} static int luacall_instance_cutoff(lua_State *L) { @@ -2846,14 +2868,19 @@ zerr: // ---------------------------------------- +void lua_cleanup(lua_State *L) +{ + lua_desync_ctx_destroy(L); + // conntrack holds lua state. must clear it before lua shoudown + ConntrackPoolDestroy(¶ms.conntrack); +} void lua_shutdown() { if (params.L) { DLOG("LUA SHUTDOWN\n"); - // conntrack holds lua state. must clear it before lua shoudown - ConntrackPoolDestroy(¶ms.conntrack); + lua_cleanup(params.L); lua_close(params.L); params.L=NULL; } @@ -3396,6 +3423,8 @@ static void lua_init_functions(void) static void lua_init_mt() { lua_mt_init_zstream(params.L); + lua_mt_init_desync_ctx(params.L); + lua_desync_ctx_create(params.L); } bool lua_init(void) @@ -3403,6 +3432,9 @@ bool lua_init(void) DLOG("\nLUA INIT\n"); if (!lua_basic_init()) return false; + + LUA_STACK_GUARD_ENTER(params.L) + lua_sec_harden(); lua_init_blobs(); lua_init_const(); @@ -3411,10 +3443,11 @@ bool lua_init(void) if (!lua_init_scripts()) goto err; if (!lua_desync_functions_exist()) goto err; + LUA_STACK_GUARD_LEAVE(params.L,0) DLOG("LUA INIT DONE\n\n"); - return true; err: + LUA_STACK_GUARD_LEAVE(params.L,0) lua_shutdown(); return false; } diff --git a/nfq2/lua.h b/nfq2/lua.h index c34718c..a1f76b7 100644 --- a/nfq2/lua.h +++ b/nfq2/lua.h @@ -14,6 +14,7 @@ #include "pools.h" #include "conntrack.h" #include "darkmagic.h" +#include "params.h" #if LUA_VERSION_NUM < 503 #define lua_isinteger lua_isnumber @@ -101,15 +102,4 @@ bool lua_reconstruct_tcphdr(lua_State *L, int idx, struct tcphdr *tcp, size_t *l bool lua_reconstruct_udphdr(lua_State *L, int idx, struct udphdr *udp); bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, bool badsum, bool ip6_preserve_next); -#define MAGIC_CTX 0xE73DC935 -typedef struct { - uint32_t magic; - unsigned int func_n; - const char *func, *instance; - const struct desync_profile *dp; - const struct dissect *dis; - t_ctrack *ctrack; - bool incoming,cancel; -} t_lua_desync_context; - bool lua_instance_cutoff_check(lua_State *L, const t_lua_desync_context *ctx, bool bIn); diff --git a/nfq2/params.c b/nfq2/params.c index 89fd7f9..1dedd8c 100644 --- a/nfq2/params.c +++ b/nfq2/params.c @@ -498,6 +498,9 @@ void cleanup_params(struct params_s *params) ipcacheDestroy(¶ms->ipcache); blob_collection_destroy(¶ms->blobs); strlist_destroy(¶ms->lua_init_scripts); + + params->desync_ctx = NULL; + #ifdef __CYGWIN__ strlist_destroy(¶ms->ssid_filter); strlist_destroy(¶ms->nlm_filter); diff --git a/nfq2/params.h b/nfq2/params.h index 02c4ea2..d018436 100644 --- a/nfq2/params.h +++ b/nfq2/params.h @@ -115,6 +115,16 @@ void dp_clear(struct desync_profile *dp); #define WINDIVERT_MAX 65536 #define WINDIVERT_PORTFILTER_MAX 4096 +typedef struct { + unsigned int func_n; + const char *func, *instance; + const struct desync_profile *dp; + const struct dissect *dis; + t_ctrack *ctrack; + bool incoming, cancel; + bool valid; +} t_lua_desync_context; + struct params_s { #if !defined( __OpenBSD__) && !defined(__ANDROID__) @@ -182,6 +192,8 @@ struct params_s char writeable_dir[PATH_MAX]; int lua_gc; + int ref_desync_ctx; // desync ctx userdata registry ref + t_lua_desync_context *desync_ctx; // desync ctx single object lua_State *L; };