summaryrefslogtreecommitdiffstats
path: root/meta
diff options
context:
space:
mode:
authorAnatol Belski <anbelski@linux.microsoft.com>2021-03-15 13:29:42 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2021-03-28 22:31:55 +0100
commita633251fc8b2e09959f98bcca037d77d8ed3105d (patch)
tree4cacde467886444d16e0c0c1fc1cabb26628edd1 /meta
parent9b9bcb844399310905c6e635390fc4c46f1dce01 (diff)
downloadpoky-a633251fc8b2e09959f98bcca037d77d8ed3105d.tar.gz
glib-2.0: Fix CVE-2021-27219
The upstream patches are only in glib >= 2.66.6 and >= 2.67.3 and won't be backported. This patch is developed based on the upstream patch set and consulting teh backports recently made by Ubuntu for the 2.64.6 series. (From OE-Core rev: 513d2a82cc9574983d017a2c0b2de87e181befa5) Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com> Signed-off-by: Anuj Mittal <anuj.mittal@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219.patch1444
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0_2.64.5.bb1
2 files changed, 1445 insertions, 0 deletions
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219.patch
new file mode 100644
index 0000000000..a4ec01134a
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219.patch
@@ -0,0 +1,1444 @@
1commit b70039028b4a39ea071f6ed368a58ad5b5b90ba3
2Author: Anatol Belski <anbelski@microsoft.com>
3Date: Sun Mar 14 17:51:53 2021 +0000
4
5 backport: 2.64.5_CVE-2021-27219
6
7CVE: CVE-2021-27219
8Upstream-Status: Backport
9[https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1926]
10
11Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
12
13diff --git a/docs/reference/glib/meson.build b/docs/reference/glib/meson.build
14index 62d95f78d..7eebb04ac 100644
15--- a/docs/reference/glib/meson.build
16+++ b/docs/reference/glib/meson.build
17@@ -22,6 +22,7 @@ if get_option('gtk_doc')
18 'gprintfint.h',
19 'gmirroringtable.h',
20 'gscripttable.h',
21+ 'gstrfuncsprivate.h',
22 'glib-mirroring-tab',
23 'gnulib',
24 'pcre',
25diff --git a/gio/gdatainputstream.c b/gio/gdatainputstream.c
26index 2e7750cb5..2cdcbda19 100644
27--- a/gio/gdatainputstream.c
28+++ b/gio/gdatainputstream.c
29@@ -27,6 +27,7 @@
30 #include "gioenumtypes.h"
31 #include "gioerror.h"
32 #include "glibintl.h"
33+#include "gstrfuncsprivate.h"
34
35 #include <string.h>
36
37@@ -856,7 +857,7 @@ static gssize
38 scan_for_chars (GDataInputStream *stream,
39 gsize *checked_out,
40 const char *stop_chars,
41- gssize stop_chars_len)
42+ gsize stop_chars_len)
43 {
44 GBufferedInputStream *bstream;
45 const char *buffer;
46@@ -952,7 +953,7 @@ typedef struct
47 gsize checked;
48
49 gchar *stop_chars;
50- gssize stop_chars_len;
51+ gsize stop_chars_len;
52 gsize length;
53 } GDataInputStreamReadData;
54
55@@ -1078,12 +1079,17 @@ g_data_input_stream_read_async (GDataInputStream *stream,
56 {
57 GDataInputStreamReadData *data;
58 GTask *task;
59+ gsize stop_chars_len_unsigned;
60
61 data = g_slice_new0 (GDataInputStreamReadData);
62- if (stop_chars_len == -1)
63- stop_chars_len = strlen (stop_chars);
64- data->stop_chars = g_memdup (stop_chars, stop_chars_len);
65- data->stop_chars_len = stop_chars_len;
66+
67+ if (stop_chars_len < 0)
68+ stop_chars_len_unsigned = strlen (stop_chars);
69+ else
70+ stop_chars_len_unsigned = (gsize) stop_chars_len;
71+
72+ data->stop_chars = g_memdup2 (stop_chars, stop_chars_len_unsigned);
73+ data->stop_chars_len = stop_chars_len_unsigned;
74 data->last_saw_cr = FALSE;
75
76 task = g_task_new (stream, cancellable, callback, user_data);
77@@ -1338,17 +1344,20 @@ g_data_input_stream_read_upto (GDataInputStream *stream,
78 gssize found_pos;
79 gssize res;
80 char *data_until;
81+ gsize stop_chars_len_unsigned;
82
83 g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
84
85 if (stop_chars_len < 0)
86- stop_chars_len = strlen (stop_chars);
87+ stop_chars_len_unsigned = strlen (stop_chars);
88+ else
89+ stop_chars_len_unsigned = (gsize) stop_chars_len;
90
91 bstream = G_BUFFERED_INPUT_STREAM (stream);
92
93 checked = 0;
94
95- while ((found_pos = scan_for_chars (stream, &checked, stop_chars, stop_chars_len)) == -1)
96+ while ((found_pos = scan_for_chars (stream, &checked, stop_chars, stop_chars_len_unsigned)) == -1)
97 {
98 if (g_buffered_input_stream_get_available (bstream) ==
99 g_buffered_input_stream_get_buffer_size (bstream))
100diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
101index 1a4dae3bd..9de661bde 100644
102--- a/gio/gdbusconnection.c
103+++ b/gio/gdbusconnection.c
104@@ -110,6 +110,7 @@
105 #include "gasyncinitable.h"
106 #include "giostream.h"
107 #include "gasyncresult.h"
108+#include "gstrfuncsprivate.h"
109 #include "gtask.h"
110 #include "gmarshal-internal.h"
111
112@@ -4007,7 +4008,7 @@ _g_dbus_interface_vtable_copy (const GDBusInterfaceVTable *vtable)
113 /* Don't waste memory by copying padding - remember to update this
114 * when changing struct _GDBusInterfaceVTable in gdbusconnection.h
115 */
116- return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer));
117+ return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
118 }
119
120 static void
121@@ -4024,7 +4025,7 @@ _g_dbus_subtree_vtable_copy (const GDBusSubtreeVTable *vtable)
122 /* Don't waste memory by copying padding - remember to update this
123 * when changing struct _GDBusSubtreeVTable in gdbusconnection.h
124 */
125- return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer));
126+ return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
127 }
128
129 static void
130diff --git a/gio/gdbusinterfaceskeleton.c b/gio/gdbusinterfaceskeleton.c
131index 4a06516c1..4a4b719a5 100644
132--- a/gio/gdbusinterfaceskeleton.c
133+++ b/gio/gdbusinterfaceskeleton.c
134@@ -28,6 +28,7 @@
135 #include "gdbusmethodinvocation.h"
136 #include "gdbusconnection.h"
137 #include "gmarshal-internal.h"
138+#include "gstrfuncsprivate.h"
139 #include "gtask.h"
140 #include "gioerror.h"
141
142@@ -701,7 +702,7 @@ add_connection_locked (GDBusInterfaceSkeleton *interface_,
143 * properly before building the hooked_vtable, so we create it
144 * once at the last minute.
145 */
146- interface_->priv->hooked_vtable = g_memdup (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
147+ interface_->priv->hooked_vtable = g_memdup2 (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
148 interface_->priv->hooked_vtable->method_call = skeleton_intercept_handle_method_call;
149 }
150
151diff --git a/gio/gfile.c b/gio/gfile.c
152index a2ded14ea..25930435f 100644
153--- a/gio/gfile.c
154+++ b/gio/gfile.c
155@@ -60,6 +60,7 @@
156 #include "gasyncresult.h"
157 #include "gioerror.h"
158 #include "glibintl.h"
159+#include "gstrfuncsprivate.h"
160
161
162 /**
163@@ -7854,7 +7855,7 @@ measure_disk_usage_progress (gboolean reporting,
164 g_main_context_invoke_full (g_task_get_context (task),
165 g_task_get_priority (task),
166 measure_disk_usage_invoke_progress,
167- g_memdup (&progress, sizeof progress),
168+ g_memdup2 (&progress, sizeof progress),
169 g_free);
170 }
171
172@@ -7872,7 +7873,7 @@ measure_disk_usage_thread (GTask *task,
173 data->progress_callback ? measure_disk_usage_progress : NULL, task,
174 &result.disk_usage, &result.num_dirs, &result.num_files,
175 &error))
176- g_task_return_pointer (task, g_memdup (&result, sizeof result), g_free);
177+ g_task_return_pointer (task, g_memdup2 (&result, sizeof result), g_free);
178 else
179 g_task_return_error (task, error);
180 }
181@@ -7896,7 +7897,7 @@ g_file_real_measure_disk_usage_async (GFile *file,
182
183 task = g_task_new (file, cancellable, callback, user_data);
184 g_task_set_source_tag (task, g_file_real_measure_disk_usage_async);
185- g_task_set_task_data (task, g_memdup (&data, sizeof data), g_free);
186+ g_task_set_task_data (task, g_memdup2 (&data, sizeof data), g_free);
187 g_task_set_priority (task, io_priority);
188
189 g_task_run_in_thread (task, measure_disk_usage_thread);
190diff --git a/gio/giowin32-private.c b/gio/giowin32-private.c
191index 7120ae0ea..47e840805 100644
192--- a/gio/giowin32-private.c
193+++ b/gio/giowin32-private.c
194@@ -16,11 +16,12 @@
195 * along with this library; if not, see <http://www.gnu.org/licenses/>.
196 */
197
198+#include "gstrfuncsprivate.h"
199
200-static gssize
201+static gsize
202 g_utf16_len (const gunichar2 *str)
203 {
204- gssize result;
205+ gsize result;
206
207 for (result = 0; str[0] != 0; str++, result++)
208 ;
209@@ -31,17 +32,20 @@ g_utf16_len (const gunichar2 *str)
210 static gunichar2 *
211 g_wcsdup (const gunichar2 *str, gssize str_len)
212 {
213- gssize str_size;
214+ gsize str_len_unsigned;
215+ gsize str_size;
216
217 g_return_val_if_fail (str != NULL, NULL);
218
219- if (str_len == -1)
220- str_len = g_utf16_len (str);
221+ if (str_len < 0)
222+ str_len_unsigned = g_utf16_len (str);
223+ else
224+ str_len_unsigned = (gsize) str_len;
225
226- g_assert (str_len <= G_MAXSIZE / sizeof (gunichar2) - 1);
227- str_size = (str_len + 1) * sizeof (gunichar2);
228+ g_assert (str_len_unsigned <= G_MAXSIZE / sizeof (gunichar2) - 1);
229+ str_size = (str_len_unsigned + 1) * sizeof (gunichar2);
230
231- return g_memdup (str, str_size);
232+ return g_memdup2 (str, str_size);
233 }
234
235 static const gunichar2 *
236diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
237index cd5765afd..de216e615 100644
238--- a/gio/gkeyfilesettingsbackend.c
239+++ b/gio/gkeyfilesettingsbackend.c
240@@ -33,6 +33,7 @@
241 #include "gfilemonitor.h"
242 #include "gsimplepermission.h"
243 #include "gsettingsbackendinternal.h"
244+#include "gstrfuncsprivate.h"
245 #include "giomodule-priv.h"
246 #include "gportalsupport.h"
247
248@@ -145,8 +146,8 @@ convert_path (GKeyfileSettingsBackend *kfsb,
249 gchar **group,
250 gchar **basename)
251 {
252- gint key_len = strlen (key);
253- gint i;
254+ gsize key_len = strlen (key);
255+ const gchar *last_slash;
256
257 if (key_len < kfsb->prefix_len ||
258 memcmp (key, kfsb->prefix, kfsb->prefix_len) != 0)
259@@ -155,38 +156,48 @@ convert_path (GKeyfileSettingsBackend *kfsb,
260 key_len -= kfsb->prefix_len;
261 key += kfsb->prefix_len;
262
263- for (i = key_len; i >= 0; i--)
264- if (key[i] == '/')
265- break;
266+ last_slash = strrchr (key, '/');
267+
268+ /* Disallow empty group names or key names */
269+ if (key_len == 0 ||
270+ (last_slash != NULL &&
271+ (*(last_slash + 1) == '\0' ||
272+ last_slash == key)))
273+ return FALSE;
274
275 if (kfsb->root_group)
276 {
277 /* if a root_group was specified, make sure the user hasn't given
278 * a path that ghosts that group name
279 */
280- if (i == kfsb->root_group_len && memcmp (key, kfsb->root_group, i) == 0)
281+ if (last_slash != NULL && (last_slash - key) == kfsb->root_group_len && memcmp (key, kfsb->root_group, last_slash - key) == 0)
282 return FALSE;
283 }
284 else
285 {
286 /* if no root_group was given, ensure that the user gave a path */
287- if (i == -1)
288+ if (last_slash == NULL)
289 return FALSE;
290 }
291
292 if (group)
293 {
294- if (i >= 0)
295+ if (last_slash != NULL)
296 {
297- *group = g_memdup (key, i + 1);
298- (*group)[i] = '\0';
299+ *group = g_memdup2 (key, (last_slash - key) + 1);
300+ (*group)[(last_slash - key)] = '\0';
301 }
302 else
303 *group = g_strdup (kfsb->root_group);
304 }
305
306 if (basename)
307- *basename = g_memdup (key + i + 1, key_len - i);
308+ {
309+ if (last_slash != NULL)
310+ *basename = g_memdup2 (last_slash + 1, key_len - (last_slash - key));
311+ else
312+ *basename = g_strdup (key);
313+ }
314
315 return TRUE;
316 }
317diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
318index 0b94f76f6..eb5a3b846 100644
319--- a/gio/gsettingsschema.c
320+++ b/gio/gsettingsschema.c
321@@ -20,6 +20,7 @@
322
323 #include "gsettingsschema-internal.h"
324 #include "gsettings.h"
325+#include "gstrfuncsprivate.h"
326
327 #include "gvdb/gvdb-reader.h"
328 #include "strinfo.c"
329@@ -1067,9 +1068,9 @@ g_settings_schema_list_children (GSettingsSchema *schema)
330
331 if (g_str_has_suffix (key, "/"))
332 {
333- gint length = strlen (key);
334+ gsize length = strlen (key);
335
336- strv[j] = g_memdup (key, length);
337+ strv[j] = g_memdup2 (key, length);
338 strv[j][length - 1] = '\0';
339 j++;
340 }
341diff --git a/gio/gsocket.c b/gio/gsocket.c
342index 2a15bdd22..554af026b 100644
343--- a/gio/gsocket.c
344+++ b/gio/gsocket.c
345@@ -75,6 +75,7 @@
346 #include "gcredentialsprivate.h"
347 #include "glibintl.h"
348 #include "gioprivate.h"
349+#include "gstrfuncsprivate.h"
350
351 #ifdef G_OS_WIN32
352 /* For Windows XP runtime compatibility, but use the system's if_nametoindex() if available */
353@@ -174,7 +175,7 @@ static gboolean g_socket_datagram_based_condition_wait (GDatagramBased
354 GError **error);
355
356 static GSocketAddress *
357-cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len);
358+cache_recv_address (GSocket *socket, struct sockaddr *native, size_t native_len);
359
360 static gssize
361 g_socket_receive_message_with_timeout (GSocket *socket,
362@@ -260,7 +261,7 @@ struct _GSocketPrivate
363 struct {
364 GSocketAddress *addr;
365 struct sockaddr *native;
366- gint native_len;
367+ gsize native_len;
368 guint64 last_used;
369 } recv_addr_cache[RECV_ADDR_CACHE_SIZE];
370 };
371@@ -5259,14 +5260,14 @@ g_socket_send_messages_with_timeout (GSocket *socket,
372 }
373
374 static GSocketAddress *
375-cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len)
376+cache_recv_address (GSocket *socket, struct sockaddr *native, size_t native_len)
377 {
378 GSocketAddress *saddr;
379 gint i;
380 guint64 oldest_time = G_MAXUINT64;
381 gint oldest_index = 0;
382
383- if (native_len <= 0)
384+ if (native_len == 0)
385 return NULL;
386
387 saddr = NULL;
388@@ -5274,7 +5275,7 @@ cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len)
389 {
390 GSocketAddress *tmp = socket->priv->recv_addr_cache[i].addr;
391 gpointer tmp_native = socket->priv->recv_addr_cache[i].native;
392- gint tmp_native_len = socket->priv->recv_addr_cache[i].native_len;
393+ gsize tmp_native_len = socket->priv->recv_addr_cache[i].native_len;
394
395 if (!tmp)
396 continue;
397@@ -5304,7 +5305,7 @@ cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len)
398 g_free (socket->priv->recv_addr_cache[oldest_index].native);
399 }
400
401- socket->priv->recv_addr_cache[oldest_index].native = g_memdup (native, native_len);
402+ socket->priv->recv_addr_cache[oldest_index].native = g_memdup2 (native, native_len);
403 socket->priv->recv_addr_cache[oldest_index].native_len = native_len;
404 socket->priv->recv_addr_cache[oldest_index].addr = g_object_ref (saddr);
405 socket->priv->recv_addr_cache[oldest_index].last_used = g_get_monotonic_time ();
406@@ -5452,6 +5453,9 @@ g_socket_receive_message_with_timeout (GSocket *socket,
407 /* do it */
408 while (1)
409 {
410+ /* addrlen has to be of type int because that’s how WSARecvFrom() is defined */
411+ G_STATIC_ASSERT (sizeof addr <= G_MAXINT);
412+
413 addrlen = sizeof addr;
414 if (address)
415 result = WSARecvFrom (socket->priv->fd,
416diff --git a/gio/gtlspassword.c b/gio/gtlspassword.c
417index 1e437a7b6..bd86a6dfe 100644
418--- a/gio/gtlspassword.c
419+++ b/gio/gtlspassword.c
420@@ -23,6 +23,7 @@
421 #include "glibintl.h"
422
423 #include "gioenumtypes.h"
424+#include "gstrfuncsprivate.h"
425 #include "gtlspassword.h"
426
427 #include <string.h>
428@@ -287,9 +288,14 @@ g_tls_password_set_value (GTlsPassword *password,
429 g_return_if_fail (G_IS_TLS_PASSWORD (password));
430
431 if (length < 0)
432- length = strlen ((gchar *)value);
433+ {
434+ /* FIXME: g_tls_password_set_value_full() doesn’t support unsigned gsize */
435+ gsize length_unsigned = strlen ((gchar *) value);
436+ g_return_if_fail (length_unsigned <= G_MAXSSIZE);
437+ length = (gssize) length_unsigned;
438+ }
439
440- g_tls_password_set_value_full (password, g_memdup (value, length), length, g_free);
441+ g_tls_password_set_value_full (password, g_memdup2 (value, (gsize) length), length, g_free);
442 }
443
444 /**
445diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c
446index aa7819294..efb9ae713 100644
447--- a/gio/gwin32registrykey.c
448+++ b/gio/gwin32registrykey.c
449@@ -28,6 +28,8 @@
450 #include <ntstatus.h>
451 #include <winternl.h>
452
453+#include "gstrfuncsprivate.h"
454+
455 #ifndef _WDMDDK_
456 typedef enum _KEY_INFORMATION_CLASS {
457 KeyBasicInformation,
458@@ -125,16 +127,34 @@ typedef enum
459 G_WIN32_REGISTRY_UPDATED_PATH = 1,
460 } GWin32RegistryKeyUpdateFlag;
461
462+static gsize
463+g_utf16_len (const gunichar2 *str)
464+{
465+ gsize result;
466+
467+ for (result = 0; str[0] != 0; str++, result++)
468+ ;
469+
470+ return result;
471+}
472+
473 static gunichar2 *
474-g_wcsdup (const gunichar2 *str,
475- gssize str_size)
476+g_wcsdup (const gunichar2 *str, gssize str_len)
477 {
478- if (str_size == -1)
479- {
480- str_size = wcslen (str) + 1;
481- str_size *= sizeof (gunichar2);
482- }
483- return g_memdup (str, str_size);
484+ gsize str_len_unsigned;
485+ gsize str_size;
486+
487+ g_return_val_if_fail (str != NULL, NULL);
488+
489+ if (str_len < 0)
490+ str_len_unsigned = g_utf16_len (str);
491+ else
492+ str_len_unsigned = (gsize) str_len;
493+
494+ g_assert (str_len_unsigned <= G_MAXSIZE / sizeof (gunichar2) - 1);
495+ str_size = (str_len_unsigned + 1) * sizeof (gunichar2);
496+
497+ return g_memdup2 (str, str_size);
498 }
499
500 /**
501@@ -247,7 +267,7 @@ g_win32_registry_value_iter_copy (const GWin32RegistryValueIter *iter)
502 new_iter->value_name_size = iter->value_name_size;
503
504 if (iter->value_data != NULL)
505- new_iter->value_data = g_memdup (iter->value_data, iter->value_data_size);
506+ new_iter->value_data = g_memdup2 (iter->value_data, iter->value_data_size);
507
508 new_iter->value_data_size = iter->value_data_size;
509
510@@ -268,8 +288,8 @@ g_win32_registry_value_iter_copy (const GWin32RegistryValueIter *iter)
511 new_iter->value_data_expanded_charsize = iter->value_data_expanded_charsize;
512
513 if (iter->value_data_expanded_u8 != NULL)
514- new_iter->value_data_expanded_u8 = g_memdup (iter->value_data_expanded_u8,
515- iter->value_data_expanded_charsize);
516+ new_iter->value_data_expanded_u8 = g_memdup2 (iter->value_data_expanded_u8,
517+ iter->value_data_expanded_charsize);
518
519 new_iter->value_data_expanded_u8_size = iter->value_data_expanded_charsize;
520
521diff --git a/gio/tests/async-close-output-stream.c b/gio/tests/async-close-output-stream.c
522index 5f6620275..d3f97a119 100644
523--- a/gio/tests/async-close-output-stream.c
524+++ b/gio/tests/async-close-output-stream.c
525@@ -24,6 +24,8 @@
526 #include <stdlib.h>
527 #include <string.h>
528
529+#include "gstrfuncsprivate.h"
530+
531 #define DATA_TO_WRITE "Hello world\n"
532
533 typedef struct
534@@ -147,9 +149,9 @@ prepare_data (SetupData *data,
535
536 data->expected_size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (data->data_stream));
537
538- g_assert_cmpint (data->expected_size, >, 0);
539+ g_assert_cmpuint (data->expected_size, >, 0);
540
541- data->expected_output = g_memdup (written, (guint)data->expected_size);
542+ data->expected_output = g_memdup2 (written, data->expected_size);
543
544 /* then recreate the streams and prepare them for the asynchronous close */
545 destroy_streams (data);
546diff --git a/gio/tests/gdbus-export.c b/gio/tests/gdbus-export.c
547index fda654c44..10dd6d82f 100644
548--- a/gio/tests/gdbus-export.c
549+++ b/gio/tests/gdbus-export.c
550@@ -23,6 +23,7 @@
551 #include <string.h>
552
553 #include "gdbus-tests.h"
554+#include "gstrfuncsprivate.h"
555
556 /* all tests rely on a shared mainloop */
557 static GMainLoop *loop = NULL;
558@@ -671,7 +672,7 @@ subtree_introspect (GDBusConnection *connection,
559 g_assert_not_reached ();
560 }
561
562- return g_memdup (interfaces, 2 * sizeof (void *));
563+ return g_memdup2 (interfaces, 2 * sizeof (void *));
564 }
565
566 static const GDBusInterfaceVTable *
567@@ -727,7 +728,7 @@ dynamic_subtree_introspect (GDBusConnection *connection,
568 {
569 const GDBusInterfaceInfo *interfaces[2] = { &dyna_interface_info, NULL };
570
571- return g_memdup (interfaces, 2 * sizeof (void *));
572+ return g_memdup2 (interfaces, 2 * sizeof (void *));
573 }
574
575 static const GDBusInterfaceVTable *
576diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c
577index baadca8f5..afe594a23 100644
578--- a/gio/tests/gsettings.c
579+++ b/gio/tests/gsettings.c
580@@ -1,3 +1,4 @@
581+#include <errno.h>
582 #include <stdlib.h>
583 #include <locale.h>
584 #include <libintl.h>
585@@ -1740,6 +1741,14 @@ key_changed_cb (GSettings *settings, const gchar *key, gpointer data)
586 (*b) = TRUE;
587 }
588
589+typedef struct
590+{
591+ const gchar *path;
592+ const gchar *root_group;
593+ const gchar *keyfile_group;
594+ const gchar *root_path;
595+} KeyfileTestData;
596+
597 /*
598 * Test that using a keyfile works
599 */
600@@ -1834,7 +1843,11 @@ test_keyfile (Fixture *fixture,
601 g_free (str);
602
603 g_settings_set (settings, "farewell", "s", "cheerio");
604-
605+
606+ /* Check that empty keys/groups are not allowed. */
607+ g_assert_false (g_settings_is_writable (settings, ""));
608+ g_assert_false (g_settings_is_writable (settings, "/"));
609+
610 /* When executing as root, changing the mode of the keyfile will have
611 * no effect on the writability of the settings.
612 */
613@@ -1866,6 +1879,149 @@ test_keyfile (Fixture *fixture,
614 g_free (keyfile_path);
615 }
616
617+/*
618+ * Test that using a keyfile works with a schema with no path set.
619+ */
620+static void
621+test_keyfile_no_path (Fixture *fixture,
622+ gconstpointer user_data)
623+{
624+ const KeyfileTestData *test_data = user_data;
625+ GSettingsBackend *kf_backend;
626+ GSettings *settings;
627+ GKeyFile *keyfile;
628+ gboolean writable;
629+ gchar *key = NULL;
630+ GError *error = NULL;
631+ gchar *keyfile_path = NULL, *store_path = NULL;
632+
633+ keyfile_path = g_build_filename (fixture->tmp_dir, "keyfile", NULL);
634+ store_path = g_build_filename (keyfile_path, "gsettings.store", NULL);
635+ kf_backend = g_keyfile_settings_backend_new (store_path, test_data->root_path, test_data->root_group);
636+ settings = g_settings_new_with_backend_and_path ("org.gtk.test.no-path", kf_backend, test_data->path);
637+ g_object_unref (kf_backend);
638+
639+ g_settings_reset (settings, "test-boolean");
640+ g_assert_true (g_settings_get_boolean (settings, "test-boolean"));
641+
642+ writable = g_settings_is_writable (settings, "test-boolean");
643+ g_assert_true (writable);
644+ g_settings_set (settings, "test-boolean", "b", FALSE);
645+
646+ g_assert_false (g_settings_get_boolean (settings, "test-boolean"));
647+
648+ g_settings_delay (settings);
649+ g_settings_set (settings, "test-boolean", "b", TRUE);
650+ g_settings_apply (settings);
651+
652+ keyfile = g_key_file_new ();
653+ g_assert_true (g_key_file_load_from_file (keyfile, store_path, 0, NULL));
654+
655+ g_assert_true (g_key_file_get_boolean (keyfile, test_data->keyfile_group, "test-boolean", NULL));
656+
657+ g_key_file_free (keyfile);
658+
659+ g_settings_reset (settings, "test-boolean");
660+ g_settings_apply (settings);
661+ keyfile = g_key_file_new ();
662+ g_assert_true (g_key_file_load_from_file (keyfile, store_path, 0, NULL));
663+
664+ g_assert_false (g_key_file_get_string (keyfile, test_data->keyfile_group, "test-boolean", &error));
665+ g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND);
666+ g_clear_error (&error);
667+
668+ /* Check that empty keys/groups are not allowed. */
669+ g_assert_false (g_settings_is_writable (settings, ""));
670+ g_assert_false (g_settings_is_writable (settings, "/"));
671+
672+ /* Keys which ghost the root group name are not allowed. This can only be
673+ * tested when the path is `/` as otherwise it acts as a prefix and prevents
674+ * any ghosting. */
675+ if (g_str_equal (test_data->path, "/"))
676+ {
677+ key = g_strdup_printf ("%s/%s", test_data->root_group, "");
678+ g_assert_false (g_settings_is_writable (settings, key));
679+ g_free (key);
680+
681+ key = g_strdup_printf ("%s/%s", test_data->root_group, "/");
682+ g_assert_false (g_settings_is_writable (settings, key));
683+ g_free (key);
684+
685+ key = g_strdup_printf ("%s/%s", test_data->root_group, "test-boolean");
686+ g_assert_false (g_settings_is_writable (settings, key));
687+ g_free (key);
688+ }
689+
690+ g_key_file_free (keyfile);
691+ g_object_unref (settings);
692+
693+ /* Clean up the temporary directory. */
694+ g_assert_cmpint (g_chmod (keyfile_path, 0777) == 0 ? 0 : errno, ==, 0);
695+ g_assert_cmpint (g_remove (store_path) == 0 ? 0 : errno, ==, 0);
696+ g_assert_cmpint (g_rmdir (keyfile_path) == 0 ? 0 : errno, ==, 0);
697+ g_free (store_path);
698+ g_free (keyfile_path);
699+}
700+
701+/*
702+ * Test that a keyfile rejects writes to keys outside its root path.
703+ */
704+static void
705+test_keyfile_outside_root_path (Fixture *fixture,
706+ gconstpointer user_data)
707+{
708+ GSettingsBackend *kf_backend;
709+ GSettings *settings;
710+ gchar *keyfile_path = NULL, *store_path = NULL;
711+
712+ keyfile_path = g_build_filename (fixture->tmp_dir, "keyfile", NULL);
713+ store_path = g_build_filename (keyfile_path, "gsettings.store", NULL);
714+ kf_backend = g_keyfile_settings_backend_new (store_path, "/tests/basic-types/", "root");
715+ settings = g_settings_new_with_backend_and_path ("org.gtk.test.no-path", kf_backend, "/tests/");
716+ g_object_unref (kf_backend);
717+
718+ g_assert_false (g_settings_is_writable (settings, "test-boolean"));
719+
720+ g_object_unref (settings);
721+
722+ /* Clean up the temporary directory. The keyfile probably doesn’t exist, so
723+ * don’t error on failure. */
724+ g_remove (store_path);
725+ g_assert_cmpint (g_rmdir (keyfile_path) == 0 ? 0 : errno, ==, 0);
726+ g_free (store_path);
727+ g_free (keyfile_path);
728+}
729+
730+/*
731+ * Test that a keyfile rejects writes to keys in the root if no root group is set.
732+ */
733+static void
734+test_keyfile_no_root_group (Fixture *fixture,
735+ gconstpointer user_data)
736+{
737+ GSettingsBackend *kf_backend;
738+ GSettings *settings;
739+ gchar *keyfile_path = NULL, *store_path = NULL;
740+
741+ keyfile_path = g_build_filename (fixture->tmp_dir, "keyfile", NULL);
742+ store_path = g_build_filename (keyfile_path, "gsettings.store", NULL);
743+ kf_backend = g_keyfile_settings_backend_new (store_path, "/", NULL);
744+ settings = g_settings_new_with_backend_and_path ("org.gtk.test.no-path", kf_backend, "/");
745+ g_object_unref (kf_backend);
746+
747+ g_assert_false (g_settings_is_writable (settings, "test-boolean"));
748+ g_assert_true (g_settings_is_writable (settings, "child/test-boolean"));
749+
750+ g_object_unref (settings);
751+
752+ /* Clean up the temporary directory. The keyfile probably doesn’t exist, so
753+ * don’t error on failure. */
754+ g_remove (store_path);
755+ g_assert_cmpint (g_rmdir (keyfile_path) == 0 ? 0 : errno, ==, 0);
756+ g_free (store_path);
757+ g_free (keyfile_path);
758+}
759+
760 /* Test that getting child schemas works
761 */
762 static void
763@@ -2844,6 +3000,14 @@ main (int argc, char *argv[])
764 gchar *override_text;
765 gchar *enums;
766 gint result;
767+ const KeyfileTestData keyfile_test_data_explicit_path = { "/tests/", "root", "tests", "/" };
768+ const KeyfileTestData keyfile_test_data_empty_path = { "/", "root", "root", "/" };
769+ const KeyfileTestData keyfile_test_data_long_path = {
770+ "/tests/path/is/very/long/and/this/makes/some/comparisons/take/a/different/branch/",
771+ "root",
772+ "tests/path/is/very/long/and/this/makes/some/comparisons/take/a/different/branch",
773+ "/"
774+ };
775
776 /* Meson build sets this */
777 #ifdef TEST_LOCALE_PATH
778@@ -2967,6 +3131,11 @@ main (int argc, char *argv[])
779 }
780
781 g_test_add ("/gsettings/keyfile", Fixture, NULL, setup, test_keyfile, teardown);
782+ g_test_add ("/gsettings/keyfile/explicit-path", Fixture, &keyfile_test_data_explicit_path, setup, test_keyfile_no_path, teardown);
783+ g_test_add ("/gsettings/keyfile/empty-path", Fixture, &keyfile_test_data_empty_path, setup, test_keyfile_no_path, teardown);
784+ g_test_add ("/gsettings/keyfile/long-path", Fixture, &keyfile_test_data_long_path, setup, test_keyfile_no_path, teardown);
785+ g_test_add ("/gsettings/keyfile/outside-root-path", Fixture, NULL, setup, test_keyfile_outside_root_path, teardown);
786+ g_test_add ("/gsettings/keyfile/no-root-group", Fixture, NULL, setup, test_keyfile_no_root_group, teardown);
787 g_test_add_func ("/gsettings/child-schema", test_child_schema);
788 g_test_add_func ("/gsettings/strinfo", test_strinfo);
789 g_test_add_func ("/gsettings/enums", test_enums);
790diff --git a/gio/tests/tls-interaction.c b/gio/tests/tls-interaction.c
791index 4f0737d7e..5661e8e0d 100644
792--- a/gio/tests/tls-interaction.c
793+++ b/gio/tests/tls-interaction.c
794@@ -174,6 +174,38 @@ test_interaction_ask_password_finish_failure (GTlsInteraction *interaction,
795 }
796
797
798+/* Return a copy of @str that is allocated in a silly way, to exercise
799+ * custom free-functions. The returned pointer points to a copy of @str
800+ * in a buffer of the form "BEFORE \0 str \0 AFTER". */
801+static guchar *
802+special_dup (const char *str)
803+{
804+ GString *buf = g_string_new ("BEFORE");
805+ guchar *ret;
806+
807+ g_string_append_c (buf, '\0');
808+ g_string_append (buf, str);
809+ g_string_append_c (buf, '\0');
810+ g_string_append (buf, "AFTER");
811+ ret = (guchar *) g_string_free (buf, FALSE);
812+ return ret + strlen ("BEFORE") + 1;
813+}
814+
815+
816+/* Free a copy of @str that was made with special_dup(), after asserting
817+ * that it has not been corrupted. */
818+static void
819+special_free (gpointer p)
820+{
821+ gchar *s = p;
822+ gchar *buf = s - strlen ("BEFORE") - 1;
823+
824+ g_assert_cmpstr (buf, ==, "BEFORE");
825+ g_assert_cmpstr (s + strlen (s) + 1, ==, "AFTER");
826+ g_free (buf);
827+}
828+
829+
830 static GTlsInteractionResult
831 test_interaction_ask_password_sync_success (GTlsInteraction *interaction,
832 GTlsPassword *password,
833@@ -181,6 +213,8 @@ test_interaction_ask_password_sync_success (GTlsInteraction *interaction,
834 GError **error)
835 {
836 TestInteraction *self;
837+ const guchar *value;
838+ gsize len;
839
840 g_assert (TEST_IS_INTERACTION (interaction));
841 self = TEST_INTERACTION (interaction);
842@@ -192,6 +226,27 @@ test_interaction_ask_password_sync_success (GTlsInteraction *interaction,
843 g_assert (error != NULL);
844 g_assert (*error == NULL);
845
846+ /* Exercise different ways to set the value */
847+ g_tls_password_set_value (password, (const guchar *) "foo", 4);
848+ len = 0;
849+ value = g_tls_password_get_value (password, &len);
850+ g_assert_cmpmem (value, len, "foo", 4);
851+
852+ g_tls_password_set_value (password, (const guchar *) "bar", -1);
853+ len = 0;
854+ value = g_tls_password_get_value (password, &len);
855+ g_assert_cmpmem (value, len, "bar", 3);
856+
857+ g_tls_password_set_value_full (password, special_dup ("baa"), 4, special_free);
858+ len = 0;
859+ value = g_tls_password_get_value (password, &len);
860+ g_assert_cmpmem (value, len, "baa", 4);
861+
862+ g_tls_password_set_value_full (password, special_dup ("baz"), -1, special_free);
863+ len = 0;
864+ value = g_tls_password_get_value (password, &len);
865+ g_assert_cmpmem (value, len, "baz", 3);
866+
867 /* Don't do this in real life. Include a null terminator for testing */
868 g_tls_password_set_value (password, (const guchar *)"the password", 13);
869 return G_TLS_INTERACTION_HANDLED;
870diff --git a/gio/win32/gwinhttpfile.c b/gio/win32/gwinhttpfile.c
871index cf5eed31d..246ec0578 100644
872--- a/gio/win32/gwinhttpfile.c
873+++ b/gio/win32/gwinhttpfile.c
874@@ -29,6 +29,7 @@
875 #include "gio/gfile.h"
876 #include "gio/gfileattribute.h"
877 #include "gio/gfileinfo.h"
878+#include "gstrfuncsprivate.h"
879 #include "gwinhttpfile.h"
880 #include "gwinhttpfileinputstream.h"
881 #include "gwinhttpfileoutputstream.h"
882@@ -393,10 +394,10 @@ g_winhttp_file_resolve_relative_path (GFile *file,
883 child = g_object_new (G_TYPE_WINHTTP_FILE, NULL);
884 child->vfs = winhttp_file->vfs;
885 child->url = winhttp_file->url;
886- child->url.lpszScheme = g_memdup (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2);
887- child->url.lpszHostName = g_memdup (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2);
888- child->url.lpszUserName = g_memdup (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2);
889- child->url.lpszPassword = g_memdup (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2);
890+ child->url.lpszScheme = g_memdup2 (winhttp_file->url.lpszScheme, ((gsize) winhttp_file->url.dwSchemeLength + 1) * 2);
891+ child->url.lpszHostName = g_memdup2 (winhttp_file->url.lpszHostName, ((gsize) winhttp_file->url.dwHostNameLength + 1) * 2);
892+ child->url.lpszUserName = g_memdup2 (winhttp_file->url.lpszUserName, ((gsize) winhttp_file->url.dwUserNameLength + 1) * 2);
893+ child->url.lpszPassword = g_memdup2 (winhttp_file->url.lpszPassword, ((gsize) winhttp_file->url.dwPasswordLength + 1) * 2);
894 child->url.lpszUrlPath = wnew_path;
895 child->url.dwUrlPathLength = wcslen (wnew_path);
896 child->url.lpszExtraInfo = NULL;
897diff --git a/glib/gbytes.c b/glib/gbytes.c
898index ec6923188..6f17d104c 100644
899--- a/glib/gbytes.c
900+++ b/glib/gbytes.c
901@@ -34,6 +34,8 @@
902
903 #include <string.h>
904
905+#include "gstrfuncsprivate.h"
906+
907 /**
908 * GBytes:
909 *
910@@ -95,7 +97,7 @@ g_bytes_new (gconstpointer data,
911 {
912 g_return_val_if_fail (data != NULL || size == 0, NULL);
913
914- return g_bytes_new_take (g_memdup (data, size), size);
915+ return g_bytes_new_take (g_memdup2 (data, size), size);
916 }
917
918 /**
919@@ -499,7 +501,7 @@ g_bytes_unref_to_data (GBytes *bytes,
920 * Copy: Non g_malloc (or compatible) allocator, or static memory,
921 * so we have to copy, and then unref.
922 */
923- result = g_memdup (bytes->data, bytes->size);
924+ result = g_memdup2 (bytes->data, bytes->size);
925 *size = bytes->size;
926 g_bytes_unref (bytes);
927 }
928diff --git a/glib/gdir.c b/glib/gdir.c
929index 6b85e99c8..6747a8c6f 100644
930--- a/glib/gdir.c
931+++ b/glib/gdir.c
932@@ -37,6 +37,7 @@
933 #include "gconvert.h"
934 #include "gfileutils.h"
935 #include "gstrfuncs.h"
936+#include "gstrfuncsprivate.h"
937 #include "gtestutils.h"
938 #include "glibintl.h"
939
940@@ -112,7 +113,7 @@ g_dir_open_with_errno (const gchar *path,
941 return NULL;
942 #endif
943
944- return g_memdup (&dir, sizeof dir);
945+ return g_memdup2 (&dir, sizeof dir);
946 }
947
948 /**
949diff --git a/glib/ghash.c b/glib/ghash.c
950index 0f1562a06..c1e15c957 100644
951--- a/glib/ghash.c
952+++ b/glib/ghash.c
953@@ -34,6 +34,7 @@
954 #include "gmacros.h"
955 #include "glib-private.h"
956 #include "gstrfuncs.h"
957+#include "gstrfuncsprivate.h"
958 #include "gatomic.h"
959 #include "gtestutils.h"
960 #include "gslice.h"
961@@ -962,7 +963,7 @@ g_hash_table_ensure_keyval_fits (GHashTable *hash_table, gpointer key, gpointer
962 if (hash_table->have_big_keys)
963 {
964 if (key != value)
965- hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size);
966+ hash_table->values = g_memdup2 (hash_table->keys, sizeof (gpointer) * hash_table->size);
967 /* Keys and values are both big now, so no need for further checks */
968 return;
969 }
970@@ -970,7 +971,7 @@ g_hash_table_ensure_keyval_fits (GHashTable *hash_table, gpointer key, gpointer
971 {
972 if (key != value)
973 {
974- hash_table->values = g_memdup (hash_table->keys, sizeof (guint) * hash_table->size);
975+ hash_table->values = g_memdup2 (hash_table->keys, sizeof (guint) * hash_table->size);
976 is_a_set = FALSE;
977 }
978 }
979@@ -998,7 +999,7 @@ g_hash_table_ensure_keyval_fits (GHashTable *hash_table, gpointer key, gpointer
980
981 /* Just split if necessary */
982 if (is_a_set && key != value)
983- hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size);
984+ hash_table->values = g_memdup2 (hash_table->keys, sizeof (gpointer) * hash_table->size);
985
986 #endif
987 }
988diff --git a/glib/giochannel.c b/glib/giochannel.c
989index d16399846..b41381d38 100644
990--- a/glib/giochannel.c
991+++ b/glib/giochannel.c
992@@ -37,6 +37,7 @@
993 #include "giochannel.h"
994
995 #include "gstrfuncs.h"
996+#include "gstrfuncsprivate.h"
997 #include "gtestutils.h"
998 #include "glibintl.h"
999
1000@@ -886,17 +887,26 @@ g_io_channel_set_line_term (GIOChannel *channel,
1001 const gchar *line_term,
1002 gint length)
1003 {
1004+ guint length_unsigned;
1005+
1006 g_return_if_fail (channel != NULL);
1007 g_return_if_fail (line_term == NULL || length != 0); /* Disallow "" */
1008
1009 if (line_term == NULL)
1010- length = 0;
1011- else if (length < 0)
1012- length = strlen (line_term);
1013+ length_unsigned = 0;
1014+ else if (length >= 0)
1015+ length_unsigned = (guint) length;
1016+ else
1017+ {
1018+ /* FIXME: We’re constrained by line_term_len being a guint here */
1019+ gsize length_size = strlen (line_term);
1020+ g_return_if_fail (length_size <= G_MAXUINT);
1021+ length_unsigned = (guint) length_size;
1022+ }
1023
1024 g_free (channel->line_term);
1025- channel->line_term = line_term ? g_memdup (line_term, length) : NULL;
1026- channel->line_term_len = length;
1027+ channel->line_term = line_term ? g_memdup2 (line_term, length_unsigned) : NULL;
1028+ channel->line_term_len = length_unsigned;
1029 }
1030
1031 /**
1032@@ -1673,10 +1683,10 @@ g_io_channel_read_line (GIOChannel *channel,
1033
1034 /* Copy the read bytes (including any embedded nuls) and nul-terminate.
1035 * `USE_BUF (channel)->str` is guaranteed to be nul-terminated as it’s a
1036- * #GString, so it’s safe to call g_memdup() with +1 length to allocate
1037+ * #GString, so it’s safe to call g_memdup2() with +1 length to allocate
1038 * a nul-terminator. */
1039 g_assert (USE_BUF (channel));
1040- line = g_memdup (USE_BUF (channel)->str, got_length + 1);
1041+ line = g_memdup2 (USE_BUF (channel)->str, got_length + 1);
1042 line[got_length] = '\0';
1043 *str_return = g_steal_pointer (&line);
1044 g_string_erase (USE_BUF (channel), 0, got_length);
1045diff --git a/glib/gslice.c b/glib/gslice.c
1046index 4c758c3be..bcdbb8853 100644
1047--- a/glib/gslice.c
1048+++ b/glib/gslice.c
1049@@ -41,6 +41,7 @@
1050 #include "gmain.h"
1051 #include "gmem.h" /* gslice.h */
1052 #include "gstrfuncs.h"
1053+#include "gstrfuncsprivate.h"
1054 #include "gutils.h"
1055 #include "gtrashstack.h"
1056 #include "gtestutils.h"
1057@@ -350,7 +351,7 @@ g_slice_get_config_state (GSliceConfig ckey,
1058 array[i++] = allocator->contention_counters[address];
1059 array[i++] = allocator_get_magazine_threshold (allocator, address);
1060 *n_values = i;
1061- return g_memdup (array, sizeof (array[0]) * *n_values);
1062+ return g_memdup2 (array, sizeof (array[0]) * *n_values);
1063 default:
1064 return NULL;
1065 }
1066diff --git a/glib/gstrfuncsprivate.h b/glib/gstrfuncsprivate.h
1067new file mode 100644
1068index 000000000..85c88328a
1069--- /dev/null
1070+++ b/glib/gstrfuncsprivate.h
1071@@ -0,0 +1,55 @@
1072+/* GLIB - Library of useful routines for C programming
1073+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
1074+ *
1075+ * This library is free software; you can redistribute it and/or
1076+ * modify it under the terms of the GNU Lesser General Public
1077+ * License as published by the Free Software Foundation; either
1078+ * version 2.1 of the License, or (at your option) any later version.
1079+ *
1080+ * This library is distributed in the hope that it will be useful,
1081+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1082+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1083+ * Lesser General Public License for more details.
1084+ *
1085+ * You should have received a copy of the GNU Lesser General Public
1086+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1087+ */
1088+
1089+#include <glib.h>
1090+#include <string.h>
1091+
1092+/*
1093+ * g_memdup2:
1094+ * @mem: (nullable): the memory to copy.
1095+ * @byte_size: the number of bytes to copy.
1096+ *
1097+ * Allocates @byte_size bytes of memory, and copies @byte_size bytes into it
1098+ * from @mem. If @mem is %NULL it returns %NULL.
1099+ *
1100+ * This replaces g_memdup(), which was prone to integer overflows when
1101+ * converting the argument from a #gsize to a #guint.
1102+ *
1103+ * This static inline version is a backport of the new public API from
1104+ * GLib 2.68, kept internal to GLib for backport to older stable releases.
1105+ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2319.
1106+ *
1107+ * Returns: (nullable): a pointer to the newly-allocated copy of the memory,
1108+ * or %NULL if @mem is %NULL.
1109+ * Since: 2.68
1110+ */
1111+static inline gpointer
1112+g_memdup2 (gconstpointer mem,
1113+ gsize byte_size)
1114+{
1115+ gpointer new_mem;
1116+
1117+ if (mem && byte_size != 0)
1118+ {
1119+ new_mem = g_malloc (byte_size);
1120+ memcpy (new_mem, mem, byte_size);
1121+ }
1122+ else
1123+ new_mem = NULL;
1124+
1125+ return new_mem;
1126+}
1127diff --git a/glib/gtestutils.c b/glib/gtestutils.c
1128index 18b117285..26d46ad75 100644
1129--- a/glib/gtestutils.c
1130+++ b/glib/gtestutils.c
1131@@ -49,6 +49,7 @@
1132 #include "gpattern.h"
1133 #include "grand.h"
1134 #include "gstrfuncs.h"
1135+#include "gstrfuncsprivate.h"
1136 #include "gtimer.h"
1137 #include "gslice.h"
1138 #include "gspawn.h"
1139@@ -3803,7 +3804,7 @@ g_test_log_extract (GTestLogBuffer *tbuffer)
1140 if (p <= tbuffer->data->str + mlength)
1141 {
1142 g_string_erase (tbuffer->data, 0, mlength);
1143- tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup (&msg, sizeof (msg)));
1144+ tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup2 (&msg, sizeof (msg)));
1145 return TRUE;
1146 }
1147
1148diff --git a/glib/gvariant.c b/glib/gvariant.c
1149index 77d7e746b..ef4257f6d 100644
1150--- a/glib/gvariant.c
1151+++ b/glib/gvariant.c
1152@@ -33,6 +33,7 @@
1153
1154 #include <string.h>
1155
1156+#include "gstrfuncsprivate.h"
1157
1158 /**
1159 * SECTION:gvariant
1160@@ -725,7 +726,7 @@ g_variant_new_variant (GVariant *value)
1161 g_variant_ref_sink (value);
1162
1163 return g_variant_new_from_children (G_VARIANT_TYPE_VARIANT,
1164- g_memdup (&value, sizeof value),
1165+ g_memdup2 (&value, sizeof value),
1166 1, g_variant_is_trusted (value));
1167 }
1168
1169@@ -1229,7 +1230,7 @@ g_variant_new_fixed_array (const GVariantType *element_type,
1170 return NULL;
1171 }
1172
1173- data = g_memdup (elements, n_elements * element_size);
1174+ data = g_memdup2 (elements, n_elements * element_size);
1175 value = g_variant_new_from_data (array_type, data,
1176 n_elements * element_size,
1177 FALSE, g_free, data);
1178@@ -1908,7 +1909,7 @@ g_variant_dup_bytestring (GVariant *value,
1179 if (length)
1180 *length = size;
1181
1182- return g_memdup (original, size + 1);
1183+ return g_memdup2 (original, size + 1);
1184 }
1185
1186 /**
1187diff --git a/glib/gvarianttype.c b/glib/gvarianttype.c
1188index c46f1a2c6..585e29ab2 100644
1189--- a/glib/gvarianttype.c
1190+++ b/glib/gvarianttype.c
1191@@ -28,6 +28,7 @@
1192
1193 #include <string.h>
1194
1195+#include "gstrfuncsprivate.h"
1196
1197 /**
1198 * SECTION:gvarianttype
1199@@ -1181,7 +1182,7 @@ g_variant_type_new_tuple (const GVariantType * const *items,
1200 g_assert (offset < sizeof buffer);
1201 buffer[offset++] = ')';
1202
1203- return (GVariantType *) g_memdup (buffer, offset);
1204+ return (GVariantType *) g_memdup2 (buffer, offset);
1205 }
1206
1207 /**
1208diff --git a/glib/meson.build b/glib/meson.build
1209index 456e0c2a1..2e5cd77bb 100644
1210--- a/glib/meson.build
1211+++ b/glib/meson.build
1212@@ -268,6 +268,7 @@ glib_sources = files(
1213 'gslist.c',
1214 'gstdio.c',
1215 'gstrfuncs.c',
1216+ 'gstrfuncsprivate.h',
1217 'gstring.c',
1218 'gstringchunk.c',
1219 'gtestutils.c',
1220diff --git a/glib/tests/array-test.c b/glib/tests/array-test.c
1221index 1da514a3e..88f22de80 100644
1222--- a/glib/tests/array-test.c
1223+++ b/glib/tests/array-test.c
1224@@ -29,6 +29,8 @@
1225 #include <string.h>
1226 #include "glib.h"
1227
1228+#include "gstrfuncsprivate.h"
1229+
1230 /* Test data to be passed to any function which calls g_array_new(), providing
1231 * the parameters for that call. Most #GArray tests should be repeated for all
1232 * possible values of #ArrayTestData. */
1233@@ -1917,7 +1919,7 @@ byte_array_new_take (void)
1234 GByteArray *gbarray;
1235 guint8 *data;
1236
1237- data = g_memdup ("woooweeewow", 11);
1238+ data = g_memdup2 ("woooweeewow", 11);
1239 gbarray = g_byte_array_new_take (data, 11);
1240 g_assert (gbarray->data == data);
1241 g_assert_cmpuint (gbarray->len, ==, 11);
1242diff --git a/glib/tests/io-channel.c b/glib/tests/io-channel.c
1243index ff53fcef7..4a1b10876 100644
1244--- a/glib/tests/io-channel.c
1245+++ b/glib/tests/io-channel.c
1246@@ -49,8 +49,10 @@ test_read_line_embedded_nuls (void)
1247 channel = g_io_channel_new_file (filename, "r", &local_error);
1248 g_assert_no_error (local_error);
1249
1250- /* Only break on newline characters, not nuls. */
1251- g_io_channel_set_line_term (channel, "\n", 1);
1252+ /* Only break on newline characters, not nuls.
1253+ * Use length -1 here to exercise glib#2323; the case where length > 0
1254+ * is covered in glib/tests/protocol.c. */
1255+ g_io_channel_set_line_term (channel, "\n", -1);
1256 g_io_channel_set_encoding (channel, NULL, &local_error);
1257 g_assert_no_error (local_error);
1258
1259diff --git a/glib/tests/option-context.c b/glib/tests/option-context.c
1260index 149d22353..88d2b80d1 100644
1261--- a/glib/tests/option-context.c
1262+++ b/glib/tests/option-context.c
1263@@ -27,6 +27,8 @@
1264 #include <string.h>
1265 #include <locale.h>
1266
1267+#include "gstrfuncsprivate.h"
1268+
1269 static GOptionEntry main_entries[] = {
1270 { "main-switch", 0, 0,
1271 G_OPTION_ARG_NONE, NULL,
1272@@ -256,7 +258,7 @@ join_stringv (int argc, char **argv)
1273 static char **
1274 copy_stringv (char **argv, int argc)
1275 {
1276- return g_memdup (argv, sizeof (char *) * (argc + 1));
1277+ return g_memdup2 (argv, sizeof (char *) * (argc + 1));
1278 }
1279
1280 static void
1281@@ -2323,7 +2325,7 @@ test_group_parse (void)
1282 g_option_context_add_group (context, group);
1283
1284 argv = split_string ("program --test arg1 -f arg2 --group-test arg3 --frob arg4 -z arg5", &argc);
1285- orig_argv = g_memdup (argv, (argc + 1) * sizeof (char *));
1286+ orig_argv = g_memdup2 (argv, (argc + 1) * sizeof (char *));
1287
1288 retval = g_option_context_parse (context, &argc, &argv, &error);
1289
1290diff --git a/glib/tests/strfuncs.c b/glib/tests/strfuncs.c
1291index e1f9619c7..d968afff9 100644
1292--- a/glib/tests/strfuncs.c
1293+++ b/glib/tests/strfuncs.c
1294@@ -32,6 +32,8 @@
1295 #include <string.h>
1296 #include "glib.h"
1297
1298+#include "gstrfuncsprivate.h"
1299+
1300 #if defined (_MSC_VER) && (_MSC_VER <= 1800)
1301 #define isnan(x) _isnan(x)
1302
1303@@ -219,6 +221,26 @@ test_memdup (void)
1304 g_free (str_dup);
1305 }
1306
1307+/* Testing g_memdup2() function with various positive and negative cases */
1308+static void
1309+test_memdup2 (void)
1310+{
1311+ gchar *str_dup = NULL;
1312+ const gchar *str = "The quick brown fox jumps over the lazy dog";
1313+
1314+ /* Testing negative cases */
1315+ g_assert_null (g_memdup2 (NULL, 1024));
1316+ g_assert_null (g_memdup2 (str, 0));
1317+ g_assert_null (g_memdup2 (NULL, 0));
1318+
1319+ /* Testing normal usage cases */
1320+ str_dup = g_memdup2 (str, strlen (str) + 1);
1321+ g_assert_nonnull (str_dup);
1322+ g_assert_cmpstr (str, ==, str_dup);
1323+
1324+ g_free (str_dup);
1325+}
1326+
1327 /* Testing g_strpcpy() function with various positive and negative cases */
1328 static void
1329 test_stpcpy (void)
1330@@ -2523,6 +2545,7 @@ main (int argc,
1331 g_test_add_func ("/strfuncs/has-prefix", test_has_prefix);
1332 g_test_add_func ("/strfuncs/has-suffix", test_has_suffix);
1333 g_test_add_func ("/strfuncs/memdup", test_memdup);
1334+ g_test_add_func ("/strfuncs/memdup2", test_memdup2);
1335 g_test_add_func ("/strfuncs/stpcpy", test_stpcpy);
1336 g_test_add_func ("/strfuncs/str_match_string", test_str_match_string);
1337 g_test_add_func ("/strfuncs/str_tokenize_and_fold", test_str_tokenize_and_fold);
1338diff --git a/gobject/gsignal.c b/gobject/gsignal.c
1339index 45effa92d..effbfec62 100644
1340--- a/gobject/gsignal.c
1341+++ b/gobject/gsignal.c
1342@@ -28,6 +28,7 @@
1343 #include <signal.h>
1344
1345 #include "gsignal.h"
1346+#include "gstrfuncsprivate.h"
1347 #include "gtype-private.h"
1348 #include "gbsearcharray.h"
1349 #include "gvaluecollector.h"
1350@@ -1809,7 +1810,7 @@ g_signal_newv (const gchar *signal_name,
1351 node->single_va_closure_is_valid = FALSE;
1352 node->flags = signal_flags & G_SIGNAL_FLAGS_MASK;
1353 node->n_params = n_params;
1354- node->param_types = g_memdup (param_types, sizeof (GType) * n_params);
1355+ node->param_types = g_memdup2 (param_types, sizeof (GType) * n_params);
1356 node->return_type = return_type;
1357 node->class_closure_bsa = NULL;
1358 if (accumulator)
1359diff --git a/gobject/gtype.c b/gobject/gtype.c
1360index b5ef2d11e..8d152dccc 100644
1361--- a/gobject/gtype.c
1362+++ b/gobject/gtype.c
1363@@ -33,6 +33,7 @@
1364
1365 #include "glib-private.h"
1366 #include "gconstructor.h"
1367+#include "gstrfuncsprivate.h"
1368
1369 #ifdef G_OS_WIN32
1370 #include <windows.h>
1371@@ -1470,7 +1471,7 @@ type_add_interface_Wm (TypeNode *node,
1372 iholder->next = iface_node_get_holders_L (iface);
1373 iface_node_set_holders_W (iface, iholder);
1374 iholder->instance_type = NODE_TYPE (node);
1375- iholder->info = info ? g_memdup (info, sizeof (*info)) : NULL;
1376+ iholder->info = info ? g_memdup2 (info, sizeof (*info)) : NULL;
1377 iholder->plugin = plugin;
1378
1379 /* create an iface entry for this type */
1380@@ -1731,7 +1732,7 @@ type_iface_retrieve_holder_info_Wm (TypeNode *iface,
1381 INVALID_RECURSION ("g_type_plugin_*", iholder->plugin, NODE_NAME (iface));
1382
1383 check_interface_info_I (iface, instance_type, &tmp_info);
1384- iholder->info = g_memdup (&tmp_info, sizeof (tmp_info));
1385+ iholder->info = g_memdup2 (&tmp_info, sizeof (tmp_info));
1386 }
1387
1388 return iholder; /* we don't modify write lock upon returning NULL */
1389@@ -2016,10 +2017,10 @@ type_iface_vtable_base_init_Wm (TypeNode *iface,
1390 IFaceEntry *pentry = type_lookup_iface_entry_L (pnode, iface);
1391
1392 if (pentry)
1393- vtable = g_memdup (pentry->vtable, iface->data->iface.vtable_size);
1394+ vtable = g_memdup2 (pentry->vtable, iface->data->iface.vtable_size);
1395 }
1396 if (!vtable)
1397- vtable = g_memdup (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size);
1398+ vtable = g_memdup2 (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size);
1399 entry->vtable = vtable;
1400 vtable->g_type = NODE_TYPE (iface);
1401 vtable->g_instance_type = NODE_TYPE (node);
1402diff --git a/gobject/gtypemodule.c b/gobject/gtypemodule.c
1403index 4ecaf8c88..20911fafd 100644
1404--- a/gobject/gtypemodule.c
1405+++ b/gobject/gtypemodule.c
1406@@ -19,6 +19,7 @@
1407
1408 #include <stdlib.h>
1409
1410+#include "gstrfuncsprivate.h"
1411 #include "gtypeplugin.h"
1412 #include "gtypemodule.h"
1413
1414@@ -436,7 +437,7 @@ g_type_module_register_type (GTypeModule *module,
1415 module_type_info->loaded = TRUE;
1416 module_type_info->info = *type_info;
1417 if (type_info->value_table)
1418- module_type_info->info.value_table = g_memdup (type_info->value_table,
1419+ module_type_info->info.value_table = g_memdup2 (type_info->value_table,
1420 sizeof (GTypeValueTable));
1421
1422 return module_type_info->type;
1423diff --git a/gobject/tests/param.c b/gobject/tests/param.c
1424index 93c3f4b94..0a77e51b7 100644
1425--- a/gobject/tests/param.c
1426+++ b/gobject/tests/param.c
1427@@ -2,6 +2,8 @@
1428 #include <glib-object.h>
1429 #include <stdlib.h>
1430
1431+#include "gstrfuncsprivate.h"
1432+
1433 static void
1434 test_param_value (void)
1435 {
1436@@ -874,7 +876,7 @@ main (int argc, char *argv[])
1437 test_path = g_strdup_printf ("/param/implement/subprocess/%d-%d-%d-%d",
1438 data.change_this_flag, data.change_this_type,
1439 data.use_this_flag, data.use_this_type);
1440- test_data = g_memdup (&data, sizeof (TestParamImplementData));
1441+ test_data = g_memdup2 (&data, sizeof (TestParamImplementData));
1442 g_test_add_data_func_full (test_path, test_data, test_param_implement_child, g_free);
1443 g_free (test_path);
1444 }
diff --git a/meta/recipes-core/glib-2.0/glib-2.0_2.64.5.bb b/meta/recipes-core/glib-2.0/glib-2.0_2.64.5.bb
index b9462bc945..ed7b649dc6 100644
--- a/meta/recipes-core/glib-2.0/glib-2.0_2.64.5.bb
+++ b/meta/recipes-core/glib-2.0/glib-2.0_2.64.5.bb
@@ -18,6 +18,7 @@ SRC_URI = "${GNOME_MIRROR}/glib/${SHRT_VER}/glib-${PV}.tar.xz \
18 file://0001-gio-tests-resources.c-comment-out-a-build-host-only-.patch \ 18 file://0001-gio-tests-resources.c-comment-out-a-build-host-only-.patch \
19 file://tzdata-update.patch \ 19 file://tzdata-update.patch \
20 file://CVE-2020-35457.patch \ 20 file://CVE-2020-35457.patch \
21 file://CVE-2021-27219.patch \
21 " 22 "
22 23
23SRC_URI_append_class-native = " file://relocate-modules.patch" 24SRC_URI_append_class-native = " file://relocate-modules.patch"