39f53b
From 5d9881309d0aeeebbc177d8af6dc26aa2ba56cfc Mon Sep 17 00:00:00 2001
39f53b
From: Frediano Ziglio <freddy77@gmail.com>
39f53b
Date: Sun, 20 Sep 2020 08:06:16 +0100
39f53b
Subject: [PATCH vd_agent_linux 13/17] Avoids user session hijacking
39f53b
39f53b
Avoids user hijacking sessions by reusing PID.
39f53b
In theory an attacker could:
39f53b
- open a connection to the daemon;
39f53b
- fork and exit the process but keep the file descriptor open
39f53b
  (inheriting or duplicating it in forked process);
39f53b
- force OS to recycle the initial PID, by creating many short lived
39f53b
  processes.
39f53b
Daemon would detect the old PID as having the new session.
39f53b
Check the user to avoid such replacements.
39f53b
39f53b
This issue was reported by SUSE security team.
39f53b
39f53b
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
39f53b
Acked-by: Uri Lublin <uril@redhat.com>
39f53b
---
39f53b
 src/vdagent-connection.c | 13 +++++++------
39f53b
 src/vdagent-connection.h | 13 +++++++++----
39f53b
 src/vdagentd/vdagentd.c  | 31 +++++++++++++++++++++++++++----
39f53b
 3 files changed, 43 insertions(+), 14 deletions(-)
39f53b
39f53b
diff --git a/src/vdagent-connection.c b/src/vdagent-connection.c
39f53b
index b1d4db6..fb331be 100644
39f53b
--- a/src/vdagent-connection.c
39f53b
+++ b/src/vdagent-connection.c
39f53b
@@ -142,24 +142,25 @@ void vdagent_connection_destroy(gpointer p)
39f53b
     g_object_unref(self);
39f53b
 }
39f53b
 
39f53b
-gint vdagent_connection_get_peer_pid(VDAgentConnection *self,
39f53b
-                                     GError           **err)
39f53b
+PidUid vdagent_connection_get_peer_pid_uid(VDAgentConnection *self,
39f53b
+                                           GError           **err)
39f53b
 {
39f53b
     VDAgentConnectionPrivate *priv = vdagent_connection_get_instance_private(self);
39f53b
     GSocket *sock;
39f53b
     GCredentials *cred;
39f53b
-    gint pid = -1;
39f53b
+    PidUid pid_uid = { -1, -1 };
39f53b
 
39f53b
-    g_return_val_if_fail(G_IS_SOCKET_CONNECTION(priv->io_stream), pid);
39f53b
+    g_return_val_if_fail(G_IS_SOCKET_CONNECTION(priv->io_stream), pid_uid);
39f53b
 
39f53b
     sock = g_socket_connection_get_socket(G_SOCKET_CONNECTION(priv->io_stream));
39f53b
     cred = g_socket_get_credentials(sock, err);
39f53b
     if (cred) {
39f53b
-        pid = g_credentials_get_unix_pid(cred, err);
39f53b
+        pid_uid.pid = g_credentials_get_unix_pid(cred, err);
39f53b
+        pid_uid.uid = g_credentials_get_unix_user(cred, err);
39f53b
         g_object_unref(cred);
39f53b
     }
39f53b
 
39f53b
-    return pid;
39f53b
+    return pid_uid;
39f53b
 }
39f53b
 
39f53b
 /* Performs single write operation,
39f53b
diff --git a/src/vdagent-connection.h b/src/vdagent-connection.h
39f53b
index 9d5a212..c515a79 100644
39f53b
--- a/src/vdagent-connection.h
39f53b
+++ b/src/vdagent-connection.h
39f53b
@@ -92,10 +92,15 @@ void vdagent_connection_write(VDAgentConnection *self,
39f53b
 /* Synchronously write all queued messages to the output stream. */
39f53b
 void vdagent_connection_flush(VDAgentConnection *self);
