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 <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Reviewed-by: Evan Huus <eapache@gmail.com>
This commit is contained in:
Peter Wu 2015-09-29 12:20:07 +02:00 committed by Evan Huus
parent 3182fbae51
commit 82b225898b
3 changed files with 33 additions and 5 deletions

View File

@ -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 \

View File

@ -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;

View File

@ -30,6 +30,7 @@
#include "wslua.h"
#include <epan/dissectors/packet-tcp.h>
#include <epan/exceptions.h>
/* 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");
}