From e23bf51c6a898f5c395ffb388a0287575a3017cb Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 4 Feb 2021 13:30:52 +0000 Subject: [PATCH 01/12] gstrfuncs: Add internal g_memdup2() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will replace the existing `g_memdup()` function for use within GLib. It 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. In GLib 2.68, `g_memdup2()` will be a new public API. In this version for backport to older stable releases, it’s a new `static inline` API in a private header, so that use of `g_memdup()` within GLib can be fixed without adding a new API in a stable release series. Signed-off-by: Philip Withnall Helps: GHSL-2021-045 Helps: #2319 --- docs/reference/glib/meson.build | 1 + glib/gstrfuncsprivate.h | 55 +++++++++++++++++++++++++++++++++ glib/meson.build | 1 + glib/tests/strfuncs.c | 23 ++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 glib/gstrfuncsprivate.h diff --git a/docs/reference/glib/meson.build b/docs/reference/glib/meson.build index f0f915e96..1a3680941 100644 --- a/docs/reference/glib/meson.build +++ b/docs/reference/glib/meson.build @@ -20,6 +20,7 @@ if get_option('gtk_doc') 'gprintfint.h', 'gmirroringtable.h', 'gscripttable.h', + 'gstrfuncsprivate.h', 'glib-mirroring-tab', 'gnulib', 'pcre', diff --git a/glib/gstrfuncsprivate.h b/glib/gstrfuncsprivate.h new file mode 100644 index 000000000..85c88328a --- /dev/null +++ b/glib/gstrfuncsprivate.h @@ -0,0 +1,55 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include +#include + +/* + * 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. + * + * This static inline version is a backport of the new public API from + * GLib 2.68, kept internal to GLib for backport to older stable releases. + * See https://gitlab.gnome.org/GNOME/glib/-/issues/2319. + * + * Returns: (nullable): a pointer to the newly-allocated copy of the memory, + * or %NULL if @mem is %NULL. + * Since: 2.68 + */ +static inline 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; +} diff --git a/glib/meson.build b/glib/meson.build index a2f9da81c..481fd06ff 100644 --- a/glib/meson.build +++ b/glib/meson.build @@ -167,6 +167,7 @@ glib_sources = files( 'gslist.c', 'gstdio.c', 'gstrfuncs.c', + 'gstrfuncsprivate.h', 'gstring.c', 'gstringchunk.c', 'gtestutils.c', diff --git a/glib/tests/strfuncs.c b/glib/tests/strfuncs.c index 7e031bdb1..2aa252946 100644 --- a/glib/tests/strfuncs.c +++ b/glib/tests/strfuncs.c @@ -32,6 +32,8 @@ #include #include "glib.h" +#include "gstrfuncsprivate.h" + #if defined (_MSC_VER) && (_MSC_VER <= 1800) #define isnan(x) _isnan(x) @@ -199,6 +201,26 @@ test_is_to_digit (void) #undef TEST_DIGIT } +/* 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); +} + static void test_strdup (void) { @@ -1726,6 +1748,7 @@ main (int argc, g_test_init (&argc, &argv, NULL); g_test_add_func ("/strfuncs/test-is-to-digit", test_is_to_digit); + g_test_add_func ("/strfuncs/memdup2", test_memdup2); g_test_add_func ("/strfuncs/strdup", test_strdup); g_test_add_func ("/strfuncs/strndup", test_strndup); g_test_add_func ("/strfuncs/strdup-printf", test_strdup_printf); -- 2.31.1