39f53b
 
39f53b
-/* Returns the PID of the foreign process connected to the socket
39f53b
- * or -1 with @err set. */
39f53b
-gint vdagent_connection_get_peer_pid(VDAgentConnection *self,
39f53b
-                                     GError           **err);
39f53b
+typedef struct PidUid {
39f53b
+    pid_t pid;
39f53b
+    uid_t uid;
39f53b
+} PidUid;
39f53b
+
39f53b
+/* Returns the PID and UID of the foreign process connected to the socket
39f53b
+ * or fill @err set. */
39f53b
+PidUid vdagent_connection_get_peer_pid_uid(VDAgentConnection *self,
39f53b
+                                           GError           **err);
39f53b
 
39f53b
 G_END_DECLS
39f53b
 
39f53b
diff --git a/src/vdagentd/vdagentd.c b/src/vdagentd/vdagentd.c
39f53b
index b31941d..e98fbe5 100644
39f53b
--- a/src/vdagentd/vdagentd.c
39f53b
+++ b/src/vdagentd/vdagentd.c
39f53b
@@ -955,16 +955,28 @@ static gboolean remove_active_xfers(gpointer key, gpointer value, gpointer conn)
39f53b
         return 0;
39f53b
 }
39f53b
 
39f53b
+/* Check a given process has a given UID */
39f53b
+static bool check_uid_of_pid(pid_t pid, uid_t uid)
39f53b
+{
39f53b
+    char fn[128];
39f53b
+    struct stat st;
39f53b
+
39f53b
+    snprintf(fn, sizeof(fn), "/proc/%u/status", (unsigned) pid);
39f53b
+    if (stat(fn, &st) != 0 || st.st_uid != uid) {
39f53b
+        return false;
39f53b
+    }
39f53b
+    return true;
39f53b
+}
39f53b
+
39f53b
 static void agent_connect(UdscsConnection *conn)
39f53b
 {
39f53b
     struct agent_data *agent_data;
39f53b
     agent_data = g_new0(struct agent_data, 1);
39f53b
     GError *err = NULL;
39f53b
-    gint pid;
39f53b
 
39f53b
     if (session_info) {
39f53b
-        pid = vdagent_connection_get_peer_pid(VDAGENT_CONNECTION(conn), &err;;
39f53b
-        if (err || pid <= 0) {
39f53b
+        PidUid pid_uid = vdagent_connection_get_peer_pid_uid(VDAGENT_CONNECTION(conn), &err;;
39f53b
+        if (err || pid_uid.pid <= 0) {
39f53b
             static const char msg[] = "Could not get peer PID, disconnecting new client";
39f53b
             if (err) {
39f53b
                 syslog(LOG_ERR, "%s: %s", msg, err->message);
39f53b
@@ -977,7 +989,18 @@ static void agent_connect(UdscsConnection *conn)
39f53b
             return;
39f53b
         }
39f53b
 
39f53b
-        agent_data->session = session_info_session_for_pid(session_info, pid);
39f53b
+        agent_data->session = session_info_session_for_pid(session_info, pid_uid.pid);
39f53b
+
39f53b
+        /* Check that the UID of the PID did not change, this should be done after
39f53b
+         * computing the session to avoid race conditions.
39f53b
+         * This can happen as vdagent_connection_get_peer_pid_uid get information
39f53b
+         * from the time of creating the socket, but the process in the meantime
39f53b
+         * have been replaced */
39f53b
+        if (!check_uid_of_pid(pid_uid.pid, pid_uid.uid)) {
39f53b
+            agent_data_destroy(agent_data);
39f53b
+            udscs_server_destroy_connection(server, conn);
39f53b
+            return;
39f53b
+        }
39f53b
     }
39f53b
 
39f53b
     g_object_set_data_full(G_OBJECT(conn), "agent_data", agent_data,
39f53b
-- 
39f53b
2.26.2
39f53b