diff -Nru policykit-1-0.104/debian/changelog policykit-1-0.104/debian/changelog --- policykit-1-0.104/debian/changelog 2013-09-11 13:48:50.000000000 +0000 +++ policykit-1-0.104/debian/changelog 2019-08-29 18:32:23.000000000 +0000 @@ -1,3 +1,51 @@ +policykit-1 (0.104-1ubuntu1.5) precise-security; urgency=medium + + [ Marc Deslauriers ] + * SECURITY UPDATE: start time protection mechanism bypass + - debian/patches/CVE-2019-6133.patch: Compare PolkitUnixProcess uids + for temporary authorizations in src/polkit/polkitsubject.c, + src/polkit/polkitunixprocess.c, + src/polkitbackend/polkitbackendinteractiveauthority.c. + - CVE-2019-6133 + + -- Leonidas S. Barbosa Thu, 29 Aug 2019 15:18:39 -0300 + +policykit-1 (0.104-1ubuntu1.4) precise-security; urgency=medium + + [ Marc Deslauriers ] + * SECURITY UPDATE: authorization bypass with large uid + - debian/patches/CVE-2018-19788-1.patch: allow negative uids/gids in + PolkitUnixUser and Group objects in src/polkit/polkitunixgroup.c, + src/polkit/polkitunixprocess.c, src/polkit/polkitunixuser.c. + - debian/patches/CVE-2018-19788-2.patch: add tests to + test/data/etc/group, test/data/etc/passwd, + test/data/etc/polkit-1/localauthority/10-test/com.example.pkla, + test/polkitbackend/polkitbackendlocalauthoritytest.c. + - debian/patches/CVE-2018-19788-3.patch: allow uid of -1 for a + PolkitUnixProcess in src/polkit/polkitunixprocess.c. + - CVE-2018-19788 + + -- Leonidas S. Barbosa Wed, 16 Jan 2019 14:01:25 -0300 + +policykit-1 (0.104-1ubuntu1.2) precise-security; urgency=medium + + [ Marc Deslauriers ] + * SECURITY UPDATE: privilege escalation via duplicate action IDs + - debian/patches/CVE-2015-3255.patch: fix GHashTable usage in + src/polkitbackend/polkitbackendactionpool.c. + - CVE-2015-3255 + * SECURITY UPDATE: DoS and information disclosure + - debian/patches/CVE-2018-1116.patch: properly check UID in + src/polkit/polkitprivate.h, src/polkit/polkitunixprocess.c, + src/polkitbackend/polkitbackendinteractiveauthority.c, + src/polkitbackend/polkitbackendsessionmonitor-systemd.c, + src/polkitbackend/polkitbackendsessionmonitor.c, + src/polkitbackend/polkitbackendsessionmonitor.h. + - debian/libpolkit-gobject-1-0.symbols: updated for new private symbol. + - CVE-2018-1116 + + -- Leonidas S. Barbosa Tue, 17 Jul 2018 09:27:50 -0300 + policykit-1 (0.104-1ubuntu1.1) precise-security; urgency=low * SECURITY UPDATE: use of pkcheck without specifying uid is racy, diff -Nru policykit-1-0.104/debian/libpolkit-gobject-1-0.symbols policykit-1-0.104/debian/libpolkit-gobject-1-0.symbols --- policykit-1-0.104/debian/libpolkit-gobject-1-0.symbols 2012-05-15 22:35:29.000000000 +0000 +++ policykit-1-0.104/debian/libpolkit-gobject-1-0.symbols 2018-07-17 12:47:08.000000000 +0000 @@ -119,6 +119,7 @@ polkit_unix_netgroup_set_name@Base 0.104 polkit_unix_process_get_owner@Base 0.94 polkit_unix_process_get_pid@Base 0.94 + polkit_unix_process_get_racy_uid__@Base 0.104-1ubuntu1.2 polkit_unix_process_get_start_time@Base 0.94 polkit_unix_process_get_type@Base 0.94 polkit_unix_process_get_uid@Base 0.101 diff -Nru policykit-1-0.104/debian/patches/CVE-2015-3255.patch policykit-1-0.104/debian/patches/CVE-2015-3255.patch --- policykit-1-0.104/debian/patches/CVE-2015-3255.patch 1970-01-01 00:00:00.000000000 +0000 +++ policykit-1-0.104/debian/patches/CVE-2015-3255.patch 2018-07-17 12:52:34.000000000 +0000 @@ -0,0 +1,63 @@ +From 9f5e0c731784003bd4d6fc75ab739ff8b2ea269f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= +Date: Wed, 1 Apr 2015 05:22:37 +0200 +Subject: CVE-2015-3255 Fix GHashTable usage. + +Don't assume that the hash table with free both the key and the value +at the same time, supply proper deallocation functions for the key +and value separately. + +Then drop ParsedAction::action_id which is no longer used for anything. + +https://bugs.freedesktop.org/show_bug.cgi?id=69501 +and +https://bugs.freedesktop.org/show_bug.cgi?id=83590 + +CVE: CVE-2015-3255 +diff --git a/src/polkitbackend/polkitbackendactionpool.c b/src/polkitbackend/polkitbackendactionpool.c +index 6561a70..e2dbf9e 100644 +--- a/src/polkitbackend/polkitbackendactionpool.c ++++ b/src/polkitbackend/polkitbackendactionpool.c +@@ -42,7 +42,6 @@ + + typedef struct + { +- gchar *action_id; + gchar *vendor_name; + gchar *vendor_url; + gchar *icon_name; +@@ -66,7 +65,6 @@ typedef struct + static void + parsed_action_free (ParsedAction *action) + { +- g_free (action->action_id); + g_free (action->vendor_name); + g_free (action->vendor_url); + g_free (action->icon_name); +@@ -141,7 +139,7 @@ polkit_backend_action_pool_init (PolkitBackendActionPool *pool) + + priv->parsed_actions = g_hash_table_new_full (g_str_hash, + g_str_equal, +- NULL, ++ g_free, + (GDestroyNotify) parsed_action_free); + + priv->parsed_files = g_hash_table_new_full (g_str_hash, +@@ -1020,7 +1018,6 @@ _end (void *data, const char *el) + icon_name = pd->global_icon_name; + + action = g_new0 (ParsedAction, 1); +- action->action_id = g_strdup (pd->action_id); + action->vendor_name = g_strdup (vendor); + action->vendor_url = g_strdup (vendor_url); + action->icon_name = g_strdup (icon_name); +@@ -1037,7 +1034,8 @@ _end (void *data, const char *el) + action->implicit_authorization_inactive = pd->implicit_authorization_inactive; + action->implicit_authorization_active = pd->implicit_authorization_active; + +- g_hash_table_insert (priv->parsed_actions, action->action_id, action); ++ g_hash_table_insert (priv->parsed_actions, g_strdup (pd->action_id), ++ action); + + /* we steal these hash tables */ + pd->annotations = NULL; diff -Nru policykit-1-0.104/debian/patches/CVE-2018-1116.patch policykit-1-0.104/debian/patches/CVE-2018-1116.patch --- policykit-1-0.104/debian/patches/CVE-2018-1116.patch 1970-01-01 00:00:00.000000000 +0000 +++ policykit-1-0.104/debian/patches/CVE-2018-1116.patch 2018-07-17 12:27:44.000000000 +0000 @@ -0,0 +1,578 @@ +Backport of: + +From bc7ffad53643a9c80231fc41f5582d6a8931c32c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= +Date: Mon, 25 Jun 2018 19:24:06 +0200 +Subject: Fix CVE-2018-1116: Trusting client-supplied UID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As part of CVE-2013-4288, the D-Bus clients were allowed (and +encouraged) to submit the UID of the subject of authorization checks +to avoid races against UID changes (notably using executables +set-UID to root). + +However, that also allowed any client to submit an arbitrary UID, and +that could be used to bypass "can only ask about / affect the same UID" +checks in CheckAuthorization / RegisterAuthenticationAgent / +UnregisterAuthenticationAgent. This allowed an attacker: + +- With CheckAuthorization, to cause the registered authentication + agent in victim's session to pop up a dialog, or to determine whether + the victim currently has a temporary authorization to perform an + operation. + + (In principle, the attacker can also determine whether JavaScript + rules allow the victim process to perform an operation; however, + usually rules base their decisions on information determined from + the supplied UID, so the attacker usually won't learn anything new.) + +- With RegisterAuthenticationAgent, to prevent the victim's + authentication agent to work (for a specific victim process), + or to learn about which operations requiring authorization + the victim is attempting. + +To fix this, expose internal _polkit_unix_process_get_owner() / +obsolete polkit_unix_process_get_owner() as a private +polkit_unix_process_get_racy_uid__() (being more explicit about the +dangers on relying on it), and use it in +polkit_backend_session_monitor_get_user_for_subject() to return +a boolean indicating whether the subject UID may be caller-chosen. + +Then, in the permission checks that require the subject to be +equal to the caller, fail on caller-chosen UIDs (and continue +through the pre-existing code paths which allow root, or root-designated +server processes, to ask about arbitrary subjects.) + +Signed-off-by: Miloslav Trmač +diff --git a/src/polkit/polkitprivate.h b/src/polkit/polkitprivate.h +index 579cc25..d6cd45d 100644 +--- a/src/polkit/polkitprivate.h ++++ b/src/polkit/polkitprivate.h +@@ -34,6 +34,8 @@ GVariant *polkit_action_description_to_gvariant (PolkitActionDescription *action + GVariant *polkit_subject_to_gvariant (PolkitSubject *subject); + GVariant *polkit_identity_to_gvariant (PolkitIdentity *identity); + ++gint polkit_unix_process_get_racy_uid__ (PolkitUnixProcess *process, GError **error); ++ + PolkitSubject *polkit_subject_new_for_gvariant (GVariant *variant, GError **error); + PolkitIdentity *polkit_identity_new_for_gvariant (GVariant *variant, GError **error); + +diff --git a/src/polkit/polkitunixprocess.c b/src/polkit/polkitunixprocess.c +index 913be3a..464f034 100644 +--- a/src/polkit/polkitunixprocess.c ++++ b/src/polkit/polkitunixprocess.c +@@ -49,6 +49,14 @@ + * To uniquely identify processes, both the process id and the start + * time of the process (a monotonic increasing value representing the + * time since the kernel was started) is used. ++ * ++ * NOTE: This object stores, and provides access to, the real UID of the ++ * process. That value can change over time (with set*uid*(2) and exec*(2)). ++ * Checks whether an operation is allowed need to take care to use the UID ++ * value as of the time when the operation was made (or, following the open() ++ * privilege check model, when the connection making the operation possible ++ * was initiated). That is usually done by initializing this with ++ * polkit_unix_process_new_for_owner() with trusted data. + */ + + /** +@@ -83,9 +91,6 @@ static void subject_iface_init (PolkitSubjectIface *subject_iface); + static guint64 get_start_time_for_pid (gint pid, + GError **error); + +-static gint _polkit_unix_process_get_owner (PolkitUnixProcess *process, +- GError **error); +- + #ifdef HAVE_FREEBSD + static gboolean get_kinfo_proc (gint pid, struct kinfo_proc *p); + #endif +@@ -170,7 +175,7 @@ polkit_unix_process_constructed (GObject *object) + { + GError *error; + error = NULL; +- process->uid = _polkit_unix_process_get_owner (process, &error); ++ process->uid = polkit_unix_process_get_racy_uid__ (process, &error); + if (error != NULL) + { + process->uid = -1; +@@ -259,6 +264,12 @@ polkit_unix_process_class_init (PolkitUnixProcessClass *klass) + * Gets the user id for @process. Note that this is the real user-id, + * not the effective user-id. + * ++ * NOTE: The UID may change over time, so the returned value may not match the ++ * current state of the underlying process; or the UID may have been set by ++ * polkit_unix_process_new_for_owner() or polkit_unix_process_set_uid(), ++ * in which case it may not correspond to the actual UID of the referenced ++ * process at all (at any point in time). ++ * + * Returns: The user id for @process or -1 if unknown. + */ + gint +@@ -655,18 +666,26 @@ out: + return start_time; + } + +-static gint +-_polkit_unix_process_get_owner (PolkitUnixProcess *process, +- GError **error) ++/* ++ * Private: Return the "current" UID. Note that this is inherently racy, ++ * and the value may already be obsolete by the time this function returns; ++ * this function only guarantees that the UID was valid at some point during ++ * its execution. ++ */ ++gint ++polkit_unix_process_get_racy_uid__ (PolkitUnixProcess *process, ++ GError **error) + { + gint result; + gchar *contents; + gchar **lines; ++ guint64 start_time; + #ifdef HAVE_FREEBSD + struct kinfo_proc p; + #else + gchar filename[64]; + guint n; ++ GError *local_error; + #endif + + g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), 0); +@@ -689,6 +708,7 @@ _polkit_unix_process_get_owner (PolkitUnixProcess *process, + } + + result = p.ki_uid; ++ start_time = (guint64) p.ki_start.tv_sec; + #else + + /* see 'man proc' for layout of the status file +@@ -722,17 +742,37 @@ _polkit_unix_process_get_owner (PolkitUnixProcess *process, + else + { + result = real_uid; +- goto out; ++ goto found; + } + } +- + g_set_error (error, + POLKIT_ERROR, + POLKIT_ERROR_FAILED, + "Didn't find any line starting with `Uid:' in file %s", + filename); ++ goto out; ++ ++found: ++ /* The UID and start time are, sadly, not available in a single file. So, ++ * read the UID first, and then the start time; if the start time is the same ++ * before and after reading the UID, it couldn't have changed. ++ */ ++ local_error = NULL; ++ start_time = get_start_time_for_pid (process->pid, &local_error); ++ if (local_error != NULL) ++ { ++ g_propagate_error (error, local_error); ++ goto out; ++ } + #endif + ++ if (process->start_time != start_time) ++ { ++ g_set_error (error, POLKIT_ERROR, POLKIT_ERROR_FAILED, ++ "process with PID %d has been replaced", process->pid); ++ goto out; ++ } ++ + out: + g_strfreev (lines); + g_free (contents); +@@ -744,5 +784,5 @@ gint + polkit_unix_process_get_owner (PolkitUnixProcess *process, + GError **error) + { +- return _polkit_unix_process_get_owner (process, error); ++ return polkit_unix_process_get_racy_uid__ (process, error); + } +diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c +index 99c4782..dffc4ec 100644 +--- a/src/polkitbackend/polkitbackendinteractiveauthority.c ++++ b/src/polkitbackend/polkitbackendinteractiveauthority.c +@@ -552,7 +552,7 @@ log_result (PolkitBackendInteractiveAuthority *authority, + if (polkit_authorization_result_get_is_authorized (result)) + log_result_str = "ALLOWING"; + +- user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, NULL); ++ user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, NULL, NULL); + + subject_str = polkit_subject_to_string (subject); + user_of_subject_str = polkit_identity_to_string (user_of_subject); +@@ -822,6 +822,7 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority + gchar *subject_str; + PolkitIdentity *user_of_caller; + PolkitIdentity *user_of_subject; ++ gboolean user_of_subject_matches; + gchar *user_of_caller_str; + gchar *user_of_subject_str; + PolkitAuthorizationResult *result; +@@ -867,7 +868,7 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority + action_id); + + user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, +- caller, ++ caller, NULL, + &error); + if (error != NULL) + { +@@ -882,7 +883,7 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority + g_debug (" user of caller is %s", user_of_caller_str); + + user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, +- subject, ++ subject, &user_of_subject_matches, + &error); + if (error != NULL) + { +@@ -912,7 +913,10 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority + * We only 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) ++ * if details are passed (otherwise you'd be able to spoof the dialog); ++ * the caller supplies the user_of_subject value, so we additionally ++ * require it to match at least at one point in time (via ++ * user_of_subject_matches). + * + * - processes running as uid 0 may check anything and pass any details + * +@@ -920,7 +924,9 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority + * then any uid referenced by that annotation is also allowed to check + * to check anything and pass any details + */ +- if (!polkit_identity_equal (user_of_caller, user_of_subject) || has_details) ++ if (!user_of_subject_matches ++ || !polkit_identity_equal (user_of_caller, user_of_subject) ++ || has_details) + { + if (!may_identity_check_authorization (interactive_authority, action_id, user_of_caller)) + { +@@ -1084,9 +1090,10 @@ check_authorization_sync (PolkitBackendAuthority *authority, + goto out; + } + +- /* every subject has a user */ ++ /* every subject has a user; this is supplied by the client, so we rely ++ * on the caller to validate its acceptability. */ + user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, +- subject, ++ subject, NULL, + error); + if (user_of_subject == NULL) + goto out; +@@ -2201,6 +2208,7 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken + PolkitSubject *session_for_caller; + PolkitIdentity *user_of_caller; + PolkitIdentity *user_of_subject; ++ gboolean user_of_subject_matches; + AuthenticationAgent *agent; + gboolean ret; + gchar *caller_cmdline; +@@ -2255,7 +2263,7 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken + goto out; + } + +- user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL); ++ user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL, NULL); + if (user_of_caller == NULL) + { + g_set_error (error, +@@ -2264,7 +2272,7 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken + "Cannot determine user of caller"); + goto out; + } +- user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, NULL); ++ user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, &user_of_subject_matches, NULL); + if (user_of_subject == NULL) + { + g_set_error (error, +@@ -2273,7 +2281,8 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken + "Cannot determine user of subject"); + goto out; + } +- if (!polkit_identity_equal (user_of_caller, user_of_subject)) ++ if (!user_of_subject_matches ++ || !polkit_identity_equal (user_of_caller, user_of_subject)) + { + if (POLKIT_IS_UNIX_USER (user_of_caller) && polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) == 0) + { +@@ -2356,6 +2365,7 @@ polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBack + PolkitSubject *session_for_caller; + PolkitIdentity *user_of_caller; + PolkitIdentity *user_of_subject; ++ gboolean user_of_subject_matches; + AuthenticationAgent *agent; + gboolean ret; + gchar *scope_str; +@@ -2404,7 +2414,7 @@ polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBack + goto out; + } + +- user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL); ++ user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL, NULL); + if (user_of_caller == NULL) + { + g_set_error (error, +@@ -2413,7 +2423,7 @@ polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBack + "Cannot determine user of caller"); + goto out; + } +- user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, NULL); ++ user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, &user_of_subject_matches, NULL); + if (user_of_subject == NULL) + { + g_set_error (error, +@@ -2422,7 +2432,8 @@ polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBack + "Cannot determine user of subject"); + goto out; + } +- if (!polkit_identity_equal (user_of_caller, user_of_subject)) ++ if (!user_of_subject_matches ++ || !polkit_identity_equal (user_of_caller, user_of_subject)) + { + if (POLKIT_IS_UNIX_USER (user_of_caller) && polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) == 0) + { +@@ -2529,7 +2540,7 @@ polkit_backend_interactive_authority_authentication_agent_response (PolkitBacken + identity_str); + + user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, +- caller, ++ caller, NULL, + error); + if (user_of_caller == NULL) + goto out; +diff --git a/src/polkitbackend/polkitbackendsessionmonitor-systemd.c b/src/polkitbackend/polkitbackendsessionmonitor-systemd.c +index 58593c3..a299e37 100644 +--- a/src/polkitbackend/polkitbackendsessionmonitor-systemd.c ++++ b/src/polkitbackend/polkitbackendsessionmonitor-systemd.c +@@ -29,6 +29,7 @@ + #include + + #include ++#include + #include "polkitbackendsessionmonitor.h" + + /* +@@ -246,26 +247,40 @@ polkit_backend_session_monitor_get_sessions (PolkitBackendSessionMonitor *monito + * polkit_backend_session_monitor_get_user: + * @monitor: A #PolkitBackendSessionMonitor. + * @subject: A #PolkitSubject. ++ * @result_matches: If not %NULL, set to indicate whether the return value matches current (RACY) state. + * @error: Return location for error. + * + * Gets the user corresponding to @subject or %NULL if no user exists. + * ++ * NOTE: For a #PolkitUnixProcess, the UID is read from @subject (which may ++ * come from e.g. a D-Bus client), so it may not correspond to the actual UID ++ * of the referenced process (at any point in time). This is indicated by ++ * setting @result_matches to %FALSE; the caller may reject such subjects or ++ * require additional privileges. @result_matches == %TRUE only indicates that ++ * the UID matched the underlying process at ONE point in time, it may not match ++ * later. ++ * + * Returns: %NULL if @error is set otherwise a #PolkitUnixUser that should be freed with g_object_unref(). + */ + PolkitIdentity * + polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor *monitor, + PolkitSubject *subject, ++ gboolean *result_matches, + GError **error) + { + PolkitIdentity *ret; +- guint32 uid; ++ gboolean matches; + + ret = NULL; ++ matches = FALSE; + + if (POLKIT_IS_UNIX_PROCESS (subject)) + { +- uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)); +- if ((gint) uid == -1) ++ gint subject_uid, current_uid; ++ GError *local_error; ++ ++ subject_uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)); ++ if (subject_uid == -1) + { + g_set_error (error, + POLKIT_ERROR, +@@ -273,11 +288,20 @@ polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor + "Unix process subject does not have uid set"); + goto out; + } +- ret = polkit_unix_user_new (uid); ++ local_error = NULL; ++ current_uid = polkit_unix_process_get_racy_uid__ (POLKIT_UNIX_PROCESS (subject), &local_error); ++ if (local_error != NULL) ++ { ++ g_propagate_error (error, local_error); ++ goto out; ++ } ++ ret = polkit_unix_user_new (subject_uid); ++ matches = (subject_uid == current_uid); + } + else if (POLKIT_IS_SYSTEM_BUS_NAME (subject)) + { + GVariant *result; ++ guint32 uid; + + result = g_dbus_connection_call_sync (monitor->system_bus, + "org.freedesktop.DBus", +@@ -296,9 +320,11 @@ polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor + g_variant_unref (result); + + ret = polkit_unix_user_new (uid); ++ matches = TRUE; + } + else if (POLKIT_IS_UNIX_SESSION (subject)) + { ++ uid_t uid; + + if (sd_session_get_uid (polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (subject)), &uid) < 0) + { +@@ -310,9 +336,14 @@ polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor + } + + ret = polkit_unix_user_new (uid); ++ matches = TRUE; + } + + out: ++ if (result_matches != NULL) ++ { ++ *result_matches = matches; ++ } + return ret; + } + +diff --git a/src/polkitbackend/polkitbackendsessionmonitor.c b/src/polkitbackend/polkitbackendsessionmonitor.c +index 9c331b6..cde7af5 100644 +--- a/src/polkitbackend/polkitbackendsessionmonitor.c ++++ b/src/polkitbackend/polkitbackendsessionmonitor.c +@@ -27,6 +27,7 @@ + #include + + #include ++#include + #include "polkitbackendsessionmonitor.h" + + #define CKDB_PATH "/var/run/ConsoleKit/database" +@@ -273,28 +274,40 @@ polkit_backend_session_monitor_get_sessions (PolkitBackendSessionMonitor *monito + * polkit_backend_session_monitor_get_user: + * @monitor: A #PolkitBackendSessionMonitor. + * @subject: A #PolkitSubject. ++ * @result_matches: If not %NULL, set to indicate whether the return value matches current (RACY) state. + * @error: Return location for error. + * + * Gets the user corresponding to @subject or %NULL if no user exists. + * ++ * NOTE: For a #PolkitUnixProcess, the UID is read from @subject (which may ++ * come from e.g. a D-Bus client), so it may not correspond to the actual UID ++ * of the referenced process (at any point in time). This is indicated by ++ * setting @result_matches to %FALSE; the caller may reject such subjects or ++ * require additional privileges. @result_matches == %TRUE only indicates that ++ * the UID matched the underlying process at ONE point in time, it may not match ++ * later. ++ * + * Returns: %NULL if @error is set otherwise a #PolkitUnixUser that should be freed with g_object_unref(). + */ + PolkitIdentity * + polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor *monitor, + PolkitSubject *subject, ++ gboolean *result_matches, + GError **error) + { + PolkitIdentity *ret; ++ gboolean matches; + GError *local_error; +- gchar *group; +- guint32 uid; + + ret = NULL; ++ matches = FALSE; + + if (POLKIT_IS_UNIX_PROCESS (subject)) + { +- uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)); +- if ((gint) uid == -1) ++ gint subject_uid, current_uid; ++ ++ subject_uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)); ++ if (subject_uid == -1) + { + g_set_error (error, + POLKIT_ERROR, +@@ -302,11 +315,20 @@ polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor + "Unix process subject does not have uid set"); + goto out; + } +- ret = polkit_unix_user_new (uid); ++ local_error = NULL; ++ current_uid = polkit_unix_process_get_racy_uid__ (POLKIT_UNIX_PROCESS (subject), &local_error); ++ if (local_error != NULL) ++ { ++ g_propagate_error (error, local_error); ++ goto out; ++ } ++ ret = polkit_unix_user_new (subject_uid); ++ matches = (subject_uid == current_uid); + } + else if (POLKIT_IS_SYSTEM_BUS_NAME (subject)) + { + GVariant *result; ++ guint32 uid; + + result = g_dbus_connection_call_sync (monitor->system_bus, + "org.freedesktop.DBus", +@@ -325,9 +347,13 @@ polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor + g_variant_unref (result); + + ret = polkit_unix_user_new (uid); ++ matches = TRUE; + } + else if (POLKIT_IS_UNIX_SESSION (subject)) + { ++ gint uid; ++ gchar *group; ++ + if (!ensure_database (monitor, error)) + { + g_prefix_error (error, "Error getting user for session: Error ensuring CK database at " CKDB_PATH ": "); +@@ -346,9 +372,14 @@ polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor + g_free (group); + + ret = polkit_unix_user_new (uid); ++ matches = TRUE; + } + + out: ++ if (result_matches != NULL) ++ { ++ *result_matches = matches; ++ } + return ret; + } + +diff --git a/src/polkitbackend/polkitbackendsessionmonitor.h b/src/polkitbackend/polkitbackendsessionmonitor.h +index 8f8a2ca..3972326 100644 +--- a/src/polkitbackend/polkitbackendsessionmonitor.h ++++ b/src/polkitbackend/polkitbackendsessionmonitor.h +@@ -47,6 +47,7 @@ GList *polkit_backend_session_monitor_get_sessions (Polkit + + PolkitIdentity *polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor *monitor, + PolkitSubject *subject, ++ gboolean *result_matches, + GError **error); + + PolkitSubject *polkit_backend_session_monitor_get_session_for_subject (PolkitBackendSessionMonitor *monitor, diff -Nru policykit-1-0.104/debian/patches/CVE-2018-19788-1.patch policykit-1-0.104/debian/patches/CVE-2018-19788-1.patch --- policykit-1-0.104/debian/patches/CVE-2018-19788-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ policykit-1-0.104/debian/patches/CVE-2018-19788-1.patch 2018-12-07 18:47:54.000000000 +0000 @@ -0,0 +1,185 @@ +From 2cb40c4d5feeaa09325522bd7d97910f1b59e379 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 3 Dec 2018 10:28:58 +0100 +Subject: [PATCH] Allow negative uids/gids in PolkitUnixUser and Group objects + +(uid_t) -1 is still used as placeholder to mean "unset". This is OK, since +there should be no users with such number, see +https://systemd.io/UIDS-GIDS#special-linux-uids. + +(uid_t) -1 is used as the default value in class initialization. + +When a user or group above INT32_MAX is created, the numeric uid or +gid wraps around to negative when the value is assigned to gint, and +polkit gets confused. Let's accept such gids, except for -1. + +A nicer fix would be to change the underlying type to e.g. uint32 to +not have negative values. But this cannot be done without breaking the +API, so likely new functions will have to be added (a +polkit_unix_user_new variant that takes a unsigned, and the same for +_group_new, _set_uid, _get_uid, _set_gid, _get_gid, etc.). This will +require a bigger patch. + +Fixes https://gitlab.freedesktop.org/polkit/polkit/issues/74. +--- + src/polkit/polkitunixgroup.c | 15 +++++++++++---- + src/polkit/polkitunixprocess.c | 12 ++++++++---- + src/polkit/polkitunixuser.c | 13 ++++++++++--- + 3 files changed, 29 insertions(+), 11 deletions(-) + +Index: policykit-1-0.105/src/polkit/polkitunixgroup.c +=================================================================== +--- policykit-1-0.105.orig/src/polkit/polkitunixgroup.c 2018-12-07 07:46:23.491243637 -0500 ++++ policykit-1-0.105/src/polkit/polkitunixgroup.c 2018-12-07 07:46:23.491243637 -0500 +@@ -71,6 +71,7 @@ G_DEFINE_TYPE_WITH_CODE (PolkitUnixGroup + static void + polkit_unix_group_init (PolkitUnixGroup *unix_group) + { ++ unix_group->gid = -1; /* (git_t) -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,9 +170,10 @@ 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)); ++ g_return_if_fail (gid != -1); + group->gid = gid; + } + +@@ -183,6 +188,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)); +Index: policykit-1-0.105/src/polkit/polkitunixprocess.c +=================================================================== +--- policykit-1-0.105.orig/src/polkit/polkitunixprocess.c 2018-12-07 07:46:23.491243637 -0500 ++++ policykit-1-0.105/src/polkit/polkitunixprocess.c 2018-12-07 07:46:23.491243637 -0500 +@@ -147,9 +147,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)); +@@ -227,7 +232,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 | +@@ -291,7 +296,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; + } + +Index: policykit-1-0.105/src/polkit/polkitunixuser.c +=================================================================== +--- policykit-1-0.105.orig/src/polkit/polkitunixuser.c 2018-12-07 07:46:23.491243637 -0500 ++++ policykit-1-0.105/src/polkit/polkitunixuser.c 2018-12-07 07:46:23.491243637 -0500 +@@ -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 -Nru policykit-1-0.104/debian/patches/CVE-2018-19788-2.patch policykit-1-0.104/debian/patches/CVE-2018-19788-2.patch --- policykit-1-0.104/debian/patches/CVE-2018-19788-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ policykit-1-0.104/debian/patches/CVE-2018-19788-2.patch 2018-12-07 18:48:04.000000000 +0000 @@ -0,0 +1,106 @@ +Backport of: + +From b534a10727455409acd54018a9c91000e7626126 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 3 Dec 2018 11:20:34 +0100 +Subject: [PATCH] tests: add tests for high uids + +--- + test/data/etc/group | 1 + + test/data/etc/passwd | 2 + + .../etc/polkit-1/rules.d/10-testing.rules | 21 ++++++ + .../test-polkitbackendjsauthority.c | 72 +++++++++++++++++++ + 4 files changed, 96 insertions(+) + +Index: policykit-1-0.105/test/data/etc/group +=================================================================== +--- policykit-1-0.105.orig/test/data/etc/group 2018-12-07 08:21:34.402387757 -0500 ++++ policykit-1-0.105/test/data/etc/group 2018-12-07 08:21:34.398387743 -0500 +@@ -5,3 +5,4 @@ john:x:500: + jane:x:501: + sally:x:502: + henry:x:503: ++highuid2:x:4000000000: +Index: policykit-1-0.105/test/data/etc/passwd +=================================================================== +--- policykit-1-0.105.orig/test/data/etc/passwd 2018-12-07 08:21:34.402387757 -0500 ++++ policykit-1-0.105/test/data/etc/passwd 2018-12-07 08:21:34.398387743 -0500 +@@ -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 +Index: policykit-1-0.105/test/data/etc/polkit-1/localauthority/10-test/com.example.pkla +=================================================================== +--- policykit-1-0.105.orig/test/data/etc/polkit-1/localauthority/10-test/com.example.pkla 2018-12-07 08:21:34.402387757 -0500 ++++ policykit-1-0.105/test/data/etc/polkit-1/localauthority/10-test/com.example.pkla 2018-12-07 08:21:34.398387743 -0500 +@@ -12,3 +12,16 @@ ResultAny=no + ResultInactive=auth_self + ResultActive=yes + ++[User john can do this] ++Identity=unix-user:john ++Action=net.company.john_action ++ResultAny=no ++ResultInactive=auth_self ++ResultActive=yes ++ ++[User highuid2 can do this] ++Identity=unix-user:highuid2 ++Action=net.company.highuid2_action ++ResultAny=no ++ResultInactive=auth_self ++ResultActive=yes +Index: policykit-1-0.105/test/polkitbackend/polkitbackendlocalauthoritytest.c +=================================================================== +--- policykit-1-0.105.orig/test/polkitbackend/polkitbackendlocalauthoritytest.c 2018-12-07 08:21:34.402387757 -0500 ++++ policykit-1-0.105/test/polkitbackend/polkitbackendlocalauthoritytest.c 2018-12-07 10:23:33.528742547 -0500 +@@ -226,7 +226,46 @@ struct auth_context check_authorization_ + {"unix-user:jane", TRUE, TRUE, "com.example.awesomeproduct.bar", + POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN, + POLKIT_IMPLICIT_AUTHORIZATION_AUTHORIZED}, +- ++ /* highuid1 is not a member of group 'users', see test/data/etc/group ++ * group_membership_with_non_member(highuid22) */ ++ {"unix-user:highuid2", TRUE, TRUE, "com.example.awesomeproduct.foo", ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN, ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN}, ++ /* highuid2 is not a member of group 'users', see test/data/etc/group ++ * group_membership_with_non_member(highuid21) */ ++ {"unix-user:highuid2", TRUE, TRUE, "com.example.awesomeproduct.foo", ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN, ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN}, ++ /* highuid1 is not a member of group 'users', see test/data/etc/group ++ * group_membership_with_non_member(highuid24) */ ++ {"unix-user:2147483648", TRUE, TRUE, "com.example.awesomeproduct.foo", ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN, ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN}, ++ /* highuid2 is not a member of group 'users', see test/data/etc/group ++ * group_membership_with_non_member(highuid23) */ ++ {"unix-user:4000000000", TRUE, TRUE, "com.example.awesomeproduct.foo", ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN, ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN}, ++ /* john is authorized to do this, see com.example.pkla ++ * john_action */ ++ {"unix-user:john", TRUE, TRUE, "net.company.john_action", ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN, ++ POLKIT_IMPLICIT_AUTHORIZATION_AUTHORIZED}, ++ /* only john is authorized to do this, see com.example.pkla ++ * jane_action */ ++ {"unix-user:jane", TRUE, TRUE, "net.company.john_action", ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN, ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN}, ++ /* highuid2 is authorized to do this, see com.example.pkla ++ * highuid2_action */ ++ {"unix-user:highuid2", TRUE, TRUE, "net.company.highuid2_action", ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN, ++ POLKIT_IMPLICIT_AUTHORIZATION_AUTHORIZED}, ++ /* only highuid2 is authorized to do this, see com.example.pkla ++ * highuid1_action */ ++ {"unix-user:highuid1", TRUE, TRUE, "net.company.highuid2_action", ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN, ++ POLKIT_IMPLICIT_AUTHORIZATION_UNKNOWN}, + {NULL}, + }; + diff -Nru policykit-1-0.104/debian/patches/CVE-2018-19788-3.patch policykit-1-0.104/debian/patches/CVE-2018-19788-3.patch --- policykit-1-0.104/debian/patches/CVE-2018-19788-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ policykit-1-0.104/debian/patches/CVE-2018-19788-3.patch 2019-01-16 16:39:46.000000000 +0000 @@ -0,0 +1,44 @@ +From bd4b563afe3f13e865805d731a3e6af09bd3649a Mon Sep 17 00:00:00 2001 +From: Matthew Leeds +Date: Tue, 11 Dec 2018 12:04:26 -0800 +Subject: [PATCH] Allow uid of -1 for a PolkitUnixProcess + +Commit 2cb40c4d5 changed PolkitUnixUser, PolkitUnixGroup, and +PolkitUnixProcess to allow negative values for their uid/gid properties, +since these are values above INT_MAX which wrap around but are still +valid, with the exception of -1 which is not valid. However, +PolkitUnixProcess allows a uid of -1 to be passed to +polkit_unix_process_new_for_owner() which means polkit is expected to +figure out the uid on its own (this happens in the _constructed +function). So this commit removes the check in +polkit_unix_process_set_property() so that new_for_owner() can be used +as documented without producing a critical error message. + +This does not affect the protection against CVE-2018-19788 which is +based on creating a user with a UID up to but not including 4294967295 +(-1). +--- + src/polkit/polkitunixprocess.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +Index: policykit-1-0.105/src/polkit/polkitunixprocess.c +=================================================================== +--- policykit-1-0.105.orig/src/polkit/polkitunixprocess.c 2019-01-15 08:20:11.413040155 -0500 ++++ policykit-1-0.105/src/polkit/polkitunixprocess.c 2019-01-15 08:20:11.413040155 -0500 +@@ -147,14 +147,9 @@ polkit_unix_process_set_property (GObjec + polkit_unix_process_set_pid (unix_process, g_value_get_int (value)); + break; + +- 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); ++ case PROP_UID: ++ polkit_unix_process_set_uid (unix_process, g_value_get_int (value)); + break; +- } + + case PROP_START_TIME: + polkit_unix_process_set_start_time (unix_process, g_value_get_uint64 (value)); diff -Nru policykit-1-0.104/debian/patches/CVE-2019-6133.patch policykit-1-0.104/debian/patches/CVE-2019-6133.patch --- policykit-1-0.104/debian/patches/CVE-2019-6133.patch 1970-01-01 00:00:00.000000000 +0000 +++ policykit-1-0.104/debian/patches/CVE-2019-6133.patch 2019-08-29 18:31:42.000000000 +0000 @@ -0,0 +1,182 @@ +From 6cc6aafee135ba44ea748250d7d29b562ca190e3 Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Fri, 4 Jan 2019 14:24:48 -0500 +Subject: [PATCH] backend: Compare PolkitUnixProcess uids for temporary + authorizations + +It turns out that the combination of `(pid, start time)` is not +enough to be unique. For temporary authorizations, we can avoid +separate users racing on pid reuse by simply comparing the uid. + +https://bugs.chromium.org/p/project-zero/issues/detail?id=1692 + +And the above original email report is included in full in a new comment. + +Reported-by: Jann Horn + +Closes: https://gitlab.freedesktop.org/polkit/polkit/issues/75 +--- + src/polkit/polkitsubject.c | 2 + + src/polkit/polkitunixprocess.c | 71 ++++++++++++++++++- + .../polkitbackendinteractiveauthority.c | 39 +++++++++- + 3 files changed, 110 insertions(+), 2 deletions(-) + +Index: policykit-1-0.104/src/polkit/polkitsubject.c +=================================================================== +--- policykit-1-0.104.orig/src/polkit/polkitsubject.c ++++ policykit-1-0.104/src/polkit/polkitsubject.c +@@ -97,6 +97,8 @@ polkit_subject_hash (PolkitSubject *subj + * @b: A #PolkitSubject. + * + * Checks if @a and @b are equal, ie. represent the same subject. ++ * However, avoid calling polkit_subject_equal() to compare two processes; ++ * for more information see the `PolkitUnixProcess` documentation. + * + * This function can be used in e.g. g_hash_table_new(). + * +Index: policykit-1-0.104/src/polkit/polkitunixprocess.c +=================================================================== +--- policykit-1-0.104.orig/src/polkit/polkitunixprocess.c ++++ policykit-1-0.104/src/polkit/polkitunixprocess.c +@@ -44,7 +44,10 @@ + * @title: PolkitUnixProcess + * @short_description: Unix processs + * +- * An object for representing a UNIX process. ++ * An object for representing a UNIX process. NOTE: This object as ++ * designed is now known broken; a mechanism to exploit a delay in ++ * start time in the Linux kernel was identified. Avoid ++ * calling polkit_subject_equal() to compare two processes. + * + * To uniquely identify processes, both the process id and the start + * time of the process (a monotonic increasing value representing the +@@ -59,6 +62,72 @@ + * polkit_unix_process_new_for_owner() with trusted data. + */ + ++/* See https://gitlab.freedesktop.org/polkit/polkit/issues/75 ++ ++ But quoting the original email in full here to ensure it's preserved: ++ ++ From: Jann Horn ++ Subject: [SECURITY] polkit: temporary auth hijacking via PID reuse and non-atomic fork ++ Date: Wednesday, October 10, 2018 5:34 PM ++ ++When a (non-root) user attempts to e.g. control systemd units in the system ++instance from an active session over DBus, the access is gated by a polkit ++policy that requires "auth_admin_keep" auth. This results in an auth prompt ++being shown to the user, asking the user to confirm the action by entering the ++password of an administrator account. ++ ++After the action has been confirmed, the auth decision for "auth_admin_keep" is ++cached for up to five minutes. Subject to some restrictions, similar actions can ++then be performed in this timespan without requiring re-auth: ++ ++ - The PID of the DBus client requesting the new action must match the PID of ++ the DBus client requesting the old action (based on SO_PEERCRED information ++ forwarded by the DBus daemon). ++ - The "start time" of the client's PID (as seen in /proc/$pid/stat, field 22) ++ must not have changed. The granularity of this timestamp is in the ++ millisecond range. ++ - polkit polls every two seconds whether a process with the expected start time ++ still exists. If not, the temporary auth entry is purged. ++ ++Without the start time check, this would obviously be buggy because an attacker ++could simply wait for the legitimate client to disappear, then create a new ++client with the same PID. ++ ++Unfortunately, the start time check is bypassable because fork() is not atomic. ++Looking at the source code of copy_process() in the kernel: ++ ++ p->start_time = ktime_get_ns(); ++ p->real_start_time = ktime_get_boot_ns(); ++ [...] ++ retval = copy_thread_tls(clone_flags, stack_start, stack_size, p, tls); ++ if (retval) ++ goto bad_fork_cleanup_io; ++ ++ if (pid != &init_struct_pid) { ++ pid = alloc_pid(p->nsproxy->pid_ns_for_children); ++ if (IS_ERR(pid)) { ++ retval = PTR_ERR(pid); ++ goto bad_fork_cleanup_thread; ++ } ++ } ++ ++The ktime_get_boot_ns() call is where the "start time" of the process is ++recorded. The alloc_pid() call is where a free PID is allocated. In between ++these, some time passes; and because the copy_thread_tls() call between them can ++access userspace memory when sys_clone() is invoked through the 32-bit syscall ++entry point, an attacker can even stall the kernel arbitrarily long at this ++point (by supplying a pointer into userspace memory that is associated with a ++userfaultfd or is backed by a custom FUSE filesystem). ++ ++This means that an attacker can immediately call sys_clone() when the victim ++process is created, often resulting in a process that has the exact same start ++time reported in procfs; and then the attacker can delay the alloc_pid() call ++until after the victim process has died and the PID assignment has cycled ++around. This results in an attacker process that polkit can't distinguish from ++the victim process. ++*/ ++ ++ + /** + * PolkitUnixProcess: + * +Index: policykit-1-0.104/src/polkitbackend/polkitbackendinteractiveauthority.c +=================================================================== +--- policykit-1-0.104.orig/src/polkitbackend/polkitbackendinteractiveauthority.c ++++ policykit-1-0.104/src/polkitbackend/polkitbackendinteractiveauthority.c +@@ -2739,6 +2739,43 @@ temporary_authorization_store_free (Temp + g_free (store); + } + ++/* See the comment at the top of polkitunixprocess.c */ ++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, +@@ -2781,7 +2818,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 -Nru policykit-1-0.104/debian/patches/series policykit-1-0.104/debian/patches/series --- policykit-1-0.104/debian/patches/series 2013-09-11 13:48:36.000000000 +0000 +++ policykit-1-0.104/debian/patches/series 2019-08-29 18:31:38.000000000 +0000 @@ -5,3 +5,9 @@ 05_revert-admin-identities-unix-group-wheel.patch 07_pam_environment.patch CVE-2013-4288.patch +CVE-2018-1116.patch +CVE-2015-3255.patch +CVE-2018-19788-1.patch +CVE-2018-19788-2.patch +CVE-2018-19788-3.patch +CVE-2019-6133.patch