diff options
Diffstat (limited to 'patches/source/polkit/CVE-2011-1485')
4 files changed, 926 insertions, 0 deletions
diff --git a/patches/source/polkit/CVE-2011-1485/0001-PolkitUnixProcess-Clarify-that-the-real-uid-is-retur.patch b/patches/source/polkit/CVE-2011-1485/0001-PolkitUnixProcess-Clarify-that-the-real-uid-is-retur.patch new file mode 100644 index 000000000..e448ce953 --- /dev/null +++ b/patches/source/polkit/CVE-2011-1485/0001-PolkitUnixProcess-Clarify-that-the-real-uid-is-retur.patch @@ -0,0 +1,122 @@ +From 83a65f1255fc3eebfb4be1f80a5ab0b5f98eef7c Mon Sep 17 00:00:00 2001 +From: David Zeuthen <davidz@redhat.com> +Date: Mon, 11 Apr 2011 11:38:22 -0400 +Subject: [PATCH 1/6] 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@google.com>. Thanks! + +Signed-off-by: David Zeuthen <davidz@redhat.com> +--- + src/polkit/polkitunixprocess.c | 58 ++++++++++++++++++++++++++++++++------- + 1 files changed, 47 insertions(+), 11 deletions(-) + +diff --git a/src/polkit/polkitunixprocess.c b/src/polkit/polkitunixprocess.c +index e132387..868e3c5 100644 +--- a/src/polkit/polkitunixprocess.c ++++ b/src/polkit/polkitunixprocess.c +@@ -34,6 +34,7 @@ + #include <stdlib.h> + #include <string.h> + #include <errno.h> ++#include <stdio.h> + + #include "polkitunixprocess.h" + #include "polkitsubject.h" +@@ -207,6 +208,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 +@@ -214,14 +217,18 @@ 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 + + result = 0; ++ lines = NULL; ++ contents = NULL; + + #ifdef HAVE_FREEBSD + if (get_kinfo_proc (process->pid, &p) == 0) +@@ -237,22 +244,51 @@ 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: ++ g_strfreev (lines); ++ g_free (contents); + + return result; + } +-- +1.7.4.4 + diff --git a/patches/source/polkit/CVE-2011-1485/0002-Make-PolkitUnixProcess-also-record-the-uid-of-the-pr.patch b/patches/source/polkit/CVE-2011-1485/0002-Make-PolkitUnixProcess-also-record-the-uid-of-the-pr.patch new file mode 100644 index 000000000..5c70a71e5 --- /dev/null +++ b/patches/source/polkit/CVE-2011-1485/0002-Make-PolkitUnixProcess-also-record-the-uid-of-the-pr.patch @@ -0,0 +1,666 @@ +From 9a44af8ab67d09a2c08be29428b8fe32da809e99 Mon Sep 17 00:00:00 2001 +From: David Zeuthen <davidz@redhat.com> +Date: Mon, 11 Apr 2011 12:41:00 -0400 +Subject: [PATCH 2/6] 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@redhat.com> +--- + docs/polkit/polkit-1-sections.txt | 7 +- + src/polkit/polkitsubject.c | 51 ++++-- + src/polkit/polkitunixprocess.c | 350 +++++++++++++++++++++++++----------- + src/polkit/polkitunixprocess.h | 10 + + 4 files changed, 296 insertions(+), 122 deletions(-) + +diff --git a/docs/polkit/polkit-1-sections.txt b/docs/polkit/polkit-1-sections.txt +index ac902b6..7f42cd2 100644 +--- a/docs/polkit/polkit-1-sections.txt ++++ b/docs/polkit/polkit-1-sections.txt +@@ -148,10 +148,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 d5039a5..02c707b 100644 +--- a/src/polkit/polkitsubject.c ++++ b/src/polkit/polkitsubject.c +@@ -24,6 +24,7 @@ + #endif + + #include <string.h> ++#include <stdio.h> + + #include "polkitsubject.h" + #include "polkitunixprocess.h" +@@ -209,8 +210,6 @@ polkit_subject_from_string (const gchar *str, + GError **error) + { + PolkitSubject *subject; +- guint64 val; +- gchar *endptr; + + g_return_val_if_fail (str != NULL, NULL); + +@@ -220,12 +219,20 @@ polkit_subject_from_string (const gchar *str, + + if (g_str_has_prefix (str, "unix-process:")) + { +- val = g_ascii_strtoull (str + sizeof "unix-process:" - 1, +- &endptr, +- 10); +- if (*endptr == '\0') ++ gint scanned_pid; ++ guint64 scanned_starttime; ++ 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 ((gint) val); ++ 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 (scanned_pid); + if (polkit_unix_process_get_start_time (POLKIT_UNIX_PROCESS (subject)) == 0) + { + g_object_unref (subject); +@@ -233,8 +240,8 @@ polkit_subject_from_string (const gchar *str, + g_set_error (error, + POLKIT_ERROR, + POLKIT_ERROR_FAILED, +- "No process with pid %" G_GUINT64_FORMAT, +- val); ++ "Unable to determine start time for process with pid %d", ++ scanned_pid); + } + } + } +@@ -268,6 +275,7 @@ polkit_subject_new_for_real (_PolkitSubject *real) + EggDBusHashMap *details; + EggDBusVariant *variant; + EggDBusVariant *variant2; ++ EggDBusVariant *variant3; + + s = NULL; + +@@ -281,10 +289,24 @@ polkit_subject_new_for_real (_PolkitSubject *real) + else if (strcmp (kind, "unix-process") == 0) + { + variant = egg_dbus_hash_map_lookup (details, "pid"); +- variant2 = egg_dbus_hash_map_lookup (details, "start-time"); +- if (variant != NULL && variant2 != NULL) +- s = polkit_unix_process_new_full (egg_dbus_variant_get_uint (variant), +- egg_dbus_variant_get_uint64 (variant2)); ++ if (variant != NULL && egg_dbus_variant_is_uint (variant)) ++ { ++ gint pid; ++ guint64 start_time; ++ gint uid; ++ variant2 = egg_dbus_hash_map_lookup (details, "start-time"); ++ pid = egg_dbus_variant_get_uint (variant); ++ if (variant2 != NULL && egg_dbus_variant_is_uint64 (variant2)) ++ start_time = egg_dbus_variant_get_uint64 (variant2); ++ else ++ start_time = 0; ++ variant3 = egg_dbus_hash_map_lookup (details, "uid"); ++ if (variant3 != NULL && egg_dbus_variant_is_int (variant3)) ++ uid = egg_dbus_variant_get_int (variant3); ++ else ++ uid = -1; ++ s = polkit_unix_process_new_for_owner (pid, start_time, uid); ++ } + } + else if (strcmp (kind, "unix-session") == 0) + { +@@ -330,6 +352,9 @@ polkit_subject_get_real (PolkitSubject *subject) + egg_dbus_hash_map_insert (details, + "start-time", + egg_dbus_variant_new_for_uint64 (polkit_unix_process_get_start_time (POLKIT_UNIX_PROCESS (subject)))); ++ egg_dbus_hash_map_insert (details, ++ "uid", ++ egg_dbus_variant_new_for_int (polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject)))); + } + else if (POLKIT_IS_UNIX_SESSION (subject)) + { +diff --git a/src/polkit/polkitunixprocess.c b/src/polkit/polkitunixprocess.c +index 868e3c5..eb455f6 100644 +--- a/src/polkit/polkitunixprocess.c ++++ b/src/polkit/polkitunixprocess.c +@@ -64,6 +64,7 @@ struct _PolkitUnixProcess + + gint pid; + guint64 start_time; ++ gint uid; + }; + + struct _PolkitUnixProcessClass +@@ -76,6 +77,7 @@ enum + PROP_0, + PROP_PID, + PROP_START_TIME, ++ PROP_UID + }; + + static void subject_iface_init (PolkitSubjectIface *subject_iface); +@@ -83,6 +85,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 +@@ -94,6 +99,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 +@@ -110,6 +116,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; +@@ -134,6 +144,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; +@@ -141,12 +159,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: +@@ -158,7 +203,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 | +@@ -168,6 +213,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. +@@ -180,7 +246,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)); +@@ -188,109 +255,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) + { +- 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: 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 +- +- 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; ++ g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), 0); ++ return process->pid; + } + + /** +@@ -304,10 +312,26 @@ polkit_unix_process_get_owner (PolkitUnixProcess *process, + guint64 + polkit_unix_process_get_start_time (PolkitUnixProcess *process) + { ++ g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), 0); + return process->start_time; + } + + /** ++ * 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. +@@ -318,21 +342,21 @@ void + polkit_unix_process_set_pid (PolkitUnixProcess *process, + gint pid) + { ++ 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. + * +- * Returns: A #PolkitSubject. Free with g_object_unref(). ++ * 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(). + */ + PolkitSubject * + polkit_unix_process_new (gint pid) +@@ -349,22 +373,42 @@ polkit_unix_process_new (gint pid) + * + * Creates a new #PolkitUnixProcess object for @pid and @start_time. + * +- * Returns: A #PolkitSubject. Free with g_object_unref(). ++ * 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 +@@ -612,3 +656,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..68c7fd7 100644 +--- a/src/polkit/polkitunixprocess.h ++++ b/src/polkit/polkitunixprocess.h +@@ -50,11 +50,21 @@ 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_for_owner (gint pid, ++ guint64 start_time, ++ gint uid); + + gint polkit_unix_process_get_pid (PolkitUnixProcess *process); ++gint polkit_unix_process_get_uid (PolkitUnixProcess *process); + guint64 polkit_unix_process_get_start_time (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); ++ ++G_GNUC_DEPRECATED + gint polkit_unix_process_get_owner (PolkitUnixProcess *process, + GError **error); + +-- +1.7.4.4 + diff --git a/patches/source/polkit/CVE-2011-1485/0003-Use-polkit_unix_process_get_uid-to-get-the-owner-of-.patch b/patches/source/polkit/CVE-2011-1485/0003-Use-polkit_unix_process_get_uid-to-get-the-owner-of-.patch new file mode 100644 index 000000000..b7d537521 --- /dev/null +++ b/patches/source/polkit/CVE-2011-1485/0003-Use-polkit_unix_process_get_uid-to-get-the-owner-of-.patch @@ -0,0 +1,41 @@ +From 55e6f92e7340d57a66f83bd69bdf26454fdf7533 Mon Sep 17 00:00:00 2001 +From: David Zeuthen <davidz@redhat.com> +Date: Mon, 11 Apr 2011 12:41:35 -0400 +Subject: [PATCH 3/6] Use polkit_unix_process_get_uid() to get the owner of a + process + +This avoids a TOCTTOU problem. + +Signed-off-by: David Zeuthen <davidz@redhat.com> +--- + src/polkitbackend/polkitbackendsessionmonitor.c | 13 ++++++------- + 1 files changed, 6 insertions(+), 7 deletions(-) + +diff --git a/src/polkitbackend/polkitbackendsessionmonitor.c b/src/polkitbackend/polkitbackendsessionmonitor.c +index 2028250..d976514 100644 +--- a/src/polkitbackend/polkitbackendsessionmonitor.c ++++ b/src/polkitbackend/polkitbackendsessionmonitor.c +@@ -418,14 +418,13 @@ polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor + + if (POLKIT_IS_UNIX_PROCESS (subject)) + { +- GError *local_error; +- +- 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_error (error, local_error); +- g_error_free (local_error); ++ g_set_error (error, ++ POLKIT_ERROR, ++ POLKIT_ERROR_FAILED, ++ "Unix process subject does not have uid set"); + goto out; + } + user = polkit_unix_user_new (uid); +-- +1.7.4.4 + diff --git a/patches/source/polkit/CVE-2011-1485/0004-pkexec-Avoid-TOCTTOU-problems-with-parent-process.patch b/patches/source/polkit/CVE-2011-1485/0004-pkexec-Avoid-TOCTTOU-problems-with-parent-process.patch new file mode 100644 index 000000000..e17947a9f --- /dev/null +++ b/patches/source/polkit/CVE-2011-1485/0004-pkexec-Avoid-TOCTTOU-problems-with-parent-process.patch @@ -0,0 +1,97 @@ +--- ./src/programs/pkexec.c.orig 2010-03-10 11:46:19.000000000 -0600 ++++ ./src/programs/pkexec.c 2011-04-19 23:14:40.505000017 -0500 +@@ -38,6 +38,10 @@ + #include <syslog.h> + #include <stdarg.h> + ++#ifdef __linux__ ++#include <sys/prctl.h> ++#endif ++ + #include <polkit/polkit.h> + + static gchar *original_user_name = NULL; +@@ -410,7 +414,6 @@ + GPtrArray *saved_env; + gchar *opt_user; + pid_t pid_of_caller; +- uid_t uid_of_caller; + + ret = 127; + authority = NULL; +@@ -578,40 +581,49 @@ + */ + 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); + + authority = polkit_authority_get (); + |