From adc45ec84298f6246d9ed219607bb5c169f50e08 Mon Sep 17 00:00:00 2001 From: tarakbumba Date: Tue, 7 Apr 2015 00:07:27 +0300 Subject: Fix for https://github.com/mate-desktop/caja/issues/398 On the Shmoocon at 2011 there was a presentation by Jon Larimer demonstrating how to abuse vulnerabilities and bugs, or even just creating socially or security compromising thumbnails in mounting and thumbnailing, which happens on automounting USB drives. This is a particular issue when this happens on a locked box where the attacker doesn't otherwise have access to the user account: http://www.net-security.org/secworld.php?id=10544 Disable automounting if the MATE screen saver is currently locked. See also https://bugzilla.gnome.org/show_bug.cgi?id=642020 This commit is merely based on : https://git.gnome.org/browse/nautilus/commit/?h=gnome-2-32&id=b7262fa945ef1ea936c15f0d248ad7a024d97dca --- src/caja-application.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++- src/caja-application.h | 4 + 2 files changed, 232 insertions(+), 4 deletions(-) diff --git a/src/caja-application.c b/src/caja-application.c index 02c1c3dc..1eb2a7cb 100644 --- a/src/caja-application.c +++ b/src/caja-application.c @@ -120,7 +120,10 @@ static void mount_added_callback (GVolumeMonitor *mo static void volume_added_callback (GVolumeMonitor *monitor, GVolume *volume, CajaApplication *application); -static void drive_connected_callback (GVolumeMonitor *monitor, +static void volume_removed_callback (GVolumeMonitor *monitor, + GVolume *volume, + CajaApplication *application); + static void drive_connected_callback (GVolumeMonitor *monitor, GDrive *drive, CajaApplication *application); static void drive_listen_for_eject_button (GDrive *drive, @@ -360,7 +363,14 @@ caja_application_finalize (GObject *object) g_object_unref (application->unique_app); - if (application->automount_idle_id != 0) + g_bus_unwatch_name (application->ss_watch_id); + + if (application->volume_queue != NULL) { + g_list_free_full (application->volume_queue, g_object_unref); + application->volume_queue = NULL; + } + + if (application->automount_idle_id != 0) { g_source_remove (application->automount_idle_id); application->automount_idle_id = 0; @@ -372,6 +382,12 @@ caja_application_finalize (GObject *object) fdb_manager = NULL; } + if (application->ss_proxy != NULL) + { + g_object_unref (application->ss_proxy); + application->ss_proxy = NULL; + } + G_OBJECT_CLASS (caja_application_parent_class)->finalize (object); } @@ -551,6 +567,180 @@ out: g_free (do_once_file); } +static void +check_volume_queue (CajaApplication *application) +{ + GList *l, *next; + GVolume *volume; + + l = application->volume_queue; + + if (application->screensaver_active) + { + return; + } + + while (l != NULL) { + volume = l->data; + next = l->next; + + caja_file_operations_mount_volume (NULL, volume, TRUE); + application->volume_queue = + g_list_remove (application->volume_queue, volume); + + g_object_unref (volume); + l = next; + } + + application->volume_queue = NULL; +} + +#define SCREENSAVER_NAME "org.mate.ScreenSaver" +#define SCREENSAVER_PATH "/org/mate/ScreenSaver" +#define SCREENSAVER_INTERFACE "org.mate.ScreenSaver" + +static void +screensaver_signal_callback (GDBusProxy *proxy, + const gchar *sender_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + CajaApplication *application = user_data; + + if (g_strcmp0 (signal_name, "ActiveChanged") == 0) + { + g_variant_get (parameters, "(b)", &application->screensaver_active); + g_debug ("Screensaver active changed to %d", application->screensaver_active); + + check_volume_queue (application); + } +} + +static void +screensaver_get_active_ready_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + CajaApplication *application = user_data; + GDBusProxy *proxy = application->ss_proxy; + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_finish (proxy, + res, + &error); + + if (error != NULL) { + g_warning ("Can't call GetActive() on the ScreenSaver object: %s", + error->message); + g_error_free (error); + + return; + } + + g_variant_get (result, "(b)", &application->screensaver_active); + g_variant_unref (result); + + g_debug ("Screensaver GetActive() returned %d", application->screensaver_active); +} + +static void +screensaver_proxy_ready_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + CajaApplication *application = user_data; + GError *error = NULL; + GDBusProxy *ss_proxy; + + ss_proxy = g_dbus_proxy_new_finish (res, &error); + + if (error != NULL) + { + g_warning ("Can't get proxy for the ScreenSaver object: %s", + error->message); + g_error_free (error); + + return; + } + + g_debug ("ScreenSaver proxy ready"); + + application->ss_proxy = ss_proxy; + + g_signal_connect (ss_proxy, "g-signal", + G_CALLBACK (screensaver_signal_callback), application); + + g_dbus_proxy_call (ss_proxy, + "GetActive", + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, + NULL, + screensaver_get_active_ready_cb, + application); +} + +static void +screensaver_appeared_callback (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + CajaApplication *application = user_data; + + g_debug ("ScreenSaver name appeared"); + + application->screensaver_active = FALSE; + + g_dbus_proxy_new (connection, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + name, + SCREENSAVER_PATH, + SCREENSAVER_INTERFACE, + NULL, + screensaver_proxy_ready_cb, + application); +} + +static void +screensaver_vanished_callback (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + CajaApplication *application = user_data; + + g_debug ("ScreenSaver name vanished"); + + application->screensaver_active = FALSE; + g_object_unref (&application->ss_proxy); + + /* in this case force a clear of the volume queue, without + * mounting them. + */ + if (application->volume_queue != NULL) + { + g_list_free_full (application->volume_queue, g_object_unref); + application->volume_queue = NULL; + } +} + +static void +do_initialize_screensaver (CajaApplication *application) +{ + application->ss_watch_id = + g_bus_watch_name (G_BUS_TYPE_SESSION, + SCREENSAVER_NAME, + G_BUS_NAME_WATCHER_FLAGS_NONE, + screensaver_appeared_callback, + screensaver_vanished_callback, + application, + NULL); +} + + static void do_upgrades_once (CajaApplication *application, gboolean no_desktop) @@ -599,7 +789,11 @@ finish_startup (CajaApplication *application, /* Initialize the desktop link monitor singleton */ caja_desktop_link_monitor_get (); - /* Watch for mounts so we can restore open windows This used + /* Initialize MATE screen saver listener to control automount + * permission */ + do_initialize_screensaver (application); + + /* Watch for mounts so we can restore open windows This used * to be for showing new window on mount, but is not used * anymore */ @@ -614,6 +808,8 @@ finish_startup (CajaApplication *application, G_CALLBACK (mount_added_callback), application, 0); g_signal_connect_object (application->volume_monitor, "volume_added", G_CALLBACK (volume_added_callback), application, 0); + g_signal_connect_object (application->volume_monitor, "volume_removed", + G_CALLBACK (volume_removed_callback), application, 0); g_signal_connect_object (application->volume_monitor, "drive_connected", G_CALLBACK (drive_connected_callback), application, 0); @@ -1474,6 +1670,34 @@ window_can_be_closed (CajaWindow *window) return FALSE; } +static void +check_screen_lock_and_mount (CajaApplication *application, + GVolume *volume) +{ + if (application->screensaver_active) + { + /* queue the volume, to mount it after the screensaver state changed */ + g_debug ("Queuing volume %p", volume); + application->volume_queue = g_list_prepend (application->volume_queue, + g_object_ref (volume)); + } else { + /* mount it immediately */ + caja_file_operations_mount_volume (NULL, volume, TRUE); + } +} + +static void +volume_removed_callback (GVolumeMonitor *monitor, + GVolume *volume, + CajaApplication *application) +{ + g_debug ("Volume %p removed, removing from the queue", volume); + + /* clear it from the queue, if present */ + application->volume_queue = + g_list_remove (application->volume_queue, volume); +} + static void volume_added_callback (GVolumeMonitor *monitor, GVolume *volume, @@ -1483,7 +1707,7 @@ volume_added_callback (GVolumeMonitor *monitor, g_volume_should_automount (volume) && g_volume_can_mount (volume)) { - caja_file_operations_mount_volume (NULL, volume, TRUE); + check_screen_lock_and_mount (application, volume); } else { diff --git a/src/caja-application.h b/src/caja-application.h index 27cd8e18..699083a8 100644 --- a/src/caja-application.h +++ b/src/caja-application.h @@ -66,6 +66,10 @@ typedef struct EggSMClient* smclient; GVolumeMonitor* volume_monitor; unsigned int automount_idle_id; + gboolean screensaver_active; + guint ss_watch_id; + GDBusProxy *ss_proxy; + GList *volume_queue; } CajaApplication; typedef struct -- cgit v1.2.1 From b9f3254b87c9a20dd75238694a8e93ba8020792a Mon Sep 17 00:00:00 2001 From: tarakbumba Date: Tue, 7 Apr 2015 00:16:35 +0300 Subject: Fix g_bus_unwatch_name assertion Guard the g_bus_unwatch_name() call to only run when we actually have set a watcher to the screensaver. --- src/caja-application.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/caja-application.c b/src/caja-application.c index 1eb2a7cb..e4d2d973 100644 --- a/src/caja-application.c +++ b/src/caja-application.c @@ -363,9 +363,13 @@ caja_application_finalize (GObject *object) g_object_unref (application->unique_app); - g_bus_unwatch_name (application->ss_watch_id); + if (application->ss_watch_id > 0) + { + g_bus_unwatch_name (application->ss_watch_id); + } - if (application->volume_queue != NULL) { + if (application->volume_queue != NULL) + { g_list_free_full (application->volume_queue, g_object_unref); application->volume_queue = NULL; } -- cgit v1.2.1