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.
This commit is contained in:
Christian Hergert
2025-03-21 12:06:27 -07:00
parent f7eb2134ad
commit 8ee9784188
4 changed files with 112 additions and 38 deletions

View File

@ -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]);
}
}

View File

@ -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

View File

@ -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,

View File

@ -27,6 +27,7 @@
#include <libdex.h>
#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,