From 8ee9784188ced8f19500f4dfd98ec884765fd680 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Fri, 21 Mar 2025 12:06:27 -0700 Subject: [PATCH] libsysprof: add SysprofProfiler:acquire-privileges property If this property is set to TRUE (the default) it queries sysprofd and policy-kit for appropriate privileges. That generally means that the instruments will use sysprofd to get access to things like /proc files, perf event streams, and what not. If set to FALSE, then this tells the instruments that they should try to do that work locally instead of querying the sysprofd instance via D-Bus. --- src/libsysprof/sysprof-profiler.c | 54 ++++++++++++++++++++- src/libsysprof/sysprof-profiler.h | 33 +++++++------ src/libsysprof/sysprof-recording-private.h | 8 +++- src/libsysprof/sysprof-recording.c | 55 +++++++++++++--------- 4 files changed, 112 insertions(+), 38 deletions(-) diff --git a/src/libsysprof/sysprof-profiler.c b/src/libsysprof/sysprof-profiler.c index ab3c133e..0017adb5 100644 --- a/src/libsysprof/sysprof-profiler.c +++ b/src/libsysprof/sysprof-profiler.c @@ -33,10 +33,12 @@ struct _SysprofProfiler GObject parent_instance; GPtrArray *instruments; SysprofSpawnable *spawnable; + guint acquire_privileges : 1; }; enum { PROP_0, + PROP_ACQUIRE_PRIVILEGES, PROP_SPAWNABLE, N_PROPS }; @@ -66,6 +68,10 @@ sysprof_profiler_get_property (GObject *object, switch (prop_id) { + case PROP_ACQUIRE_PRIVILEGES: + g_value_set_boolean (value, sysprof_profiler_get_acquire_privileges (self)); + break; + case PROP_SPAWNABLE: g_value_set_object (value, sysprof_profiler_get_spawnable (self)); break; @@ -85,6 +91,10 @@ sysprof_profiler_set_property (GObject *object, switch (prop_id) { + case PROP_ACQUIRE_PRIVILEGES: + sysprof_profiler_set_acquire_privileges (self, g_value_get_boolean (value)); + break; + case PROP_SPAWNABLE: sysprof_profiler_set_spawnable (self, g_value_get_object (value)); break; @@ -103,6 +113,13 @@ sysprof_profiler_class_init (SysprofProfilerClass *klass) object_class->get_property = sysprof_profiler_get_property; object_class->set_property = sysprof_profiler_set_property; + properties[PROP_ACQUIRE_PRIVILEGES] = + g_param_spec_boolean ("acquire-privileges", NULL, NULL, + TRUE, + (G_PARAM_READWRITE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS)); + properties [PROP_SPAWNABLE] = g_param_spec_object ("spawnable", NULL, NULL, SYSPROF_TYPE_SPAWNABLE, @@ -114,6 +131,7 @@ sysprof_profiler_class_init (SysprofProfilerClass *klass) static void sysprof_profiler_init (SysprofProfiler *self) { + self->acquire_privileges = TRUE; self->instruments = g_ptr_array_new_with_free_func (g_object_unref); #ifdef __linux__ @@ -169,7 +187,8 @@ sysprof_profiler_record_async (SysprofProfiler *self, recording = _sysprof_recording_new (writer, self->spawnable, (SysprofInstrument **)self->instruments->pdata, - self->instruments->len); + self->instruments->len, + self->acquire_privileges); g_task_return_pointer (task, g_object_ref (recording), g_object_unref); @@ -225,3 +244,36 @@ sysprof_profiler_set_spawnable (SysprofProfiler *self, if (g_set_object (&self->spawnable, spawnable)) g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SPAWNABLE]); } + +gboolean +sysprof_profiler_get_acquire_privileges (SysprofProfiler *self) +{ + g_return_val_if_fail (SYSPROF_IS_PROFILER (self), FALSE); + + return self->acquire_privileges; +} + +/** + * sysprof_profiler_set_acquire_privileges: + * @self: a [class@Sysprof.Profiler] + * + * Sets if the the profiler should automatically acquire privileges using + * D-Bus, Policy-Kit, and sysprofd. + * + * Set to false if you want to profile only from what the current process + * can see. Generally that means your user needs perf capabilities. + */ +void +sysprof_profiler_set_acquire_privileges (SysprofProfiler *self, + gboolean acquire_privileges) +{ + g_return_if_fail (SYSPROF_IS_PROFILER (self)); + + acquire_privileges = !!acquire_privileges; + + if (self->acquire_privileges != acquire_privileges) + { + self->acquire_privileges = acquire_privileges; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACQUIRE_PRIVILEGES]); + } +} diff --git a/src/libsysprof/sysprof-profiler.h b/src/libsysprof/sysprof-profiler.h index 42fec019..9b5ac45a 100644 --- a/src/libsysprof/sysprof-profiler.h +++ b/src/libsysprof/sysprof-profiler.h @@ -36,24 +36,29 @@ SYSPROF_AVAILABLE_IN_ALL G_DECLARE_FINAL_TYPE (SysprofProfiler, sysprof_profiler, SYSPROF, PROFILER, GObject) SYSPROF_AVAILABLE_IN_ALL -SysprofProfiler *sysprof_profiler_new (void); +SysprofProfiler *sysprof_profiler_new (void); SYSPROF_AVAILABLE_IN_ALL -SysprofSpawnable *sysprof_profiler_get_spawnable (SysprofProfiler *self); +SysprofSpawnable *sysprof_profiler_get_spawnable (SysprofProfiler *self); SYSPROF_AVAILABLE_IN_ALL -void sysprof_profiler_set_spawnable (SysprofProfiler *self, - SysprofSpawnable *spawnable); +void sysprof_profiler_set_spawnable (SysprofProfiler *self, + SysprofSpawnable *spawnable); SYSPROF_AVAILABLE_IN_ALL -void sysprof_profiler_add_instrument (SysprofProfiler *self, - SysprofInstrument *instrument); +void sysprof_profiler_add_instrument (SysprofProfiler *self, + SysprofInstrument *instrument); SYSPROF_AVAILABLE_IN_ALL -void sysprof_profiler_record_async (SysprofProfiler *self, - SysprofCaptureWriter *writer, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); +void sysprof_profiler_record_async (SysprofProfiler *self, + SysprofCaptureWriter *writer, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); SYSPROF_AVAILABLE_IN_ALL -SysprofRecording *sysprof_profiler_record_finish (SysprofProfiler *self, - GAsyncResult *result, - GError **error); +SysprofRecording *sysprof_profiler_record_finish (SysprofProfiler *self, + GAsyncResult *result, + GError **error); +SYSPROF_AVAILABLE_IN_49 +gboolean sysprof_profiler_get_acquire_privileges (SysprofProfiler *self); +SYSPROF_AVAILABLE_IN_49 +void sysprof_profiler_set_acquire_privileges (SysprofProfiler *self, + gboolean acquire_privileges); G_END_DECLS diff --git a/src/libsysprof/sysprof-recording-private.h b/src/libsysprof/sysprof-recording-private.h index 15fb7f16..3d67b6b2 100644 --- a/src/libsysprof/sysprof-recording-private.h +++ b/src/libsysprof/sysprof-recording-private.h @@ -79,12 +79,18 @@ struct _SysprofRecording /* The process we have spawned, if any */ GSubprocess *subprocess; + + /* If we should preauth or otherwise use sysprofd to access + * privileges when setting up the recording. + */ + guint use_sysprofd : 1; }; SysprofRecording *_sysprof_recording_new (SysprofCaptureWriter *writer, SysprofSpawnable *spawnable, SysprofInstrument **instruments, - guint n_instruments); + guint n_instruments, + gboolean use_sysprofd); void _sysprof_recording_start (SysprofRecording *self); SysprofSpawnable *_sysprof_recording_get_spawnable (SysprofRecording *self); DexFuture *_sysprof_recording_add_file (SysprofRecording *self, diff --git a/src/libsysprof/sysprof-recording.c b/src/libsysprof/sysprof-recording.c index 57e53e7e..bb7580d2 100644 --- a/src/libsysprof/sysprof-recording.c +++ b/src/libsysprof/sysprof-recording.c @@ -27,6 +27,7 @@ #include #include "sysprof-recording-private.h" +#include "sysprof-util-private.h" enum { PROP_0, @@ -99,6 +100,7 @@ static DexFuture * sysprof_recording_fiber (gpointer user_data) { SysprofRecording *self = user_data; + g_autoptr(GDBusConnection) connection = NULL; g_autoptr(GCancellable) cancellable = NULL; g_autoptr(DexFuture) record = NULL; g_autoptr(DexFuture) monitor = NULL; @@ -115,12 +117,24 @@ sysprof_recording_fiber (gpointer user_data) cancellable = g_cancellable_new (); - /* First ensure that all our required policy have been acquired on - * the bus so that we don't need to individually acquire them from - * each of the instruments after the recording starts. - */ - if (!dex_await (_sysprof_instruments_acquire_policy (self->instruments, self), &error)) - return dex_future_new_for_error (g_steal_pointer (&error)); + if (self->use_sysprofd) + { + /* Get our D-Bus system connection if we're using sysprofd. */ + if (!(connection = dex_await_object (dex_bus_get (G_BUS_TYPE_SYSTEM), NULL))) + return dex_future_new_for_error (g_steal_pointer (&error)); + + /* Let every instrument know what bus we're using so that they can + * automatically enable/disable sysprofd/policy-kit integration. + */ + _sysprof_instruments_set_connection (self->instruments, connection); + + /* First ensure that all our required policy have been acquired on + * the bus so that we don't need to individually acquire them from + * each of the instruments after the recording starts. + */ + if (!dex_await (_sysprof_instruments_acquire_policy (self->instruments, self), &error)) + return dex_future_new_for_error (g_steal_pointer (&error)); + } /* Now allow instruments to prepare for the recording */ if (!dex_await (_sysprof_instruments_prepare (self->instruments, self), &error)) @@ -420,7 +434,8 @@ SysprofRecording * _sysprof_recording_new (SysprofCaptureWriter *writer, SysprofSpawnable *spawnable, SysprofInstrument **instruments, - guint n_instruments) + guint n_instruments, + gboolean use_sysprofd) { SysprofRecording *self; @@ -428,6 +443,7 @@ _sysprof_recording_new (SysprofCaptureWriter *writer, self = g_object_new (SYSPROF_TYPE_RECORDING, NULL); self->writer = sysprof_capture_writer_ref (writer); + self->use_sysprofd = !!use_sysprofd; g_set_object (&self->spawnable, spawnable); @@ -517,6 +533,7 @@ typedef struct _AddFile SysprofCaptureWriter *writer; char *path; guint compress : 1; + guint use_sysprofd : 1; } AddFile; static void @@ -572,25 +589,18 @@ sysprof_recording_add_file_fiber (gpointer user_data) if (g_file_has_prefix (file, proc)) { g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GVariant) reply = NULL; g_autoptr(GBytes) input_bytes = NULL; - if (!(connection = dex_await_object (dex_bus_get (G_BUS_TYPE_SYSTEM), &error))) + if (add_file->use_sysprofd) + { + /* Only use D-Bus if sysprofd use is requested */ + if (!(connection = dex_await_object (dex_bus_get (G_BUS_TYPE_SYSTEM), &error))) + return dex_future_new_for_error (g_steal_pointer (&error)); + } + + if (!(input_bytes = dex_await_boxed (sysprof_get_proc_file_bytes (connection, g_file_get_path (file)), &error))) return dex_future_new_for_error (g_steal_pointer (&error)); - if (!(reply = dex_await_variant (dex_dbus_connection_call (connection, - "org.gnome.Sysprof3", - "/org/gnome/Sysprof3", - "org.gnome.Sysprof3.Service", - "GetProcFile", - g_variant_new ("(^ay)", g_file_get_path (file)), - G_VARIANT_TYPE ("(ay)"), - G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION, - G_MAXINT), - &error))) - return dex_future_new_for_error (g_steal_pointer (&error)); - - input_bytes = g_variant_get_data_as_bytes (reply); input = g_memory_input_stream_new_from_bytes (input_bytes); } else @@ -662,6 +672,7 @@ _sysprof_recording_add_file (SysprofRecording *self, add_file->writer = sysprof_capture_writer_ref (self->writer); add_file->path = g_strdup (path); add_file->compress = !!compress; + add_file->use_sysprofd = self->use_sysprofd; return dex_scheduler_spawn (NULL, 0, sysprof_recording_add_file_fiber,