Blame SOURCES/polkit-0.112-CVE-2018-1116.patch

8c7385
diff -up ./src/polkitbackend/polkitbackendinteractiveauthority.c.ori ./src/polkitbackend/polkitbackendinteractiveauthority.c
8c7385
--- ./src/polkitbackend/polkitbackendinteractiveauthority.c.ori	2019-10-23 14:05:44.252434959 +0200
8c7385
+++ ./src/polkitbackend/polkitbackendinteractiveauthority.c	2019-10-23 14:07:08.329436414 +0200
8c7385
@@ -556,7 +556,7 @@ log_result (PolkitBackendInteractiveAuth
8c7385
   if (polkit_authorization_result_get_is_authorized (result))
8c7385
     log_result_str = "ALLOWING";
8c7385
 
8c7385
-  user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, NULL);
8c7385
+  user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, NULL, NULL);
8c7385
 
8c7385
   subject_str = polkit_subject_to_string (subject);
8c7385
   user_of_subject_str = polkit_identity_to_string (user_of_subject);
8c7385
@@ -824,6 +824,7 @@ polkit_backend_interactive_authority_che
8c7385
   gchar *subject_str;
8c7385
   PolkitIdentity *user_of_caller;
8c7385
   PolkitIdentity *user_of_subject;
8c7385
+  gboolean user_of_subject_matches;
8c7385
   gchar *user_of_caller_str;
8c7385
   gchar *user_of_subject_str;
8c7385
   PolkitAuthorizationResult *result;
8c7385
@@ -869,7 +870,7 @@ polkit_backend_interactive_authority_che
8c7385
            action_id);
8c7385
 
8c7385
   user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
8c7385
-                                                                        caller,
8c7385
+                                                                        caller, NULL,
8c7385
                                                                         &error);
8c7385
   if (error != NULL)
8c7385
     {
8c7385
@@ -884,7 +885,7 @@ polkit_backend_interactive_authority_che
8c7385
   g_debug (" user of caller is %s", user_of_caller_str);
8c7385
 
8c7385
   user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
8c7385
-                                                                         subject,
8c7385
+                                                                         subject, &user_of_subject_matches,
8c7385
                                                                          &error);
8c7385
   if (error != NULL)
8c7385
     {
8c7385
@@ -914,7 +915,10 @@ polkit_backend_interactive_authority_che
8c7385
    * We only allow this if, and only if,
8c7385
    *
8c7385
    *  - processes may check for another process owned by the *same* user but not
8c7385
-   *    if details are passed (otherwise you'd be able to spoof the dialog)
8c7385
+   *    if details are passed (otherwise you'd be able to spoof the dialog);
8c7385
+   *    the caller supplies the user_of_subject value, so we additionally
8c7385
+   *    require it to match at least at one point in time (via
8c7385
+   *    user_of_subject_matches).
8c7385
    *
8c7385
    *  - processes running as uid 0 may check anything and pass any details
8c7385
    *
8c7385
@@ -922,7 +926,9 @@ polkit_backend_interactive_authority_che
8c7385
    *    then any uid referenced by that annotation is also allowed to check
8c7385
    *    to check anything and pass any details
8c7385
    */
8c7385
-  if (!polkit_identity_equal (user_of_caller, user_of_subject) || has_details)
8c7385
+  if (!user_of_subject_matches
8c7385
+      || !polkit_identity_equal (user_of_caller, user_of_subject)
8c7385
+      || has_details)
8c7385
     {
8c7385
       if (!may_identity_check_authorization (interactive_authority, action_id, user_of_caller))
8c7385
         {
8c7385
@@ -1087,9 +1093,10 @@ check_authorization_sync (PolkitBackendA
8c7385
       goto out;
8c7385
     }
8c7385
 
8c7385
-  /* every subject has a user */
8c7385
+  /* every subject has a user; this is supplied by the client, so we rely
8c7385
+   * on the caller to validate its acceptability. */
8c7385
   user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
8c7385
-                                                                         subject,
8c7385
+                                                                         subject, NULL,
8c7385
                                                                          error);
8c7385
   if (user_of_subject == NULL)
8c7385
       goto out;
8c7385
@@ -2369,6 +2376,7 @@ polkit_backend_interactive_authority_reg
8c7385
   PolkitSubject *session_for_caller;
8c7385
   PolkitIdentity *user_of_caller;
8c7385
   PolkitIdentity *user_of_subject;
8c7385
+  gboolean user_of_subject_matches;
8c7385
   AuthenticationAgent *agent;
8c7385
   gboolean ret;
8c7385
   gchar *caller_cmdline;
8c7385
@@ -2423,7 +2431,7 @@ polkit_backend_interactive_authority_reg
8c7385
       goto out;
8c7385
     }
8c7385
 
8c7385
-  user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL);
8c7385
+  user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL, NULL);
8c7385
   if (user_of_caller == NULL)
8c7385
     {
8c7385
       g_set_error (error,
8c7385
@@ -2432,7 +2440,7 @@ polkit_backend_interactive_authority_reg
8c7385
                    "Cannot determine user of caller");
8c7385
       goto out;
8c7385
     }
8c7385
-  user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, NULL);
8c7385
+  user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, &user_of_subject_matches, NULL);
8c7385
   if (user_of_subject == NULL)
