Blame SOURCES/polkit-0.112-CVE-2019-6133.patch

b0f342
diff -up ./src/polkitbackend/polkitbackendinteractiveauthority.c.ori ./src/polkitbackend/polkitbackendinteractiveauthority.c
b0f342
--- ./src/polkitbackend/polkitbackendinteractiveauthority.c.ori	2019-01-21 17:30:43.468115782 +0100
b0f342
+++ ./src/polkitbackend/polkitbackendinteractiveauthority.c	2019-01-21 17:31:03.220029178 +0100
b0f342
@@ -2904,6 +2904,43 @@ temporary_authorization_store_free (Temp
b0f342
   g_free (store);
b0f342
 }
b0f342
 
b0f342
+/* See the comment at the top of polkitunixprocess.c */
b0f342
+static gboolean
b0f342
+subject_equal_for_authz (PolkitSubject *a,
b0f342
+                         PolkitSubject *b)
b0f342
+{
b0f342
+  if (!polkit_subject_equal (a, b))
b0f342
+    return FALSE;
b0f342
+
b0f342
+  /* Now special case unix processes, as we want to protect against
b0f342
+   * pid reuse by including the UID.
b0f342
+   */
b0f342
+  if (POLKIT_IS_UNIX_PROCESS (a) && POLKIT_IS_UNIX_PROCESS (b)) {
b0f342
+    PolkitUnixProcess *ap = (PolkitUnixProcess*)a;
b0f342
+    int uid_a = polkit_unix_process_get_uid ((PolkitUnixProcess*)a);
b0f342
+    PolkitUnixProcess *bp = (PolkitUnixProcess*)b;
b0f342
+    int uid_b = polkit_unix_process_get_uid ((PolkitUnixProcess*)b);
b0f342
+
b0f342
+    if (uid_a != -1 && uid_b != -1)
b0f342
+      {
b0f342
+        if (uid_a == uid_b)
b0f342
+          {
b0f342
+            return TRUE;
b0f342
+          }
b0f342
+        else
b0f342
+          {
b0f342
+            g_printerr ("denying slowfork; pid %d uid %d != %d!\n",
b0f342
+                        polkit_unix_process_get_pid (ap),
b0f342
+                        uid_a, uid_b);
b0f342
+            return FALSE;
b0f342
+          }
b0f342
+      }
b0f342
+    /* Fall through; one of the uids is unset so we can't reliably compare */
b0f342
+  }
b0f342
+
b0f342
+  return TRUE;
b0f342
+}
b0f342
+
b0f342
 static gboolean
