diff --git a/debian/patches/0700-modules-add-snappy-policy-module.patch b/debian/patches/0700-modules-add-snappy-policy-module.patch index 52ec724fe..0fb4baa0f 100644 --- a/debian/patches/0700-modules-add-snappy-policy-module.patch +++ b/debian/patches/0700-modules-add-snappy-policy-module.patch @@ -1,6 +1,6 @@ From: James Henstridge Date: Tue, 28 Apr 2020 14:42:07 +0800 -Subject: [PATCH] modules: add snap policy module +Subject: modules: add snap policy module Forwarded: not-needed @@ -13,8 +13,8 @@ Co-authored-by: Simon Fels --- configure.ac | 15 ++ src/Makefile.am | 13 ++ - src/modules/module-snap-policy.c | 414 +++++++++++++++++++++++++++++++++++++++ - 3 files changed, 442 insertions(+) + src/modules/module-snap-policy.c | 416 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 444 insertions(+) create mode 100644 src/modules/module-snap-policy.c diff --git a/configure.ac b/configure.ac @@ -90,10 +90,10 @@ index 6ff75d4..8b7effa 100644 module_rtp_send_la_LDFLAGS = $(MODULE_LDFLAGS) diff --git a/src/modules/module-snap-policy.c b/src/modules/module-snap-policy.c new file mode 100644 -index 0000000..08d1b9e +index 0000000..57ed40a --- /dev/null +++ b/src/modules/module-snap-policy.c -@@ -0,0 +1,414 @@ +@@ -0,0 +1,416 @@ +/*** + This file is part of PulseAudio. + @@ -141,13 +141,19 @@ index 0000000..08d1b9e +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(true); + ++typedef enum snap_access { ++ SNAP_ACCESS_NONE = 0, ++ SNAP_ACCESS_RECORD = 1 << 0, ++ SNAP_ACCESS_CONTROL = 1 << 1, ++} snap_access_t; ++ +struct per_client { + struct userdata *userdata; + uint32_t index; + char *snap_name; + pa_dynarray *pending_requests; /* of pa_access_data */ + bool completed; -+ bool grant_access; ++ snap_access_t access; +}; + +struct userdata { @@ -175,12 +181,12 @@ index 0000000..08d1b9e + +/* ---- Code running in glib thread ---- */ + -+static void complete_check_access(struct per_client *pc, bool grant_access) ++static void complete_check_access(struct per_client *pc, snap_access_t access) +{ + struct userdata *u = pc->userdata; + + pa_mutex_lock(u->mutex); -+ pc->grant_access = grant_access; ++ pc->access = access; + pc->completed = true; + pa_asyncq_push(u->results, pc, true); + pa_mutex_unlock(u->mutex); @@ -192,7 +198,7 @@ index 0000000..08d1b9e +{ + struct per_client *pc = user_data; + struct userdata *u = pc->userdata; -+ bool grant_access = false; ++ snap_access_t access = SNAP_ACCESS_NONE; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) established = NULL; + unsigned i; @@ -202,7 +208,7 @@ index 0000000..08d1b9e + goto end; + } + -+ /* determine pc->grant_access */ ++ /* determine pc->access */ + for (i = 0; i < established->len; i++) { + SnapdConnection *conn = established->pdata[i]; + SnapdPlugRef *plug = snapd_connection_get_plug(conn); @@ -214,13 +220,13 @@ index 0000000..08d1b9e + continue; + } + if (!strcmp(iface, "pulseaudio") || !strcmp(iface, "audio-record")) { -+ grant_access = true; ++ access |= SNAP_ACCESS_RECORD; + break; + } + } + +end: -+ complete_check_access(pc, grant_access); ++ complete_check_access(pc, access); +} + +static void get_snap_finished(GObject *source_object, @@ -235,13 +241,13 @@ index 0000000..08d1b9e + snap = snapd_client_get_snap_finish(u->snapd, result, &error); + if (!snap) { + pa_log_warn("snapd_client_get_snap failed: %s", error->message); -+ complete_check_access(pc, false); ++ complete_check_access(pc, SNAP_ACCESS_NONE); + return; + } + + /* Snaps using classic confinement are granted access */ + if (snapd_snap_get_confinement(snap) == SNAPD_CONFINEMENT_CLASSIC) { -+ complete_check_access(pc, true); ++ complete_check_access(pc, SNAP_ACCESS_RECORD | SNAP_ACCESS_CONTROL); + return; + } + @@ -311,7 +317,7 @@ index 0000000..08d1b9e + pc->snap_name = snap_name; + pc->pending_requests = pa_dynarray_new(NULL); + pc->completed = false; -+ pc->grant_access = false; ++ pc->access = SNAP_ACCESS_NONE; + return pc; +} + @@ -325,7 +331,6 @@ index 0000000..08d1b9e +static char *client_get_snap_name(pa_core *core, uint32_t client_index) { + pa_client *client; + char *label = NULL; -+ char *snap_name = NULL; + char *dot; + + client = pa_idxset_get_by_index(core->clients, client_index); @@ -350,8 +355,9 @@ index 0000000..08d1b9e + return pa_xstrndup(label, dot - label); +} + -+static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, -+ struct userdata *u) { ++static pa_hook_result_t check_snap_access(pa_core *core, pa_access_data *d, ++ struct userdata *u, ++ snap_access_t required_access) { + pa_hook_result_t result = PA_HOOK_STOP; + struct per_client *pc = NULL; + char *snap_name = NULL; @@ -360,7 +366,8 @@ index 0000000..08d1b9e + pc = pa_hashmap_get(u->clients, (void *)(size_t)d->client_index); + if (pc) { + if (pc->completed) { -+ result = pc->grant_access ? PA_HOOK_OK : PA_HOOK_STOP; ++ result = ((pc->access & required_access) == required_access) ++ ? PA_HOOK_OK : PA_HOOK_STOP; + } else { + /* A permission check for this snap is currently in progress */ + pa_dynarray_append(pc->pending_requests, d); @@ -395,14 +402,14 @@ index 0000000..08d1b9e + unsigned i; + + pa_log_info("Access check for client %u (%s): %d", -+ pc->index, pc->snap_name, pc->grant_access); ++ pc->index, pc->snap_name, pc->access); + + /* Call the hooks without holding the mutex, since this will -+ * recurse into connect_record_hook. Access to pending_requests ++ * recurse into check_snap_access. Access to pending_requests + * should be safe here, since connect_record_hook wont alter the + * array when the access check is complete. */ + PA_DYNARRAY_FOREACH(ad, pc->pending_requests, i) { -+ ad->async_finish_cb(ad, pc->grant_access); ++ ad->async_finish_cb(ad, pc->access != SNAP_ACCESS_NONE); + } + pa_mutex_lock(u->mutex); + pa_hashmap_remove_and_free(u->clients, (void *) (size_t) pc->index); @@ -420,20 +427,15 @@ index 0000000..08d1b9e + pa_asyncq_read_before_poll(u->results); +} + -+/* An access control hook that blocks access to snaps */ -+static pa_hook_result_t deny_to_snaps_hook(pa_core *core, pa_access_data *d, -+ struct userdata *u) { -+ char *snap_name = NULL; -+ bool is_snap; -+ -+ snap_name = client_get_snap_name(core, d->client_index); -+ is_snap = snap_name != NULL; -+ pa_xfree(snap_name); ++static pa_hook_result_t require_record_access(pa_core *core, pa_access_data *d, ++ struct userdata *u) { ++ return check_snap_access(core, d, u, SNAP_ACCESS_RECORD); ++} + -+ if (is_snap) { -+ return PA_HOOK_STOP; -+ } -+ return PA_HOOK_OK; ++/* An access control hook that blocks access to non-classic snaps */ ++static pa_hook_result_t require_control_access(pa_core *core, pa_access_data *d, ++ struct userdata *u) { ++ return check_snap_access(core, d, u, SNAP_ACCESS_CONTROL); +} + +int pa__init(pa_module *m) { @@ -456,22 +458,22 @@ index 0000000..08d1b9e + + u->connect_record_hook_slot = pa_hook_connect( + &m->core->access[PA_ACCESS_HOOK_CONNECT_RECORD], PA_HOOK_NORMAL, -+ (pa_hook_cb_t) connect_record_hook, u); ++ (pa_hook_cb_t) require_record_access, u); + u->exit_daemon_hook_slot = pa_hook_connect( + &m->core->access[PA_ACCESS_HOOK_EXIT_DAEMON], PA_HOOK_NORMAL, -+ (pa_hook_cb_t) deny_to_snaps_hook, NULL); ++ (pa_hook_cb_t) require_control_access, u); + u->get_module_info_hook_slot = pa_hook_connect( + &m->core->access[PA_ACCESS_HOOK_GET_MODULE_INFO], PA_HOOK_NORMAL, -+ (pa_hook_cb_t) deny_to_snaps_hook, NULL); ++ (pa_hook_cb_t) require_control_access, u); + u->load_module_hook_slot = pa_hook_connect( + &m->core->access[PA_ACCESS_HOOK_LOAD_MODULE], PA_HOOK_NORMAL, -+ (pa_hook_cb_t) deny_to_snaps_hook, NULL); ++ (pa_hook_cb_t) require_control_access, u); + u->unload_module_hook_slot = pa_hook_connect( + &m->core->access[PA_ACCESS_HOOK_UNLOAD_MODULE], PA_HOOK_NORMAL, -+ (pa_hook_cb_t) deny_to_snaps_hook, NULL); ++ (pa_hook_cb_t) require_control_access, u); + u->kill_client_hook_slot = pa_hook_connect( + &m->core->access[PA_ACCESS_HOOK_KILL_CLIENT], PA_HOOK_NORMAL, -+ (pa_hook_cb_t) deny_to_snaps_hook, NULL); ++ (pa_hook_cb_t) require_control_access, u); + + /* Start glib thread and wait for it to finish initialising. */ + pa_mutex_lock(u->mutex);