summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2012-06-19 12:02:24 -0400
committerRay Strode <rstrode@redhat.com>2012-06-28 11:27:05 -0400
commit26213aa0e0d8dca5f36cc23f6942525224cbe9f5 (patch)
tree85683230a95efc53f9bf3b76fc95c928fb21c702
parent5e2f077e97a752092a31756eb6b3df03bc119c3d (diff)
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, switches to 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. There 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.
-rw-r--r--src/util.c37
1 files 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;
}