Skip to content

Commit

Permalink
jsauthority: parse groups from GetConnectionCredentials() if available
Browse files Browse the repository at this point in the history
D-Bus will give us supplementary groups too, using SO_PEERSEC which is
secure and safe against races, so prefer that to parsing the group from
the uid. This is available when using dbus-broker.

Fixes https://gitlab.freedesktop.org/polkit/polkit/-/issues/165
  • Loading branch information
bluca committed Aug 17, 2023
1 parent 7f0d792 commit 8cabb11
Show file tree
Hide file tree
Showing 5 changed files with 293 additions and 63 deletions.
129 changes: 116 additions & 13 deletions src/polkit/polkitsystembusname.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,26 +390,19 @@ on_retrieved_unix_uid_pid (GObject *src,
}

static gboolean
polkit_system_bus_name_get_creds_sync (PolkitSystemBusName *system_bus_name,
polkit_system_bus_name_get_creds_fallback (PolkitSystemBusName *system_bus_name,
guint32 *out_uid,
guint32 *out_pid,
GCancellable *cancellable,
GDBusConnection *connection,
GMainContext *tmp_context,
GError **error)
{
gboolean ret = FALSE;
AsyncGetBusNameCredsData data = { 0, };
GDBusConnection *connection = NULL;
GMainContext *tmp_context = NULL;

connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error);
if (connection == NULL)
goto out;
AsyncGetBusNameCredsData data = { };

data.error = error;

tmp_context = g_main_context_new ();
g_main_context_push_thread_default (tmp_context);

dbus_call_respond_fails = 0;

/* Do two async calls as it's basically as fast as one sync call.
Expand Down Expand Up @@ -481,6 +474,112 @@ polkit_system_bus_name_get_creds_sync (PolkitSystemBusName *system_bus
}
if (connection != NULL)
g_object_unref (connection);

return ret;
}

static gboolean
polkit_system_bus_name_get_creds_sync (PolkitSystemBusName *system_bus_name,
guint32 *out_uid,
GArray **out_gids,
guint32 *out_pid,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GDBusConnection *connection = NULL;
GMainContext *tmp_context = NULL;
GVariantIter *iter;
GVariant *result, *value;
GError *dbus_error = NULL;
const gchar *key;
guint32 uid = G_MAXUINT32, pid = 0;
GArray *gids = NULL;

connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error);
if (connection == NULL)
goto out;

tmp_context = g_main_context_new ();
g_main_context_push_thread_default (tmp_context);

/* If the new unified API is available (since dbus-daemon 1.10.4) use it,
* or fallback to the old separate calls.
*/
result = g_dbus_connection_call_sync (connection,
"org.freedesktop.DBus", /* name */
"/org/freedesktop/DBus", /* object path */
"org.freedesktop.DBus", /* interface name */
"GetConnectionCredentials", /* method */
g_variant_new ("(s)", system_bus_name->name),
G_VARIANT_TYPE ("(a{sv})"),
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
&dbus_error);

if (result == NULL)
{
if (g_error_matches (dbus_error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD))
{
g_error_free (dbus_error);
return polkit_system_bus_name_get_creds_fallback(system_bus_name,
out_uid,
out_pid,
cancellable,
connection,
tmp_context,
error);
}
else
goto out;
}

g_variant_get (result, "(a{sv})", &iter);

while (g_variant_iter_loop (iter, "{&sv}", &key, &value))
{
if (g_strcmp0 (key, "ProcessID") == 0)
pid = g_variant_get_uint32 (value);
else if (g_strcmp0 (key, "UnixUserID") == 0)
uid = g_variant_get_uint32 (value);
else if (g_strcmp0 (key, "UnixGroupIDs") == 0)
{
GVariantIter *group_iter;
gid_t gid;

gids = g_array_new (FALSE, FALSE, sizeof (gid_t));
g_variant_get (value, "au", &group_iter);
while (g_variant_iter_loop (group_iter, "u", &gid))
g_array_append_val (gids, gid);
g_variant_iter_free (group_iter);
}
}

g_variant_unref (result);

if (out_uid)
*out_uid = uid;
if (out_gids && gids)
*out_gids = g_array_ref(gids);
if (out_pid)
*out_pid = pid;
ret = TRUE;
out:
if (tmp_context)
{
g_main_context_pop_thread_default (tmp_context);
g_main_context_unref (tmp_context);
}
if (connection != NULL)
g_object_unref (connection);
if (dbus_error && error)
g_propagate_error (error, dbus_error);
else if (dbus_error)
g_error_free (dbus_error);
if (gids)
g_array_unref (gids);

return ret;
}

Expand All @@ -503,18 +602,22 @@ polkit_system_bus_name_get_process_sync (PolkitSystemBusName *system_bus_name,
PolkitSubject *ret = NULL;
guint32 pid;
guint32 uid;
GArray *gids = NULL;

g_return_val_if_fail (POLKIT_IS_SYSTEM_BUS_NAME (system_bus_name), NULL);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);

