[polkit/f14/master] CVE-2011-1485 (#697951)

David Zeuthen davidz at fedoraproject.org
Tue Apr 19 19:27:50 UTC 2011


commit ec60ab3da33b8e2d22c7c64d550016a086b9d5bc
Author: David Zeuthen <davidz at redhat.com>
Date:   Tue Apr 19 15:27:55 2011 -0400

    CVE-2011-1485 (#697951)

 ...missing-GObject-Introspection-annotations.patch |  374 ++++++++++++
 ...rocess-Clarify-that-the-real-uid-is-retur.patch |  138 +++++
 ...UnixProcess-also-record-the-uid-of-the-pr.patch |  622 ++++++++++++++++++++
 ...unix_process_get_uid-to-get-the-owner-of-.patch |   40 ++
 ...void-TOCTTOU-problems-with-parent-process.patch |  127 ++++
 polkit.spec                                        |   16 +-
 6 files changed, 1316 insertions(+), 1 deletions(-)
---
diff --git a/0001-Add-missing-GObject-Introspection-annotations.patch b/0001-Add-missing-GObject-Introspection-annotations.patch
new file mode 100644
index 0000000..7f74580
--- /dev/null
+++ b/0001-Add-missing-GObject-Introspection-annotations.patch
@@ -0,0 +1,374 @@
+From cb7bfcb8188169ac1cc9085359500637120dfa0c Mon Sep 17 00:00:00 2001
+From: David Zeuthen <davidz at redhat.com>
+Date: Thu, 17 Feb 2011 15:10:49 -0500
+Subject: [PATCH] Add missing GObject Introspection annotations
+
+Signed-off-by: David Zeuthen <davidz at redhat.com>
+---
+ src/polkit/Makefile.am               |   21 +--------------
+ src/polkit/polkitactiondescription.c |    2 +-
+ src/polkit/polkitauthority.c         |   45 +++++++++++++++++++++++----------
+ src/polkit/polkitauthority.h         |    8 ------
+ src/polkit/polkitdetails.c           |    5 ++-
+ src/polkit/polkitidentity.c          |    4 +-
+ src/polkit/polkitsubject.c           |    4 +-
+ src/polkit/polkitsystembusname.c     |    4 +-
+ src/polkit/polkitunixgroup.c         |    4 +-
+ src/polkit/polkitunixprocess.c       |    4 +-
+ src/polkit/polkitunixsession.c       |    8 +++---
+ src/polkit/polkitunixuser.c          |    4 +-
+ 12 files changed, 53 insertions(+), 60 deletions(-)
+
+diff --git a/src/polkit/Makefile.am b/src/polkit/Makefile.am
+index 4afd4ee..e44df1f 100644
+--- a/src/polkit/Makefile.am
++++ b/src/polkit/Makefile.am
+@@ -100,6 +100,7 @@ typelibs_DATA = Polkit-1.0.typelib
+ 
+ Polkit-1.0.gir: libpolkit-gobject-1.la $(G_IR_SCANNER) Makefile.am
+ 	$(G_IR_SCANNER) -v 					\
++		--warn-all					\
+ 		--namespace Polkit 				\
+ 		--nsversion=1.0 				\
+ 		--include=Gio-2.0 				\
+@@ -111,25 +112,7 @@ Polkit-1.0.gir: libpolkit-gobject-1.la $(G_IR_SCANNER) Makefile.am
+ 		--libtool=$(top_builddir)/libtool		\
+                 -I$(top_srcdir)/src	 			\
+ 	        -D_POLKIT_COMPILATION                   	\
+-		$(srcdir)/polkit.h 				\
+-		$(srcdir)/polkittypes.h 			\
+-		$(srcdir)/polkitactiondescription.h 		\
+-		$(srcdir)/polkitauthority.h 			\
+-		$(srcdir)/polkitauthorizationresult.h 		\
+-		$(srcdir)/polkitcheckauthorizationflags.h 	\
+-		$(srcdir)/polkitdetails.h 			\
+-		$(builddir)/polkitenumtypes.h 			\
+-		$(srcdir)/polkiterror.h 			\
+-		$(srcdir)/polkitidentity.h 			\
+-		$(srcdir)/polkitimplicitauthorization.h 	\
+-		$(srcdir)/polkitsubject.h 			\
+-		$(srcdir)/polkitsystembusname.h 		\
+-		$(srcdir)/polkittemporaryauthorization.h 	\
+-		$(srcdir)/polkitunixgroup.h 			\
+-		$(srcdir)/polkitunixprocess.h 			\
+-		$(srcdir)/polkitunixsession.h 			\
+-		$(srcdir)/polkitunixuser.h 			\
+-		$(srcdir)/polkitpermission.h 			\
++		$(libpolkit_gobject_1_la_SOURCES)		\
+ 		$(NULL)
+ 
+ Polkit-1.0.typelib: Polkit-1.0.gir $(G_IR_COMPILER)
+diff --git a/src/polkit/polkitactiondescription.c b/src/polkit/polkitactiondescription.c
+index 6930cc4..0391efd 100644
+--- a/src/polkit/polkitactiondescription.c
++++ b/src/polkit/polkitactiondescription.c
+@@ -265,7 +265,7 @@ polkit_action_description_get_annotation (PolkitActionDescription *action_descri
+  *
+  * Gets the keys of annotations defined in @action_description.
+  *
+- * Returns: The annotation keys owned by @action_description. Do not free.
++ * Returns: (transfer none): The annotation keys owned by @action_description. Do not free.
+  */
+ const gchar * const *
+ polkit_action_description_get_annotation_keys (PolkitActionDescription *action_description)
+diff --git a/src/polkit/polkitauthority.c b/src/polkit/polkitauthority.c
+index 404be18..cc24e6c 100644
+--- a/src/polkit/polkitauthority.c
++++ b/src/polkit/polkitauthority.c
+@@ -370,6 +370,14 @@ async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
+ /* ---------------------------------------------------------------------------------------------------- */
+ 
+ /* deprecated, see polkitauthority.h */
++
++/**
++ * polkit_authority_get:
++ *
++ * (deprecated)
++ *
++ * Returns: (transfer full): value
++ */
+ PolkitAuthority *
+ polkit_authority_get (void)
+ {
+@@ -498,8 +506,8 @@ polkit_authority_get_async  (GCancellable        *cancellable,
+  *
+  * Finishes an operation started with polkit_authority_get_async().
+  *
+- * Returns: A #PolkitAuthority. Free it with g_object_unref() when
+- * done with it.
++ * Returns: (transfer full): A #PolkitAuthority. Free it with
++ * g_object_unref() when done with it.
+  */
+ PolkitAuthority *
+ polkit_authority_get_finish (GAsyncResult        *res,
+@@ -540,8 +548,8 @@ polkit_authority_get_finish (GAsyncResult        *res,
+  * blocked until a reply is received. See polkit_authority_get_async()
+  * for the asynchronous version.
+  *
+- * Returns: A #PolkitAuthority. Free it with g_object_unref() when
+- * done with it.
++ * Returns: (transfer full): A #PolkitAuthority. Free it with
++ * g_object_unref() when done with it.
+  */
+ PolkitAuthority *
+ polkit_authority_get_sync (GCancellable        *cancellable,
+@@ -672,8 +680,10 @@ polkit_authority_enumerate_actions (PolkitAuthority     *authority,
+  *
+  * Finishes retrieving all registered actions.
+  *
+- * Returns: A list of #PolkitActionDescription objects or %NULL if @error is set. The returned list
+- * should be freed with g_list_free() after each element have been freed with g_object_unref().
++ * Returns: (transfer full): A list of #PolkitActionDescription
++ * objects or %NULL if @error is set. The returned list should be
++ * freed with g_list_free() after each element have been freed with
++ * g_object_unref().
+  **/
+ GList *
+ polkit_authority_enumerate_actions_finish (PolkitAuthority *authority,
+@@ -726,8 +736,10 @@ polkit_authority_enumerate_actions_finish (PolkitAuthority *authority,
+  * is blocked until a reply is received. See
+  * polkit_authority_enumerate_actions() for the asynchronous version.
+  *
+- * Returns: A list of #PolkitActionDescription or %NULL if @error is set. The returned list
+- * should be freed with g_list_free() after each element have been freed with g_object_unref().
++ * Returns: (transfer full): A list of #PolkitActionDescription or
++ * %NULL if @error is set. The returned list should be freed with
++ * g_list_free() after each element have been freed with
++ * g_object_unref().
+  **/
+ GList *
+ polkit_authority_enumerate_actions_sync (PolkitAuthority *authority,
+@@ -919,7 +931,8 @@ polkit_authority_check_authorization (PolkitAuthority               *authority,
+  *
+  * Finishes checking if a subject is authorized for an action.
+  *
+- * Returns: A #PolkitAuthorizationResult or %NULL if @error is set. Free with g_object_unref().
++ * Returns: (transfer full): A #PolkitAuthorizationResult or %NULL if
++ * @error is set. Free with g_object_unref().
+  **/
+ PolkitAuthorizationResult *
+ polkit_authority_check_authorization_finish (PolkitAuthority          *authority,
+@@ -972,7 +985,7 @@ polkit_authority_check_authorization_finish (PolkitAuthority          *authority
+  * operation to complete because it involves waiting for the user to
+  * authenticate.
+  *
+- * Returns: A #PolkitAuthorizationResult or %NULL if @error is set. Free with g_object_unref().
++ * Returns: (transfer full): A #PolkitAuthorizationResult or %NULL if @error is set. Free with g_object_unref().
+  */
+ PolkitAuthorizationResult *
+ polkit_authority_check_authorization_sync (PolkitAuthority               *authority,
+@@ -1469,8 +1482,10 @@ polkit_authority_enumerate_temporary_authorizations (PolkitAuthority     *author
+  *
+  * Finishes retrieving all registered actions.
+  *
+- * Returns: A list of #PolkitTemporaryAuthorization objects or %NULL if @error is set. The returned list
+- * should be freed with g_list_free() after each element have been freed with g_object_unref().
++ * Returns: (transfer full): A list of #PolkitTemporaryAuthorization
++ * objects or %NULL if @error is set. The returned list should be
++ * freed with g_list_free() after each element have been freed with
++ * g_object_unref().
+  **/
+ GList *
+ polkit_authority_enumerate_temporary_authorizations_finish (PolkitAuthority *authority,
+@@ -1534,8 +1549,10 @@ polkit_authority_enumerate_temporary_authorizations_finish (PolkitAuthority *aut
+  * polkit_authority_enumerate_temporary_authorizations() for the
+  * asynchronous version.
+  *
+- * Returns: A list of #PolkitTemporaryAuthorization objects or %NULL if @error is set. The returned list
+- * should be freed with g_list_free() after each element have been freed with g_object_unref().
++ * Returns: (transfer full): A list of #PolkitTemporaryAuthorization
++ * objects or %NULL if @error is set. The returned list should be
++ * freed with g_list_free() after each element have been freed with
++ * g_object_unref().
+  **/
+ GList *
+ polkit_authority_enumerate_temporary_authorizations_sync (PolkitAuthority     *authority,
+diff --git a/src/polkit/polkitauthority.h b/src/polkit/polkitauthority.h
+index f363228..edd8a62 100644
+--- a/src/polkit/polkitauthority.h
++++ b/src/polkit/polkitauthority.h
+@@ -68,14 +68,6 @@ GList                     *polkit_authority_enumerate_actions_sync (PolkitAuthor
+                                                                     GCancellable    *cancellable,
+                                                                     GError         **error);
+ 
+-GList                     *polkit_authority_enumerate_users_sync (PolkitAuthority *authority,
+-                                                                  GCancellable    *cancellable,
+-                                                                  GError         **error);
+-
+-GList                     *polkit_authority_enumerate_groups_sync (PolkitAuthority *authority,
+-                                                                   GCancellable    *cancellable,
+-                                                                   GError         **error);
+-
+ PolkitAuthorizationResult *polkit_authority_check_authorization_sync (PolkitAuthority               *authority,
+                                                                       PolkitSubject                 *subject,
+                                                                       const gchar                   *action_id,
+diff --git a/src/polkit/polkitdetails.c b/src/polkit/polkitdetails.c
+index 4f6555d..9c5c7e7 100644
+--- a/src/polkit/polkitdetails.c
++++ b/src/polkit/polkitdetails.c
+@@ -164,8 +164,9 @@ polkit_details_insert (PolkitDetails *details,
+  *
+  * Gets a list of all keys on @details.
+  *
+- * Returns: (allow-none): %NULL if there are no keys otherwise an
+- * array of strings that should be freed with g_strfreev().
++ * Returns: (transfer full) (allow-none): %NULL if there are no keys
++ * otherwise an array of strings that should be freed with
++ * g_strfreev().
+  */
+ gchar **
+ polkit_details_get_keys (PolkitDetails *details)
+diff --git a/src/polkit/polkitidentity.c b/src/polkit/polkitidentity.c
+index 413b41f..21c326b 100644
+--- a/src/polkit/polkitidentity.c
++++ b/src/polkit/polkitidentity.c
+@@ -137,8 +137,8 @@ polkit_identity_to_string (PolkitIdentity *identity)
+  * Creates an object from @str that implements the #PolkitIdentity
+  * interface.
+  *
+- * Returns: (allow-none): A #PolkitIdentity or %NULL if @error is
+- * set. Free with g_object_unref().
++ * Returns: (allow-none) (transfer full): A #PolkitIdentity or %NULL
++ * if @error is set. Free with g_object_unref().
+  */
+ PolkitIdentity *
+ polkit_identity_from_string  (const gchar   *str,
+diff --git a/src/polkit/polkitsubject.c b/src/polkit/polkitsubject.c
+index d193eb2..577afec 100644
+--- a/src/polkit/polkitsubject.c
++++ b/src/polkit/polkitsubject.c
+@@ -218,8 +218,8 @@ polkit_subject_exists_sync   (PolkitSubject  *subject,
+  * Creates an object from @str that implements the #PolkitSubject
+  * interface.
+  *
+- * Returns: A #PolkitSubject or %NULL if @error is set. Free with
+- * g_object_unref().
++ * Returns: (transfer full): A #PolkitSubject or %NULL if @error is
++ * set. Free with g_object_unref().
+  */
+ PolkitSubject *
+ polkit_subject_from_string  (const gchar   *str,
+diff --git a/src/polkit/polkitsystembusname.c b/src/polkit/polkitsystembusname.c
+index 41f2762..2a297c4 100644
+--- a/src/polkit/polkitsystembusname.c
++++ b/src/polkit/polkitsystembusname.c
+@@ -190,7 +190,7 @@ polkit_system_bus_name_set_name (PolkitSystemBusName *system_bus_name,
+  *
+  * Creates a new #PolkitSystemBusName for @name.
+  *
+- * Returns: A #PolkitSystemBusName. Free with g_object_unref().
++ * Returns: (transfer full): A #PolkitSystemBusName. Free with g_object_unref().
+  */
+ PolkitSubject *
+ polkit_system_bus_name_new (const gchar *name)
+@@ -349,7 +349,7 @@ subject_iface_init (PolkitSubjectIface *subject_iface)
+  * Synchronously gets a #PolkitUnixProcess object for @system_bus_name
+  * - the calling thread is blocked until a reply is received.
+  *
+- * Returns: (allow-none): A #PolkitUnixProcess object or %NULL if @error is set.
++ * Returns: (allow-none) (transfer full): A #PolkitUnixProcess object or %NULL if @error is set.
+  **/
+ PolkitSubject *
+ polkit_system_bus_name_get_process_sync (PolkitSystemBusName  *system_bus_name,
+diff --git a/src/polkit/polkitunixgroup.c b/src/polkit/polkitunixgroup.c
+index c9838e5..c57a1aa 100644
+--- a/src/polkit/polkitunixgroup.c
++++ b/src/polkit/polkitunixgroup.c
+@@ -178,7 +178,7 @@ polkit_unix_group_set_gid (PolkitUnixGroup *group,
+  *
+  * Creates a new #PolkitUnixGroup object for @gid.
+  *
+- * Returns: A #PolkitUnixGroup object. Free with g_object_unref().
++ * Returns: (transfer full): A #PolkitUnixGroup object. Free with g_object_unref().
+  */
+ PolkitIdentity *
+ polkit_unix_group_new (gint gid)
+@@ -196,7 +196,7 @@ polkit_unix_group_new (gint gid)
+  * Creates a new #PolkitUnixGroup object for a group with the group name
+  * @name.
+  *
+- * Returns: (allow-none): A #PolkitUnixGroup object or %NULL if @error
++ * Returns: (transfer full): (allow-none): A #PolkitUnixGroup object or %NULL if @error
+  * is set.
+  */
+ PolkitIdentity *
+diff --git a/src/polkit/polkitunixprocess.c b/src/polkit/polkitunixprocess.c
+index b293ea0..d95a1d4 100644
+--- a/src/polkit/polkitunixprocess.c
++++ b/src/polkit/polkitunixprocess.c
+@@ -302,7 +302,7 @@ polkit_unix_process_set_pid (PolkitUnixProcess *process,
+  * <filename>/proc</filename> filesystem depending on the platform in
+  * use.
+  *
+- * Returns: A #PolkitSubject. Free with g_object_unref().
++ * Returns: (transfer full): A #PolkitSubject. Free with g_object_unref().
+  */
+ PolkitSubject *
+ polkit_unix_process_new (gint pid)
+@@ -319,7 +319,7 @@ polkit_unix_process_new (gint pid)
+  *
+  * Creates a new #PolkitUnixProcess object for @pid and @start_time.
+  *
+- * Returns: A #PolkitSubject. Free with g_object_unref().
++ * Returns: (transfer full): A #PolkitSubject. Free with g_object_unref().
+  */
+ PolkitSubject *
+ polkit_unix_process_new_full (gint pid,
+diff --git a/src/polkit/polkitunixsession.c b/src/polkit/polkitunixsession.c
+index c466561..40817de 100644
+--- a/src/polkit/polkitunixsession.c
++++ b/src/polkit/polkitunixsession.c
+@@ -222,7 +222,7 @@ polkit_unix_session_set_session_id (PolkitUnixSession *session,
+  *
+  * Creates a new #PolkitUnixSession for @session_id.
+  *
+- * Returns: A #PolkitUnixSession. Free with g_object_unref().
++ * Returns: (transfer full): A #PolkitUnixSession. Free with g_object_unref().
+  **/
+ PolkitSubject *
+ polkit_unix_session_new (const gchar *session_id)
+@@ -274,7 +274,7 @@ polkit_unix_session_new_for_process (gint                pid,
+  *
+  * Finishes constructing a #PolkitSubject for a process id.
+  *
+- * Returns: (allow-none): A #PolkitUnixSession for the @pid passed to
++ * Returns: (transfer full) (allow-none): A #PolkitUnixSession for the @pid passed to
+  *     polkit_unix_session_new_for_process() or %NULL if @error is
+  *     set. Free with g_object_unref().
+  **/
+@@ -312,8 +312,8 @@ polkit_unix_session_new_for_process_finish (GAsyncResult   *res,
+  * reply is received. For the asynchronous version, see
+  * polkit_unix_session_new_for_process().
+  *
+- * Returns: (allow-none): A #PolkitUnixSession for @pid or %NULL if
+- * @error is set. Free with g_object_unref().
++ * Returns: (allow-none) (transfer full): A #PolkitUnixSession for
++ * @pid or %NULL if @error is set. Free with g_object_unref().
+  **/
+ PolkitSubject *
+ polkit_unix_session_new_for_process_sync (gint           pid,
+diff --git a/src/polkit/polkitunixuser.c b/src/polkit/polkitunixuser.c
+index a57adaf..1c9cf49 100644
+--- a/src/polkit/polkitunixuser.c
++++ b/src/polkit/polkitunixuser.c
+@@ -178,7 +178,7 @@ polkit_unix_user_set_uid (PolkitUnixUser *user,
+  *
+  * Creates a new #PolkitUnixUser object for @uid.
+  *
+- * Returns: A #PolkitUnixUser object. Free with g_object_unref().
++ * Returns: (transfer full): A #PolkitUnixUser object. Free with g_object_unref().
+  */
+ PolkitIdentity *
+ polkit_unix_user_new (gint uid)
+@@ -196,7 +196,7 @@ polkit_unix_user_new (gint uid)
+  * Creates a new #PolkitUnixUser object for a user with the user name
+  * @name.
+  *
+- * Returns: (allow-none): A #PolkitUnixUser object or %NULL if @error is set.
++ * Returns: (allow-none) (transfer full): A #PolkitUnixUser object or %NULL if @error is set.
+  */
+ PolkitIdentity *
+ polkit_unix_user_new_for_name (const gchar    *name,
+-- 
+1.7.4.4
+
diff --git a/0001-PolkitUnixProcess-Clarify-that-the-real-uid-is-retur.patch b/0001-PolkitUnixProcess-Clarify-that-the-real-uid-is-retur.patch
new file mode 100644
index 0000000..7f803a7
--- /dev/null
+++ b/0001-PolkitUnixProcess-Clarify-that-the-real-uid-is-retur.patch
@@ -0,0 +1,138 @@
+From dd848a42a64a3b22a0cc60f6657b56ce9b6010ae Mon Sep 17 00:00:00 2001
+From: David Zeuthen <davidz at redhat.com>
+Date: Thu, 31 Mar 2011 12:59:09 -0400
+Subject: [PATCH 1/4] PolkitUnixProcess: Clarify that the real uid is returned, not the effective one
+
+On Linux, also switch to parsing /proc/<pid>/status instead of relying
+on the st_uid returned by stat(2) to be the uid we want.
+
+This was pointed out by Neel Mehta <nmehta at google.com>. Thanks!
+
+Signed-off-by: David Zeuthen <davidz at redhat.com>
+---
+ src/polkit/polkitunixprocess.c |   66 ++++++++++++++++++++++++++++++----------
+ 1 files changed, 50 insertions(+), 16 deletions(-)
+
+diff --git a/src/polkit/polkitunixprocess.c b/src/polkit/polkitunixprocess.c
+index d95a1d4..876da69 100644
+--- a/src/polkit/polkitunixprocess.c
++++ b/src/polkit/polkitunixprocess.c
+@@ -24,9 +24,7 @@
+ #endif
+ 
+ #include <sys/types.h>
+-#ifndef HAVE_FREEBSD
+-#include <sys/stat.h>
+-#else
++#ifdef HAVE_FREEBSD
+ #include <sys/param.h>
+ #include <sys/sysctl.h>
+ #include <sys/user.h>
+@@ -34,6 +32,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <errno.h>
++#include <stdio.h>
+ 
+ #include "polkitunixprocess.h"
+ #include "polkitsubject.h"
+@@ -208,6 +207,8 @@ polkit_unix_process_get_pid (PolkitUnixProcess *process)
+  *
+  * Gets the uid of the owner of @process.
+  *
++ * Note that this returns the real user-id (not the effective user-id) of @process.
++ *
+  * Returns: The UNIX user id of the owner for @process or 0 if @error is set.
+  **/
+ gint
+@@ -215,17 +216,21 @@ polkit_unix_process_get_owner (PolkitUnixProcess  *process,
+                                GError            **error)
+ {
+   gint result;
++  gchar *contents;
++  gchar **lines;
+ #ifdef HAVE_FREEBSD
+   struct kinfo_proc p;
+ #else
+-  struct stat statbuf;
+-  char procbuf[32];
++  gchar filename[64];
++  guint n;
+ #endif
+ 
+   g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), 0);
+   g_return_val_if_fail (error == NULL || *error == NULL, 0);
+ 
+   result = 0;
++  lines = NULL;
++  contents = NULL;
+ 
+ #ifdef HAVE_FREEBSD
+   if (get_kinfo_proc (process->pid, &p) == 0)
+@@ -241,23 +246,52 @@ polkit_unix_process_get_owner (PolkitUnixProcess  *process,
+ 
+   result = p.ki_uid;
+ #else
+-  g_snprintf (procbuf, sizeof procbuf, "/proc/%d", process->pid);
+-  if (stat (procbuf, &statbuf) != 0)
++
++  /* see 'man proc' for layout of the status file
++   *
++   * Uid, Gid: Real, effective, saved set,  and  file  system  UIDs (GIDs).
++   */
++  g_snprintf (filename, sizeof filename, "/proc/%d/status", process->pid);
++  if (!g_file_get_contents (filename,
++                            &contents,
++                            NULL,
++                            error))
+     {
+-      g_set_error (error,
+-                   POLKIT_ERROR,
+-                   POLKIT_ERROR_FAILED,
+-                   "stat() failed for /proc/%d: %s",
+-                   process->pid,
+-                   g_strerror (errno));
+       goto out;
+     }
++  lines = g_strsplit (contents, "\n", -1);
++  for (n = 0; lines != NULL && lines[n] != NULL; n++)
++    {
++      gint real_uid, effective_uid;
++      if (!g_str_has_prefix (lines[n], "Uid:"))
++        continue;
++      if (sscanf (lines[n] + 4, "%d %d", &real_uid, &effective_uid) != 2)
++        {
++          g_set_error (error,
++                       POLKIT_ERROR,
++                       POLKIT_ERROR_FAILED,
++                       "Unexpected line `%s' in file %s",
++                       lines[n],
++                       filename);
++          goto out;
++        }
++      else
++        {
++          result = real_uid;
++          goto out;
++        }
++    }
+ 
+-  result = statbuf.st_uid;
++  g_set_error (error,
++               POLKIT_ERROR,
++               POLKIT_ERROR_FAILED,
++               "Didn't find any line starting with `Uid:' in file %s",
++               filename);
+ #endif
+ 
+- out:
+-
++out:
++  g_strfreev (lines);
++  g_free (contents);
+   return result;
+ }
+ 
+-- 
+1.7.4.2
+
diff --git a/0002-Make-PolkitUnixProcess-also-record-the-uid-of-the-pr.patch b/0002-Make-PolkitUnixProcess-also-record-the-uid-of-the-pr.patch
new file mode 100644
index 0000000..29ff49e
--- /dev/null
+++ b/0002-Make-PolkitUnixProcess-also-record-the-uid-of-the-pr.patch
@@ -0,0 +1,622 @@
+From 129b6223a19e7fb2753f8cad7957ac5402394076 Mon Sep 17 00:00:00 2001
+From: David Zeuthen <davidz at redhat.com>
+Date: Fri, 1 Apr 2011 12:09:45 -0400
+Subject: [PATCH 2/4] Make PolkitUnixProcess also record the uid of the process
+
+This is needed to avoid possible TOCTTOU issues since a process can
+change both its real uid and effective uid.
+
+Signed-off-by: David Zeuthen <davidz at redhat.com>
+---
+ docs/polkit/polkit-1-sections.txt |    7 +-
+ src/polkit/polkitsubject.c        |   25 +++-
+ src/polkit/polkitunixprocess.c    |  346 +++++++++++++++++++++++++------------
+ src/polkit/polkitunixprocess.h    |   18 ++-
+ 4 files changed, 278 insertions(+), 118 deletions(-)
+
+diff --git a/docs/polkit/polkit-1-sections.txt b/docs/polkit/polkit-1-sections.txt
+index 12141e3..9f4fcf8 100644
+--- a/docs/polkit/polkit-1-sections.txt
++++ b/docs/polkit/polkit-1-sections.txt
+@@ -145,10 +145,13 @@ POLKIT_UNIX_SESSION_GET_CLASS
+ PolkitUnixProcess
+ polkit_unix_process_new
+ polkit_unix_process_new_full
++polkit_unix_process_new_for_owner
++polkit_unix_process_set_pid
+ polkit_unix_process_get_pid
++polkit_unix_process_set_start_time
+ polkit_unix_process_get_start_time
+-polkit_unix_process_set_pid
+-polkit_unix_process_get_owner
++polkit_unix_process_set_uid
++polkit_unix_process_get_uid
+ <SUBSECTION Standard>
+ PolkitUnixProcessClass
+ POLKIT_UNIX_PROCESS
+diff --git a/src/polkit/polkitsubject.c b/src/polkit/polkitsubject.c
+index 577afec..d2c4c20 100644
+--- a/src/polkit/polkitsubject.c
++++ b/src/polkit/polkitsubject.c
+@@ -238,13 +238,18 @@ polkit_subject_from_string  (const gchar   *str,
+     {
+       gint scanned_pid;
+       guint64 scanned_starttime;
+-      if (sscanf (str, "unix-process:%d:%" G_GUINT64_FORMAT, &scanned_pid, &scanned_starttime) == 2)
++      gint scanned_uid;
++      if (sscanf (str, "unix-process:%d:%" G_GUINT64_FORMAT ":%d", &scanned_pid, &scanned_starttime, &scanned_uid) == 3)
++        {
++          subject = polkit_unix_process_new_for_owner (scanned_pid, scanned_starttime, scanned_uid);
++        }
++      else if (sscanf (str, "unix-process:%d:%" G_GUINT64_FORMAT, &scanned_pid, &scanned_starttime) == 2)
+         {
+           subject = polkit_unix_process_new_full (scanned_pid, scanned_starttime);
+         }
+       else if (sscanf (str, "unix-process:%d", &scanned_pid) == 1)
+         {
+-          subject = polkit_unix_process_new_full (scanned_pid, 0);
++          subject = polkit_unix_process_new (scanned_pid);
+           if (polkit_unix_process_get_start_time (POLKIT_UNIX_PROCESS (subject)) == 0)
+             {
+               g_object_unref (subject);
+@@ -297,6 +302,8 @@ polkit_subject_to_gvariant (PolkitSubject *subject)
+                              g_variant_new_uint32 (polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (subject))));
+       g_variant_builder_add (&builder, "{sv}", "start-time",
+                              g_variant_new_uint64 (polkit_unix_process_get_start_time (POLKIT_UNIX_PROCESS (subject))));
++      g_variant_builder_add (&builder, "{sv}", "uid",
++                             g_variant_new_int32 (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject))));
+     }
+   else if (POLKIT_IS_UNIX_SESSION (subject))
+     {
+@@ -395,6 +402,7 @@ polkit_subject_new_for_gvariant (GVariant  *variant,
+       GVariant *v;
+       guint32 pid;
+       guint64 start_time;
++      gint32 uid;
+ 
+       v = lookup_asv (details_gvariant, "pid", G_VARIANT_TYPE_UINT32, error);
+       if (v == NULL)
+@@ -414,7 +422,18 @@ polkit_subject_new_for_gvariant (GVariant  *variant,
+       start_time = g_variant_get_uint64 (v);
+       g_variant_unref (v);
+ 
+-      ret = polkit_unix_process_new_full (pid, start_time);
++      v = lookup_asv (details_gvariant, "uid", G_VARIANT_TYPE_INT32, error);
++      if (v != NULL)
++        {
++          uid = g_variant_get_int32 (v);
++          g_variant_unref (v);
++        }
++      else
++        {
++          uid = -1;
++        }
++
++      ret = polkit_unix_process_new_for_owner (pid, start_time, uid);
+     }
+   else if (g_strcmp0 (kind, "unix-session") == 0)
+     {
+diff --git a/src/polkit/polkitunixprocess.c b/src/polkit/polkitunixprocess.c
+index 876da69..913be3a 100644
+--- a/src/polkit/polkitunixprocess.c
++++ b/src/polkit/polkitunixprocess.c
+@@ -62,6 +62,7 @@ struct _PolkitUnixProcess
+ 
+   gint pid;
+   guint64 start_time;
++  gint uid;
+ };
+ 
+ struct _PolkitUnixProcessClass
+@@ -74,6 +75,7 @@ enum
+   PROP_0,
+   PROP_PID,
+   PROP_START_TIME,
++  PROP_UID
+ };
+ 
+ static void subject_iface_init (PolkitSubjectIface *subject_iface);
+@@ -81,6 +83,9 @@ 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
+@@ -92,6 +97,7 @@ G_DEFINE_TYPE_WITH_CODE (PolkitUnixProcess, polkit_unix_process, G_TYPE_OBJECT,
+ static void
+ polkit_unix_process_init (PolkitUnixProcess *unix_process)
+ {
++  unix_process->uid = -1;
+ }
+ 
+ static void
+@@ -108,6 +114,10 @@ polkit_unix_process_get_property (GObject    *object,
+       g_value_set_int (value, unix_process->pid);
+       break;
+ 
++    case PROP_UID:
++      g_value_set_int (value, unix_process->uid);
++      break;
++
+     case PROP_START_TIME:
+       g_value_set_uint64 (value, unix_process->start_time);
+       break;
+@@ -132,6 +142,14 @@ polkit_unix_process_set_property (GObject      *object,
+       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));
++      break;
++
++    case PROP_START_TIME:
++      polkit_unix_process_set_start_time (unix_process, g_value_get_uint64 (value));
++      break;
++
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       break;
+@@ -139,12 +157,39 @@ polkit_unix_process_set_property (GObject      *object,
+ }
+ 
+ static void
++polkit_unix_process_constructed (GObject *object)
++{
++  PolkitUnixProcess *process = POLKIT_UNIX_PROCESS (object);
++
++  /* sets start_time and uid in case they are unset */
++
++  if (process->start_time == 0)
++    process->start_time = get_start_time_for_pid (process->pid, NULL);
++
++  if (process->uid == -1)
++    {
++      GError *error;
++      error = NULL;
++      process->uid = _polkit_unix_process_get_owner (process, &error);
++      if (error != NULL)
++        {
++          process->uid = -1;
++          g_error_free (error);
++        }
++    }
++
++  if (G_OBJECT_CLASS (polkit_unix_process_parent_class)->constructed != NULL)
++    G_OBJECT_CLASS (polkit_unix_process_parent_class)->constructed (object);
++}
++
++static void
+ polkit_unix_process_class_init (PolkitUnixProcessClass *klass)
+ {
+   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ 
+   gobject_class->get_property = polkit_unix_process_get_property;
+   gobject_class->set_property = polkit_unix_process_set_property;
++  gobject_class->constructed =  polkit_unix_process_constructed;
+ 
+   /**
+    * PolkitUnixProcess:pid:
+@@ -156,7 +201,7 @@ polkit_unix_process_class_init (PolkitUnixProcessClass *klass)
+                                    g_param_spec_int ("pid",
+                                                      "Process ID",
+                                                      "The UNIX process ID",
+-                                                     -1,
++                                                     0,
+                                                      G_MAXINT,
+                                                      0,
+                                                      G_PARAM_CONSTRUCT |
+@@ -166,6 +211,27 @@ polkit_unix_process_class_init (PolkitUnixProcessClass *klass)
+                                                      G_PARAM_STATIC_NICK));
+ 
+   /**
++   * PolkitUnixProcess:uid:
++   *
++   * The UNIX user id of the process or -1 if unknown.
++   *
++   * Note that this is the real user-id, not the effective user-id.
++   */
++  g_object_class_install_property (gobject_class,
++                                   PROP_UID,
++                                   g_param_spec_int ("uid",
++                                                     "User ID",
++                                                     "The UNIX user ID",
++                                                     -1,
++                                                     G_MAXINT,
++                                                     -1,
++                                                     G_PARAM_CONSTRUCT |
++                                                     G_PARAM_READWRITE |
++                                                     G_PARAM_STATIC_NAME |
++                                                     G_PARAM_STATIC_BLURB |
++                                                     G_PARAM_STATIC_NICK));
++
++  /**
+    * PolkitUnixProcess:start-time:
+    *
+    * The start time of the process.
+@@ -178,7 +244,8 @@ polkit_unix_process_class_init (PolkitUnixProcessClass *klass)
+                                                         0,
+                                                         G_MAXUINT64,
+                                                         0,
+-                                                        G_PARAM_READABLE |
++                                                        G_PARAM_CONSTRUCT |
++                                                        G_PARAM_READWRITE |
+                                                         G_PARAM_STATIC_NAME |
+                                                         G_PARAM_STATIC_BLURB |
+                                                         G_PARAM_STATIC_NICK));
+@@ -186,113 +253,50 @@ polkit_unix_process_class_init (PolkitUnixProcessClass *klass)
+ }
+ 
+ /**
+- * polkit_unix_process_get_pid:
++ * polkit_unix_process_get_uid:
+  * @process: A #PolkitUnixProcess.
+  *
+- * Gets the process id for @process.
++ * Gets the user id for @process. Note that this is the real user-id,
++ * not the effective user-id.
+  *
+- * Returns: The process id for @process.
++ * Returns: The user id for @process or -1 if unknown.
+  */
+ gint
+-polkit_unix_process_get_pid (PolkitUnixProcess *process)
++polkit_unix_process_get_uid (PolkitUnixProcess *process)
+ {
+-  g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), 0);
+-  return process->pid;
++  g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), -1);
++  return process->uid;
+ }
+ 
+ /**
+- * polkit_unix_process_get_owner:
++ * polkit_unix_process_set_uid:
+  * @process: A #PolkitUnixProcess.
+- * @error: (allow-none): Return location for error or %NULL.
++ * @uid: The user id to set for @process or -1 to unset it.
+  *
+- * Gets the uid of the owner of @process.
++ * Sets the (real, not effective) user id for @process.
++ */
++void
++polkit_unix_process_set_uid (PolkitUnixProcess *process,
++                             gint               uid)
++{
++  g_return_if_fail (POLKIT_IS_UNIX_PROCESS (process));
++  g_return_if_fail (uid >= -1);
++  process->uid = uid;
++}
++
++/**
++ * polkit_unix_process_get_pid:
++ * @process: A #PolkitUnixProcess.
+  *
+- * Note that this returns the real user-id (not the effective user-id) of @process.
++ * Gets the process id for @process.
+  *
+- * Returns: The UNIX user id of the owner for @process or 0 if @error is set.
+- **/
++ * Returns: The process id for @process.
++ */
+ gint
+-polkit_unix_process_get_owner (PolkitUnixProcess  *process,
+-                               GError            **error)
++polkit_unix_process_get_pid (PolkitUnixProcess *process)
+ {
+-  gint result;
+-  gchar *contents;
+-  gchar **lines;
+-#ifdef HAVE_FREEBSD
+-  struct kinfo_proc p;
+-#else
+-  gchar filename[64];
+-  guint n;
+-#endif
+-
+   g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), 0);
+-  g_return_val_if_fail (error == NULL || *error == NULL, 0);
+-
+-  result = 0;
+-  lines = NULL;
+-  contents = NULL;
+-
+-#ifdef HAVE_FREEBSD
+-  if (get_kinfo_proc (process->pid, &p) == 0)
+-    {
+-      g_set_error (error,
+-                   POLKIT_ERROR,
+-                   POLKIT_ERROR_FAILED,
+-                   "get_kinfo_proc() failed for pid %d: %s",
+-                   process->pid,
+-                   g_strerror (errno));
+-      goto out;
+-    }
+-
+-  result = p.ki_uid;
+-#else
+-
+-  /* see 'man proc' for layout of the status file
+-   *
+-   * Uid, Gid: Real, effective, saved set,  and  file  system  UIDs (GIDs).
+-   */
+-  g_snprintf (filename, sizeof filename, "/proc/%d/status", process->pid);
+-  if (!g_file_get_contents (filename,
+-                            &contents,
+-                            NULL,
+-                            error))
+-    {
+-      goto out;
+-    }
+-  lines = g_strsplit (contents, "\n", -1);
+-  for (n = 0; lines != NULL && lines[n] != NULL; n++)
+-    {
+-      gint real_uid, effective_uid;
+-      if (!g_str_has_prefix (lines[n], "Uid:"))
+-        continue;
+-      if (sscanf (lines[n] + 4, "%d %d", &real_uid, &effective_uid) != 2)
+-        {
+-          g_set_error (error,
+-                       POLKIT_ERROR,
+-                       POLKIT_ERROR_FAILED,
+-                       "Unexpected line `%s' in file %s",
+-                       lines[n],
+-                       filename);
+-          goto out;
+-        }
+-      else
+-        {
+-          result = real_uid;
+-          goto out;
+-        }
+-    }
+-
+-  g_set_error (error,
+-               POLKIT_ERROR,
+-               POLKIT_ERROR_FAILED,
+-               "Didn't find any line starting with `Uid:' in file %s",
+-               filename);
+-#endif
+-
+-out:
+-  g_strfreev (lines);
+-  g_free (contents);
+-  return result;
++  return process->pid;
+ }
+ 
+ /**
+@@ -311,6 +315,21 @@ polkit_unix_process_get_start_time (PolkitUnixProcess *process)
+ }
+ 
+ /**
++ * polkit_unix_process_set_start_time:
++ * @process: A #PolkitUnixProcess.
++ * @start_time: The start time for @pid.
++ *
++ * Set the start time of @process.
++ */
++void
++polkit_unix_process_set_start_time (PolkitUnixProcess *process,
++                                    guint64            start_time)
++{
++  g_return_if_fail (POLKIT_IS_UNIX_PROCESS (process));
++  process->start_time = start_time;
++}
++
++/**
+  * polkit_unix_process_set_pid:
+  * @process: A #PolkitUnixProcess.
+  * @pid: A process id.
+@@ -323,18 +342,17 @@ polkit_unix_process_set_pid (PolkitUnixProcess *process,
+ {
+   g_return_if_fail (POLKIT_IS_UNIX_PROCESS (process));
+   process->pid = pid;
+-  if (pid != (gint) -1)
+-    process->start_time = get_start_time_for_pid (pid, NULL);
+ }
+ 
+ /**
+  * polkit_unix_process_new:
+  * @pid: The process id.
+  *
+- * Creates a new #PolkitUnixProcess for @pid. The start time of the
+- * process will be looked up in using e.g. the
+- * <filename>/proc</filename> filesystem depending on the platform in
+- * use.
++ * Creates a new #PolkitUnixProcess for @pid.
++ *
++ * The uid and start time of the process will be looked up in using
++ * e.g. the <filename>/proc</filename> filesystem depending on the
++ * platform in use.
+  *
+  * Returns: (transfer full): A #PolkitSubject. Free with g_object_unref().
+  */
+@@ -353,22 +371,42 @@ polkit_unix_process_new (gint pid)
+  *
+  * Creates a new #PolkitUnixProcess object for @pid and @start_time.
+  *
++ * The uid of the process will be looked up in using e.g. the
++ * <filename>/proc</filename> filesystem depending on the platform in
++ * use.
++ *
+  * Returns: (transfer full): A #PolkitSubject. Free with g_object_unref().
+  */
+ PolkitSubject *
+ polkit_unix_process_new_full (gint pid,
+                               guint64 start_time)
+ {
+-  PolkitUnixProcess *process;
+-
+-  process = POLKIT_UNIX_PROCESS (polkit_unix_process_new ((gint) -1));
+-  process->pid = pid;
+-  if (start_time != 0)
+-    process->start_time = start_time;
+-  else
+-    process->start_time = get_start_time_for_pid (pid, NULL);
++  return POLKIT_SUBJECT (g_object_new (POLKIT_TYPE_UNIX_PROCESS,
++                                       "pid", pid,
++                                       "start_time", start_time,
++                                       NULL));
++}
+ 
+-  return POLKIT_SUBJECT (process);
++/**
++ * polkit_unix_process_new_for_owner:
++ * @pid: The process id.
++ * @start_time: The start time for @pid or 0 to look it up in e.g. <filename>/proc</filename>.
++ * @uid: The (real, not effective) uid of the owner of @pid or -1 to look it up in e.g. <filename>/proc</filename>.
++ *
++ * Creates a new #PolkitUnixProcess object for @pid, @start_time and @uid.
++ *
++ * Returns: (transfer full): A #PolkitSubject. Free with g_object_unref().
++ */
++PolkitSubject *
++polkit_unix_process_new_for_owner (gint    pid,
++                                   guint64 start_time,
++                                   gint    uid)
++{
++  return POLKIT_SUBJECT (g_object_new (POLKIT_TYPE_UNIX_PROCESS,
++                                       "pid", pid,
++                                       "start_time", start_time,
++                                       "uid", uid,
++                                       NULL));
+ }
+ 
+ static guint
+@@ -616,3 +654,95 @@ out:
+ 
+   return start_time;
+ }
++
++static gint
++_polkit_unix_process_get_owner (PolkitUnixProcess  *process,
++                                GError            **error)
++{
++  gint result;
++  gchar *contents;
++  gchar **lines;
++#ifdef HAVE_FREEBSD
++  struct kinfo_proc p;
++#else
++  gchar filename[64];
++  guint n;
++#endif
++
++  g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), 0);
++  g_return_val_if_fail (error == NULL || *error == NULL, 0);
++
++  result = 0;
++  lines = NULL;
++  contents = NULL;
++
++#ifdef HAVE_FREEBSD
++  if (get_kinfo_proc (process->pid, &p) == 0)
++    {
++      g_set_error (error,
++                   POLKIT_ERROR,
++                   POLKIT_ERROR_FAILED,
++                   "get_kinfo_proc() failed for pid %d: %s",
++                   process->pid,
++                   g_strerror (errno));
++      goto out;
++    }
++
++  result = p.ki_uid;
++#else
++
++  /* see 'man proc' for layout of the status file
++   *
++   * Uid, Gid: Real, effective, saved set,  and  file  system  UIDs (GIDs).
++   */
++  g_snprintf (filename, sizeof filename, "/proc/%d/status", process->pid);
++  if (!g_file_get_contents (filename,
++                            &contents,
++                            NULL,
++                            error))
++    {
++      goto out;
++    }
++  lines = g_strsplit (contents, "\n", -1);
++  for (n = 0; lines != NULL && lines[n] != NULL; n++)
++    {
++      gint real_uid, effective_uid;
++      if (!g_str_has_prefix (lines[n], "Uid:"))
++        continue;
++      if (sscanf (lines[n] + 4, "%d %d", &real_uid, &effective_uid) != 2)
++        {
++          g_set_error (error,
++                       POLKIT_ERROR,
++                       POLKIT_ERROR_FAILED,
++                       "Unexpected line `%s' in file %s",
++                       lines[n],
++                       filename);
++          goto out;
++        }
++      else
++        {
++          result = real_uid;
++          goto out;
++        }
++    }
++
++  g_set_error (error,
++               POLKIT_ERROR,
++               POLKIT_ERROR_FAILED,
++               "Didn't find any line starting with `Uid:' in file %s",
++               filename);
++#endif
++
++out:
++  g_strfreev (lines);
++  g_free (contents);
++  return result;
++}
++
++/* deprecated public method */
++gint
++polkit_unix_process_get_owner (PolkitUnixProcess  *process,
++                               GError            **error)
++{
++  return _polkit_unix_process_get_owner (process, error);
++}
+diff --git a/src/polkit/polkitunixprocess.h b/src/polkit/polkitunixprocess.h
+index b88cd03..531a57d 100644
+--- a/src/polkit/polkitunixprocess.h
++++ b/src/polkit/polkitunixprocess.h
+@@ -47,16 +47,24 @@ typedef struct _PolkitUnixProcess PolkitUnixProcess;
+ typedef struct _PolkitUnixProcessClass PolkitUnixProcessClass;
+ 
+ GType           polkit_unix_process_get_type       (void) G_GNUC_CONST;
+-PolkitSubject  *polkit_unix_process_new            (gint pid);
+-PolkitSubject  *polkit_unix_process_new_full       (gint pid,
+-                                                    guint64 start_time);
+-
++PolkitSubject  *polkit_unix_process_new            (gint               pid);
++PolkitSubject  *polkit_unix_process_new_full       (gint               pid,
++                                                    guint64            start_time);
++PolkitSubject  *polkit_unix_process_new_for_owner  (gint               pid,
++                                                    guint64            start_time,
++                                                    gint               uid);
+ gint            polkit_unix_process_get_pid        (PolkitUnixProcess *process);
+ guint64         polkit_unix_process_get_start_time (PolkitUnixProcess *process);
++gint            polkit_unix_process_get_uid        (PolkitUnixProcess *process);
+ void            polkit_unix_process_set_pid        (PolkitUnixProcess *process,
+                                                     gint               pid);
++void            polkit_unix_process_set_uid        (PolkitUnixProcess *process,
++                                                    gint               uid);
++void            polkit_unix_process_set_start_time (PolkitUnixProcess *process,
++                                                    guint64            start_time);
++
+ gint            polkit_unix_process_get_owner      (PolkitUnixProcess  *process,
+-                                                    GError            **error);
++                                                    GError            **error) G_GNUC_DEPRECATED_FOR (polkit_unix_process_get_uid);
+ 
+ G_END_DECLS
+ 
+-- 
+1.7.4.2
+
diff --git a/0003-Use-polkit_unix_process_get_uid-to-get-the-owner-of-.patch b/0003-Use-polkit_unix_process_get_uid-to-get-the-owner-of-.patch
new file mode 100644
index 0000000..9c7be68
--- /dev/null
+++ b/0003-Use-polkit_unix_process_get_uid-to-get-the-owner-of-.patch
@@ -0,0 +1,40 @@
+From c23d74447c7615dc74dae259f0fc3688ec988867 Mon Sep 17 00:00:00 2001
+From: David Zeuthen <davidz at redhat.com>
+Date: Fri, 1 Apr 2011 12:12:27 -0400
+Subject: [PATCH 3/4] Use polkit_unix_process_get_uid() to get the owner of a process
+
+This avoids a TOCTTOU problem.
+
+Signed-off-by: David Zeuthen <davidz at redhat.com>
+---
+ src/polkitbackend/polkitbackendsessionmonitor.c |   11 ++++++-----
+ 1 files changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/src/polkitbackend/polkitbackendsessionmonitor.c b/src/polkitbackend/polkitbackendsessionmonitor.c
+index 495f752..9c331b6 100644
+--- a/src/polkitbackend/polkitbackendsessionmonitor.c
++++ b/src/polkitbackend/polkitbackendsessionmonitor.c
+@@ -293,14 +293,15 @@ polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor
+ 
+   if (POLKIT_IS_UNIX_PROCESS (subject))
+     {
+-      local_error = NULL;
+-      uid = polkit_unix_process_get_owner (POLKIT_UNIX_PROCESS (subject), &local_error);
+-      if (local_error != NULL)
++      uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject));
++      if ((gint) uid == -1)
+         {
+-          g_propagate_prefixed_error (error, local_error, "Error getting user for process: ");
++          g_set_error (error,
++                       POLKIT_ERROR,
++                       POLKIT_ERROR_FAILED,
++                       "Unix process subject does not have uid set");
+           goto out;
+         }
+-
+       ret = polkit_unix_user_new (uid);
+     }
+   else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
+-- 
+1.7.4.2
+
diff --git a/0004-pkexec-Avoid-TOCTTOU-problems-with-parent-process.patch b/0004-pkexec-Avoid-TOCTTOU-problems-with-parent-process.patch
new file mode 100644
index 0000000..f61dcdd
--- /dev/null
+++ b/0004-pkexec-Avoid-TOCTTOU-problems-with-parent-process.patch
@@ -0,0 +1,127 @@
+From 3b12cfac29dddd27f1f166a7574d8374cc1dccf2 Mon Sep 17 00:00:00 2001
+From: David Zeuthen <davidz at redhat.com>
+Date: Fri, 1 Apr 2011 12:13:15 -0400
+Subject: [PATCH 4/4] pkexec: Avoid TOCTTOU problems with parent process
+
+In a nutshell, the parent process may change its uid (either real- or
+effective uid) after launching pkexec. It can do this by exec()'ing
+e.g. a setuid root program.
+
+To avoid this problem, just use the uid the parent process had when it
+executed pkexec. This happens to be the same uid of the pkexec process
+itself.
+
+Additionally, remove some dubious code that allowed pkexec to continue
+when the parent process died as there is no reason to support
+something like that. Also ensure that the pkexec process is killed if
+the parent process dies.
+
+This problem was pointed out by Neel Mehta <nmehta at google.com>.
+
+Signed-off-by: David Zeuthen <davidz at redhat.com>
+---
+ src/programs/pkexec.c |   66 +++++++++++++++++++++++++++++--------------------
+ 1 files changed, 39 insertions(+), 27 deletions(-)
+
+diff --git a/src/programs/pkexec.c b/src/programs/pkexec.c
+index 9217954..3e656be 100644
+--- a/src/programs/pkexec.c
++++ b/src/programs/pkexec.c
+@@ -35,6 +35,10 @@
+ #include <pwd.h>
+ #include <errno.h>
+ 
++#ifdef __linux__
++#include <sys/prctl.h>
++#endif
++
+ #ifdef POLKIT_AUTHFW_PAM
+ #include <security/pam_appl.h>
+ #endif /* POLKIT_AUTHFW_PAM */
+@@ -423,7 +427,6 @@ main (int argc, char *argv[])
+   GPtrArray *saved_env;
+   gchar *opt_user;
+   pid_t pid_of_caller;
+-  uid_t uid_of_caller;
+   gpointer local_agent_handle;
+ 
+   ret = 127;
+@@ -598,40 +601,49 @@ main (int argc, char *argv[])
+    */
+   g_type_init ();
+ 
+-  /* now check if the program that invoked us is authorized */
++  /* make sure we are nuked if the parent process dies */
++#ifdef __linux__
++  if (prctl (PR_SET_PDEATHSIG, SIGTERM) != 0)
++    {
++      g_printerr ("prctl(PR_SET_PDEATHSIG, SIGTERM) failed: %s\n", g_strerror (errno));
++      goto out;
++    }
++#else
++#warning "Please add OS specific code to catch when the parent dies"
++#endif
++
++  /* Figure out the parent process */
+   pid_of_caller = getppid ();
+   if (pid_of_caller == 1)
+     {
+       /* getppid() can return 1 if the parent died (meaning that we are reaped
+-       * by /sbin/init); get process group leader instead - for example, this
+-       * happens when launching via gnome-panel (alt+f2, then 'pkexec gedit').
++       * by /sbin/init); In that case we simpy bail.
+        */
+-      pid_of_caller = getpgrp ();
+-    }
+-
+-  subject = polkit_unix_process_new (pid_of_caller);
+-  if (subject == NULL)
+-    {
+-      g_printerr ("No such process for pid %d: %s\n", (gint) pid_of_caller, error->message);
+-      g_error_free (error);
++      g_printerr ("Refusing to render service to dead parents.\n");
+       goto out;
+     }
+ 
+-  /* paranoia: check that the uid of pid_of_caller matches getuid() */
+-  error = NULL;
+-  uid_of_caller = polkit_unix_process_get_owner (POLKIT_UNIX_PROCESS (subject),
+-                                                 &error);
+-  if (error != NULL)
+-    {
+-      g_printerr ("Error determing pid of caller (pid %d): %s\n", (gint) pid_of_caller, error->message);
+-      g_error_free (error);
+-      goto out;
+-    }
+-  if (uid_of_caller != getuid ())
+-    {
+-      g_printerr ("User of caller (%d) does not match our uid (%d)\n", uid_of_caller, getuid ());
+-      goto out;
+-    }
++  /* This process we want to check an authorization for is the process
++   * that launched us - our parent process.
++   *
++   * At the time the parent process fork()'ed and exec()'ed us, the
++   * process had the same real-uid that we have now. So we use this
++   * real-uid instead of of looking it up to avoid TOCTTOU issues
++   * (consider the parent process exec()'ing a setuid helper).
++   *
++   * On the other hand, the monotonic process start-time is guaranteed
++   * to never change so it's safe to look that up given only the PID
++   * since we are guaranteed to be nuked if the parent goes away
++   * (cf. the prctl(2) call above).
++   */
++  subject = polkit_unix_process_new_for_owner (pid_of_caller,
++                                               0, /* 0 means "look up start-time in /proc" */
++                                               getuid ());
++  /* really double-check the invariants guaranteed by the PolkitUnixProcess class */
++  g_assert (subject != NULL);
++  g_assert (polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (subject)) == pid_of_caller);
++  g_assert (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)) >= 0);
++  g_assert (polkit_unix_process_get_start_time (POLKIT_UNIX_PROCESS (subject)) > 0);
+ 
+   error = NULL;
+   authority = polkit_authority_get_sync (NULL /* GCancellable* */, &error);
+-- 
+1.7.4.2
+
diff --git a/polkit.spec b/polkit.spec
index 99186c2..09cc701 100644
--- a/polkit.spec
+++ b/polkit.spec
@@ -1,7 +1,7 @@
 Summary: PolicyKit Authorization Framework
 Name: polkit
 Version: 0.98
-Release: 4%{?dist}
+Release: 5%{?dist}
 License: LGPLv2+
 URL: http://www.freedesktop.org/wiki/Software/PolicyKit
 Source0: http://hal.freedesktop.org/releases/%{name}-%{version}.tar.gz
@@ -13,6 +13,12 @@ BuildRequires: gtk-doc
 BuildRequires: intltool
 BuildRequires: gobject-introspection-devel
 
+Patch1: 0001-Add-missing-GObject-Introspection-annotations.patch
+Patch11: 0001-PolkitUnixProcess-Clarify-that-the-real-uid-is-retur.patch
+Patch12: 0002-Make-PolkitUnixProcess-also-record-the-uid-of-the-pr.patch
+Patch13: 0003-Use-polkit_unix_process_get_uid-to-get-the-owner-of-.patch
+Patch14: 0004-pkexec-Avoid-TOCTTOU-problems-with-parent-process.patch
+
 Requires: ConsoleKit
 Requires: dbus
 
@@ -63,6 +69,11 @@ Roles and default policy for desktop usage.
 
 %prep
 %setup -q
+%patch1 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
 
 %build
 %configure --enable-gtk-doc --disable-static --libexecdir=%{_libexecdir}/polkit-1 --disable-introspection --enable-examples
@@ -183,6 +194,9 @@ EOF
 %{_datadir}/gtk-doc/html/*
 
 %changelog
+* Tue Apr 19 2011 David Zeuthen <davidz at redhat.com> - 0.98-5
+- CVE-2011-1485 (#697951)
+
 * Thu Sep 02 2010 David Zeuthen <davidz at redhat.com> - 0.98-4
 - Fix #629515 in a way that doesn't require autoreconf
 


More information about the scm-commits mailing list