Hi Tavis,

On Fri, May 29, 2015, at 02:08 PM, Tavis Ormandy wrote:
> Hello, I've noticed polkitd dumps core if you set an invalid object
> path when calling RegisterAuthenticationAgent. It looks like this code
> doesn't check if error was set before dereferencing it:

Indeed, thanks for the report.  Can someone review this patch?

I suppose this'll need a CVE, as local, authenticated users can
can DoS polkitd.

I also updated your test program to properly handle errors,
new version attached.
From 9e074421d5623b6962dc66994d519012b40334b9 Mon Sep 17 00:00:00 2001
From: Colin Walters <walt...@verbum.org>
Date: Sat, 30 May 2015 09:06:23 -0400
Subject: [PATCH] backend: Handle invalid object paths in
 RegisterAuthenticationAgent

Properly propagate the error, otherwise we dereference a `NULL`
pointer.  This is a local, authenticated DoS.

Reported-by: Tavis Ormandy <tav...@google.com>
Signed-off-by: Colin Walters <walt...@verbum.org>
---
 .../polkitbackendinteractiveauthority.c            | 53 ++++++++++++----------
 1 file changed, 30 insertions(+), 23 deletions(-)

diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c
index 59028d5..f45fdf1 100644
--- a/src/polkitbackend/polkitbackendinteractiveauthority.c
+++ b/src/polkitbackend/polkitbackendinteractiveauthority.c
@@ -1551,36 +1551,42 @@ authentication_agent_new (PolkitSubject *scope,
                           const gchar *unique_system_bus_name,
                           const gchar *locale,
                           const gchar *object_path,
-                          GVariant    *registration_options)
+                          GVariant    *registration_options,
+			  GError     **error)
 {
   AuthenticationAgent *agent;
-  GError *error;
+  GDBusProxy *proxy;
 
-  agent = g_new0 (AuthenticationAgent, 1);
+  if (!g_variant_is_object_path (object_path))
+    {
+      g_set_error (error, POLKIT_ERROR, POLKIT_ERROR_FAILED,
+		   "Invalid object path '%s'", object_path);
+      return NULL;
+    }
+
+  proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+					 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+					 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+					 NULL, /* GDBusInterfaceInfo* */
+					 unique_system_bus_name,
+					 object_path,
+					 "org.freedesktop.PolicyKit1.AuthenticationAgent",
+					 NULL, /* GCancellable* */
+					 error);
+  if (proxy == NULL)
+    {
+      g_prefix_error (error, "Failed to construct proxy for agent: " );
+      return NULL;
+    }
 
+  agent = g_new0 (AuthenticationAgent, 1);
   agent->ref_count = 1;
   agent->scope = g_object_ref (scope);
   agent->object_path = g_strdup (object_path);
   agent->unique_system_bus_name = g_strdup (unique_system_bus_name);
   agent->locale = g_strdup (locale);
   agent->registration_options = registration_options != NULL ? g_variant_ref (registration_options) : NULL;
-
-  error = NULL;
-  agent->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
-                                                G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
-                                                G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
-                                                NULL, /* GDBusInterfaceInfo* */
-                                                agent->unique_system_bus_name,
-                                                agent->object_path,
-                                                "org.freedesktop.PolicyKit1.AuthenticationAgent",
-                                                NULL, /* GCancellable* */
-                                                &error);
-  if (agent->proxy == NULL)
-    {
-      g_warning ("Error constructing proxy for agent: %s", error->message);
-      g_error_free (error);
-      /* TODO: Make authentication_agent_new() return NULL and set a GError */
-    }
+  agent->proxy = proxy;
 
   return agent;
 }
@@ -2383,8 +2389,6 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken
   caller_cmdline = NULL;
   agent = NULL;
 
-  /* TODO: validate that object path is well-formed */
-
   interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
   priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
 
@@ -2471,7 +2475,10 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken
                                     polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
                                     locale,
                                     object_path,
-                                    options);
+                                    options,
+				    error);
+  if (!agent)
+    goto out;
 
   g_hash_table_insert (priv->hash_scope_to_authentication_agent,
                        g_object_ref (subject),
-- 
1.8.3.1

#define _GNU_SOURCE
#include <gio/gio.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
    GDBusMessage *request;
    GDBusMessage *reply;
    GDBusConnection *bus;
    GVariantBuilder session;
    GError *error = NULL;

    bus     = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
    request = g_dbus_message_new_method_call("org.freedesktop.PolicyKit1",
                                             
"/org/freedesktop/PolicyKit1/Authority",
                                             
"org.freedesktop.PolicyKit1.Authority",
                                             "RegisterAuthenticationAgent");

    g_variant_builder_init(&session, G_VARIANT_TYPE("a{sv}"));
    g_variant_builder_add(&session, "{sv}", "pid", 
g_variant_new_uint32(getpid()));
    g_variant_builder_add(&session, "{sv}", "start-time", 
g_variant_new_uint64(0));
    g_dbus_message_set_body(request, g_variant_new("((sa{sv})ss)", 
"unix-process", &session, "C", "**invalid**"));
    reply = g_dbus_connection_send_message_with_reply_sync(bus, request, 
G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &error);
    if (!reply)
      goto out;
    else
      g_print("%s\n", g_dbus_message_print(reply, 0));
      
 out:
    if (error)
      {
        g_printerr("%s\n", error->message);
        g_error_free (error);
      }
    if (reply)
      g_object_unref(reply);
    g_object_unref(request);
    g_variant_builder_clear(&session);
    return 0;
}
_______________________________________________
polkit-devel mailing list
polkit-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/polkit-devel

Reply via email to