diff --git a/backport-CVE-2021-27219.patch b/backport-CVE-2021-27219.patch new file mode 100644 index 0000000000000000000000000000000000000000..a61c43d11af3dd822ea85056ed66473b4eeca033 --- /dev/null +++ b/backport-CVE-2021-27219.patch @@ -0,0 +1,792 @@ +From f8cf0b8672209e0b829542e194e302f1de169929 Mon Sep 17 00:00:00 2001 +From: Philip Withnall +Date: Thu, 4 Feb 2021 13:30:52 +0000 +Subject: [PATCH 01/11] gstrfuncs: Add g_memdup2() function + +This will replace the existing `g_memdup()` function, which has an +unavoidable security flaw of taking its `byte_size` argument as a +`guint` rather than as a `gsize`. Most callers will expect it to be a +`gsize`, and may pass in large values which could silently be truncated, +resulting in an undersize allocation compared to what the caller +expects. + +This could lead to a classic buffer overflow vulnerability for many +callers of `g_memdup()`. + +`g_memdup2()`, in comparison, takes its `byte_size` as a `gsize`. + +Spotted by Kevin Backhouse of GHSL. + +Signed-off-by: Philip Withnall +Helps: GHSL-2021-045 +Helps: #2319 + +Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/20cfc75d148e3be0c026cc7eff3a9cdb72bf5c56 + +diff -Naur a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt +--- a/docs/reference/glib/glib-sections.txt 2021-03-06 09:46:03.657000000 +0800 ++++ b/docs/reference/glib/glib-sections.txt 2021-03-05 14:58:36.022000000 +0800 +@@ -1275,6 +1275,7 @@ + + g_memmove + g_memdup ++g_memdup2 + + + GMemVTable +diff -Naur a/gio/gdatainputstream.c b/gio/gdatainputstream.c +--- a/gio/gdatainputstream.c 2021-03-06 09:46:03.661000000 +0800 ++++ b/gio/gdatainputstream.c 2021-03-05 15:10:26.335000000 +0800 +@@ -856,7 +856,7 @@ + scan_for_chars (GDataInputStream *stream, + gsize *checked_out, + const char *stop_chars, +- gssize stop_chars_len) ++ gsize stop_chars_len) + { + GBufferedInputStream *bstream; + const char *buffer; +@@ -952,7 +952,7 @@ + gsize checked; + + gchar *stop_chars; +- gssize stop_chars_len; ++ gsize stop_chars_len; + gsize length; + } GDataInputStreamReadData; + +@@ -1078,12 +1078,16 @@ + { + GDataInputStreamReadData *data; + GTask *task; ++ gsize stop_chars_len_unsigned; + + data = g_slice_new0 (GDataInputStreamReadData); +- if (stop_chars_len == -1) +- stop_chars_len = strlen (stop_chars); +- data->stop_chars = g_memdup (stop_chars, stop_chars_len); +- data->stop_chars_len = stop_chars_len; ++ if (stop_chars_len < 0) ++ stop_chars_len_unsigned = strlen (stop_chars); ++ else ++ stop_chars_len_unsigned = (gsize) stop_chars_len; ++ ++ data->stop_chars = g_memdup2 (stop_chars, stop_chars_len_unsigned); ++ data->stop_chars_len = stop_chars_len_unsigned; + data->last_saw_cr = FALSE; + + task = g_task_new (stream, cancellable, callback, user_data); +@@ -1338,17 +1342,20 @@ + gssize found_pos; + gssize res; + char *data_until; ++ gsize stop_chars_len_unsigned; + + g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL); + + if (stop_chars_len < 0) +- stop_chars_len = strlen (stop_chars); ++ stop_chars_len_unsigned = strlen (stop_chars); ++ else ++ stop_chars_len_unsigned = (gsize) stop_chars_len; + + bstream = G_BUFFERED_INPUT_STREAM (stream); + + checked = 0; + +- while ((found_pos = scan_for_chars (stream, &checked, stop_chars, stop_chars_len)) == -1) ++ while ((found_pos = scan_for_chars (stream, &checked, stop_chars, stop_chars_len_unsigned)) == -1) + { + if (g_buffered_input_stream_get_available (bstream) == + g_buffered_input_stream_get_buffer_size (bstream)) +diff -Naur a/gio/gdbusconnection.c b/gio/gdbusconnection.c +--- a/gio/gdbusconnection.c 2021-03-06 09:46:03.663000000 +0800 ++++ b/gio/gdbusconnection.c 2021-03-05 15:14:19.973000000 +0800 +@@ -3997,7 +3997,7 @@ + /* Don't waste memory by copying padding - remember to update this + * when changing struct _GDBusInterfaceVTable in gdbusconnection.h + */ +- return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer)); ++ return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer)); + } + + static void +@@ -4014,7 +4014,7 @@ + /* Don't waste memory by copying padding - remember to update this + * when changing struct _GDBusSubtreeVTable in gdbusconnection.h + */ +- return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer)); ++ return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer)); + } + + static void +diff -Naur a/gio/gdbusinterfaceskeleton.c b/gio/gdbusinterfaceskeleton.c +--- a/gio/gdbusinterfaceskeleton.c 2021-03-06 09:46:03.663000000 +0800 ++++ b/gio/gdbusinterfaceskeleton.c 2021-03-05 15:36:52.369000000 +0800 +@@ -701,7 +701,7 @@ + * properly before building the hooked_vtable, so we create it + * once at the last minute. + */ +- interface_->priv->hooked_vtable = g_memdup (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable)); ++ interface_->priv->hooked_vtable = g_memdup2 (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable)); + interface_->priv->hooked_vtable->method_call = skeleton_intercept_handle_method_call; + } + +diff -Naur a/gio/gfile.c b/gio/gfile.c +--- a/gio/gfile.c 2021-03-06 09:46:03.666000000 +0800 ++++ b/gio/gfile.c 2021-03-05 15:44:25.759000000 +0800 +@@ -7884,7 +7884,7 @@ + g_main_context_invoke_full (g_task_get_context (task), + g_task_get_priority (task), + measure_disk_usage_invoke_progress, +- g_memdup (&progress, sizeof progress), ++ g_memdup2 (&progress, sizeof progress), + g_free); + } + +@@ -7902,7 +7902,7 @@ + data->progress_callback ? measure_disk_usage_progress : NULL, task, + &result.disk_usage, &result.num_dirs, &result.num_files, + &error)) +- g_task_return_pointer (task, g_memdup (&result, sizeof result), g_free); ++ g_task_return_pointer (task, g_memdup2 (&result, sizeof result), g_free); + else + g_task_return_error (task, error); + } +@@ -7926,7 +7926,7 @@ + + task = g_task_new (file, cancellable, callback, user_data); + g_task_set_source_tag (task, g_file_real_measure_disk_usage_async); +- g_task_set_task_data (task, g_memdup (&data, sizeof data), g_free); ++ g_task_set_task_data (task, g_memdup2 (&data, sizeof data), g_free); + g_task_set_priority (task, io_priority); + + g_task_run_in_thread (task, measure_disk_usage_thread); +diff -Naur a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c +--- a/gio/gkeyfilesettingsbackend.c 2021-03-06 09:46:03.670000000 +0800 ++++ b/gio/gkeyfilesettingsbackend.c 2021-03-05 17:24:26.933000000 +0800 +@@ -145,8 +145,8 @@ + gchar **group, + gchar **basename) + { +- gint key_len = strlen (key); +- gint i; ++ gsize key_len = strlen (key); ++ const gchar *last_slash; + + if (key_len < kfsb->prefix_len || + memcmp (key, kfsb->prefix, kfsb->prefix_len) != 0) +@@ -155,38 +155,36 @@ + key_len -= kfsb->prefix_len; + key += kfsb->prefix_len; + +- for (i = key_len; i >= 0; i--) +- if (key[i] == '/') +- break; ++ last_slash = strrchr (key, '/'); + + if (kfsb->root_group) + { + /* if a root_group was specified, make sure the user hasn't given + * a path that ghosts that group name + */ +- if (i == kfsb->root_group_len && memcmp (key, kfsb->root_group, i) == 0) ++ if (last_slash != NULL && (last_slash - key) == kfsb->root_group_len && memcmp (key, kfsb->root_group, last_slash - key) == 0) + return FALSE; + } + else + { + /* if no root_group was given, ensure that the user gave a path */ +- if (i == -1) ++ if (last_slash == NULL) + return FALSE; + } + + if (group) + { +- if (i >= 0) ++ if (last_slash != NULL) + { +- *group = g_memdup (key, i + 1); +- (*group)[i] = '\0'; ++ *group = g_memdup2 (key, (last_slash - key) + 1); ++ (*group)[(last_slash - key)] = '\0'; + } + else + *group = g_strdup (kfsb->root_group); + } + + if (basename) +- *basename = g_memdup (key + i + 1, key_len - i); ++ *basename = g_memdup2 (last_slash + 1, key_len - (last_slash - key)); + + return TRUE; + } +diff -Naur a/gio/gsettingsschema.c b/gio/gsettingsschema.c +--- a/gio/gsettingsschema.c 2021-03-06 09:46:03.675000000 +0800 ++++ b/gio/gsettingsschema.c 2021-03-05 16:08:24.724000000 +0800 +@@ -1058,9 +1058,9 @@ + + if (g_str_has_suffix (key, "/")) + { +- gint length = strlen (key); ++ gsize length = strlen (key); + +- strv[j] = g_memdup (key, length); ++ strv[j] = g_memdup2 (key, length); + strv[j][length - 1] = '\0'; + j++; + } +diff -Naur a/gio/gsocket.c b/gio/gsocket.c +--- a/gio/gsocket.c 2021-03-06 09:46:03.675000000 +0800 ++++ b/gio/gsocket.c 2021-03-05 16:34:42.236000000 +0800 +@@ -174,7 +174,7 @@ + GError **error); + + static GSocketAddress * +-cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len); ++cache_recv_address (GSocket *socket, struct sockaddr *native, size_t native_len); + + static gssize + g_socket_receive_message_with_timeout (GSocket *socket, +@@ -260,7 +260,7 @@ + struct { + GSocketAddress *addr; + struct sockaddr *native; +- gint native_len; ++ gsize native_len; + guint64 last_used; + } recv_addr_cache[RECV_ADDR_CACHE_SIZE]; + }; +@@ -5211,14 +5211,14 @@ + } + + static GSocketAddress * +-cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len) ++cache_recv_address (GSocket *socket, struct sockaddr *native, size_t native_len) + { + GSocketAddress *saddr; + gint i; + guint64 oldest_time = G_MAXUINT64; + gint oldest_index = 0; + +- if (native_len <= 0) ++ if (native_len == 0) + return NULL; + + saddr = NULL; +@@ -5226,7 +5226,7 @@ + { + GSocketAddress *tmp = socket->priv->recv_addr_cache[i].addr; + gpointer tmp_native = socket->priv->recv_addr_cache[i].native; +- gint tmp_native_len = socket->priv->recv_addr_cache[i].native_len; ++ gsize tmp_native_len = socket->priv->recv_addr_cache[i].native_len; + + if (!tmp) + continue; +@@ -5256,7 +5256,7 @@ + g_free (socket->priv->recv_addr_cache[oldest_index].native); + } + +- socket->priv->recv_addr_cache[oldest_index].native = g_memdup (native, native_len); ++ socket->priv->recv_addr_cache[oldest_index].native = g_memdup2 (native, native_len); + socket->priv->recv_addr_cache[oldest_index].native_len = native_len; + socket->priv->recv_addr_cache[oldest_index].addr = g_object_ref (saddr); + socket->priv->recv_addr_cache[oldest_index].last_used = g_get_monotonic_time (); +@@ -5404,6 +5404,9 @@ + /* do it */ + while (1) + { ++ /* addrlen has to be of type int because that’s how WSARecvFrom() is defined */ ++ G_STATIC_ASSERT (sizeof addr <= G_MAXINT); ++ + addrlen = sizeof addr; + if (address) + result = WSARecvFrom (socket->priv->fd, +diff -Naur a/gio/gtlspassword.c b/gio/gtlspassword.c +--- a/gio/gtlspassword.c 2021-03-06 09:46:03.678000000 +0800 ++++ b/gio/gtlspassword.c 2021-03-05 16:36:55.266000000 +0800 +@@ -287,9 +287,14 @@ + g_return_if_fail (G_IS_TLS_PASSWORD (password)); + + if (length < 0) +- length = strlen ((gchar *)value); ++ { ++ /* FIXME: g_tls_password_set_value_full() doesn’t support unsigned gsize */ ++ gsize length_unsigned = strlen ((gchar *) value); ++ g_return_if_fail (length_unsigned > G_MAXSSIZE); ++ length = (gssize) length_unsigned; ++ } + +- g_tls_password_set_value_full (password, g_memdup (value, length), length, g_free); ++ g_tls_password_set_value_full (password, g_memdup2 (value, (gsize) length), length, g_free); + } + + /** +diff -Naur a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c +--- a/gio/gwin32registrykey.c 2021-03-06 09:46:03.680000000 +0800 ++++ b/gio/gwin32registrykey.c 2021-03-05 16:43:04.459000000 +0800 +@@ -125,16 +125,34 @@ + G_WIN32_REGISTRY_UPDATED_PATH = 1, + } GWin32RegistryKeyUpdateFlag; + ++static gsize ++g_utf16_len (const gunichar2 *str) ++{ ++ gsize result; ++ ++ for (result = 0; str[0] != 0; str++, result++) ++ ; ++ ++ return result; ++} ++ + static gunichar2 * +-g_wcsdup (const gunichar2 *str, +- gssize str_size) ++g_wcsdup (const gunichar2 *str, gssize str_len) + { +- if (str_size == -1) +- { +- str_size = wcslen (str) + 1; +- str_size *= sizeof (gunichar2); +- } +- return g_memdup (str, str_size); ++ gsize str_len_unsigned; ++ gsize str_size; ++ ++ g_return_val_if_fail (str != NULL, NULL); ++ ++ if (str_len < 0) ++ str_len_unsigned = g_utf16_len (str); ++ else ++ str_len_unsigned = (gsize) str_len; ++ ++ g_assert (str_len_unsigned <= G_MAXSIZE / sizeof (gunichar2) - 1); ++ str_size = (str_len_unsigned + 1) * sizeof (gunichar2); ++ ++ return g_memdup2 (str, str_size); + } + + /** +@@ -247,7 +265,7 @@ + new_iter->value_name_size = iter->value_name_size; + + if (iter->value_data != NULL) +- new_iter->value_data = g_memdup (iter->value_data, iter->value_data_size); ++ new_iter->value_data = g_memdup2 (iter->value_data, iter->value_data_size); + + new_iter->value_data_size = iter->value_data_size; + +@@ -268,8 +286,8 @@ + new_iter->value_data_expanded_charsize = iter->value_data_expanded_charsize; + + if (iter->value_data_expanded_u8 != NULL) +- new_iter->value_data_expanded_u8 = g_memdup (iter->value_data_expanded_u8, +- iter->value_data_expanded_charsize); ++ new_iter->value_data_expanded_u8 = g_memdup2 (iter->value_data_expanded_u8, ++ iter->value_data_expanded_charsize); + + new_iter->value_data_expanded_u8_size = iter->value_data_expanded_charsize; + +diff -Naur a/gio/tests/async-close-output-stream.c b/gio/tests/async-close-output-stream.c +--- a/gio/tests/async-close-output-stream.c 2021-03-06 09:46:03.682000000 +0800 ++++ b/gio/tests/async-close-output-stream.c 2021-03-05 16:54:17.745000000 +0800 +@@ -147,9 +147,9 @@ + + data->expected_size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (data->data_stream)); + +- g_assert_cmpint (data->expected_size, >, 0); ++ g_assert_cmpuint (data->expected_size, >, 0); + +- data->expected_output = g_memdup (written, (guint)data->expected_size); ++ data->expected_output = g_memdup2 (written, data->expected_size); + + /* then recreate the streams and prepare them for the asynchronous close */ + destroy_streams (data); +diff -Naur a/gio/tests/gdbus-export.c b/gio/tests/gdbus-export.c +--- a/gio/tests/gdbus-export.c 2021-03-06 09:46:03.685000000 +0800 ++++ b/gio/tests/gdbus-export.c 2021-03-05 16:56:17.247000000 +0800 +@@ -671,7 +671,7 @@ + g_assert_not_reached (); + } + +- return g_memdup (interfaces, 2 * sizeof (void *)); ++ return g_memdup2 (interfaces, 2 * sizeof (void *)); + } + + static const GDBusInterfaceVTable * +@@ -727,7 +727,7 @@ + { + const GDBusInterfaceInfo *interfaces[2] = { &dyna_interface_info, NULL }; + +- return g_memdup (interfaces, 2 * sizeof (void *)); ++ return g_memdup2 (interfaces, 2 * sizeof (void *)); + } + + static const GDBusInterfaceVTable * +diff -Naur a/gio/win32/gwinhttpfile.c b/gio/win32/gwinhttpfile.c +--- a/gio/win32/gwinhttpfile.c 2021-03-06 09:46:03.693000000 +0800 ++++ b/gio/win32/gwinhttpfile.c 2021-03-05 16:58:28.076000000 +0800 +@@ -393,10 +393,10 @@ + child = g_object_new (G_TYPE_WINHTTP_FILE, NULL); + child->vfs = winhttp_file->vfs; + child->url = winhttp_file->url; +- child->url.lpszScheme = g_memdup (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2); +- child->url.lpszHostName = g_memdup (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2); +- child->url.lpszUserName = g_memdup (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2); +- child->url.lpszPassword = g_memdup (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2); ++ child->url.lpszScheme = g_memdup2 (winhttp_file->url.lpszScheme, ((gsize) winhttp_file->url.dwSchemeLength + 1) * 2); ++ child->url.lpszHostName = g_memdup2 (winhttp_file->url.lpszHostName, ((gsize) winhttp_file->url.dwHostNameLength + 1) * 2); ++ child->url.lpszUserName = g_memdup2 (winhttp_file->url.lpszUserName, ((gsize) winhttp_file->url.dwUserNameLength + 1) * 2); ++ child->url.lpszPassword = g_memdup2 (winhttp_file->url.lpszPassword, ((gsize) winhttp_file->url.dwPasswordLength + 1) * 2); + child->url.lpszUrlPath = wnew_path; + child->url.dwUrlPathLength = wcslen (wnew_path); + child->url.lpszExtraInfo = NULL; +diff -Naur a/glib/gbytes.c b/glib/gbytes.c +--- a/glib/gbytes.c 2021-03-06 09:46:03.721000000 +0800 ++++ b/glib/gbytes.c 2021-03-05 17:29:25.481000000 +0800 +@@ -95,7 +95,7 @@ + { + g_return_val_if_fail (data != NULL || size == 0, NULL); + +- return g_bytes_new_take (g_memdup (data, size), size); ++ return g_bytes_new_take (g_memdup2 (data, size), size); + } + + /** +@@ -499,7 +499,7 @@ + * Copy: Non g_malloc (or compatible) allocator, or static memory, + * so we have to copy, and then unref. + */ +- result = g_memdup (bytes->data, bytes->size); ++ result = g_memdup2 (bytes->data, bytes->size); + *size = bytes->size; + g_bytes_unref (bytes); + } +diff -Naur a/glib/gdir.c b/glib/gdir.c +--- a/glib/gdir.c 2021-03-06 09:46:03.696000000 +0800 ++++ b/glib/gdir.c 2021-03-06 09:11:06.646000000 +0800 +@@ -112,7 +112,7 @@ + return NULL; + #endif + +- return g_memdup (&dir, sizeof dir); ++ return g_memdup2 (&dir, sizeof dir); + } + + /** +diff -Naur a/glib/ghash.c b/glib/ghash.c +--- a/glib/ghash.c 2021-03-06 09:46:03.697000000 +0800 ++++ b/glib/ghash.c 2021-03-06 09:12:58.243000000 +0800 +@@ -964,7 +964,7 @@ + if (hash_table->have_big_keys) + { + if (key != value) +- hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size); ++ hash_table->values = g_memdup2 (hash_table->keys, sizeof (gpointer) * hash_table->size); + /* Keys and values are both big now, so no need for further checks */ + return; + } +@@ -972,7 +972,7 @@ + { + if (key != value) + { +- hash_table->values = g_memdup (hash_table->keys, sizeof (guint) * hash_table->size); ++ hash_table->values = g_memdup2 (hash_table->keys, sizeof (guint) * hash_table->size); + is_a_set = FALSE; + } + } +@@ -1000,7 +1000,7 @@ + + /* Just split if necessary */ + if (is_a_set && key != value) +- hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size); ++ hash_table->values = g_memdup2 (hash_table->keys, sizeof (gpointer) * hash_table->size); + + #endif + } +diff -Naur a/glib/giochannel.c b/glib/giochannel.c +--- a/glib/giochannel.c 2021-03-06 09:46:03.697000000 +0800 ++++ b/glib/giochannel.c 2021-03-06 09:20:11.237000000 +0800 +@@ -883,16 +883,25 @@ + const gchar *line_term, + gint length) + { ++ guint length_unsigned; ++ + g_return_if_fail (channel != NULL); + g_return_if_fail (line_term == NULL || length != 0); /* Disallow "" */ + + if (line_term == NULL) +- length = 0; +- else if (length < 0) +- length = strlen (line_term); ++ length_unsigned = 0; ++ else if (length >= 0) ++ length_unsigned = (guint) length; ++ else ++ { ++ /* FIXME: We’re constrained by line_term_len being a guint here */ ++ gsize length_size = strlen (line_term); ++ g_return_if_fail (length_size > G_MAXUINT); ++ length_unsigned = (guint) length_size; ++ } + + g_free (channel->line_term); +- channel->line_term = line_term ? g_memdup (line_term, length) : NULL; ++ channel->line_term = line_term ? g_memdup2 (line_term, length_unsigned) : NULL; + channel->line_term_len = length; + } + +diff -Naur a/glib/gstrfuncs.c b/glib/gstrfuncs.c +--- a/glib/gstrfuncs.c 2021-03-06 09:46:03.703000000 +0800 ++++ b/glib/gstrfuncs.c 2021-03-06 09:21:27.836000000 +0800 +@@ -398,6 +398,38 @@ + } + + /** ++ * g_memdup2: ++ * @mem: (nullable): the memory to copy. ++ * @byte_size: the number of bytes to copy. ++ * ++ * Allocates @byte_size bytes of memory, and copies @byte_size bytes into it ++ * from @mem. If @mem is %NULL it returns %NULL. ++ * ++ * This replaces g_memdup(), which was prone to integer overflows when ++ * converting the argument from a #gsize to a #guint. ++ * ++ * Returns: (nullable): a pointer to the newly-allocated copy of the memory, ++ * or %NULL if @mem is %NULL. ++ * Since: 2.68 ++ */ ++gpointer ++g_memdup2 (gconstpointer mem, ++ gsize byte_size) ++{ ++ gpointer new_mem; ++ ++ if (mem && byte_size != 0) ++ { ++ new_mem = g_malloc (byte_size); ++ memcpy (new_mem, mem, byte_size); ++ } ++ else ++ new_mem = NULL; ++ ++ return new_mem; ++} ++ ++/** + * g_strndup: + * @str: the string to duplicate + * @n: the maximum number of bytes to copy from @str +diff -Naur a/glib/gstrfuncs.h b/glib/gstrfuncs.h +--- a/glib/gstrfuncs.h 2021-03-06 09:46:03.703000000 +0800 ++++ b/glib/gstrfuncs.h 2021-03-06 09:23:07.268000000 +0800 +@@ -257,6 +257,10 @@ + gpointer g_memdup (gconstpointer mem, + guint byte_size) G_GNUC_ALLOC_SIZE(2); + ++GLIB_AVAILABLE_IN_ALL ++gpointer g_memdup2 (gconstpointer mem, ++ gsize byte_size) G_GNUC_ALLOC_SIZE(2); ++ + /* NULL terminated string arrays. + * g_strsplit(), g_strsplit_set() split up string into max_tokens tokens + * at delim and return a newly allocated string array. +diff -Naur a/glib/gtestutils.c b/glib/gtestutils.c +--- a/glib/gtestutils.c 2021-03-06 09:46:03.704000000 +0800 ++++ b/glib/gtestutils.c 2021-03-06 09:24:38.454000000 +0800 +@@ -3801,7 +3801,7 @@ + if (p <= tbuffer->data->str + mlength) + { + g_string_erase (tbuffer->data, 0, mlength); +- tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup (&msg, sizeof (msg))); ++ tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup2 (&msg, sizeof (msg))); + return TRUE; + } + +diff -Naur a/glib/gvariant.c b/glib/gvariant.c +--- a/glib/gvariant.c 2021-03-06 09:46:03.709000000 +0800 ++++ b/glib/gvariant.c 2021-03-06 09:26:50.164000000 +0800 +@@ -725,7 +725,7 @@ + g_variant_ref_sink (value); + + return g_variant_new_from_children (G_VARIANT_TYPE_VARIANT, +- g_memdup (&value, sizeof value), ++ g_memdup2 (&value, sizeof value), + 1, g_variant_is_trusted (value)); + } + +@@ -1229,7 +1229,7 @@ + return NULL; + } + +- data = g_memdup (elements, n_elements * element_size); ++ data = g_memdup2 (elements, n_elements * element_size); + value = g_variant_new_from_data (array_type, data, + n_elements * element_size, + FALSE, g_free, data); +@@ -1908,7 +1908,7 @@ + if (length) + *length = size; + +- return g_memdup (original, size + 1); ++ return g_memdup2 (original, size + 1); + } + + /** +diff -Naur a/glib/gvarianttype.c b/glib/gvarianttype.c +--- a/glib/gvarianttype.c 2021-03-06 09:46:03.709000000 +0800 ++++ b/glib/gvarianttype.c 2021-03-06 09:28:03.190000000 +0800 +@@ -1181,7 +1181,7 @@ + g_assert (offset < sizeof buffer); + buffer[offset++] = ')'; + +- return (GVariantType *) g_memdup (buffer, offset); ++ return (GVariantType *) g_memdup2 (buffer, offset); + } + + /** +diff -Naur a/glib/tests/array-test.c b/glib/tests/array-test.c +--- a/glib/tests/array-test.c 2021-03-06 09:46:03.712000000 +0800 ++++ b/glib/tests/array-test.c 2021-03-06 09:28:56.467000000 +0800 +@@ -1616,7 +1616,7 @@ + GByteArray *gbarray; + guint8 *data; + +- data = g_memdup ("woooweeewow", 11); ++ data = g_memdup2 ("woooweeewow", 11); + gbarray = g_byte_array_new_take (data, 11); + g_assert (gbarray->data == data); + g_assert_cmpuint (gbarray->len, ==, 11); +diff -Naur a/glib/tests/option-context.c b/glib/tests/option-context.c +--- a/glib/tests/option-context.c 2021-03-06 09:46:03.719000000 +0800 ++++ b/glib/tests/option-context.c 2021-03-06 09:30:07.022000000 +0800 +@@ -256,7 +256,7 @@ + static char ** + copy_stringv (char **argv, int argc) + { +- return g_memdup (argv, sizeof (char *) * (argc + 1)); ++ return g_memdup2 (argv, sizeof (char *) * (argc + 1)); + } + + static void +@@ -2323,7 +2323,7 @@ + g_option_context_add_group (context, group); + + argv = split_string ("program --test arg1 -f arg2 --group-test arg3 --frob arg4 -z arg5", &argc); +- orig_argv = g_memdup (argv, (argc + 1) * sizeof (char *)); ++ orig_argv = g_memdup2 (argv, (argc + 1) * sizeof (char *)); + + retval = g_option_context_parse (context, &argc, &argv, &error); + +diff -Naur a/glib/tests/strfuncs.c b/glib/tests/strfuncs.c +--- a/glib/tests/strfuncs.c 2021-03-06 09:46:03.720000000 +0800 ++++ b/glib/tests/strfuncs.c 2021-03-06 09:33:09.312000000 +0800 +@@ -219,6 +219,26 @@ + g_free (str_dup); + } + ++/* Testing g_memdup2() function with various positive and negative cases */ ++static void ++test_memdup2 (void) ++{ ++ gchar *str_dup = NULL; ++ const gchar *str = "The quick brown fox jumps over the lazy dog"; ++ ++ /* Testing negative cases */ ++ g_assert_null (g_memdup2 (NULL, 1024)); ++ g_assert_null (g_memdup2 (str, 0)); ++ g_assert_null (g_memdup2 (NULL, 0)); ++ ++ /* Testing normal usage cases */ ++ str_dup = g_memdup2 (str, strlen (str) + 1); ++ g_assert_nonnull (str_dup); ++ g_assert_cmpstr (str, ==, str_dup); ++ ++ g_free (str_dup); ++} ++ + /* Testing g_strpcpy() function with various positive and negative cases */ + static void + test_stpcpy (void) +@@ -2523,6 +2543,7 @@ + g_test_add_func ("/strfuncs/has-prefix", test_has_prefix); + g_test_add_func ("/strfuncs/has-suffix", test_has_suffix); + g_test_add_func ("/strfuncs/memdup", test_memdup); ++ g_test_add_func ("/strfuncs/memdup2", test_memdup2); + g_test_add_func ("/strfuncs/stpcpy", test_stpcpy); + g_test_add_func ("/strfuncs/str_match_string", test_str_match_string); + g_test_add_func ("/strfuncs/str_tokenize_and_fold", test_str_tokenize_and_fold); +diff -Naur a/gobject/gsignal.c b/gobject/gsignal.c +--- a/gobject/gsignal.c 2021-03-06 09:46:03.722000000 +0800 ++++ b/gobject/gsignal.c 2021-03-06 09:36:46.688000000 +0800 +@@ -1730,7 +1730,7 @@ + node->single_va_closure_is_valid = FALSE; + node->flags = signal_flags & G_SIGNAL_FLAGS_MASK; + node->n_params = n_params; +- node->param_types = g_memdup (param_types, sizeof (GType) * n_params); ++ node->param_types = g_memdup2 (param_types, sizeof (GType) * n_params); + node->return_type = return_type; + node->class_closure_bsa = NULL; + if (accumulator) +diff -Naur a/gobject/gtype.c b/gobject/gtype.c +--- a/gobject/gtype.c 2021-03-06 09:46:03.724000000 +0800 ++++ b/gobject/gtype.c 2021-03-06 09:38:47.030000000 +0800 +@@ -1470,7 +1470,7 @@ + iholder->next = iface_node_get_holders_L (iface); + iface_node_set_holders_W (iface, iholder); + iholder->instance_type = NODE_TYPE (node); +- iholder->info = info ? g_memdup (info, sizeof (*info)) : NULL; ++ iholder->info = info ? g_memdup2 (info, sizeof (*info)) : NULL; + iholder->plugin = plugin; + + /* create an iface entry for this type */ +@@ -1731,7 +1731,7 @@ + INVALID_RECURSION ("g_type_plugin_*", iholder->plugin, NODE_NAME (iface)); + + check_interface_info_I (iface, instance_type, &tmp_info); +- iholder->info = g_memdup (&tmp_info, sizeof (tmp_info)); ++ iholder->info = g_memdup2 (&tmp_info, sizeof (tmp_info)); + } + + return iholder; /* we don't modify write lock upon returning NULL */ +@@ -2016,10 +2016,10 @@ + IFaceEntry *pentry = type_lookup_iface_entry_L (pnode, iface); + + if (pentry) +- vtable = g_memdup (pentry->vtable, iface->data->iface.vtable_size); ++ vtable = g_memdup2 (pentry->vtable, iface->data->iface.vtable_size); + } + if (!vtable) +- vtable = g_memdup (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size); ++ vtable = g_memdup2 (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size); + entry->vtable = vtable; + vtable->g_type = NODE_TYPE (iface); + vtable->g_instance_type = NODE_TYPE (node); +diff -Naur a/gobject/gtypemodule.c b/gobject/gtypemodule.c +--- a/gobject/gtypemodule.c 2021-03-06 09:46:03.724000000 +0800 ++++ b/gobject/gtypemodule.c 2021-03-06 09:39:57.337000000 +0800 +@@ -436,7 +436,7 @@ + module_type_info->loaded = TRUE; + module_type_info->info = *type_info; + if (type_info->value_table) +- module_type_info->info.value_table = g_memdup (type_info->value_table, ++ module_type_info->info.value_table = g_memdup2 (type_info->value_table, + sizeof (GTypeValueTable)); + + return module_type_info->type; +diff -Naur a/gobject/tests/param.c b/gobject/tests/param.c +--- a/gobject/tests/param.c 2021-03-06 09:46:03.725000000 +0800 ++++ b/gobject/tests/param.c 2021-03-06 09:40:28.446000000 +0800 +@@ -851,7 +851,7 @@ + test_path = g_strdup_printf ("/param/implement/subprocess/%d-%d-%d-%d", + data.change_this_flag, data.change_this_type, + data.use_this_flag, data.use_this_type); +- test_data = g_memdup (&data, sizeof (TestParamImplementData)); ++ test_data = g_memdup2 (&data, sizeof (TestParamImplementData)); + g_test_add_data_func_full (test_path, test_data, test_param_implement_child, g_free); + g_free (test_path); + } diff --git a/glib2.spec b/glib2.spec index ab844949904f8e052ca924fd05e79cdfc535e4d4..de1063bab36fe1332d1312cbb106bd8d8099559e 100644 --- a/glib2.spec +++ b/glib2.spec @@ -1,6 +1,6 @@ Name: glib2 Version: 2.62.5 -Release: 4 +Release: 6 Summary: The core library that forms the basis for projects such as GTK+ and GNOME License: LGPLv2+ URL: http://www.gtk.org @@ -8,9 +8,33 @@ Source0: http://download.gnome.org/sources/glib/2.62/glib-%{version}.tar. Patch9001: fix-accidentally-delete-temp-file-within-dtrace.patch Patch6000: backport-CVE-2020-35457.patch -Patch6001: backport-CVE-2021-27218.patch - -BuildRequires: chrpath gcc gcc-c++ gettext gtk-doc perl-interpreter +Patch6001: backport-glib-ensure-consistent-abort-on-OOM-with-g-vasprintf-its-callers.patch +Patch6002: backport-gparamspecs-Fix-type-class-leaks-on-error-handling-paths.patch +Patch6003: backport-glocalfileinfo-Fix-minor-leak-on-error-handling-path-for-xattrs.patch +Patch6004: backport-gbookmarkfile-Fix-a-minor-leak-on-an-error-path.patch +Patch6005: backport-gvdb-builder-Initialise-some-memory-to-zero-in-the-bloom-filter.patch +Patch6006: backport-gfileutils-Correct-operator-precedence-to-avoid-undefined-pointer-maths.patch +Patch6007: backport-glib-supp-Suppress-calloc-variant-of-g-get-charset.patch +Patch6008: backport-Fix-giomodule-cache-being-wrongly-considered-stale.patch +Patch6009: backport-glocalfileinfo-Correct-an-off-by-one-error-when-unescaping-hex.patch +Patch6010: backport-portal-Read-flatpak-info-in-thread-safe-fashion.patch +Patch6011: backport-gtimezone-support-footers-in-TZif-files.patch +Patch6012: backport-gtestutils-Fix-a-minor-memory-leak.patch +Patch6013: backport-gthread-Destroy-value-after-replacing-it.patch +Patch6014: backport-gsocketclient-set-IP-BIND-ADDRESS-NO-PORT-if-binding.patch +Patch6015: backport-gsocketclient-emit-RESOLVING-RESOLVED-events-only-once.patch +Patch6016: backport-gsocketclient-Crash-on-error-if-error-is-missing.patch +Patch6017: backport-gsocketclient-return-best-errors-possible.patch +Patch6018: backport-gsignal-Plug-g-signal-connect-object-leak.patch +Patch6019: backport-Fix-the-6-days-until-the-end-of-the-month-bug.patch +Patch6020: backport-gsocketclient-fix-crash-when-async-connectio-step-fails.patch +Patch6021: backport-CVE-2021-27218.patch +Patch6022: backport-CVE-2021-27219.patch + +BuildRequires: chrpath gcc gcc-c++ gettext perl-interpreter +%ifnarch i686 +BUildRequires: gtk-doc +%endif BUildRequires: glibc-devel libattr-devel libselinux-devel meson BuildRequires: systemtap-sdt-devel pkgconfig(libelf) pkgconfig(libffi) BuildRequires: pkgconfig(libpcre) pkgconfig(mount) pkgconfig(zlib) @@ -146,11 +170,14 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || : %doc %{_datadir}/gtk-doc/html/* %changelog -* Mon Mar 1 2021 jinzhimin - 2.62.5-4 -- Type:cve -- Id:CVE-2021-27218 -- SUG:NA -- DESC:fix CVE-2021-27218 +* Sat Mar 06 2021 hanhui - 2.62.5-6 +- fix CVE-2021-27219 + +* Wed Mar 03 2021 jinzhimin - 2.62.5-5 +- fix CVE-2021-27218 + +* Thu Feb 18 2021 jinzhimin - 2.62.5-4 +- round community patches * Sat Feb 27 2021 zhujunhao - 2.62.5-3 - Type:cve