summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <pwithnall@endlessos.org>2021-02-04 13:30:52 +0000
committerSimon McVittie <smcv@collabora.com>2021-03-18 10:25:22 +0000
commit24b944692b55bf8a894a753143f9a510fba7df03 (patch)
tree6bf7ffa653898e225063d7d3e6abd28d6d101b1e
parentc1a66787cbdfc19f1bda8cf899f16d614799a309 (diff)
downloadglib-24b944692b55bf8a894a753143f9a510fba7df03.tar.gz
gstrfuncs: Add internal g_memdup2() function
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 <pwithnall@endlessos.org> Helps: CVE-2021-27219 Helps: GHSL-2021-045 Helps: #2319 (cherry picked from commit 5e5f75a77e399c638be66d74e5daa8caeb433e00)
-rw-r--r--docs/reference/glib/meson.build1
-rw-r--r--glib/gstrfuncsprivate.h55
-rw-r--r--glib/meson.build1
-rw-r--r--glib/tests/strfuncs.c23
4 files changed, 80 insertions, 0 deletions
diff --git a/docs/reference/glib/meson.build b/docs/reference/glib/meson.build
index f14824bff..f0b0cb526 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <string.h>
+
+/*
+ * 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 6fc56da7c..dcbd20e34 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -182,6 +182,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 d974ad436..1111226de 100644
--- a/glib/tests/strfuncs.c
+++ b/glib/tests/strfuncs.c
@@ -32,6 +32,8 @@
#include <string.h>
#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)
{
@@ -1731,6 +1753,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);