diff options
author | Guy Harris <gharris@sonic.net> | 2022-01-11 02:11:10 -0800 |
---|---|---|
committer | Guy Harris <gharris@sonic.net> | 2022-01-11 19:56:14 +0000 |
commit | 18748abb5e3c536d3e60e76967e2ee4ce43117f9 (patch) | |
tree | 091a5d7df37d47c46d6cc98707b992e8c4e5da05 /epan/register.c | |
parent | 16e0ba7dd7bad5ffc11211ee61c895e10b249acb (diff) |
Fix handling of dissector registration errors.
Report all registration errors with REPORT_DISSECTOR_BUG().
In the workers for register_all_protocols() and
register_all_protocol_handlers(), use TRY/CATCH/ENDTRY to catch
DissectorError exceptions thrown by REPORT_DISSECTOR_BUG() when
registering dissectors. Return the error message from the main thread
routine and, when joining the worker thread, if there's an error message
returned, throw it in the current thread, so that it gets caught by the
main libwireshark initialization code.
Fixes the crash in #17856.
Diffstat (limited to 'epan/register.c')
-rw-r--r-- | epan/register.c | 63 |
1 files changed, 53 insertions, 10 deletions
diff --git a/epan/register.c b/epan/register.c index e8387c112a..cd6bf735c7 100644 --- a/epan/register.c +++ b/epan/register.c @@ -12,6 +12,9 @@ #include "ws_attributes.h" #include <glib.h> + +#include <epan/exceptions.h> + #include "epan/dissectors/dissectors.h" static const char *cur_cb_name = NULL; @@ -31,13 +34,30 @@ static void set_cb_name(const char *proto) { static void * register_all_protocols_worker(void *arg _U_) { - for (gulong i = 0; i < dissector_reg_proto_count; i++) { - set_cb_name(dissector_reg_proto[i].cb_name); - dissector_reg_proto[i].cb_func(); + void *volatile error_message = NULL; + + TRY { + for (gulong i = 0; i < dissector_reg_proto_count; i++) { + set_cb_name(dissector_reg_proto[i].cb_name); + dissector_reg_proto[i].cb_func(); + } } + CATCH(DissectorError) { + /* + * This is probably a dissector, or something it calls, + * calling REPORT_DISSECTOR_ERROR() in a registration + * routine or something else outside the normal dissection + * code path. + * + * The message gets freed by ENDTRY, so we must make a copy + * of it. + */ + error_message = g_strdup(GET_MESSAGE); + } + ENDTRY; g_async_queue_push(register_cb_done_q, GINT_TO_POINTER(TRUE)); - return NULL; + return (void *) error_message; } void @@ -47,6 +67,7 @@ register_all_protocols(register_cb cb, gpointer cb_data) register_cb_done_q = g_async_queue_new(); gboolean called_back = FALSE; GThread *rapw_thread; + const char *error_message; rapw_thread = g_thread_new("register_all_protocols_worker", ®ister_all_protocols_worker, NULL); while (!g_async_queue_timeout_pop(register_cb_done_q, CB_WAIT_TIME)) { @@ -58,7 +79,9 @@ register_all_protocols(register_cb cb, gpointer cb_data) called_back = TRUE; } } - g_thread_join(rapw_thread); + error_message = (const char *) g_thread_join(rapw_thread); + if (error_message != NULL) + THROW_MESSAGE(DissectorError, error_message); if (cb && !called_back) { cb(RA_REGISTER, "finished", cb_data); } @@ -67,13 +90,30 @@ register_all_protocols(register_cb cb, gpointer cb_data) static void * register_all_protocol_handoffs_worker(void *arg _U_) { - for (gulong i = 0; i < dissector_reg_handoff_count; i++) { - set_cb_name(dissector_reg_handoff[i].cb_name); - dissector_reg_handoff[i].cb_func(); + void *volatile error_message = NULL; + + TRY { + for (gulong i = 0; i < dissector_reg_handoff_count; i++) { + set_cb_name(dissector_reg_handoff[i].cb_name); + dissector_reg_handoff[i].cb_func(); + } + } + CATCH(DissectorError) { + /* + * This is probably a dissector, or something it calls, + * calling REPORT_DISSECTOR_ERROR() in a registration + * routine or something else outside the normal dissection + * code path. + * + * The message gets freed by ENDTRY, so we must make a copy + * of it. + */ + error_message = g_strdup(GET_MESSAGE); } + ENDTRY; g_async_queue_push(register_cb_done_q, GINT_TO_POINTER(TRUE)); - return NULL; + return (void *) error_message; } void @@ -83,6 +123,7 @@ register_all_protocol_handoffs(register_cb cb, gpointer cb_data) const char *cb_name; gboolean called_back = FALSE; GThread *raphw_thread; + const char *error_message; raphw_thread = g_thread_new("register_all_protocol_handoffs_worker", ®ister_all_protocol_handoffs_worker, NULL); while (!g_async_queue_timeout_pop(register_cb_done_q, CB_WAIT_TIME)) { @@ -94,7 +135,9 @@ register_all_protocol_handoffs(register_cb cb, gpointer cb_data) called_back = TRUE; } } - g_thread_join(raphw_thread); + error_message = (const char *) g_thread_join(raphw_thread); + if (error_message != NULL) + THROW_MESSAGE(DissectorError, error_message); if (cb && !called_back) { cb(RA_HANDOFF, "finished", cb_data); } |