b0f342
 temporary_authorization_store_has_authorization (TemporaryAuthorizationStore *store,
b0f342
                                                  PolkitSubject               *subject,
b0f342
@@ -2946,7 +2983,7 @@ temporary_authorization_store_has_author
b0f342
     TemporaryAuthorization *authorization = l->data;
b0f342
 
b0f342
     if (strcmp (action_id, authorization->action_id) == 0 &&
b0f342
-        polkit_subject_equal (subject_to_use, authorization->subject))
b0f342
+        subject_equal_for_authz (subject_to_use, authorization->subject))
b0f342
       {
b0f342
         ret = TRUE;
b0f342
         if (out_tmp_authz_id != NULL)
b0f342
diff -up ./src/polkit/polkitsubject.c.ori ./src/polkit/polkitsubject.c
b0f342
--- ./src/polkit/polkitsubject.c.ori	2013-05-29 16:51:37.000000000 +0200
b0f342
+++ ./src/polkit/polkitsubject.c	2019-01-21 17:31:03.218029187 +0100
b0f342
@@ -99,6 +99,8 @@ polkit_subject_hash (PolkitSubject *subj
b0f342
  * @b: A #PolkitSubject.
b0f342
  *
b0f342
  * Checks if @a and @b are equal, ie. represent the same subject.
b0f342
+ * However, avoid calling polkit_subject_equal() to compare two processes;
b0f342
+ * for more information see the `PolkitUnixProcess` documentation.
b0f342
  *
b0f342
  * This function can be used in e.g. g_hash_table_new().
b0f342
  *
b0f342
diff -up ./src/polkit/polkitunixprocess.c.ori ./src/polkit/polkitunixprocess.c
b0f342
--- ./src/polkit/polkitunixprocess.c.ori	2019-01-21 17:30:43.477115743 +0100
b0f342
+++ ./src/polkit/polkitunixprocess.c	2019-01-21 17:31:03.219029182 +0100
b0f342
@@ -44,13 +44,82 @@
b0f342
  * @title: PolkitUnixProcess
b0f342
  * @short_description: Unix processs
b0f342
  *
b0f342
- * An object for representing a UNIX process.
b0f342
+ * An object for representing a UNIX process.  NOTE: This object as
b0f342
+ * designed is now known broken; a mechanism to exploit a delay in
b0f342
+ * start time in the Linux kernel was identified.  Avoid
b0f342
+ * calling polkit_subject_equal() to compare two processes.
b0f342
  *
b0f342
  * To uniquely identify processes, both the process id and the start
b0f342
  * time of the process (a monotonic increasing value representing the
b0f342
  * time since the kernel was started) is used.
b0f342
  */
b0f342
 
b0f342
+/* See https://gitlab.freedesktop.org/polkit/polkit/issues/75
b0f342
+
b0f342
+  But quoting the original email in full here to ensure it's preserved:
b0f342
+
b0f342
+  From: Jann Horn <jannh@google.com>
b0f342
+  Subject: [SECURITY] polkit: temporary auth hijacking via PID reuse and non-atomic fork
b0f342
+  Date: Wednesday, October 10, 2018 5:34 PM
b0f342
+
b0f342
+When a (non-root) user attempts to e.g. control systemd units in the system
b0f342
+instance from an active session over DBus, the access is gated by a polkit
b0f342
+policy that requires "auth_admin_keep" auth. This results in an auth prompt
b0f342
+being shown to the user, asking the user to confirm the action by entering the
b0f342
+password of an administrator account.
b0f342
+
b0f342
+After the action has been confirmed, the auth decision for "auth_admin_keep" is
b0f342
+cached for up to five minutes. Subject to some restrictions, similar actions can
b0f342
+then be performed in this timespan without requiring re-auth:
b0f342
+
b0f342
+ - The PID of the DBus client requesting the new action must match the PID of
b0f342
+   the DBus client requesting the old action (based on SO_PEERCRED information
b0f342
+   forwarded by the DBus daemon).
b0f342
+ - The "start time" of the client's PID (as seen in /proc/$pid/stat, field 22)
b0f342
+   must not have changed. The granularity of this timestamp is in the
b0f342
+   millisecond range.
b0f342
+ - polkit polls every two seconds whether a process with the expected start time
b0f342
+   still exists. If not, the temporary auth entry is purged.
b0f342
+
b0f342
+Without the start time check, this would obviously be buggy because an attacker
b0f342
+could simply wait for the legitimate client to disappear, then create a new
b0f342
+client with the same PID.
b0f342
+
b0f342
+Unfortunately, the start time check is bypassable because fork() is not atomic.
b0f342
+Looking at the source code of copy_process() in the kernel:
b0f342
+
b0f342
+        p->start_time = ktime_get_ns();
b0f342
+        p->real_start_time = ktime_get_boot_ns();
b0f342
+        [...]
b0f342
+        retval = copy_thread_tls(clone_flags, stack_start, stack_size, p, tls);
b0f342
+        if (retval)
b0f342
+                goto bad_fork_cleanup_io;
b0f342
+
b0f342
+        if (pid != &init_struct_pid) {
b0f342
+                pid = alloc_pid(p->nsproxy->pid_ns_for_children);
b0f342
+                if (IS_ERR(pid)) {
b0f342
+                        retval = PTR_ERR(pid);
b0f342
+                        goto bad_fork_cleanup_thread;
b0f342
+                }
b0f342
+        }
b0f342
+
b0f342
+The ktime_get_boot_ns() call is where the "start time" of the process is
b0f342
+recorded. The alloc_pid() call is where a free PID is allocated. In between
b0f342
+these, some time passes; and because the copy_thread_tls() call between them can
b0f342
+access userspace memory when sys_clone() is invoked through the 32-bit syscall
b0f342
+entry point, an attacker can even stall the kernel arbitrarily long at this
b0f342
+point (by supplying a pointer into userspace memory that is associated with a
b0f342
+userfaultfd or is backed by a custom FUSE filesystem).
b0f342
+
b0f342
+This means that an attacker can immediately call sys_clone() when the victim
b0f342
+process is created, often resulting in a process that has the exact same start
b0f342
+time reported in procfs; and then the attacker can delay the alloc_pid() call
b0f342
+until after the victim process has died and the PID assignment has cycled
b0f342
+around. This results in an attacker process that polkit can't distinguish from
b0f342
+the victim process.
b0f342
+*/
b0f342
+
b0f342
+
b0f342
 /**
b0f342
  * PolkitUnixProcess:
b0f342
  *