8c7385
     {
8c7385
       g_set_error (error,
8c7385
@@ -2441,7 +2449,8 @@ polkit_backend_interactive_authority_reg
8c7385
                    "Cannot determine user of subject");
8c7385
       goto out;
8c7385
     }
8c7385
-  if (!polkit_identity_equal (user_of_caller, user_of_subject))
8c7385
+  if (!user_of_subject_matches
8c7385
+      || !polkit_identity_equal (user_of_caller, user_of_subject))
8c7385
     {
8c7385
       if (POLKIT_IS_UNIX_USER (user_of_caller) && polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) == 0)
8c7385
         {
8c7385
@@ -2528,6 +2537,7 @@ polkit_backend_interactive_authority_unr
8c7385
   PolkitSubject *session_for_caller;
8c7385
   PolkitIdentity *user_of_caller;
8c7385
   PolkitIdentity *user_of_subject;
8c7385
+  gboolean user_of_subject_matches;
8c7385
   AuthenticationAgent *agent;
8c7385
   gboolean ret;
8c7385
   gchar *scope_str;
8c7385
@@ -2576,7 +2586,7 @@ polkit_backend_interactive_authority_unr
8c7385
       goto out;
8c7385
     }
8c7385
 
8c7385
-  user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL);
8c7385
+  user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL, NULL);
8c7385
   if (user_of_caller == NULL)
8c7385
     {
8c7385
       g_set_error (error,
8c7385
@@ -2585,7 +2595,7 @@ polkit_backend_interactive_authority_unr
8c7385
                    "Cannot determine user of caller");
8c7385
       goto out;
8c7385
     }
8c7385
-  user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, NULL);
8c7385
+  user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, &user_of_subject_matches, NULL);
8c7385
   if (user_of_subject == NULL)
8c7385
     {
8c7385
       g_set_error (error,
8c7385
@@ -2594,7 +2604,8 @@ polkit_backend_interactive_authority_unr
8c7385
                    "Cannot determine user of subject");
8c7385
       goto out;
8c7385
     }
8c7385
-  if (!polkit_identity_equal (user_of_caller, user_of_subject))
8c7385
+  if (!user_of_subject_matches
8c7385
+      || !polkit_identity_equal (user_of_caller, user_of_subject))
8c7385
     {
8c7385
       if (POLKIT_IS_UNIX_USER (user_of_caller) && polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) == 0)
8c7385
         {
8c7385
@@ -2703,7 +2714,7 @@ polkit_backend_interactive_authority_aut
8c7385
            identity_str);
8c7385
 
8c7385
   user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
8c7385
-                                                                        caller,
8c7385
+                                                                        caller, NULL,
8c7385
                                                                         error);
8c7385
   if (user_of_caller == NULL)
8c7385
     goto out;
8c7385
diff -up ./src/polkitbackend/polkitbackendsessionmonitor.c.ori ./src/polkitbackend/polkitbackendsessionmonitor.c
8c7385
--- ./src/polkitbackend/polkitbackendsessionmonitor.c.ori	2013-02-02 04:22:52.000000000 +0100
8c7385
+++ ./src/polkitbackend/polkitbackendsessionmonitor.c	2019-10-23 15:05:06.313135051 +0200
8c7385
@@ -27,6 +27,7 @@
8c7385
 #include <glib/gstdio.h>
8c7385
 
8c7385
 #include <polkit/polkit.h>
8c7385
+#include <polkit/polkitunixprocess.h>
8c7385
 #include "polkitbackendsessionmonitor.h"
8c7385
 
