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 #define FLATPAK_CLI_UPDATE_INTERVAL_MS 300
typedef struct _PolkitSubject PolkitSubject;
typedef struct typedef struct
{ {
FlatpakDecomposed *ref; 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_locales (FlatpakDir *self);
char ** flatpak_dir_get_locale_languages (FlatpakDir *self); char ** flatpak_dir_get_locale_languages (FlatpakDir *self);
char ** flatpak_dir_get_locale_subpaths (FlatpakDir *self); char ** flatpak_dir_get_locale_subpaths (FlatpakDir *self);
void flatpak_dir_set_source_pid (FlatpakDir *self, void flatpak_dir_set_subject (FlatpakDir *self,
pid_t pid); PolkitSubject *subject);
pid_t flatpak_dir_get_source_pid (FlatpakDir *self);
gboolean flatpak_dir_delete_mirror_refs (FlatpakDir *self, gboolean flatpak_dir_delete_mirror_refs (FlatpakDir *self,
gboolean dry_run, gboolean dry_run,
GCancellable *cancellable, GCancellable *cancellable,

View File

@@ -249,7 +249,7 @@ struct FlatpakDir
GFile *cache_dir; GFile *cache_dir;
gboolean no_system_helper; gboolean no_system_helper;
gboolean no_interaction; gboolean no_interaction;
pid_t source_pid; PolkitSubject *subject;
GDBusConnection *system_helper_bus; 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->remote_filters, g_hash_table_unref);
g_clear_pointer (&self->masked, g_regex_unref); g_clear_pointer (&self->masked, g_regex_unref);
g_clear_pointer (&self->pinned, 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); 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 /* Assume that root is allowed to install any ref and shouldn't have any
* parental controls restrictions applied to them. Note that this branch * 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 * 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 * runs as root but on behalf of another process. */
* system-helper, self->source_pid is non-zero. */ if (!self->subject && getuid () == 0)
if (self->source_pid == 0 && getuid () == 0)
{ {
g_info ("Skipping parental controls check for %s due to running as root", ref); g_info ("Skipping parental controls check for %s due to running as root", ref);
return TRUE; return TRUE;
@@ -9141,13 +9141,25 @@ flatpak_dir_check_parental_controls (FlatpakDir *self,
return FALSE; return FALSE;
} }
if (self->user || self->source_pid == 0) if (self->subject)
subject = polkit_unix_process_new_for_owner (getpid (), 0, getuid ()); {
else g_autoptr(PolkitSubject) process_subject = NULL;
subject = polkit_unix_process_new_for_owner (self->source_pid, 0, -1);
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) if (subject_uid == -1)
{ {
g_set_error_literal (error, G_DBUS_ERROR, G_DBUS_ERROR_AUTH_FAILED, 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; return FALSE;
} }
g_assert (subject != NULL);
manager = mct_manager_new (dbus_connection); manager = mct_manager_new (dbus_connection);
manager_flags = MCT_MANAGER_GET_VALUE_FLAGS_NONE; manager_flags = MCT_MANAGER_GET_VALUE_FLAGS_NONE;
if (!flatpak_dir_get_no_interaction (self)) if (!flatpak_dir_get_no_interaction (self))
@@ -17016,16 +17030,10 @@ flatpak_dir_get_locale_subpaths (FlatpakDir *self)
} }
void void
flatpak_dir_set_source_pid (FlatpakDir *self, flatpak_dir_set_subject (FlatpakDir *self,
pid_t pid) PolkitSubject *subject)
{ {
self->source_pid = pid; g_set_object (&self->subject, subject);
}
pid_t
flatpak_dir_get_source_pid (FlatpakDir *self)
{
return self->source_pid;
} }
static void static void
@@ -17045,7 +17053,7 @@ static void
{ {
#ifdef HAVE_LIBSYSTEMD #ifdef HAVE_LIBSYSTEMD
const char *installation = source ? source : flatpak_dir_get_name_cached (self); 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]; char message[1024];
int len; int len;
va_list args; va_list args;
@@ -17061,7 +17069,7 @@ static void
*/ */
sd_journal_send ("MESSAGE_ID=" FLATPAK_MESSAGE_ID, sd_journal_send ("MESSAGE_ID=" FLATPAK_MESSAGE_ID,
"PRIORITY=5", "PRIORITY=5",
"OBJECT_PID=%d", source_pid, "SUBJECT=%s", subject,
"CODE_FILE=%s", file, "CODE_FILE=%s", file,
"CODE_LINE=%d", line, "CODE_LINE=%d", line,
"CODE_FUNC=%s", func, "CODE_FUNC=%s", func,

View File

@@ -226,56 +226,6 @@ schedule_idle_callback (void)
G_UNLOCK (idle); 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 * static FlatpakDir *
dir_get_system (const char *installation, dir_get_system (const char *installation,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
@@ -283,7 +233,8 @@ dir_get_system (const char *installation,
GError **error) GError **error)
{ {
FlatpakDir *system = NULL; 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') if (installation != NULL && *installation != '\0')
system = flatpak_dir_get_system_by_id (installation, NULL, error); system = flatpak_dir_get_system_by_id (installation, NULL, error);
@@ -294,7 +245,10 @@ dir_get_system (const char *installation,
if (system == NULL) if (system == NULL)
return 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_system_helper (system, TRUE);
flatpak_dir_set_no_interaction (system, no_interaction); flatpak_dir_set_no_interaction (system, no_interaction);