1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
/* PipeWire */
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#ifndef FLATPAK_UTILS_H
#define FLATPAK_UTILS_H
#define HAVE_GLIB2
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#ifdef HAVE_GLIB2
#include <glib.h>
#endif
#include <spa/utils/cleanup.h>
#include <spa/utils/result.h>
#include <pipewire/log.h>
static int pw_check_flatpak_parse_metadata(const char *buf, size_t size, char **app_id, char **instance_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;
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);
}
if (instance_id) {
s = g_key_file_get_value(metadata, "Instance", "instance-id", NULL);
*instance_id = 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 **instance_id, char **devices)
{
#if defined(__linux__)
char root_path[2048];
struct stat stat_buf;
int res;
if (app_id)
*app_id = NULL;
if (instance_id)
*instance_id = NULL;
if (devices)
*devices = NULL;
snprintf(root_path, sizeof(root_path), "/proc/%d/root", (int)pid);
spa_autoclose int root_fd = openat(AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
if (root_fd < 0) {
res = -errno;
pw_log_info("failed to open \"%s\": %s", root_path, spa_strerror(res));
if (res == -EACCES) {
/* If we can't access the root filesystem, consider not sandboxed.
* This should not happen but for now it is a workaround for selinux
* where we can't access the gnome-shell root when it connects for
* screen sharing.
*/
return 0;
}
/* Not able to open the root dir shouldn't happen. Probably the app died and
* we're failing due to /proc/$pid not existing. In that case fail instead
* of treating this as privileged. */
return res;
}
spa_autoclose int info_fd = openat(root_fd, ".flatpak-info", O_RDONLY | O_CLOEXEC | O_NOCTTY);
if (info_fd < 0) {
if (errno == ENOENT) {
pw_log_debug("no .flatpak-info, client on the host");
/* No file => on the host */
return 0;
}
res = -errno;
pw_log_error("error opening .flatpak-info: %m");
return res;
}
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 || instance_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, instance_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));
}
return 1;
#else
return 0;
#endif
}
#endif /* FLATPAK_UTILS_H */
|