8c7385
 #define CKDB_PATH "/var/run/ConsoleKit/database"
8c7385
@@ -273,28 +274,40 @@ polkit_backend_session_monitor_get_sessi
8c7385
  * polkit_backend_session_monitor_get_user:
8c7385
  * @monitor: A #PolkitBackendSessionMonitor.
8c7385
  * @subject: A #PolkitSubject.
8c7385
+ * @result_matches: If not %NULL, set to indicate whether the return value matches current (RACY) state.
8c7385
  * @error: Return location for error.
8c7385
  *
8c7385
  * Gets the user corresponding to @subject or %NULL if no user exists.
8c7385
  *
8c7385
+ * NOTE: For a #PolkitUnixProcess, the UID is read from @subject (which may
8c7385
+ * come from e.g. a D-Bus client), so it may not correspond to the actual UID
8c7385
+ * of the referenced process (at any point in time).  This is indicated by
8c7385
+ * setting @result_matches to %FALSE; the caller may reject such subjects or
8c7385
+ * require additional privileges. @result_matches == %TRUE only indicates that
8c7385
+ * the UID matched the underlying process at ONE point in time, it may not match
8c7385
+ * later.
8c7385
+ *
8c7385
  * Returns: %NULL if @error is set otherwise a #PolkitUnixUser that should be freed with g_object_unref().
8c7385
  */
8c7385
 PolkitIdentity *
8c7385
 polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor  *monitor,
8c7385
                                                      PolkitSubject                *subject,
8c7385
+                                                     gboolean                     *result_matches,
8c7385
                                                      GError                      **error)
8c7385
 {
8c7385
   PolkitIdentity *ret;
8c7385
+  gboolean matches;
8c7385
   GError *local_error;
8c7385
-  gchar *group;
8c7385
-  guint32 uid;
8c7385
 
8c7385
   ret = NULL;
8c7385
+  matches = FALSE;
8c7385
 
8c7385
   if (POLKIT_IS_UNIX_PROCESS (subject))
8c7385
     {
8c7385
-      uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject));
8c7385
-      if ((gint) uid == -1)
8c7385
+      gint subject_uid, current_uid;
8c7385
+
8c7385
+      subject_uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject));
8c7385
+      if (subject_uid == -1)
8c7385
         {
8c7385
           g_set_error (error,
8c7385
                        POLKIT_ERROR,
8c7385
@@ -302,11 +315,21 @@ polkit_backend_session_monitor_get_user_
8c7385
                        "Unix process subject does not have uid set");
8c7385
           goto out;
8c7385
         }
8c7385
-      ret = polkit_unix_user_new (uid);
8c7385
+      local_error = NULL;
8c7385
+      current_uid = polkit_unix_process_get_owner (POLKIT_UNIX_PROCESS (subject), &local_error);
8c7385
+      if (local_error != NULL)
8c7385
+      {
8c7385
+        g_propagate_error (error, local_error);
8c7385
+        goto out;
8c7385
+      }
8c7385
+      ret = polkit_unix_user_new (subject_uid);
8c7385
+      matches = (subject_uid == current_uid);
8c7385
+
8c7385
     }
8c7385
   else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
8c7385
     {
8c7385
       GVariant *result;
8c7385
+      gint uid;
8c7385
 
8c7385
       result = g_dbus_connection_call_sync (monitor->system_bus,
8c7385
                                             "org.freedesktop.DBus",
8c7385
@@ -325,9 +348,13 @@ polkit_backend_session_monitor_get_user_
8c7385
       g_variant_unref (result);
8c7385
 
8c7385
       ret = polkit_unix_user_new (uid);
8c7385
+      matches = TRUE;
8c7385
     }
8c7385
   else if (POLKIT_IS_UNIX_SESSION (subject))
8c7385
     {
8c7385
+      gint uid;
8c7385
+      gchar *group;
8c7385
+
8c7385
       if (!ensure_database (monitor, error))
8c7385
         {
8c7385
           g_prefix_error (error, "Error getting user for session: Error ensuring CK database at " CKDB_PATH ": ");
8c7385
@@ -346,9 +373,14 @@ polkit_backend_session_monitor_get_user_
8c7385
       g_free (group);
8c7385
 
8c7385
       ret = polkit_unix_user_new (uid);
8c7385
+      matches = TRUE;
8c7385
     }
8c7385
 
8c7385
  out:
8c7385
+  if (result_matches != NULL)
8c7385
+    {
8c7385
+      *result_matches = matches;
8c7385
+    }
8c7385
   return ret;
8c7385
 }
8c7385
 
8c7385
diff -up ./src/polkitbackend/polkitbackendsessionmonitor.h.ori ./src/polkitbackend/polkitbackendsessionmonitor.h
8c7385
--- ./src/polkitbackend/polkitbackendsessionmonitor.h.ori	2013-02-02 04:22:52.000000000 +0100
8c7385
+++ ./src/polkitbackend/polkitbackendsessionmonitor.h	2019-10-23 14:07:08.330436425 +0200
8c7385
@@ -47,6 +47,7 @@ GList                       *polkit_back
8c7385
 
8c7385
 PolkitIdentity              *polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor *monitor,
8c7385
                                                                                   PolkitSubject               *subject,
8c7385
+                                                                                  gboolean                    *result_matches,
8c7385
                                                                                   GError                     **error);
