[gnome-initial-setup/wip/pwithnall/misc-fixes: 70/70] timezone: Fix use-after-free when cancelling GeoClue lookup




commit 6bcff45ac1c7492bc7e27cc6e17d8d9d1f0d34ab
Author: Philip Withnall <withnall endlessm com>
Date:   Fri Sep 11 12:30:01 2020 +0100

    timezone: Fix use-after-free when cancelling GeoClue lookup
    
    When rebuilding the timezone page after the user has chosen a language,
    any ongoing GeoClue construction operation is cancelled. However, the
    callback for that might be called after the page has been disposed
    (since the operation doesn’t hold a strong ref on the page). Avoid
    writing to `priv->geoclue_simple` in that case, until after checking the
    error code.
    
    Signed-off-by: Philip Withnall <withnall endlessm com>

 gnome-initial-setup/pages/timezone/gis-timezone-page.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
---
diff --git a/gnome-initial-setup/pages/timezone/gis-timezone-page.c 
b/gnome-initial-setup/pages/timezone/gis-timezone-page.c
index e8c30b2a..35d56e02 100644
--- a/gnome-initial-setup/pages/timezone/gis-timezone-page.c
+++ b/gnome-initial-setup/pages/timezone/gis-timezone-page.c
@@ -57,6 +57,11 @@
 #define CLOCK_SCHEMA "org.gnome.desktop.interface"
 #define CLOCK_FORMAT_KEY "clock-format"
 
+/* FIXME: Drop this when we depend on a version of GeoClue which has
+ * https://gitlab.freedesktop.org/geoclue/geoclue/-/merge_requests/73 */
+typedef GClueSimple MyGClueSimple;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyGClueSimple, g_object_unref)
+
 static void stop_geolocation (GisTimezonePage *page);
 
 struct _GisTimezonePagePrivate
@@ -182,8 +187,12 @@ on_geoclue_simple_ready (GObject      *source_object,
   GisTimezonePage *page = user_data;
   GisTimezonePagePrivate *priv = gis_timezone_page_get_instance_private (page);
   g_autoptr(GError) local_error = NULL;
+  g_autoptr(MyGClueSimple) geoclue_simple = NULL;
 
-  priv->geoclue_simple = gclue_simple_new_finish (res, &local_error);
+  /* This function may be called in an idle callback once @page has been
+   * disposed, if going through cancellation. So don’t dereference @priv or
+   * @page until the error has been checked. */
+  geoclue_simple = gclue_simple_new_finish (res, &local_error);
   if (local_error != NULL)
     {
       if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
@@ -191,6 +200,7 @@ on_geoclue_simple_ready (GObject      *source_object,
       return;
     }
 
+  priv->geoclue_simple = g_steal_pointer (&geoclue_simple);
   priv->geoclue_client = gclue_simple_get_client (priv->geoclue_simple);
   gclue_client_set_distance_threshold (priv->geoclue_client,
                                        GEOCODE_LOCATION_ACCURACY_CITY);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]