From 393c50f1c45067e7a7080165d6f1dff94a849aa9 Mon Sep 17 00:00:00 2001 From: Chengwei Yang Date: Fri, 11 Oct 2013 15:45:29 +0800 Subject: [PATCH v2] Fix memory or unix fd may leak in dbus_message_iter_get_args_valist This is an aged bug since 2009, so let's fix it. Say if a previous parsing for unix fd or array of string successfully but then a later element parsing fail, then the unix fd or array of string leaked. https://bugs.freedesktop.org/show_bug.cgi?id=21259 --- dbus/dbus-message.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 9546da1..3251016 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -801,15 +801,19 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter, { DBusMessageRealIter *real = (DBusMessageRealIter *)iter; int spec_type, msg_type, i, j; - dbus_bool_t retval; + va_list copy_args; _dbus_assert (_dbus_message_iter_check (real)); - retval = FALSE; - spec_type = first_arg_type; i = 0; + /* copy var_args first, then we can do another iteration over it to + * free memory and close unix fds if parse failed at some point. + */ + va_copy (copy_args, var_args); + va_end (var_args); + while (spec_type != DBUS_TYPE_INVALID) { msg_type = dbus_message_iter_get_arg_type (iter); @@ -993,11 +997,62 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter, i++; } - retval = TRUE; + return TRUE; out: + /* there may memory or unix fd leak in the above iteration if parse failed. + * so we have another iteration over copy_args to free memory and close + * unix fds. + */ + spec_type = first_arg_type; + j = 0; - return retval; + while (j < i) + { + if (dbus_type_is_basic (spec_type)) + { + /* move the index forward */ + va_arg (copy_args, DBusBasicValue*); + } + else if (spec_type == DBUS_TYPE_ARRAY) + { + int spec_element_type; + + spec_element_type = va_arg (copy_args, int); + if (dbus_type_is_fixed (spec_element_type)) + { + /* move the index forward */ + va_arg (copy_args, const DBusBasicValue**); + va_arg (copy_args, int*); + } + else if (_DBUS_TYPE_IS_STRINGLIKE (spec_element_type)) + { + char ***str_array_p; + + str_array_p = va_arg (copy_args, char***); + /* move the index forward */ + va_arg (copy_args, int*); + _dbus_assert (str_array_p != NULL); + dbus_free_string_array (*str_array_p); + } + } +#ifdef HAVE_UNIX_FD_PASSING + else if (spec_type == DBUS_TYPE_UNIX_FD) + { + int *pfd; + + pfd = va_arg (copy_args, int*); + _dbus_assert(pfd); + if (*pfd > 0) + _dbus_close (*pfd, NULL); + } +#endif + + spec_type = va_arg (copy_args, int); + j++; + } + + return FALSE; } /** @} */ -- 1.7.9.5