8c7385
 
8c7385
 PolkitSubject               *polkit_backend_session_monitor_get_session_for_subject (PolkitBackendSessionMonitor *monitor,
8c7385
diff -up ./src/polkitbackend/polkitbackendsessionmonitor-systemd.c.ori ./src/polkitbackend/polkitbackendsessionmonitor-systemd.c
8c7385
--- ./src/polkitbackend/polkitbackendsessionmonitor-systemd.c.ori	2013-02-02 04:22:52.000000000 +0100
8c7385
+++ ./src/polkitbackend/polkitbackendsessionmonitor-systemd.c	2019-10-23 15:04:36.304774015 +0200
8c7385
@@ -29,6 +29,7 @@
8c7385
 #include <stdlib.h>
8c7385
 
8c7385
 #include <polkit/polkit.h>
8c7385
+#include <polkit/polkitunixprocess.h>
8c7385
 #include "polkitbackendsessionmonitor.h"
8c7385
 
8c7385
 /* <internal>
8c7385
@@ -246,26 +247,40 @@ polkit_backend_session_monitor_get_sessi
8c7385
  * polkit_backend_session_monitor_get_user:
8c7385
  * @monitor: A #PolkitBackendSessionMonitor.
8c7385
  * @subject: A #PolkitSubject.
8c7385
+ * @result_matches: If not %NULL, set to indicate whether the return value matches current (RACY) state.
8c7385
  * @error: Return location for error.
8c7385
  *
8c7385
  * Gets the user corresponding to @subject or %NULL if no user exists.
8c7385
  *
8c7385
+ * NOTE: For a #PolkitUnixProcess, the UID is read from @subject (which may
8c7385
+ * come from e.g. a D-Bus client), so it may not correspond to the actual UID
8c7385
+ * of the referenced process (at any point in time).  This is indicated by
8c7385
+ * setting @result_matches to %FALSE; the caller may reject such subjects or
8c7385
+ * require additional privileges. @result_matches == %TRUE only indicates that
8c7385
+ * the UID matched the underlying process at ONE point in time, it may not match
8c7385
+ * later.
8c7385
+ *
8c7385
  * Returns: %NULL if @error is set otherwise a #PolkitUnixUser that should be freed with g_object_unref().
8c7385
  */
8c7385
 PolkitIdentity *
8c7385
 polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor  *monitor,
8c7385
                                                      PolkitSubject                *subject,
8c7385
+                                                     gboolean                     *result_matches,
8c7385
                                                      GError                      **error)
8c7385
 {
8c7385
   PolkitIdentity *ret;
8c7385
-  guint32 uid;
8c7385
+  gboolean matches;
8c7385
 
8c7385
   ret = NULL;
8c7385
+  matches = FALSE;
8c7385
 
8c7385
   if (POLKIT_IS_UNIX_PROCESS (subject))
8c7385
     {
8c7385
-      uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject));
8c7385
-      if ((gint) uid == -1)
8c7385
+      gint subject_uid, current_uid;
8c7385
+      GError *local_error;
8c7385
+
8c7385
+      subject_uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject));
8c7385
+      if (subject_uid == -1)
8c7385
         {
8c7385
           g_set_error (error,
8c7385
                        POLKIT_ERROR,
8c7385
@@ -273,11 +288,20 @@ polkit_backend_session_monitor_get_user_
8c7385
                        "Unix process subject does not have uid set");
8c7385
           goto out;
8c7385
         }
