dir: Check parental control authorization via system bus name

PIDs are pretty much always a bad idea because they can be racy. The
authorization did use the PID though. We can replace it by a check via
the system bus name.

Closes: https://github.com/flatpak/flatpak/issues/6212
This commit is contained in:
Sebastian Wick 2025-09-01 20:43:48 +02:00
parent 6fd0930858
commit 1372e16d05
3 changed files with 39 additions and 76 deletions

View File

@ -60,6 +60,8 @@ GType flatpak_deploy_get_type (void);
#define FLATPAK_CLI_UPDATE_INTERVAL_MS 300
typedef struct _PolkitSubject PolkitSubject;
typedef struct
{
FlatpakDecomposed *ref;
@ -1022,9 +1024,8 @@ char ** flatpak_dir_get_default_locale_languages (Fla
char ** flatpak_dir_get_locales (FlatpakDir *self);
char ** flatpak_dir_get_locale_languages (FlatpakDir *self);
char ** flatpak_dir_get_locale_subpaths (FlatpakDir *self);
void flatpak_dir_set_source_pid (FlatpakDir *self,
pid_t pid);
pid_t flatpak_dir_get_source_pid (FlatpakDir *self);
void flatpak_dir_set_subject (FlatpakDir *self,
PolkitSubject *subject);
gboolean flatpak_dir_delete_mirror_refs (FlatpakDir *self,
gboolean dry_run,
GCancellable *cancellable,

View File

@ -249,7 +249,7 @@ struct FlatpakDir
GFile *cache_dir;
gboolean no_system_helper;
gboolean no_interaction;
pid_t source_pid;
PolkitSubject *subject;
GDBusConnection *system_helper_bus;
@ -3216,6 +3216,7 @@ flatpak_dir_finalize (GObject *object)
g_clear_pointer (&self->remote_filters, g_hash_table_unref);
g_clear_pointer (&self->masked, g_regex_unref);
g_clear_pointer (&self->pinned, g_regex_unref);
g_clear_object (&self->subject);
G_OBJECT_CLASS (flatpak_dir_parent_class)->finalize (object);
}
@ -9107,9 +9108,8 @@ flatpak_dir_check_parental_controls (FlatpakDir *self,
/* Assume that root is allowed to install any ref and shouldn't have any
* parental controls restrictions applied to them. Note that this branch
* must not be taken if this code is running within the system-helper, as that
* runs as root but on behalf of another process. If running within the
* system-helper, self->source_pid is non-zero. */
if (self->source_pid == 0 && getuid () == 0)
* runs as root but on behalf of another process. */
if (!self->subject && getuid () == 0)
{
g_info ("Skipping parental controls check for %s due to running as root", ref);
return TRUE;
@ -9141,13 +9141,25 @@ flatpak_dir_check_parental_controls (FlatpakDir *self,
return FALSE;
}
if (self->user || self->source_pid == 0)
subject = polkit_unix_process_new_for_owner (getpid (), 0, getuid ());
else
subject = polkit_unix_process_new_for_owner (self->source_pid, 0, -1);
if (self->subject)
{
g_autoptr(PolkitSubject) process_subject = NULL;
subject = g_object_ref (self->subject);
/* This internally uses dbus GetConnectionCredentials which ensures we
* get the right UID. We should *not* use it for authorization via the
* PID though! */
process_subject =
polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject),
cancellable, NULL);
subject_uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (process_subject));
}
else
{
subject_uid = getuid ();
subject = polkit_unix_process_new_for_owner (getpid (), 0, subject_uid);
}
/* Get the parental controls for the invoking user. */
subject_uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject));
if (subject_uid == -1)
{
g_set_error_literal (error, G_DBUS_ERROR, G_DBUS_ERROR_AUTH_FAILED,
@ -9155,6 +9167,8 @@ flatpak_dir_check_parental_controls (FlatpakDir *self,
return FALSE;
}
g_assert (subject != NULL);
manager = mct_manager_new (dbus_connection);
manager_flags = MCT_MANAGER_GET_VALUE_FLAGS_NONE;
if (!flatpak_dir_get_no_interaction (self))
@ -17016,16 +17030,10 @@ flatpak_dir_get_locale_subpaths (FlatpakDir *self)
}
void
flatpak_dir_set_source_pid (FlatpakDir *self,
pid_t pid)
flatpak_dir_set_subject (FlatpakDir *self,
PolkitSubject *subject)
{
self->source_pid = pid;
}
pid_t
flatpak_dir_get_source_pid (FlatpakDir *self)
{
return self->source_pid;
g_set_object (&self->subject, subject);
}
static void
@ -17045,7 +17053,7 @@ static void
{
#ifdef HAVE_LIBSYSTEMD
const char *installation = source ? source : flatpak_dir_get_name_cached (self);
pid_t source_pid = flatpak_dir_get_source_pid (self);
const char *subject = self->subject ? polkit_subject_to_string (self->subject) : "(none)";
char message[1024];
int len;
va_list args;
@ -17061,7 +17069,7 @@ static void
*/
sd_journal_send ("MESSAGE_ID=" FLATPAK_MESSAGE_ID,
"PRIORITY=5",
"OBJECT_PID=%d", source_pid,
"SUBJECT=%s", subject,
"CODE_FILE=%s", file,
"CODE_LINE=%d", line,
"CODE_FUNC=%s", func,

View File

@ -226,56 +226,6 @@ schedule_idle_callback (void)
G_UNLOCK (idle);
}
#define DBUS_NAME_DBUS "org.freedesktop.DBus"
#define DBUS_INTERFACE_DBUS DBUS_NAME_DBUS
#define DBUS_PATH_DBUS "/org/freedesktop/DBus"
static int
get_sender_pid (GDBusMethodInvocation *invocation)
{
g_autoptr(GDBusMessage) msg = NULL;
g_autoptr(GDBusMessage) reply = NULL;
GDBusConnection *connection;
const char *sender;
GVariant *body;
g_autoptr(GVariantIter) iter = NULL;
const char *key;
g_autoptr(GVariant) value = NULL;
connection = g_dbus_method_invocation_get_connection (invocation);
sender = g_dbus_method_invocation_get_sender (invocation);
msg = g_dbus_message_new_method_call (DBUS_NAME_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
"GetConnectionCredentials");
g_dbus_message_set_body (msg, g_variant_new ("(s)", sender));
reply = g_dbus_connection_send_message_with_reply_sync (connection, msg,
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
30000,
NULL,
NULL,
NULL);
if (reply == NULL)
return 0;
if (g_dbus_message_get_message_type (reply) == G_DBUS_MESSAGE_TYPE_ERROR)
return 0;
body = g_dbus_message_get_body (reply);
g_variant_get (body, "(a{sv})", &iter);
while (g_variant_iter_loop (iter, "{&sv}", &key, &value))
{
if (strcmp (key, "ProcessID") == 0)
return g_variant_get_uint32 (value);
}
value = NULL; /* g_variant_iter_loop freed it */
return 0;
}
static FlatpakDir *
dir_get_system (const char *installation,
GDBusMethodInvocation *invocation,
@ -283,7 +233,8 @@ dir_get_system (const char *installation,
GError **error)
{
FlatpakDir *system = NULL;
pid_t source_pid = invocation ? get_sender_pid (invocation) : 0;
const char *sender;
g_autoptr(AutoPolkitSubject) subject = NULL;
if (installation != NULL && *installation != '\0')
system = flatpak_dir_get_system_by_id (installation, NULL, error);
@ -294,7 +245,10 @@ dir_get_system (const char *installation,
if (system == NULL)
return NULL;
flatpak_dir_set_source_pid (system, source_pid);
sender = g_dbus_method_invocation_get_sender (invocation);
subject = polkit_system_bus_name_new (sender);
flatpak_dir_set_subject (system, subject);
flatpak_dir_set_no_system_helper (system, TRUE);
flatpak_dir_set_no_interaction (system, no_interaction);