From 82b225898b677e7a7e0176941ef73c824d761a98 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Tue, 29 Sep 2015 12:20:07 +0200 Subject: [PATCH] wslua: fix crash when a LUA error is raised in TRY block The dissect_tcp_pdus function in LUA is passed two LUA functions that get the PDU length and the dissect a PDU. When one of these functions fail, a longjmp is made to the the caller of lua_pcall. This is no problem for the PDU length function, but the PDU dissect function is wrapped in a TRY/CATCH/ENDTRY block which also uses longjmp and need to be fully executed. Without doing so, LUA exceptions will crash on a weird location (except_pop). Fix the crash by not using luaL_error, but throw dissector errors which properly breaks out of the tcp_dissect_pdus C function and then convert it to a LUA error such that the dissector can handle it. Test with `tshark -X lua_script:crash.lua -r ssl.pcap`: trivial_proto = Proto("trivial", "Trivial Protocol") function dissect_foo(tvb, pinfo, tree) error("triggering a LUA error"); end function get_pdu_len(tvb, pinfo, tree) return 5; end function trivial_proto.dissector(tvb, pinfo, tree) dissect_tcp_pdus(tvb, tree, 5, get_pdu_len, dissect_foo) end tcp_table = DissectorTable.get("tcp.port") tcp_table:add(443, trivial_proto) It should not crash and will print this: Lua Error: dissect_tcp_pdus dissect_func: [string "crash.lua"]:3: triggering a LUA error Change-Id: Ibd079cc5eb3a2e4d2e62ea49a512fa2cc8e561ea Reviewed-on: https://code.wireshark.org/review/10685 Petri-Dish: Peter Wu Tested-by: Petri Dish Buildbot Reviewed-by: Peter Wu Reviewed-by: Evan Huus --- epan/exceptions.h | 4 ++++ epan/wslua/wslua.h | 20 ++++++++++++++++++++ epan/wslua/wslua_proto.c | 14 +++++++++----- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/epan/exceptions.h b/epan/exceptions.h index e6ed6f5a96..5106852bca 100644 --- a/epan/exceptions.h +++ b/epan/exceptions.h @@ -372,6 +372,10 @@ except_throw(XCEPT_GROUP_WIRESHARK, (x), (y)); \ } G_STMT_END +/* Throws a formatted message, its memory is cleared after catching it. */ +#define THROW_FORMATTED(x, ...) \ + except_throwf(XCEPT_GROUP_WIRESHARK, (x), __VA_ARGS__) + #define GET_MESSAGE except_message(exc) #define RETHROW \ diff --git a/epan/wslua/wslua.h b/epan/wslua/wslua.h index 7ad7926db6..4d0ca22b60 100644 --- a/epan/wslua/wslua.h +++ b/epan/wslua/wslua.h @@ -654,6 +654,26 @@ extern int C##_register(lua_State* L); \ extern gboolean is##C(lua_State* L,int i); \ extern C shift##C(lua_State* L,int i) + +/* Throws a Wireshark exception, catchable via normal exceptions.h routines. */ +#define THROW_LUA_ERROR(...) \ + THROW_FORMATTED(DissectorError, __VA_ARGS__) + +/* Catches any Wireshark exceptions in code and convert it into a LUA error. + * Normal restrictions for TRY/CATCH apply, in particular, do not return! */ +#define WRAP_NON_LUA_EXCEPTIONS(code) \ +{ \ + volatile gboolean has_error = FALSE; \ + TRY { \ + code \ + } CATCH_ALL { \ + lua_pushstring(L, GET_MESSAGE); \ + has_error = TRUE; \ + } ENDTRY; \ + if (has_error) { lua_error(L); } \ +} + + extern packet_info* lua_pinfo; extern TreeItem lua_tree; extern tvbuff_t* lua_tvb; diff --git a/epan/wslua/wslua_proto.c b/epan/wslua/wslua_proto.c index 155d0fe194..4cfe734683 100644 --- a/epan/wslua/wslua_proto.c +++ b/epan/wslua/wslua_proto.c @@ -30,6 +30,7 @@ #include "wslua.h" #include +#include /* WSLUA_MODULE Proto Functions for new protocols and dissectors @@ -761,6 +762,7 @@ static int wslua_dissect_tcp_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { + /* WARNING: called from a TRY block, do not call luaL_error! */ func_saver_t* fs = (func_saver_t*)data; lua_State* L = fs->state; int consumed_bytes = 0; @@ -776,7 +778,7 @@ wslua_dissect_tcp_dissector(tvbuff_t *tvb, packet_info *pinfo, push_TreeItem(L, tree, (proto_item*)tree); if ( lua_pcall(L,3,1,0) ) { - luaL_error(L, "Lua Error dissect_tcp_pdus dissect_func: %s", lua_tostring(L,-1)); + THROW_LUA_ERROR("dissect_tcp_pdus dissect_func: %s", lua_tostring(L, -1)); } else { /* if the Lua dissector reported the consumed bytes, pass it to our caller */ if (lua_isnumber(L, -1)) { @@ -787,7 +789,7 @@ wslua_dissect_tcp_dissector(tvbuff_t *tvb, packet_info *pinfo, } } else { - luaL_error(L,"Lua Error dissect_tcp_pdus: did not find the dissect_func dissector"); + REPORT_DISSECTOR_BUG("dissect_tcp_pdus: did not find the dissect_func dissector"); } return consumed_bytes; @@ -857,9 +859,11 @@ WSLUA_FUNCTION wslua_dissect_tcp_pdus(lua_State* L) { destroy them before they get invoked */ g_ptr_array_add(outstanding_FuncSavers, fs); - tcp_dissect_pdus(tvb->ws_tvb, lua_pinfo, ti->tree, proto_desegment, - fixed_len, wslua_dissect_tcp_get_pdu_len, - wslua_dissect_tcp_dissector, (void*)fs); + WRAP_NON_LUA_EXCEPTIONS( + tcp_dissect_pdus(tvb->ws_tvb, lua_pinfo, ti->tree, proto_desegment, + fixed_len, wslua_dissect_tcp_get_pdu_len, + wslua_dissect_tcp_dissector, (void*)fs); + ) } else { luaL_error(L,"The third and fourth arguments need to be Lua functions"); }