Accepting request 126335 from home:vuntz:branches:GNOME:Factory

CVE-2012-2737

OBS-URL: https://build.opensuse.org/request/show/126335
OBS-URL: https://build.opensuse.org/package/show/GNOME:Factory/accountsservice?expand=0&rev=38
This commit is contained in:
Dominique Leuenberger 2012-06-27 17:07:31 +00:00 committed by Git OBS Bridge
parent edaa50f605
commit 2b27d60a41
3 changed files with 487 additions and 0 deletions

View File

@ -0,0 +1,478 @@
From 4da994eeab9a6b04938d84dd398d5781eb1fc94f Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 19 Jun 2012 12:02:24 -0400
Subject: [PATCH 1/3] util: CVE-2012-2737: Validate SetIconFile caller over
bus
The AccountsService SetIconFile call associates an icon
with a user.
SetIconFile allows users to have icons visible at the login
screen that don't necessarily originate in globally
readable or always available locations. This is accomplished
by copying the originating icon to the local disk in /var.
Since AccountsService runs with with root privileges, the
implemention of the SetIconFile method queries the uid of
the method caller, forks, assumes that uid and performs
the image copy as if it were the user.
Unfortunately, the UID lookup peformed is done "just in time"
instead of looking at peer credentials from the time the call
was initiated. This is a race condition that means a caller
could invoke the method call, quickly exec a setuid binary, and
then cause the copy to be performed as the uid of the setuid
process.
This commit changes the uid lookup logic to query the system
bus daemon for the peer credentials that were cached from the
caller at the time of the initial connection.
---
src/util.c | 37 ++++++++++++++++++++++++++-----------
1 file changed, 26 insertions(+), 11 deletions(-)
diff --git a/src/util.c b/src/util.c
index 66ddd98..1ce375b 100644
--- a/src/util.c
+++ b/src/util.c
@@ -251,22 +251,37 @@ get_user_groups (const gchar *user,
gboolean
-get_caller_uid (GDBusMethodInvocation *context, gint *uid)
+get_caller_uid (GDBusMethodInvocation *context,
+ gint *uid)
{
- PolkitSubject *subject;
- PolkitSubject *process;
+ GVariant *reply;
+ GError *error;
+
+ error = NULL;
+ reply = g_dbus_connection_call_sync (g_dbus_method_invocation_get_connection (context),
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "GetConnectionUnixUser",
+ g_variant_new ("(s)",
+ g_dbus_method_invocation_get_sender (context)),
+ G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (reply == NULL) {
+ g_warning ("Could not talk to message bus to find uid of sender %s: %s",
+ g_dbus_method_invocation_get_sender (context),
+ error->message);
+ g_error_free (error);
- subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (context));
- process = polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject), NULL, NULL);
- if (!process) {
- g_object_unref (subject);
return FALSE;
}
- *uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (process));
-
- g_object_unref (subject);
- g_object_unref (process);
+ g_variant_get (reply, "(u)", uid);
+ g_variant_unref (reply);
return TRUE;
}
--
1.7.10.2
From b9eb2a51d7eda658ad104e0af0c8b41c3745f37a Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 19 Jun 2012 14:02:42 -0400
Subject: [PATCH 2/3] user: CVE-2012-2737: verify caller through bus in more
cases
The previous commit changed the SetIconFile call to identify
the uid of the calling process via cached peer credentials
stored by the bus daemon.
This commit fixes other similar cases where we try to figure
out process identity on our own instead of through the bus
daemon.
---
src/user.c | 78 ++++++++++++++++++++++++++++++++----------------------------
1 file changed, 42 insertions(+), 36 deletions(-)
diff --git a/src/user.c b/src/user.c
index 55c238d..9713ecd 100644
--- a/src/user.c
+++ b/src/user.c
@@ -552,35 +552,21 @@ user_change_real_name_authorized_cb (Daemon *daemon,
accounts_user_complete_set_real_name (ACCOUNTS_USER (user), context);
}
-static uid_t
-method_invocation_get_uid (GDBusMethodInvocation *context)
-{
- const gchar *sender;
- PolkitSubject *busname;
- PolkitSubject *process;
- uid_t uid;
-
- sender = g_dbus_method_invocation_get_sender (context);
- busname = polkit_system_bus_name_new (sender);
- process = polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (busname), NULL, NULL);
- uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (process));
- g_object_unref (busname);
- g_object_unref (process);
-
- return uid;
-}
-
static gboolean
user_set_real_name (AccountsUser *auser,
GDBusMethodInvocation *context,
const gchar *real_name)
{
User *user = (User*)auser;
- uid_t uid;
+ int uid;
const gchar *action_id;
- uid = method_invocation_get_uid (context);
- if (user->uid == uid)
+ if (!get_caller_uid (context, &uid)) {
+ throw_error (context, ERROR_FAILED, "identifying caller failed");
+ return FALSE;
+ }
+
+ if (user->uid == (uid_t) uid)
action_id = "org.freedesktop.accounts.change-own-user-data";
else
action_id = "org.freedesktop.accounts.user-administration";
@@ -692,11 +678,15 @@ user_set_email (AccountsUser *auser,
const gchar *email)
{
User *user = (User*)auser;
- uid_t uid;
+ int uid;
const gchar *action_id;
- uid = method_invocation_get_uid (context);
- if (user->uid == uid)
+ if (!get_caller_uid (context, &uid)) {
+ throw_error (context, ERROR_FAILED, "identifying caller failed");
+ return FALSE;
+ }
+
+ if (user->uid == (uid_t) uid)
action_id = "org.freedesktop.accounts.change-own-user-data";
else
action_id = "org.freedesktop.accounts.user-administration";
@@ -744,11 +734,15 @@ user_set_language (AccountsUser *auser,
const gchar *language)
{
User *user = (User*)auser;
- uid_t uid;
+ int uid;
const gchar *action_id;
- uid = method_invocation_get_uid (context);
- if (user->uid == uid)
+ if (!get_caller_uid (context, &uid)) {
+ throw_error (context, ERROR_FAILED, "identifying caller failed");
+ return FALSE;
+ }
+
+ if (user->uid == (uid_t) uid)
action_id = "org.freedesktop.accounts.change-own-user-data";
else
action_id = "org.freedesktop.accounts.user-administration";
@@ -794,11 +788,15 @@ user_set_x_session (AccountsUser *auser,
const gchar *x_session)
{
User *user = (User*)auser;
- uid_t uid;
+ int uid;
const gchar *action_id;
- uid = method_invocation_get_uid (context);
- if (user->uid == uid)
+ if (!get_caller_uid (context, &uid)) {
+ throw_error (context, ERROR_FAILED, "identifying caller failed");
+ return FALSE;
+ }
+
+ if (user->uid == (uid_t) uid)
action_id = "org.freedesktop.accounts.change-own-user-data";
else
action_id = "org.freedesktop.accounts.user-administration";
@@ -844,11 +842,15 @@ user_set_location (AccountsUser *auser,
const gchar *location)
{
User *user = (User*)auser;
- uid_t uid;
+ int uid;
const gchar *action_id;
- uid = method_invocation_get_uid (context);
- if (user->uid == uid)
+ if (!get_caller_uid (context, &uid)) {
+ throw_error (context, ERROR_FAILED, "identifying caller failed");
+ return FALSE;
+ }
+
+ if (user->uid == (uid_t) uid)
action_id = "org.freedesktop.accounts.change-own-user-data";
else
action_id = "org.freedesktop.accounts.user-administration";
@@ -1163,11 +1165,15 @@ user_set_icon_file (AccountsUser *auser,
const gchar *filename)
{
User *user = (User*)auser;
- uid_t uid;
+ int uid;
const gchar *action_id;
- uid = method_invocation_get_uid (context);
- if (user->uid == uid)
+ if (!get_caller_uid (context, &uid)) {
+ throw_error (context, ERROR_FAILED, "identifying caller failed");
+ return FALSE;
+ }
+
+ if (user->uid == (uid_t) uid)
action_id = "org.freedesktop.accounts.change-own-user-data";
else
action_id = "org.freedesktop.accounts.user-administration";
--
1.7.10.2
From 02631411131c48f0616c94dc330f4146c3c25a8a Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 19 Jun 2012 14:34:18 -0400
Subject: [PATCH 3/3] util: CVE-2012-2737: drop _polkit_subject_get_cmdline
_polkit_subject_get_cmdline is a function copy and pasted
from the polkit code that returns the command line, uid, and
pid of a particular polkit subject. It's used for helping to
generate log entries that detail what processes are invoking methods
on the accounts service.
It's also used, on older kernels, for setting up the the loginuid
of subprocesses that are run on behalf of AccountsService clients,
so the audit trail leads back to the user initiating a request.
_polkit_subject_get_cmdline directly looks up the uid of the caller,
instead of querying the system bus. As such, it's vulnerable to
the same race condition discussed in the previous two commits.
This commit guts _polkit_subject_get_cmdline, keeping only the part
that reads /proc/pid/cmdline. We now get the uid and pid from the
bus daemon.
---
src/util.c | 136 ++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 77 insertions(+), 59 deletions(-)
diff --git a/src/util.c b/src/util.c
index 1ce375b..8f023cf 100644
--- a/src/util.c
+++ b/src/util.c
@@ -34,11 +34,9 @@
#include "util.h"
-
static gchar *
-_polkit_subject_get_cmdline (PolkitSubject *subject, gint *pid, gint *uid)
+get_cmdline_of_pid (GPid pid)
{
- PolkitSubject *process;
gchar *ret;
gchar *filename;
gchar *contents;
@@ -46,43 +44,7 @@ _polkit_subject_get_cmdline (PolkitSubject *subject, gint *pid, gint *uid)
GError *error;
guint n;
- g_return_val_if_fail (subject != NULL, NULL);
-
- error = NULL;
-
- ret = NULL;
- process = NULL;
- filename = NULL;
- contents = NULL;
-
- if (POLKIT_IS_UNIX_PROCESS (subject))
- {
- process = g_object_ref (subject);
- }
- else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
- {
- process = polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject),
- NULL,
- &error);
- if (process == NULL)
- {
- g_warning ("Error getting process for system bus name `%s': %s",
- polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject)),
- error->message);
- g_error_free (error);
- goto out;
- }
- }
- else
- {
- g_warning ("Unknown subject type passed to guess_program_name()");
- goto out;
- }
-
- *pid = polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (process));
- *uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (process));
-
- filename = g_strdup_printf ("/proc/%d/cmdline", *pid);
+ filename = g_strdup_printf ("/proc/%d/cmdline", (int) pid);
if (!g_file_get_contents (filename,
&contents,
@@ -108,11 +70,49 @@ _polkit_subject_get_cmdline (PolkitSubject *subject, gint *pid, gint *uid)
out:
g_free (filename);
g_free (contents);
- if (process != NULL)
- g_object_unref (process);
+
return ret;
}
+static gboolean
+get_caller_pid (GDBusMethodInvocation *context,
+ GPid *pid)
+{
+ GVariant *reply;
+ GError *error;
+ guint32 pid_as_int;
+
+ error = NULL;
+ reply = g_dbus_connection_call_sync (g_dbus_method_invocation_get_connection (context),
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "GetConnectionUnixProcessID",
+ g_variant_new ("(s)",
+ g_dbus_method_invocation_get_sender (context)),
+ G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (reply == NULL) {
+ g_warning ("Could not talk to message bus to find uid of sender %s: %s",
+ g_dbus_method_invocation_get_sender (context),
+ error->message);
+ g_error_free (error);
+
+ return FALSE;
+ }
+
+ g_variant_get (reply, "(u)", &pid_as_int);
+ *pid = pid_as_int;
+
+ g_variant_unref (reply);
+
+ return TRUE;
+}
+
void
sys_log (GDBusMethodInvocation *context,
const gchar *format,
@@ -127,21 +127,36 @@ sys_log (GDBusMethodInvocation *context,
if (context) {
PolkitSubject *subject;
- gchar *cmdline;
+ gchar *cmdline = NULL;
gchar *id;
- gint pid = 0;
- gint uid = 0;
+ GPid pid = 0;
+ gint uid = -1;
gchar *tmp;
subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (context));
id = polkit_subject_to_string (subject);
- cmdline = _polkit_subject_get_cmdline (subject, &pid, &uid);
- if (cmdline == NULL) {
- tmp = g_strdup_printf ("request by %s: %s", id, msg);
+ if (get_caller_pid (context, &pid)) {
+ cmdline = get_cmdline_of_pid (pid);
+ } else {
+ pid = 0;
+ cmdline = NULL;
}
- else {
- tmp = g_strdup_printf ("request by %s [%s pid:%d uid:%d]: %s", id, cmdline, pid, uid, msg);
+
+ if (cmdline != NULL) {
+ if (get_caller_uid (context, &uid)) {
+ tmp = g_strdup_printf ("request by %s [%s pid:%d uid:%d]: %s", id, cmdline, (int) pid, uid, msg);
+ } else {
+ tmp = g_strdup_printf ("request by %s [%s pid:%d]: %s", id, cmdline, (int) pid, msg);
+ }
+ } else {
+ if (get_caller_uid (context, &uid) && pid != 0) {
+ tmp = g_strdup_printf ("request by %s [pid:%d uid:%d]: %s", id, (int) pid, uid, msg);
+ } else if (pid != 0) {
+ tmp = g_strdup_printf ("request by %s [pid:%d]: %s", id, (int) pid, msg);
+ } else {
+ tmp = g_strdup_printf ("request by %s: %s", id, msg);
+ }
}
g_free (msg);
@@ -160,20 +175,22 @@ sys_log (GDBusMethodInvocation *context,
static void
get_caller_loginuid (GDBusMethodInvocation *context, gchar *loginuid, gint size)
{
- PolkitSubject *subject;
- gchar *cmdline;
- gint pid;
+ GPid pid;
gint uid;
gchar *path;
gchar *buf;
- subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (context));
- cmdline = _polkit_subject_get_cmdline (subject, &pid, &uid);
- g_free (cmdline);
- g_object_unref (subject);
+ if (!get_caller_uid (context, &uid)) {
+ uid = getuid ();
+ }
+
+ if (get_caller_pid (context, &pid)) {
+ path = g_strdup_printf ("/proc/%d/loginuid", (int) pid);
+ } else {
+ path = NULL;
+ }
- path = g_strdup_printf ("/proc/%d/loginuid", pid);
- if (g_file_get_contents (path, &buf, NULL, NULL)) {
+ if (path != NULL && g_file_get_contents (path, &buf, NULL, NULL)) {
strncpy (loginuid, buf, size);
g_free (buf);
}
@@ -285,3 +302,4 @@ get_caller_uid (GDBusMethodInvocation *context,
return TRUE;
}
+
--
1.7.10.2

View File

@ -1,3 +1,9 @@
-------------------------------------------------------------------
Wed Jun 27 13:53:12 CEST 2012 - vuntz@opensuse.org
- Add accountsservice-CVE-2012-2737.patch: fix local file
disclosure flaw. Fix bnc#768807, CVE-2012-2737.
-------------------------------------------------------------------
Tue Jun 26 21:37:04 UTC 2012 - dimstar@opensuse.org

View File

@ -29,6 +29,8 @@ Source: http://www.freedesktop.org/software/accountsservice/%{name}-%{ve
Patch0: accountsservice-sysconfig.patch
# PATCH-FIX-OPENSUSE accountsservice-filter-suse-accounts.patch vuntz@opensuse.org -- Filter out some system users that are specific to openSUSE
Patch1: accountsservice-filter-suse-accounts.patch
# PATCH-FIX-UPSTREAM accountsservice-CVE-2012-2737.patch bnc#768807 CVE-2012-2737 vuntz@opensuse.org -- Fix local file disclosure flaw
Patch2: accountsservice-CVE-2012-2737.patch
# needed for patch0
BuildRequires: gnome-common
BuildRequires: gobject-introspection-devel
@ -89,6 +91,7 @@ querying and manipulating user account information.
%setup -q
%patch0 -p1
%patch1 -p1
%patch2 -p1
%build
# needed for patch0