From 3730e5448491827286fc333e204393c9e2456103 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Sat, 30 Jul 2022 21:29:42 +0300 Subject: [PATCH] modules: support getting app_id in pw_check_flatpak Support getting the Flatpak application ID from the .flatpak-info file, similarly as what xdg-desktop-portal does. --- meson.build | 5 ++ meson_options.txt | 4 ++ src/modules/flatpak-utils.h | 70 +++++++++++++++++++++- src/modules/meson.build | 11 +++- src/modules/module-access.c | 2 +- src/modules/module-protocol-pulse/server.c | 2 +- 6 files changed, 89 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index ed61efc9a..b6c01f191 100644 --- a/meson.build +++ b/meson.build @@ -295,6 +295,11 @@ cdata.set('HAVE_LIBUSB', libusb_dep.found()) cap_lib = dependency('libcap', required : false) cdata.set('HAVE_LIBCAP', cap_lib.found()) +glib2_dep = dependency('glib-2.0', required : get_option('flatpak')) +summary({'GLib-2.0 (Flatpak support)': glib2_dep.found()}, bool_yn: true, section: 'Misc dependencies') +flatpak_support = glib2_dep.found() +cdata.set('HAVE_GLIB2', flatpak_support) + gst_option = get_option('gstreamer') gst_deps_def = { 'glib-2.0': {'version': '>=2.32.0'}, diff --git a/meson_options.txt b/meson_options.txt index 4b99bbc55..e6a5623e0 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -253,3 +253,7 @@ option('avb', description: 'Enable AVB code', type: 'feature', value: 'auto') +option('flatpak', + description: 'Enable Flatpak support', + type: 'feature', + value: 'enabled') diff --git a/src/modules/flatpak-utils.h b/src/modules/flatpak-utils.h index 331c879b2..d1d3951bf 100644 --- a/src/modules/flatpak-utils.h +++ b/src/modules/flatpak-utils.h @@ -28,20 +28,64 @@ #include #include #include +#include #include #include -#include +#include "config.h" + +#ifdef HAVE_GLIB2 +#include +#endif + +#include #include +static int pw_check_flatpak_parse_metadata(const char *buf, size_t size, char **app_id, char **devices) +{ +#ifdef HAVE_GLIB2 + /* + * See flatpak-metadata(5) + * + * The .flatpak-info file is in GLib key_file .ini format. + */ + g_autoptr(GKeyFile) metadata = NULL; + char *s; -static int pw_check_flatpak(pid_t pid) + metadata = g_key_file_new(); + if (!g_key_file_load_from_data(metadata, buf, size, G_KEY_FILE_NONE, NULL)) + return -EINVAL; + + if (app_id) { + s = g_key_file_get_value(metadata, "Application", "name", NULL); + *app_id = s ? strdup(s) : NULL; + g_free(s); + } + + if (devices) { + s = g_key_file_get_value(metadata, "Context", "devices", NULL); + *devices = s ? strdup(s) : NULL; + g_free(s); + } + + return 0; +#else + return -ENOTSUP; +#endif +} + +static int pw_check_flatpak(pid_t pid, char **app_id, char **devices) { #if defined(__linux__) char root_path[2048]; int root_fd, info_fd, res; struct stat stat_buf; + if (app_id) + *app_id = NULL; + if (devices) + *devices = NULL; + snprintf(root_path, sizeof(root_path), "/proc/%d/root", (int)pid); root_fd = openat (AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); if (root_fd == -1) { @@ -77,6 +121,28 @@ static int pw_check_flatpak(pid_t pid) if (fstat (info_fd, &stat_buf) != 0 || !S_ISREG (stat_buf.st_mode)) { /* Some weird fd => failure, assume sandboxed */ pw_log_error("error fstat .flatpak-info: %m"); + } else if (app_id || devices) { + /* Parse the application ID if needed */ + const size_t size = stat_buf.st_size; + + if (size > 0) { + void *buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, info_fd, 0); + if (buf != MAP_FAILED) { + res = pw_check_flatpak_parse_metadata(buf, size, app_id, devices); + munmap(buf, size); + } else { + res = -errno; + } + } else { + res = -EINVAL; + } + + if (res == -EINVAL) + pw_log_error("PID %d .flatpak-info file is malformed", + (int)pid); + else if (res < 0) + pw_log_error("PID %d .flatpak-info parsing failed: %s", + (int)pid, spa_strerror(res)); } close(info_fd); return 1; diff --git a/src/modules/meson.build b/src/modules/meson.build index a21acddfb..bca1c9b14 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -33,12 +33,17 @@ module_sources = [ 'module-x11-bell.c', ] +pipewire_module_access_deps = [spa_dep, mathlib, dl_lib, pipewire_dep] +if flatpak_support + pipewire_module_access_deps += glib2_dep +endif + pipewire_module_access = shared_library('pipewire-module-access', [ 'module-access.c' ], include_directories : [configinc], install : true, install_dir : modules_install_dir, install_rpath: modules_install_dir, - dependencies : [spa_dep, mathlib, dl_lib, pipewire_dep], + dependencies : pipewire_module_access_deps ) pipewire_module_loopback = shared_library('pipewire-module-loopback', @@ -277,6 +282,10 @@ if avahi_dep.found() cdata.set('HAVE_AVAHI', true) endif +if flatpak_support + pipewire_module_protocol_pulse_deps += glib2_dep +endif + pipewire_module_protocol_pulse = shared_library('pipewire-module-protocol-pulse', pipewire_module_protocol_pulse_sources, include_directories : [configinc], diff --git a/src/modules/module-access.c b/src/modules/module-access.c index bc0928943..3d868231d 100644 --- a/src/modules/module-access.c +++ b/src/modules/module-access.c @@ -252,7 +252,7 @@ context_check_access(void *data, struct pw_impl_client *client) (access = pw_properties_get(impl->properties, "access.force")) != NULL) goto wait_permissions; - res = pw_check_flatpak(pid); + res = pw_check_flatpak(pid, NULL, NULL); if (res != 0) { if (res < 0) { if (res == -EACCES) { diff --git a/src/modules/module-protocol-pulse/server.c b/src/modules/module-protocol-pulse/server.c index 1a9b3df93..4e89c35ba 100644 --- a/src/modules/module-protocol-pulse/server.c +++ b/src/modules/module-protocol-pulse/server.c @@ -424,7 +424,7 @@ on_connect(void *data, int fd, uint32_t mask) pw_log_warn("setsockopt(SO_PRIORITY) failed: %m"); #endif pid = get_client_pid(client, client_fd); - if (pid != 0 && pw_check_flatpak(pid) == 1) + if (pid != 0 && pw_check_flatpak(pid, NULL, NULL) == 1) client_access = "flatpak"; } else if (server->addr.ss_family == AF_INET || server->addr.ss_family == AF_INET6) {