Submitted By:            Douglas R. Reno <renodr at linuxfromscratch dot org>
Date:                    2018-12-13
Update Date:             2019-02-22
Initial Package Version: 0.115
Upstream Status:         Applied
Origin:                  Upstream/Self
Description:             Security fixes to polkit since version 0.115. Includes
                         one that has gotten attention worldwide for allowing
                         anyone with a UID over 4,000,000 to execute commands
                         without authentication.
Update Description:      Fix another authentication bypass.

diff -Naurp polkit-0.115.orig/src/polkit/polkitpermission.c polkit-0.115/src/polkit/polkitpermission.c
--- polkit-0.115.orig/src/polkit/polkitpermission.c	2018-04-03 15:57:57.000000000 -0500
+++ polkit-0.115/src/polkit/polkitpermission.c	2019-02-22 07:34:49.226233421 -0600
@@ -137,10 +137,13 @@ polkit_permission_finalize (GObject *obj
   g_free (permission->tmp_authz_id);
   g_object_unref (permission->subject);
 
-  g_signal_handlers_disconnect_by_func (permission->authority,
-                                        on_authority_changed,
-                                        permission);
-  g_object_unref (permission->authority);
+  if (permission->authority != NULL)
+  {
+     g_signal_handlers_disconnect_by_func (permission->authority,
+                                           on_authority_changed,
+                                           permission);
+     g_object_unref (permission->authority);
+  }
 
   if (G_OBJECT_CLASS (polkit_permission_parent_class)->finalize != NULL)
     G_OBJECT_CLASS (polkit_permission_parent_class)->finalize (object);
diff -Naurp polkit-0.115.orig/src/polkit/polkitunixgroup.c polkit-0.115/src/polkit/polkitunixgroup.c
--- polkit-0.115.orig/src/polkit/polkitunixgroup.c	2017-09-04 14:52:53.000000000 -0500
+++ polkit-0.115/src/polkit/polkitunixgroup.c	2019-02-22 07:34:49.227233402 -0600
@@ -71,6 +71,7 @@ G_DEFINE_TYPE_WITH_CODE (PolkitUnixGroup
 static void
 polkit_unix_group_init (PolkitUnixGroup *unix_group)
 {
+   unix_group->gid = -1; /* -1 is not a valid GID under Linux */
 }
 
 static void
@@ -100,11 +101,14 @@ polkit_unix_group_set_property (GObject
                                GParamSpec   *pspec)
 {
   PolkitUnixGroup *unix_group = POLKIT_UNIX_GROUP (object);
+  gint val;
 
   switch (prop_id)
     {
     case PROP_GID:
-      unix_group->gid = g_value_get_int (value);
+      val = g_value_get_int (value);
+      g_return_if_fail (val != -1);
+      unix_group->gid = val;
       break;
 
     default:
@@ -131,9 +135,9 @@ polkit_unix_group_class_init (PolkitUnix
                                    g_param_spec_int ("gid",
                                                      "Group ID",
                                                      "The UNIX group ID",
-                                                     0,
+                                                     G_MININT,
                                                      G_MAXINT,
-                                                     0,
+                                                     -1,
                                                      G_PARAM_CONSTRUCT |
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_STATIC_NAME |
@@ -166,7 +170,7 @@ polkit_unix_group_get_gid (PolkitUnixGro
  */
 void
 polkit_unix_group_set_gid (PolkitUnixGroup *group,
-                          gint gid)
+                           gint gid)
 {
   g_return_if_fail (POLKIT_IS_UNIX_GROUP (group));
   group->gid = gid;
@@ -183,6 +187,8 @@ polkit_unix_group_set_gid (PolkitUnixGro
 PolkitIdentity *
 polkit_unix_group_new (gint gid)
 {
+  g_return_val_if_fail (gid != -1, NULL);
+
   return POLKIT_IDENTITY (g_object_new (POLKIT_TYPE_UNIX_GROUP,
                                        "gid", gid,
                                        NULL));
diff -Naurp polkit-0.115.orig/src/polkit/polkitunixprocess.c polkit-0.115/src/polkit/polkitunixprocess.c
--- polkit-0.115.orig/src/polkit/polkitunixprocess.c	2018-06-25 08:55:45.000000000 -0500
+++ polkit-0.115/src/polkit/polkitunixprocess.c	2019-02-22 07:34:49.227233402 -0600
@@ -159,9 +159,14 @@ polkit_unix_process_set_property (GObjec
       polkit_unix_process_set_pid (unix_process, g_value_get_int (value));
       break;
 
-    case PROP_UID:
-      polkit_unix_process_set_uid (unix_process, g_value_get_int (value));
+    case PROP_UID: {
+      gint val;
+
+      val = g_value_get_int (value);
+      g_return_if_fail (val != -1);
+      polkit_unix_process_set_uid (unix_process, val);
       break;
+    }
 
     case PROP_START_TIME:
       polkit_unix_process_set_start_time (unix_process, g_value_get_uint64 (value));
@@ -239,7 +244,7 @@ polkit_unix_process_class_init (PolkitUn
                                    g_param_spec_int ("uid",
                                                      "User ID",
                                                      "The UNIX user ID",
-                                                     -1,
+                                                     G_MININT,
                                                      G_MAXINT,
                                                      -1,
                                                      G_PARAM_CONSTRUCT |
@@ -303,7 +308,6 @@ polkit_unix_process_set_uid (PolkitUnixP
                              gint               uid)
 {
   g_return_if_fail (POLKIT_IS_UNIX_PROCESS (process));
-  g_return_if_fail (uid >= -1);
   process->uid = uid;
 }
 
diff -Naurp polkit-0.115.orig/src/polkit/polkitunixuser.c polkit-0.115/src/polkit/polkitunixuser.c
--- polkit-0.115.orig/src/polkit/polkitunixuser.c	2017-09-04 14:52:53.000000000 -0500
+++ polkit-0.115/src/polkit/polkitunixuser.c	2019-02-22 07:34:49.227233402 -0600
@@ -72,6 +72,7 @@ G_DEFINE_TYPE_WITH_CODE (PolkitUnixUser,
 static void
 polkit_unix_user_init (PolkitUnixUser *unix_user)
 {
+  unix_user->uid = -1; /* (uid_t) -1 is not a valid UID under Linux */
   unix_user->name = NULL;
 }
 
@@ -112,11 +113,14 @@ polkit_unix_user_set_property (GObject
                                GParamSpec   *pspec)
 {
   PolkitUnixUser *unix_user = POLKIT_UNIX_USER (object);
+  gint val;
 
   switch (prop_id)
     {
     case PROP_UID:
-      unix_user->uid = g_value_get_int (value);
+      val = g_value_get_int (value);
+      g_return_if_fail (val != -1);
+      unix_user->uid = val;
       break;
 
     default:
@@ -144,9 +148,9 @@ polkit_unix_user_class_init (PolkitUnixU
                                    g_param_spec_int ("uid",
                                                      "User ID",
                                                      "The UNIX user ID",
-                                                     0,
+                                                     G_MININT,
                                                      G_MAXINT,
-                                                     0,
+                                                     -1,
                                                      G_PARAM_CONSTRUCT |
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_STATIC_NAME |
@@ -182,6 +186,7 @@ polkit_unix_user_set_uid (PolkitUnixUser
                           gint uid)
 {
   g_return_if_fail (POLKIT_IS_UNIX_USER (user));
+  g_return_if_fail (uid != -1);
   user->uid = uid;
 }
 
@@ -196,6 +201,8 @@ polkit_unix_user_set_uid (PolkitUnixUser
 PolkitIdentity *
 polkit_unix_user_new (gint uid)
 {
+  g_return_val_if_fail (uid != -1, NULL);
+
   return POLKIT_IDENTITY (g_object_new (POLKIT_TYPE_UNIX_USER,
                                         "uid", uid,
                                         NULL));
diff -Naurp polkit-0.115.orig/src/polkitagent/polkitagentlistener.c polkit-0.115/src/polkitagent/polkitagentlistener.c
--- polkit-0.115.orig/src/polkitagent/polkitagentlistener.c	2018-04-03 15:57:57.000000000 -0500
+++ polkit-0.115/src/polkitagent/polkitagentlistener.c	2019-02-22 07:34:49.227233402 -0600
@@ -178,10 +178,10 @@ on_notify_authority_owner (GObject    *o
   owner = polkit_authority_get_owner (server->authority);
   if (owner == NULL)
     {
-      g_printerr ("PolicyKit daemon disconnected from the bus.\n");
+      g_debug ("PolicyKit daemon disconnected from the bus.\n");
 
       if (server->is_registered)
-        g_printerr ("We are no longer a registered authentication agent.\n");
+        g_debug ("We are no longer a registered authentication agent.\n");
 
       server->is_registered = FALSE;
     }
@@ -192,17 +192,17 @@ on_notify_authority_owner (GObject    *o
         {
           GError *error;
 
-          g_printerr ("PolicyKit daemon reconnected to bus.\n");
-          g_printerr ("Attempting to re-register as an authentication agent.\n");
+          g_debug ("PolicyKit daemon reconnected to bus.\n");
+          g_debug ("Attempting to re-register as an authentication agent.\n");
 
           error = NULL;
           if (server_register (server, &error))
             {
-              g_printerr ("We are now a registered authentication agent.\n");
+              g_debug ("We are now a registered authentication agent.\n");
             }
           else
             {
-              g_printerr ("Failed to register as an authentication agent: %s\n", error->message);
+              g_debug ("Failed to register as an authentication agent: %s\n", error->message);
               g_error_free (error);
             }
         }
@@ -439,6 +439,7 @@ polkit_agent_listener_register_with_opti
           server->thread_initialization_error = NULL;
           g_thread_join (server->thread);
           server_free (server);
+          server = NULL;
           goto out;
         }
     }
diff -Naurp polkit-0.115.orig/src/polkitbackend/polkitbackendinteractiveauthority.c polkit-0.115/src/polkitbackend/polkitbackendinteractiveauthority.c
--- polkit-0.115.orig/src/polkitbackend/polkitbackendinteractiveauthority.c	2018-06-22 17:20:18.000000000 -0500
+++ polkit-0.115/src/polkitbackend/polkitbackendinteractiveauthority.c	2019-02-22 07:39:08.109674233 -0600
@@ -935,7 +935,7 @@ polkit_backend_interactive_authority_che
     }
 
   /* Not anyone is allowed to check that process XYZ is allowed to do ABC.
-   * We only allow this if, and only if,
+   * We allow this if, and only if,
    *
    *  - processes may check for another process owned by the *same* user but not
    *    if details are passed (otherwise you'd be able to spoof the dialog);
@@ -947,7 +947,7 @@ polkit_backend_interactive_authority_che
    *
    *  - if the action_id has the "org.freedesktop.policykit.owner" annotation
    *    then any uid referenced by that annotation is also allowed to check
-   *    to check anything and pass any details
+   *    anything and pass any details
    */
   if (!user_of_subject_matches
       || !polkit_identity_equal (user_of_caller, user_of_subject)
@@ -3032,6 +3032,42 @@ temporary_authorization_store_free (Temp
 }
 
 static gboolean
+subject_equal_for_authz (PolkitSubject *a,
+                         PolkitSubject *b)
+{
+   if (!polkit_subject_equal (a, b))
+      return FALSE;
+
+   /* Now special case unix processes, as we want to protect against
+    * PID reuse by including the UID.
+    */
+   if (POLKIT_IS_UNIX_PROCESS (a) && POLKIT_IS_UNIX_PROCESS (b)) {
+      PolkitUnixProcess *ap = (PolkitUnixProcess*)a;
+      int uid_a = polkit_unix_process_get_uid ((PolkitUnixProcess*)a);
+      PolkitUnixProcess *bp = (PolkitUnixProcess*)b;
+      int uid_b = polkit_unix_process_get_uid ((PolkitUnixProcess*)b);
+
+      if (uid_a != -1 && uid_b != -1)
+      {
+         if (uid_a == uid_b)
+         {
+            return TRUE;
+         }
+         else
+         {
+            g_printerr ("denying slowfork; pid %d uid %d != %d!\n",
+                        polkit_unix_process_get_pid (ap),
+                        uid_a, uid_b);
+            return FALSE;
+         }
+      }
+      /* Fall through, one of the UIDs is unset so we can't reliably compare. */
+   }
+   
+   return TRUE;
+}
+
+static gboolean
 temporary_authorization_store_has_authorization (TemporaryAuthorizationStore *store,
                                                  PolkitSubject               *subject,
                                                  const gchar                 *action_id,
@@ -3073,7 +3109,7 @@ temporary_authorization_store_has_author
     TemporaryAuthorization *authorization = l->data;
 
     if (strcmp (action_id, authorization->action_id) == 0 &&
-        polkit_subject_equal (subject_to_use, authorization->subject))
+        subject_equal_for_authz (subject_to_use, authorization->subject))
       {
         ret = TRUE;
         if (out_tmp_authz_id != NULL)
diff -Naurp polkit-0.115.orig/src/polkitbackend/polkitbackendjsauthority.cpp polkit-0.115/src/polkitbackend/polkitbackendjsauthority.cpp
--- polkit-0.115.orig/src/polkitbackend/polkitbackendjsauthority.cpp	2018-04-03 15:57:57.000000000 -0500
+++ polkit-0.115/src/polkitbackend/polkitbackendjsauthority.cpp	2019-02-22 07:34:49.229233364 -0600
@@ -1595,7 +1595,8 @@ utils_spawn_data_free (UtilsSpawnData *d
                              (GSourceFunc) utils_child_watch_from_release_cb,
                              source,
                              (GDestroyNotify) g_source_destroy);
-      g_source_attach (source, data->main_context);
+      /* Attach source to the global default main context */
+      g_source_attach (source, NULL);
       g_source_unref (source);
       data->child_pid = 0;
     }
diff -Naurp polkit-0.115.orig/src/programs/pkttyagent.c polkit-0.115/src/programs/pkttyagent.c
--- polkit-0.115.orig/src/programs/pkttyagent.c	2018-04-03 15:57:57.000000000 -0500
+++ polkit-0.115/src/programs/pkttyagent.c	2019-02-22 07:34:49.229233364 -0600
@@ -160,7 +160,8 @@ main (int argc, char *argv[])
   authority = polkit_authority_get_sync (NULL /* GCancellable* */, &error);
   if (authority == NULL)
     {
-      g_printerr ("Error getting authority: %s (%s, %d)\n",
+      g_printerr ("Authorization not available. Check if polkit service is running or see debug message for more information.\n");
+      g_debug ("Error getting authority: %s (%s, %d)\n",
                   error->message, g_quark_to_string (error->domain), error->code);
       g_error_free (error);
       ret = 127;
diff -Naurp polkit-0.115.orig/test/data/etc/group polkit-0.115/test/data/etc/group
--- polkit-0.115.orig/test/data/etc/group	2017-09-04 14:52:54.000000000 -0500
+++ polkit-0.115/test/data/etc/group	2019-02-22 07:34:49.229233364 -0600
@@ -5,3 +5,4 @@ john:x:500:
 jane:x:501:
 sally:x:502:
 henry:x:503:
+highuid2:x:4000000000:
diff -Naurp polkit-0.115.orig/test/data/etc/passwd polkit-0.115/test/data/etc/passwd
--- polkit-0.115.orig/test/data/etc/passwd	2017-09-04 14:52:54.000000000 -0500
+++ polkit-0.115/test/data/etc/passwd	2019-02-22 07:34:49.229233364 -0600
@@ -3,3 +3,5 @@ john:x:500:500:John Done:/home/john:/bin
 jane:x:501:501:Jane Smith:/home/jane:/bin/bash
 sally:x:502:502:Sally Derp:/home/sally:/bin/bash
 henry:x:503:503:Henry Herp:/home/henry:/bin/bash
+highuid1:x:2147483648:2147483648:The first high uid:/home/highuid1:/sbin/nologin
+highuid2:x:4000000000:4000000000:An example high uid:/home/example:/sbin/nologin
diff -Naurp polkit-0.115.orig/test/data/etc/polkit-1/rules.d/10-testing.rules polkit-0.115/test/data/etc/polkit-1/rules.d/10-testing.rules
--- polkit-0.115.orig/test/data/etc/polkit-1/rules.d/10-testing.rules	2017-09-04 14:52:54.000000000 -0500
+++ polkit-0.115/test/data/etc/polkit-1/rules.d/10-testing.rules	2019-02-22 07:34:49.230233345 -0600
@@ -53,6 +53,27 @@ polkit.addRule(function(action, subject)
     }
 });
 
+polkit.addRule(function(action, subject) {
+   if (action.id == "net.company.john_action") {
+       if (subject.user == "john") {
+           return polkit.Result.YES;
+       } else {
+           return polkit.Result.NO;
+       }
+   }
+});
+
+polkit.addRule(function(action,subject) {
+   if (action.id == "net.company.highuid2_action") {
+       if (subject.user == "highuid2") {
+           return polkit.Result.YES;
+       } else {
+           return polkit.Result.NO;
+       }
+   }
+});
+
+
 // ---------------------------------------------------------------------
 // variables
 
diff -Naurp polkit-0.115.orig/test/polkitbackend/test-polkitbackendjsauthority.c polkit-0.115/test/polkitbackend/test-polkitbackendjsauthority.c
--- polkit-0.115.orig/test/polkitbackend/test-polkitbackendjsauthority.c	2018-04-03 15:57:57.000000000 -0500
+++ polkit-0.115/test/polkitbackend/test-polkitbackendjsauthority.c	2019-02-22 07:34:49.230233345 -0600
@@ -330,6 +330,78 @@ static const RulesTestCase rules_test_ca
     NULL,
     POLKIT_IMPLICIT_AUTHORIZATION_AUTHORIZED,
   },
+
+  {
+    /* highuid1 is not a member of group 'users', see test/data/etc/group */
+    "group_membership_with_non_member(highuid22)",
+    "net.company.group.only_group_users",
+    "unix-user:highuid2",
+    NULL,
+    POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED,
+  },
+
+  {
+    /* highuid2 is not a member of group 'users', see test/data/etc/group */
+    "group_membership_with_non_member(highuid21)",
+    "net.company.group.only_group_users",
+    "unix-user:highuid2",
+    NULL,
+    POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED,
+  },
+
+  {
+    /* highuid1 is not a member of group 'users', see test/data/etc/group */
+    "group_membership_with_non_member(highuid24)",
+    "net.company.group.only_group_users",
+    "unix-user:2147483648",
+    NULL,
+    POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED,
+  },
+
+  {
+    /* highuid2 is not a member of group 'users', see test/data/etc/group */
+    "group_membership_with_non_member(highuid23)",
+    "net.company.group.only_group_users",
+    "unix-user:4000000000",
+    NULL,
+    POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED,
+  },
+
+  {
+    /* john is authorized to do this, see 10-testing.rules */
+    "john.action",
+    "net.company.john_action",
+    "unix-user:john",
+    NULL,
+    POLKIT_IMPLICIT_AUTHORIZATION_AUTHORIZED,
+  },
+
+  {
+    /* ONLY john is authorized to do this, see 10-testing.rules */
+    "jane_action",
+    "net.company.john_action",
+    "unix-user:jane",
+    NULL,
+    POLKIT_IMPLICIT_AUTHORIZATION_AUTHORIZED,
+  },
+
+  {
+    /* highuid2 is authorized to do this, see 10-testing.rules */
+    "highuid2_action",
+    "net.company.highuid2_action",
+    "unix-user:highuid2",
+    NULL,
+    POLKIT_IMPLICIT_AUTHORIZATION_AUTHORIZED,
+  },
+
+  {
+    /* ONLY highuid2 is authorized to do this, see 10-testing.rules */
+    "highuid1_action",
+    "net.company.highuid2_action",
+    "unix-user:highuid1",
+    NULL,
+    POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED
+  },
 };
 
 /* ---------------------------------------------------------------------------------------------------- */
