prefs: fix range preferences-related crash after switching profiles

The HTTP dissector could crash (use-after-free) after switching
profiles. In reinit_http, it would assign the return value from
prefs_get_range_value to a global variable which is consulted during
dissection. This value is invalidated while switching profiles (via the
"prefs_reset" function), but is not reinitialized (because the
reinit_http function was not called).

A similar issue exists in the Kafka, UAUDP, VNC, TFTP, Gopher and TDS
dissectors. To reproduce using a capture from the SampleCaptures wiki,
start "wireshark -r vnc-sample.pcap -ovnc.tcp.port:1" and switch
profiles. For the HTTP crash, load any HTTP pcap and switch profiles.

Change-Id: I8725615504a8a82ae46255625a41e2188c07320a
Fixes: v2.3.0rc0-2097-g21a3b8cc71 ("Internalize struct preference")
Reviewed-on: https://code.wireshark.org/review/29030
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Peter Wu 2018-08-08 20:00:48 +02:00 committed by Anders Broman
parent 5e2e9de930
commit 0be9d149d0
1 changed files with 19 additions and 9 deletions

View File

@ -4216,26 +4216,36 @@ reset_pref(pref_t *pref)
}
static void
reset_pref_cb(gpointer data, gpointer user_data _U_)
reset_pref_cb(gpointer data, gpointer user_data)
{
pref_t *pref = (pref_t *) data;
module_t *module = (module_t *)user_data;
if (pref && (pref->type == PREF_RANGE || pref->type == PREF_DECODE_AS_RANGE)) {
/*
* Some dissectors expect the range (returned via prefs_get_range_value)
* to remain valid if it has not changed. If it did change, then we
* should set "prefs_changed_flags" to ensure that the preference apply
* callback is invoked. That callback will notify dissectors that it
* should no longer assume the range to be valid.
*/
if (ranges_are_equal(*pref->varp.range, pref->default_val.range)) {
/* Optimization: do not invoke apply callback if nothing changed. */
return;
}
module->prefs_changed_flags |= prefs_get_effect_flags(pref);
}
reset_pref(pref);
}
typedef struct {
module_t *module;
} reset_pref_arg_t;
/*
* Reset all preferences for a module.
*/
static gboolean
reset_module_prefs(const void *key _U_, void *value, void *data _U_)
{
reset_pref_arg_t arg;
arg.module = (module_t *)value;
g_list_foreach(arg.module->prefs, reset_pref_cb, &arg);
module_t *module = (module_t *)value;
g_list_foreach(module->prefs, reset_pref_cb, module);
return FALSE;
}