LAKITU: Fix CVE-2021-28153 in glib and glib-utils.

This CL is adding fixes for CVE-2021-28153 from upstream:
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1982/diffs?commit_id=317b3b587058a05dca95d56dac26568c5b098d33

BUG=b/183876723,b/183876588
TEST=presubmit
RELEASE_NOTE=Fixed CVE-2021-28153 in glib and glib-utils.

cos-patch: security-moderate
Change-Id: I9f44a2cef02f4a84dc8bb4590e70eca799c46ef3
Reviewed-on: https://cos-review.googlesource.com/c/third_party/overlays/chromiumos-overlay/+/22830
Main-Branch-Verified: Cusky Presubmit Bot <presubmit@cos-infra-prod.iam.gserviceaccount.com>
Tested-by: Cusky Presubmit Bot <presubmit@cos-infra-prod.iam.gserviceaccount.com>
Reviewed-by: Meena Shanmugam <meenashanmugam@google.com>
diff --git a/dev-libs/glib/files/glib-2.66.7-fix-CVE-2021-28153.patch b/dev-libs/glib/files/glib-2.66.7-fix-CVE-2021-28153.patch
new file mode 100644
index 0000000..6732bff
--- /dev/null
+++ b/dev-libs/glib/files/glib-2.66.7-fix-CVE-2021-28153.patch
@@ -0,0 +1,232 @@
+From b0ee8d82e470a6365bf7201cfd093f7b953ec899 Mon Sep 17 00:00:00 2001
+From: Vaibhav Rustagi <vaibhavrustagi@google.com>
+Date: Tue, 21 Sep 2021 15:56:04 -0700
+Subject: [PATCH] Fixes for CVE-2021-28153.
+
+Cherry-pick from
+https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1982/diffs?commit_id=317b3b587058a05dca95d56dac26568c5b098d33
+---
+ gio/glocalfileoutputstream.c |  20 +++++--
+ gio/tests/file.c             | 112 ++++++++++++++++++++++++++++++++++-
+ 2 files changed, 124 insertions(+), 8 deletions(-)
+
+diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c
+index f34c3e439..f04180095 100644
+--- a/gio/glocalfileoutputstream.c
++++ b/gio/glocalfileoutputstream.c
+@@ -63,6 +63,12 @@
+ #define O_BINARY 0
+ #endif
+ 
++#ifndef O_CLOEXEC
++#define O_CLOEXEC 0
++#else
++#define HAVE_O_CLOEXEC 1
++#endif
++
+ struct _GLocalFileOutputStreamPrivate {
+   char *tmp_filename;
+   char *original_filename;
+@@ -850,6 +856,7 @@ handle_overwrite_open (const char    *filename,
+   int res;
+   int mode;
+   int errsv;
++  gboolean replace_destination_set = (flags & G_FILE_CREATE_REPLACE_DESTINATION);
+ 
+   mode = mode_from_flags_or_info (flags, reference_info);
+ 
+@@ -960,7 +967,7 @@ handle_overwrite_open (const char    *filename,
+    * to a backup file and rewrite the contents of the file.
+    */
+   
+-  if ((flags & G_FILE_CREATE_REPLACE_DESTINATION) ||
++  if (replace_destination_set ||
+       (!(_g_stat_nlink (&original_stat) > 1) && !is_symlink))
+     {
+       char *dirname, *tmp_filename;
+@@ -979,7 +986,7 @@ handle_overwrite_open (const char    *filename,
+       
+       /* try to keep permissions (unless replacing) */
+ 
+-      if ( ! (flags & G_FILE_CREATE_REPLACE_DESTINATION) &&
++      if ( !replace_destination_set &&
+ 	   (
+ #ifdef HAVE_FCHOWN
+ 	    fchown (tmpfd, _g_stat_uid (&original_stat), _g_stat_gid (&original_stat)) == -1 ||
+@@ -1120,7 +1127,7 @@ handle_overwrite_open (const char    *filename,
+ 	}
+     }
+ 
+-  if (flags & G_FILE_CREATE_REPLACE_DESTINATION)
++  if (replace_destination_set)
+     {
+       g_close (fd, NULL);
+       
+@@ -1205,7 +1212,7 @@ _g_local_file_output_stream_replace (const char        *filename,
+   sync_on_close = FALSE;
+ 
+   /* If the file doesn't exist, create it */
+-  open_flags = O_CREAT | O_EXCL | O_BINARY;
++  open_flags = O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC;
+   if (readable)
+     open_flags |= O_RDWR;
+   else
+@@ -1235,7 +1242,10 @@ _g_local_file_output_stream_replace (const char        *filename,
+       set_error_from_open_errno (filename, error);
+       return NULL;
+     }
+-  
++#if !defined(HAVE_O_CLOEXEC) && defined(F_SETFD)
++  else
++    fcntl (fd, F_SETFD, FD_CLOEXEC);
++#endif  
+  
+   stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
+   stream->priv->fd = fd;
+diff --git a/gio/tests/file.c b/gio/tests/file.c
+index d8769656c..ddd1ffcba 100644
+--- a/gio/tests/file.c
++++ b/gio/tests/file.c
+@@ -686,7 +686,7 @@ test_replace_cancel (void)
+   guint count;
+   GError *error = NULL;
+ 
+-  g_test_bug ("629301");
++  g_test_bug ("https://bugzilla.gnome.org/629301");
+ 
+   path = g_dir_make_tmp ("g_file_replace_cancel_XXXXXX", &error);
+   g_assert_no_error (error);
+@@ -805,6 +805,113 @@ test_replace_cancel (void)
+   g_object_unref (tmpdir);
+ }
+ 
++static void
++test_replace_symlink (void)
++{
++#ifdef G_OS_UNIX
++  gchar *tmpdir_path = NULL;
++  GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL;
++  GFileOutputStream *stream = NULL;
++  const gchar *new_contents = "this is a test message which should be written to source and not target";
++  gsize n_written;
++  GFileEnumerator *enumerator = NULL;
++  GFileInfo *info = NULL;
++  gchar *contents = NULL;
++  gsize length = 0;
++  GError *local_error = NULL;
++
++  g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2325");
++  g_test_summary ("Test that G_FILE_CREATE_REPLACE_DESTINATION doesn’t follow symlinks");
++
++  /* Create a fresh, empty working directory. */
++  tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_XXXXXX", &local_error);
++  g_assert_no_error (local_error);
++  tmpdir = g_file_new_for_path (tmpdir_path);
++
++  g_test_message ("Using temporary directory %s", tmpdir_path);
++  g_free (tmpdir_path);
++
++  /* Create symlink `source` which points to `target`. */
++  source_file = g_file_get_child (tmpdir, "source");
++  target_file = g_file_get_child (tmpdir, "target");
++  g_file_make_symbolic_link (source_file, "target", NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  /* Ensure that `target` doesn’t exist */
++  g_assert_false (g_file_query_exists (target_file, NULL));
++
++  /* Replace the `source` symlink with a regular file using
++   * %G_FILE_CREATE_REPLACE_DESTINATION, which should replace it *without*
++   * following the symlink */
++  stream = g_file_replace (source_file, NULL, FALSE  /* no backup */,
++                           G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents),
++                             &n_written, NULL, &local_error);
++  g_assert_no_error (local_error);
++  g_assert_cmpint (n_written, ==, strlen (new_contents));
++
++  g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  g_clear_object (&stream);
++
++  /* At this point, there should still only be one file: `source`. It should
++   * now be a regular file. `target` should not exist. */
++  enumerator = g_file_enumerate_children (tmpdir,
++                                          G_FILE_ATTRIBUTE_STANDARD_NAME ","
++                                          G_FILE_ATTRIBUTE_STANDARD_TYPE,
++                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
++  g_assert_no_error (local_error);
++  g_assert_nonnull (info);
++
++  g_assert_cmpstr (g_file_info_get_name (info), ==, "source");
++  g_assert_cmpint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR);
++
++  g_clear_object (&info);
++
++  info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
++  g_assert_no_error (local_error);
++  g_assert_null (info);
++
++  g_file_enumerator_close (enumerator, NULL, &local_error);
++  g_assert_no_error (local_error);
++  g_clear_object (&enumerator);
++
++  /* Double-check that `target` doesn’t exist */
++  g_assert_false (g_file_query_exists (target_file, NULL));
++
++  /* Check the content of `source`. */
++  g_file_load_contents (source_file,
++                        NULL,
++                        &contents,
++                        &length,
++                        NULL,
++                        &local_error);
++  g_assert_no_error (local_error);
++  g_assert_cmpstr (contents, ==, new_contents);
++  g_assert_cmpuint (length, ==, strlen (new_contents));
++  g_free (contents);
++
++  /* Tidy up. */
++  g_file_delete (source_file, NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  g_file_delete (tmpdir, NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  g_clear_object (&target_file);
++  g_clear_object (&source_file);
++  g_clear_object (&tmpdir);
++#else  /* if !G_OS_UNIX */
++  g_test_skip ("Symlink replacement tests can only be run on Unix")
++#endif
++}
++
+ static void
+ on_file_deleted (GObject      *object,
+ 		 GAsyncResult *result,
+@@ -1785,8 +1892,6 @@ main (int argc, char *argv[])
+ {
+   g_test_init (&argc, &argv, NULL);
+ 
+-  g_test_bug_base ("http://bugzilla.gnome.org/");
+-
+   g_test_add_func ("/file/basic", test_basic);
+   g_test_add_func ("/file/build-filename", test_build_filename);
+   g_test_add_func ("/file/parent", test_parent);
+@@ -1800,6 +1905,7 @@ main (int argc, char *argv[])
+   g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete);
+   g_test_add_func ("/file/replace-load", test_replace_load);
+   g_test_add_func ("/file/replace-cancel", test_replace_cancel);
++  g_test_add_func ("/file/replace-symlink", test_replace_symlink);
+   g_test_add_func ("/file/async-delete", test_async_delete);
+   g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
+   g_test_add_func ("/file/measure", test_measure);
+-- 
+2.33.0.464.g1972c5931b-goog
+
diff --git a/dev-libs/glib/glib-2.66.7-r1.ebuild b/dev-libs/glib/glib-2.66.7-r2.ebuild
similarity index 99%
rename from dev-libs/glib/glib-2.66.7-r1.ebuild
rename to dev-libs/glib/glib-2.66.7-r2.ebuild
index 82680f0..29e29cd 100644
--- a/dev-libs/glib/glib-2.66.7-r1.ebuild
+++ b/dev-libs/glib/glib-2.66.7-r2.ebuild
@@ -72,6 +72,10 @@
 	/usr/bin/gio-querymodules$(get_exeext)
 )
 
+PATCHES=(
+	"${FILESDIR}"/glib-2.66.7-fix-CVE-2021-28153.patch
+)
+
 pkg_setup() {
 	if use kernel_linux ; then
 		CONFIG_CHECK="~INOTIFY_USER"
diff --git a/dev-util/glib-utils/files/glib-2.66.7-fix-CVE-2021-28153.patch b/dev-util/glib-utils/files/glib-2.66.7-fix-CVE-2021-28153.patch
new file mode 100644
index 0000000..6732bff
--- /dev/null
+++ b/dev-util/glib-utils/files/glib-2.66.7-fix-CVE-2021-28153.patch
@@ -0,0 +1,232 @@
+From b0ee8d82e470a6365bf7201cfd093f7b953ec899 Mon Sep 17 00:00:00 2001
+From: Vaibhav Rustagi <vaibhavrustagi@google.com>
+Date: Tue, 21 Sep 2021 15:56:04 -0700
+Subject: [PATCH] Fixes for CVE-2021-28153.
+
+Cherry-pick from
+https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1982/diffs?commit_id=317b3b587058a05dca95d56dac26568c5b098d33
+---
+ gio/glocalfileoutputstream.c |  20 +++++--
+ gio/tests/file.c             | 112 ++++++++++++++++++++++++++++++++++-
+ 2 files changed, 124 insertions(+), 8 deletions(-)
+
+diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c
+index f34c3e439..f04180095 100644
+--- a/gio/glocalfileoutputstream.c
++++ b/gio/glocalfileoutputstream.c
+@@ -63,6 +63,12 @@
+ #define O_BINARY 0
+ #endif
+ 
++#ifndef O_CLOEXEC
++#define O_CLOEXEC 0
++#else
++#define HAVE_O_CLOEXEC 1
++#endif
++
+ struct _GLocalFileOutputStreamPrivate {
+   char *tmp_filename;
+   char *original_filename;
+@@ -850,6 +856,7 @@ handle_overwrite_open (const char    *filename,
+   int res;
+   int mode;
+   int errsv;
++  gboolean replace_destination_set = (flags & G_FILE_CREATE_REPLACE_DESTINATION);
+ 
+   mode = mode_from_flags_or_info (flags, reference_info);
+ 
+@@ -960,7 +967,7 @@ handle_overwrite_open (const char    *filename,
+    * to a backup file and rewrite the contents of the file.
+    */
+   
+-  if ((flags & G_FILE_CREATE_REPLACE_DESTINATION) ||
++  if (replace_destination_set ||
+       (!(_g_stat_nlink (&original_stat) > 1) && !is_symlink))
+     {
+       char *dirname, *tmp_filename;
+@@ -979,7 +986,7 @@ handle_overwrite_open (const char    *filename,
+       
+       /* try to keep permissions (unless replacing) */
+ 
+-      if ( ! (flags & G_FILE_CREATE_REPLACE_DESTINATION) &&
++      if ( !replace_destination_set &&
+ 	   (
+ #ifdef HAVE_FCHOWN
+ 	    fchown (tmpfd, _g_stat_uid (&original_stat), _g_stat_gid (&original_stat)) == -1 ||
+@@ -1120,7 +1127,7 @@ handle_overwrite_open (const char    *filename,
+ 	}
+     }
+ 
+-  if (flags & G_FILE_CREATE_REPLACE_DESTINATION)
++  if (replace_destination_set)
+     {
+       g_close (fd, NULL);
+       
+@@ -1205,7 +1212,7 @@ _g_local_file_output_stream_replace (const char        *filename,
+   sync_on_close = FALSE;
+ 
+   /* If the file doesn't exist, create it */
+-  open_flags = O_CREAT | O_EXCL | O_BINARY;
++  open_flags = O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC;
+   if (readable)
+     open_flags |= O_RDWR;
+   else
+@@ -1235,7 +1242,10 @@ _g_local_file_output_stream_replace (const char        *filename,
+       set_error_from_open_errno (filename, error);
+       return NULL;
+     }
+-  
++#if !defined(HAVE_O_CLOEXEC) && defined(F_SETFD)
++  else
++    fcntl (fd, F_SETFD, FD_CLOEXEC);
++#endif  
+  
+   stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
+   stream->priv->fd = fd;
+diff --git a/gio/tests/file.c b/gio/tests/file.c
+index d8769656c..ddd1ffcba 100644
+--- a/gio/tests/file.c
++++ b/gio/tests/file.c
+@@ -686,7 +686,7 @@ test_replace_cancel (void)
+   guint count;
+   GError *error = NULL;
+ 
+-  g_test_bug ("629301");
++  g_test_bug ("https://bugzilla.gnome.org/629301");
+ 
+   path = g_dir_make_tmp ("g_file_replace_cancel_XXXXXX", &error);
+   g_assert_no_error (error);
+@@ -805,6 +805,113 @@ test_replace_cancel (void)
+   g_object_unref (tmpdir);
+ }
+ 
++static void
++test_replace_symlink (void)
++{
++#ifdef G_OS_UNIX
++  gchar *tmpdir_path = NULL;
++  GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL;
++  GFileOutputStream *stream = NULL;
++  const gchar *new_contents = "this is a test message which should be written to source and not target";
++  gsize n_written;
++  GFileEnumerator *enumerator = NULL;
++  GFileInfo *info = NULL;
++  gchar *contents = NULL;
++  gsize length = 0;
++  GError *local_error = NULL;
++
++  g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2325");
++  g_test_summary ("Test that G_FILE_CREATE_REPLACE_DESTINATION doesn’t follow symlinks");
++
++  /* Create a fresh, empty working directory. */
++  tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_XXXXXX", &local_error);
++  g_assert_no_error (local_error);
++  tmpdir = g_file_new_for_path (tmpdir_path);
++
++  g_test_message ("Using temporary directory %s", tmpdir_path);
++  g_free (tmpdir_path);
++
++  /* Create symlink `source` which points to `target`. */
++  source_file = g_file_get_child (tmpdir, "source");
++  target_file = g_file_get_child (tmpdir, "target");
++  g_file_make_symbolic_link (source_file, "target", NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  /* Ensure that `target` doesn’t exist */
++  g_assert_false (g_file_query_exists (target_file, NULL));
++
++  /* Replace the `source` symlink with a regular file using
++   * %G_FILE_CREATE_REPLACE_DESTINATION, which should replace it *without*
++   * following the symlink */
++  stream = g_file_replace (source_file, NULL, FALSE  /* no backup */,
++                           G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents),
++                             &n_written, NULL, &local_error);
++  g_assert_no_error (local_error);
++  g_assert_cmpint (n_written, ==, strlen (new_contents));
++
++  g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  g_clear_object (&stream);
++
++  /* At this point, there should still only be one file: `source`. It should
++   * now be a regular file. `target` should not exist. */
++  enumerator = g_file_enumerate_children (tmpdir,
++                                          G_FILE_ATTRIBUTE_STANDARD_NAME ","
++                                          G_FILE_ATTRIBUTE_STANDARD_TYPE,
++                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
++  g_assert_no_error (local_error);
++  g_assert_nonnull (info);
++
++  g_assert_cmpstr (g_file_info_get_name (info), ==, "source");
++  g_assert_cmpint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR);
++
++  g_clear_object (&info);
++
++  info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
++  g_assert_no_error (local_error);
++  g_assert_null (info);
++
++  g_file_enumerator_close (enumerator, NULL, &local_error);
++  g_assert_no_error (local_error);
++  g_clear_object (&enumerator);
++
++  /* Double-check that `target` doesn’t exist */
++  g_assert_false (g_file_query_exists (target_file, NULL));
++
++  /* Check the content of `source`. */
++  g_file_load_contents (source_file,
++                        NULL,
++                        &contents,
++                        &length,
++                        NULL,
++                        &local_error);
++  g_assert_no_error (local_error);
++  g_assert_cmpstr (contents, ==, new_contents);
++  g_assert_cmpuint (length, ==, strlen (new_contents));
++  g_free (contents);
++
++  /* Tidy up. */
++  g_file_delete (source_file, NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  g_file_delete (tmpdir, NULL, &local_error);
++  g_assert_no_error (local_error);
++
++  g_clear_object (&target_file);
++  g_clear_object (&source_file);
++  g_clear_object (&tmpdir);
++#else  /* if !G_OS_UNIX */
++  g_test_skip ("Symlink replacement tests can only be run on Unix")
++#endif
++}
++
+ static void
+ on_file_deleted (GObject      *object,
+ 		 GAsyncResult *result,
+@@ -1785,8 +1892,6 @@ main (int argc, char *argv[])
+ {
+   g_test_init (&argc, &argv, NULL);
+ 
+-  g_test_bug_base ("http://bugzilla.gnome.org/");
+-
+   g_test_add_func ("/file/basic", test_basic);
+   g_test_add_func ("/file/build-filename", test_build_filename);
+   g_test_add_func ("/file/parent", test_parent);
+@@ -1800,6 +1905,7 @@ main (int argc, char *argv[])
+   g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete);
+   g_test_add_func ("/file/replace-load", test_replace_load);
+   g_test_add_func ("/file/replace-cancel", test_replace_cancel);
++  g_test_add_func ("/file/replace-symlink", test_replace_symlink);
+   g_test_add_func ("/file/async-delete", test_async_delete);
+   g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
+   g_test_add_func ("/file/measure", test_measure);
+-- 
+2.33.0.464.g1972c5931b-goog
+
diff --git a/dev-util/glib-utils/glib-utils-2.66.7-r1.ebuild b/dev-util/glib-utils/glib-utils-2.66.7-r2.ebuild
similarity index 96%
rename from dev-util/glib-utils/glib-utils-2.66.7-r1.ebuild
rename to dev-util/glib-utils/glib-utils-2.66.7-r2.ebuild
index c9f88eb..6c89264 100644
--- a/dev-util/glib-utils/glib-utils-2.66.7-r1.ebuild
+++ b/dev-util/glib-utils/glib-utils-2.66.7-r2.ebuild
@@ -28,6 +28,10 @@
 	cros-host? ( ${BDEPEND} )
 "
 
+PATCHES=(
+	"${FILESDIR}"/glib-2.66.7-fix-CVE-2021-28153.patch
+)
+
 src_configure() { :; }
 
 do_xsltproc_command() {