if (!polkit_system_bus_name_get_creds_sync (system_bus_name, &uid, &pid,
if (!polkit_system_bus_name_get_creds_sync (system_bus_name, &uid, &gids, &pid,
cancellable, error))
goto out;

ret = polkit_unix_process_new_for_owner (pid, 0, uid);
polkit_unix_process_set_gids (POLKIT_UNIX_PROCESS (ret), gids);

out:
if (gids)
g_array_unref (gids);
return ret;
}

Expand All @@ -541,7 +644,7 @@ polkit_system_bus_name_get_user_sync (PolkitSystemBusName *system_bus_name,
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);

if (!polkit_system_bus_name_get_creds_sync (system_bus_name, &uid, NULL,
if (!polkit_system_bus_name_get_creds_sync (system_bus_name, &uid, NULL, NULL,
cancellable, error))
goto out;

Expand Down
73 changes: 72 additions & 1 deletion src/polkit/polkitunixprocess.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ struct _PolkitUnixProcess
guint64 start_time;
gint uid;
gint pidfd;
GArray *gids;
};

struct _PolkitUnixProcessClass
Expand All @@ -171,6 +172,7 @@ enum
PROP_START_TIME,
PROP_UID,
PROP_PIDFD,
PROP_GIDS,
};

static void subject_iface_init (PolkitSubjectIface *subject_iface);
Expand Down Expand Up @@ -216,6 +218,10 @@ polkit_unix_process_get_property (GObject *object,
g_value_set_int (value, unix_process->uid);
break;

case PROP_GIDS:
g_value_set_boxed (value, unix_process->gids);
break;

case PROP_PIDFD:
g_value_set_int (value, unix_process->pidfd);
break;
Expand Down Expand Up @@ -248,6 +254,10 @@ polkit_unix_process_set_property (GObject *object,
polkit_unix_process_set_uid (unix_process, g_value_get_int (value));
break;

case PROP_GIDS:
polkit_unix_process_set_gids (unix_process, g_value_get_boxed (value));
break;

case PROP_PIDFD:
polkit_unix_process_set_pidfd (unix_process, g_value_get_int (value));
break;
Expand Down Expand Up @@ -366,6 +376,9 @@ polkit_unix_process_finalize (GObject *object)
process->pidfd = -1;
}

if (process->gids)
g_array_unref (process->gids);

if (G_OBJECT_CLASS (polkit_unix_process_parent_class)->finalize != NULL)
G_OBJECT_CLASS (polkit_unix_process_parent_class)->finalize (object);
}
Expand Down Expand Up @@ -457,6 +470,23 @@ polkit_unix_process_class_init (PolkitUnixProcessClass *klass)
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK));

/**
* PolkitUnixProcess:gids:
*
* The UNIX group ids of the process.
*/
g_object_class_install_property (gobject_class,
PROP_GIDS,
g_param_spec_boxed ("gids",
"Group IDs",
"The UNIX group IDs",
G_TYPE_ARRAY,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB |
G_PARAM_STATIC_NICK));
}

/**
Expand Down Expand Up @@ -496,6 +526,44 @@ polkit_unix_process_set_uid (PolkitUnixProcess *process,
process->uid = uid;
}

/**
* polkit_unix_process_get_gids:
* @process: A #PolkitUnixProcess.
*
* Gets the group ids for @process. Note that this is the real group-ids,
* not the effective group-ids.
*
* Returns: (element-type GArray) (transfer full) (allow-none): a #GArray
* of #gid_t containing the group ids for @process or NULL if unknown,
* as a new reference to the array, caller must deref it when done.
*/
GArray *
polkit_unix_process_get_gids (PolkitUnixProcess *process)
{
g_return_val_if_fail (POLKIT_IS_UNIX_PROCESS (process), NULL);
return process->gids ? g_array_ref (process->gids) : NULL;
}

/**
* polkit_unix_process_set_gids:
* @process: A #PolkitUnixProcess.
* @gids: (element-type GArray): A #GList of #gid_t containing the group
* ids to set for @process or NULL to unset them.
* A reference to @gids is taken.
*
* Sets the (real, not effective) group ids for @process.
*/
void
polkit_unix_process_set_gids (PolkitUnixProcess *process,
GArray *gids)
{
g_return_if_fail (POLKIT_IS_UNIX_PROCESS (process));
if (process->gids)
g_array_unref (g_steal_pointer (&process->gids));
if (gids)
process->gids = g_array_ref (gids);
}

/**
* polkit_unix_process_get_pid:
* @process: A #PolkitUnixProcess.
Expand Down Expand Up @@ -689,18 +757,21 @@ polkit_unix_process_new_for_owner (gint pid,
* polkit_unix_process_new_pidfd:
* @pidfd: The process id file descriptor.
* @uid: The (real, not effective) uid of the owner of @pid or -1 to look it up in e.g. <filename>/proc</filename>.
* @gids: (element-type gint) (allow-none): The (real, not effective) gids of the owner of @pid or %NULL.
*
* Creates a new #PolkitUnixProcess object for @pidfd and @uid.
*
* Returns: (transfer full): A #PolkitSubject. Free with g_object_unref().
*/
PolkitSubject *
polkit_unix_process_new_pidfd (gint pidfd,
gint uid)
gint uid,
GArray *gids)
{
return POLKIT_SUBJECT (g_object_new (POLKIT_TYPE_UNIX_PROCESS,
"pidfd", pidfd,
"uid", uid,
"gids", gids,
NULL));
}

Expand Down
6 changes: 5 additions & 1 deletion src/polkit/polkitunixprocess.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,14 @@ PolkitSubject *polkit_unix_process_new_for_owner (gint pid,
guint64 start_time,
gint uid);
PolkitSubject *polkit_unix_process_new_pidfd (gint pidfd,
gint uid);
gint uid,
GArray *gids);
GArray *polkit_unix_process_get_gids (PolkitUnixProcess *process);
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_gids (PolkitUnixProcess *process,
GArray *gids);
void polkit_unix_process_set_pid (PolkitUnixProcess *process,
gint pid);
void polkit_unix_process_set_uid (PolkitUnixProcess *process,
Expand Down
Loading

0 comments on commit 8cabb11

Please sign in to comment.