From 7b83c1dc9645cabadfeb253d7eca427f6a26d10f Mon Sep 17 00:00:00 2001 From: Iain Lane Date: Thu, 31 Jan 2019 17:51:52 +0000 Subject: [PATCH 3/4] session: Don't allow greeter operations on an running session If a client has a reference to a session that starts running, refuse to allow further operations on the session. CVE-2019-3825 --- daemon/gdm-session.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c index f23a83c5e..a8263ba11 100644 --- a/daemon/gdm-session.c +++ b/daemon/gdm-session.c @@ -1401,130 +1401,205 @@ gdm_session_handle_client_begin_verification_for_user (GdmDBusUserVerifier *u static gboolean gdm_session_handle_client_answer_query (GdmDBusUserVerifier *user_verifier_interface, GDBusMethodInvocation *invocation, const char *service_name, const char *answer, GdmSession *self) { gdm_dbus_user_verifier_complete_answer_query (user_verifier_interface, invocation); gdm_session_answer_query (self, service_name, answer); return TRUE; } static gboolean gdm_session_handle_client_cancel (GdmDBusUserVerifier *user_verifier_interface, GDBusMethodInvocation *invocation, GdmSession *self) { gdm_dbus_user_verifier_complete_cancel (user_verifier_interface, invocation); gdm_session_cancel (self); return TRUE; } static gboolean gdm_session_handle_client_select_session (GdmDBusGreeter *greeter_interface, GDBusMethodInvocation *invocation, const char *session, GdmSession *self) { + if (gdm_session_is_running (self)) { + const char *username; + + username = gdm_session_get_username (self); + g_debug ("GdmSession: refusing to select session %s since it's already running (for user %s)", + session, + username); + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Session already running for user %s", + username); + return TRUE; + } + if (self->priv->greeter_interface != NULL) { gdm_dbus_greeter_complete_select_session (greeter_interface, invocation); } gdm_session_select_session (self, session); return TRUE; } static gboolean gdm_session_handle_client_select_user (GdmDBusGreeter *greeter_interface, GDBusMethodInvocation *invocation, const char *username, GdmSession *self) { + if (gdm_session_is_running (self)) { + const char *session_username; + + session_username = gdm_session_get_username (self); + g_debug ("GdmSession: refusing to select user %s, since session (%p) already running (for user %s)", + username, + self, + session_username); + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Session already running for user %s", + session_username); + return TRUE; + } + if (self->priv->greeter_interface != NULL) { gdm_dbus_greeter_complete_select_user (greeter_interface, invocation); } g_debug ("GdmSession: client selected user '%s' on session (%p)", username, self); gdm_session_select_user (self, username); return TRUE; } static gboolean gdm_session_handle_client_start_session_when_ready (GdmDBusGreeter *greeter_interface, GDBusMethodInvocation *invocation, const char *service_name, gboolean client_is_ready, GdmSession *self) { + if (gdm_session_is_running (self)) { + const char *username; + + username = gdm_session_get_username (self); + g_debug ("GdmSession: refusing to start session (%p), since it's already running (for user %s)", + self, + username); + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Session already running for user %s", + username); + return TRUE; + } if (self->priv->greeter_interface != NULL) { gdm_dbus_greeter_complete_start_session_when_ready (greeter_interface, invocation); } g_signal_emit (G_OBJECT (self), signals [CLIENT_READY_FOR_SESSION_TO_START], 0, service_name, client_is_ready); return TRUE; } static gboolean gdm_session_handle_get_timed_login_details (GdmDBusGreeter *greeter_interface, GDBusMethodInvocation *invocation, GdmSession *self) { + if (gdm_session_is_running (self)) { + const char *username; + + username = gdm_session_get_username (self); + g_debug ("GdmSession: refusing to give timed login details, session (%p) already running (for user %s)", + self, + username); + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Session already running for user %s", + username); + return TRUE; + } if (self->priv->greeter_interface != NULL) { gdm_dbus_greeter_complete_get_timed_login_details (greeter_interface, invocation, self->priv->timed_login_username != NULL, self->priv->timed_login_username != NULL? self->priv->timed_login_username : "", self->priv->timed_login_delay); if (self->priv->timed_login_username != NULL) { gdm_dbus_greeter_emit_timed_login_requested (self->priv->greeter_interface, self->priv->timed_login_username, self->priv->timed_login_delay); } } return TRUE; } static gboolean gdm_session_handle_client_begin_auto_login (GdmDBusGreeter *greeter_interface, GDBusMethodInvocation *invocation, const char *username, GdmSession *self) { + const char *session_username; + + if (gdm_session_is_running (self)) { + session_username = gdm_session_get_username (self); + g_debug ("GdmSession: refusing auto login operation, session (%p) already running for user %s (%s requested)", + self, + session_username, + username); + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Session already owned by user %s", + session_username); + return TRUE; + } + if (self->priv->greeter_interface != NULL) { gdm_dbus_greeter_complete_begin_auto_login (greeter_interface, invocation); } g_debug ("GdmSession: client requesting automatic login for user '%s' on session '%s' (%p)", username, gdm_session_get_session_id (self), self); gdm_session_setup_for_user (self, "gdm-autologin", username); return TRUE; } static void export_user_verifier_interface (GdmSession *self, GDBusConnection *connection) { GdmDBusUserVerifier *user_verifier_interface; user_verifier_interface = GDM_DBUS_USER_VERIFIER (gdm_dbus_user_verifier_skeleton_new ()); g_object_set_data (G_OBJECT (connection), "gdm-session", self); g_signal_connect (user_verifier_interface, "handle-enable-extensions", G_CALLBACK (gdm_session_handle_client_enable_extensions), connection); g_signal_connect (user_verifier_interface, "handle-begin-verification", -- 2.21.0