File 0002-CVE-2020-25653-Better-check-for-sessions.patch of Package spice-vdagent.20485
Subject: Better check for sessions
From: Frediano Ziglio freddy77@gmail.com Mon Sep 21 07:06:09 2020 +0100
Date: Thu Oct 29 14:59:18 2020 +0000:
Git: 5c50131797e985d0a5654c1fd7000ae945ed29a7
Do not allow other users to hijack a session checking that
the process is launched by the owner of the session.
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
Index: spice-vdagent-0.16.0/src/console-kit.c
===================================================================
--- spice-vdagent-0.16.0.orig/src/console-kit.c
+++ spice-vdagent-0.16.0/src/console-kit.c
@@ -352,3 +352,70 @@ static char *console_kit_check_active_se
return ck->active_session;
}
+
+uid_t session_info_uid_for_session(struct session_info *info, const char *session)
+{
+ DBusError error;
+ DBusMessage *message = NULL;
+ DBusMessage *reply = NULL;
+ uint32_t uid;
+ uid_t ret = -1;
+ const char *err_msg;
+
+ g_return_val_if_fail(info != NULL, ret);
+ g_return_val_if_fail(info->connection != NULL, ret);
+ g_return_val_if_fail(info->active_session != NULL, ret);
+
+ dbus_error_init(&error);
+
+ err_msg = "(console-kit) Unable to create dbus message for GetUnixUser";
+ message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
+ session,
+ INTERFACE_CONSOLE_KIT_SESSION,
+ "GetUnixUser");
+ if (message == NULL) {
+ goto exit;
+ }
+
+ err_msg = "(console-kit) GetUnixUser failed";
+ reply = dbus_connection_send_with_reply_and_block(info->connection,
+ message,
+ -1,
+ &error);
+ if (reply == NULL || dbus_error_is_set(&error)) {
+ goto exit;
+ }
+
+ dbus_error_init(&error);
+ err_msg = "(console-kit) fail to get session-type from reply";
+ if (!dbus_message_get_args(reply,
+ &error,
+ DBUS_TYPE_UINT32, &uid,
+ DBUS_TYPE_INVALID)) {
+ goto exit;
+ }
+
+ if (info->verbose) {
+ syslog(LOG_DEBUG, "(console-kit) unix user is '%u'", (unsigned) uid);
+ }
+
+ err_msg = NULL;
+ ret = uid;
+
+exit:
+ if (err_msg) {
+ if (dbus_error_is_set(&error)) {
+ syslog(LOG_ERR, "%s: %s", err_msg, error.message);
+ dbus_error_free(&error);
+ } else {
+ syslog(LOG_ERR, "%s", err_msg);
+ }
+ }
+ if (reply != NULL) {
+ dbus_message_unref(reply);
+ }
+ if (message != NULL) {
+ dbus_message_unref(message);
+ }
+ return ret;
+}
Index: spice-vdagent-0.16.0/src/dummy-session-info.c
===================================================================
--- spice-vdagent-0.16.0.orig/src/dummy-session-info.c
+++ spice-vdagent-0.16.0/src/dummy-session-info.c
@@ -44,3 +44,8 @@ char *session_info_session_for_pid(struc
{
return NULL;
}
+
+uid_t session_info_uid_for_session(struct session_info *si, const char *session)
+{
+ return -1;
+}
Index: spice-vdagent-0.16.0/src/session-info.h
===================================================================
--- spice-vdagent-0.16.0.orig/src/session-info.h
+++ spice-vdagent-0.16.0/src/session-info.h
@@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdint.h>
+#include <glib.h>
struct session_info;
@@ -36,4 +37,7 @@ const char *session_info_get_active_sess
/* Note result must be free()-ed by caller */
char *session_info_session_for_pid(struct session_info *ck, uint32_t pid);
+/* get owner of a given session */
+uid_t session_info_uid_for_session(struct session_info *si, const char *session);
+
#endif
Index: spice-vdagent-0.16.0/src/systemd-login.c
===================================================================
--- spice-vdagent-0.16.0.orig/src/systemd-login.c
+++ spice-vdagent-0.16.0/src/systemd-login.c
@@ -104,3 +104,12 @@ char *session_info_session_for_pid(struc
return session;
}
+
+uid_t session_info_uid_for_session(struct session_info *si, const char *session)
+{
+ uid_t ret = -1;
+ if (sd_session_get_uid(session, &ret) < 0) {
+ return -1;
+ }
+ return ret;
+}
Index: spice-vdagent-0.16.0/src/vdagentd.c
===================================================================
--- spice-vdagent-0.16.0.orig/src/vdagentd.c
+++ spice-vdagent-0.16.0/src/vdagentd.c
@@ -847,12 +847,20 @@ void agent_connect(struct udscs_connecti
uint32_t uid = udscs_get_peer_cred(conn).uid;
agent_data->session = session_info_session_for_pid(session_info, pid);
+ uid_t session_uid = session_info_uid_for_session(session_info, agent_data->session);
+
/* Check that the UID of the PID did not change, this should be done after
* computing the session to avoid race conditions.
* This can happen as vdagent_connection_get_peer_pid_uid get information
* from the time of creating the socket, but the process in the meantime
* have been replaced */
- if (!check_uid_of_pid(pid, uid)) {
+ if (!check_uid_of_pid(pid, uid) ||
+ /* Check that the user launching the Agent is the same as session one
+ * or root user.
+ * This prevents session hijacks from other users. */
+ (uid != 0 && uid != session_uid)) {
+ syslog(LOG_ERR, "UID mismatch: UID=%u PID=%u suid=%u", uid,
+ pid, session_uid);
udscs_destroy_connection(&conn);
return;
}