8c7385
-      ret = polkit_unix_user_new (uid);
8c7385
+      local_error = NULL;
8c7385
+      current_uid = polkit_unix_process_get_owner (POLKIT_UNIX_PROCESS (subject), &local_error);
8c7385
+      if (local_error != NULL)
8c7385
+      {
8c7385
+        g_propagate_error (error, local_error);
8c7385
+        goto out;
8c7385
+      }
8c7385
+      ret = polkit_unix_user_new (subject_uid);
8c7385
+      matches = (subject_uid == current_uid);
8c7385
     }
8c7385
   else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
8c7385
     {
8c7385
       GVariant *result;
8c7385
+      gint uid;
8c7385
 
8c7385
       result = g_dbus_connection_call_sync (monitor->system_bus,
8c7385
                                             "org.freedesktop.DBus",
8c7385
@@ -296,9 +320,11 @@ polkit_backend_session_monitor_get_user_
8c7385
       g_variant_unref (result);
8c7385
 
8c7385
       ret = polkit_unix_user_new (uid);
8c7385
+      matches = TRUE;
8c7385
     }
8c7385
   else if (POLKIT_IS_UNIX_SESSION (subject))
8c7385
     {
8c7385
+      uid_t uid;
8c7385
 
8c7385
       if (sd_session_get_uid (polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (subject)), &uid) < 0)
8c7385
         {
8c7385
@@ -310,9 +336,14 @@ polkit_backend_session_monitor_get_user_
8c7385
         }
8c7385
 
8c7385
       ret = polkit_unix_user_new (uid);
8c7385
+      matches = TRUE;
8c7385
     }
8c7385
 
8c7385
  out:
8c7385
+  if (result_matches != NULL)
8c7385
+    {
8c7385
+      *result_matches = matches;
8c7385
+    }
8c7385
   return ret;
8c7385
 }
8c7385
 
8c7385
diff -up ./src/polkit/polkitprivate.h.ori ./src/polkit/polkitprivate.h
8c7385
diff -up ./src/polkit/polkitunixprocess.c.ori ./src/polkit/polkitunixprocess.c
8c7385
--- ./src/polkit/polkitunixprocess.c.ori	2019-10-23 14:05:44.254434983 +0200
8c7385
+++ ./src/polkit/polkitunixprocess.c	2019-10-23 15:03:01.643635120 +0200
8c7385
@@ -52,6 +52,15 @@
8c7385
  * To uniquely identify processes, both the process id and the start
8c7385
  * time of the process (a monotonic increasing value representing the
8c7385
  * time since the kernel was started) is used.
8c7385
+ * 
8c7385
+ * NOTE: This object stores, and provides access to, the real UID of the
8c7385
+ * process.  That value can change over time (with set*uid*(2) and exec*(2)).
8c7385
+ * Checks whether an operation is allowed need to take care to use the UID
8c7385
+ * value as of the time when the operation was made (or, following the open()
8c7385
+ * privilege check model, when the connection making the operation possible
8c7385
+ * was initiated).  That is usually done by initializing this with
8c7385
+ * polkit_unix_process_new_for_owner() with trusted data.
8c7385
+
8c7385
  */
8c7385
 
8c7385
 /* See https://gitlab.freedesktop.org/polkit/polkit/issues/75
8c7385
@@ -148,13 +157,12 @@ enum
8c7385
 };
8c7385
 
8c7385
 static void subject_iface_init (PolkitSubjectIface *subject_iface);
8c7385
+static gint polkit_unix_process_get_racy_uid__ (PolkitUnixProcess  *process,
8c7385
+                                    GError            **error);
8c7385
 
8c7385
 static guint64 get_start_time_for_pid (gint    pid,
8c7385
                                        GError **error);
8c7385
 
8c7385
-static gint _polkit_unix_process_get_owner (PolkitUnixProcess  *process,
8c7385
-                                            GError            **error);
8c7385
-
8c7385
 #ifdef HAVE_FREEBSD
8c7385
 static gboolean get_kinfo_proc (gint pid, struct kinfo_proc *p);
8c7385
 #endif
8c7385
@@ -239,7 +247,7 @@ polkit_unix_process_constructed (GObject
8c7385
     {
8c7385
       GError *error;
8c7385
       error = NULL;
8c7385
-      process->uid = _polkit_unix_process_get_owner (process, &error);
8c7385
+      process->uid = polkit_unix_process_get_racy_uid__ (process, &error);
8c7385
       if (error != NULL)
8c7385
         {
8c7385
           process->uid = -1;
8c7385
@@ -328,6 +336,12 @@ polkit_unix_process_class_init (PolkitUn
8c7385
  * Gets the user id for @process. Note that this is the real user-id,
8c7385
  * not the effective user-id.
8c7385
  *
8c7385
+ * NOTE: The UID may change over time, so the returned value may not match the
8c7385
+ * current state of the underlying process; or the UID may have been set by
8c7385
+ * polkit_unix_process_new_for_owner() or polkit_unix_process_set_uid(),
8c7385
+ * in which case it may not correspond to the actual UID of the referenced
8c7385
+ * process at all (at any point in time).
8c7385
+ *
8c7385
  * Returns: The user id for @process or -1 if unknown.
8c7385
  */
8c7385
 gint
8c7385
@@ -723,18 +737,27 @@ out:
8c7385
   return start_time;
8c7385
 }
8c7385
 
8c7385
+/*
8c7385
+ * Private: Return the "current" UID.  Note that this is inherently racy,
8c7385
+ * and the value may already be obsolete by the time this function returns;
8c7385
+ * this function only guarantees that the UID was valid at some point during
8c7385
+ * its execution.
8c7385
+ */
8c7385
 static gint
8c7385
-_polkit_unix_process_get_owner (PolkitUnixProcess  *process,
8c7385
-                                GError            **error)
8c7385
+polkit_unix_process_get_racy_uid__ (PolkitUnixProcess  *process,
8c7385
+                                    GError            **error)
8c7385
 {
8c7385
   gint result;
8c7385
   gchar *contents;
8c7385
   gchar **lines;
8c7385
+  guint64 start_time;
8c7385
+
8c7385
 #ifdef HAVE_FREEBSD
8c7385
   struct kinfo_proc p;
8c7385
 #else
8c7385
   gchar filename[64];
8c7385
   guint n;
8c7385
+  GError *local_error;
8c7385
 #endif
8c7385
 
8c7385
   g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), 0);
8c7385
@@ -757,6 +780,8 @@ _polkit_unix_process_get_owner (PolkitUn
8c7385
     }
8c7385
 
8c7385
   result = p.ki_uid;
8c7385
+  start_time = (guint64) p.ki_start.tv_sec;
8c7385
+
8c7385
 #else
8c7385
 
8c7385
   /* see 'man proc' for layout of the status file
8c7385
@@ -790,17 +815,37 @@ _polkit_unix_process_get_owner (PolkitUn
8c7385
       else
8c7385
         {
8c7385
           result = real_uid;
8c7385
-          goto out;
8c7385
+          goto found;
8c7385
         }
8c7385
     }
8c7385
-
8c7385
   g_set_error (error,
8c7385
                POLKIT_ERROR,
8c7385
                POLKIT_ERROR_FAILED,
8c7385
                "Didn't find any line starting with `Uid:' in file %s",
8c7385
                filename);
8c7385
+  goto out;
8c7385
+
8c7385
+found:
8c7385
+  /* The UID and start time are, sadly, not available in a single file.  So,
8c7385
+   * read the UID first, and then the start time; if the start time is the same
8c7385
+   * before and after reading the UID, it couldn't have changed.
8c7385
+   */
8c7385
+  local_error = NULL;
8c7385
+  start_time = get_start_time_for_pid (process->pid, &local_error);
8c7385
+  if (local_error != NULL)
8c7385
+    {
8c7385
+      g_propagate_error (error, local_error);
8c7385
+      goto out;
8c7385
+    }
8c7385
 #endif
8c7385
 
8c7385
+  if (process->start_time != start_time)
8c7385
+    {
8c7385
+      g_set_error (error, POLKIT_ERROR, POLKIT_ERROR_FAILED,
8c7385
+		   "process with PID %d has been replaced", process->pid);
8c7385
+      goto out;
8c7385
+    }
8c7385
+
8c7385
 out:
8c7385
   g_strfreev (lines);
8c7385
   g_free (contents);
8c7385
@@ -819,5 +864,5 @@ gint
8c7385
 polkit_unix_process_get_owner (PolkitUnixProcess  *process,
8c7385
                                GError            **error)
8c7385
 {
8c7385
-  return _polkit_unix_process_get_owner (process, error);
8c7385
+  return polkit_unix_process_get_racy_uid__ (process, error);
8c7385
 }