diff -Nru pulseaudio-11.1/debian/changelog pulseaudio-11.1/debian/changelog --- pulseaudio-11.1/debian/changelog 2020-07-09 08:03:25.000000000 +0000 +++ pulseaudio-11.1/debian/changelog 2020-09-22 04:30:20.000000000 +0000 @@ -1,3 +1,23 @@ +pulseaudio (1:11.1-1ubuntu7.11) bionic-security; urgency=medium + + * SECURITY UPDATE: don't rely on SCM_CREDENTIALS to detect snap confined + clients (LP: #1895928) + - d/p/0409-pa-client-peer-credentials.patch: drop patch + - d/p/0409-fix-arg-parsing-after-async-hook.patch: remains of old 0409 + patch not related to pa_creds. + - d/p/0410-pa-client-peer-apparmor-label.patch: new patch, records + AppArmor label in pa_client struct for native connections using + aa_getpeercon. + - d/p/0702-add-snappy-policy-module.patch: use the AppArmor + label in the pa_client rather than looking it up via the process ID + from SCM_CREDENTIALS. + - CVE-2020-16123 + * Don't block classic snaps from module loading/unloading (LP: #1886854) + - d/p/0702-add-snappy-policy-module.patch: replace + deny_to_snaps_hook with a version that allows classic snaps. + + -- James Henstridge Tue, 22 Sep 2020 12:30:20 +0800 + pulseaudio (1:11.1-1ubuntu7.10) bionic; urgency=medium * d/p/0903-device-port-switch-on-port-available-fix-automatic-p.patch diff -Nru pulseaudio-11.1/debian/patches/0409-fix-arg-parsing-after-async-hook.patch pulseaudio-11.1/debian/patches/0409-fix-arg-parsing-after-async-hook.patch --- pulseaudio-11.1/debian/patches/0409-fix-arg-parsing-after-async-hook.patch 1970-01-01 00:00:00.000000000 +0000 +++ pulseaudio-11.1/debian/patches/0409-fix-arg-parsing-after-async-hook.patch 2020-09-22 04:30:20.000000000 +0000 @@ -0,0 +1,30 @@ +From: David Henningsson +Date: Wed, 22 Jul 2015 16:37:19 +0200 +Subject: [PATCH 4/5] Fix command argument parsing after async hook execution + +--- + src/pulsecore/protocol-native.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/src/pulsecore/protocol-native.c ++++ b/src/pulsecore/protocol-native.c +@@ -5631,6 +5631,7 @@ typedef struct pa_protocol_native_access + } pa_protocol_native_access_data; + + static void check_access_finish_cb(pa_access_data *data, bool res) { ++ uint32_t command, tag; + pa_protocol_native_access_data *d = (pa_protocol_native_access_data *) data; + pa_native_connection *c = PA_NATIVE_CONNECTION(d->userdata); + +@@ -5639,6 +5640,11 @@ static void check_access_finish_cb(pa_ac + goto finish; + } + ++ pa_assert_se(pa_tagstruct_getu32(d->tc, &command) >= 0); ++ pa_assert_se(pa_tagstruct_getu32(d->tc, &tag) >= 0); ++ pa_assert(command == d->command); ++ pa_assert(tag == d->tag); ++ + /* call the dispatcher again, hopefully this time, the access check will + * fail or succeed immediately */ + command_table[d->command](d->pd, d->command, d->tag, d->tc, d->userdata); diff -Nru pulseaudio-11.1/debian/patches/0409-pa-client-peer-credentials.patch pulseaudio-11.1/debian/patches/0409-pa-client-peer-credentials.patch --- pulseaudio-11.1/debian/patches/0409-pa-client-peer-credentials.patch 2020-05-27 08:42:50.000000000 +0000 +++ pulseaudio-11.1/debian/patches/0409-pa-client-peer-credentials.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -From: David Henningsson -Date: Wed, 22 Jul 2015 16:37:19 +0200 -Subject: [PATCH 4/5] Expose peer credentials on pa_client - -Signed-off-by: David Henningsson ---- - src/pulsecore/client.h | 4 ++++ - src/pulsecore/creds.h | 1 + - src/pulsecore/iochannel.c | 2 ++ - src/pulsecore/protocol-native.c | 13 +++++++++++++ - 4 files changed, 20 insertions(+) - -diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h -index eb8173d..a038a0c 100644 ---- a/src/pulsecore/client.h -+++ b/src/pulsecore/client.h -@@ -26,6 +26,7 @@ - #include - #include - #include -+#include - - /* Every connection to the server should have a pa_client - * attached. That way the user may generate a listing of all connected -@@ -35,6 +36,9 @@ struct pa_client { - uint32_t index; - pa_core *core; - -+ pa_creds creds; -+ bool creds_valid; -+ - pa_proplist *proplist; - pa_module *module; - char *driver; -diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h -index 9fdbb4f..8bcf636 100644 ---- a/src/pulsecore/creds.h -+++ b/src/pulsecore/creds.h -@@ -41,6 +41,7 @@ typedef struct pa_cmsg_ancil_data pa_cmsg_ancil_data; - struct pa_creds { - gid_t gid; - uid_t uid; -+ pid_t pid; - }; - - /* Struct for handling ancillary data, i e, extra data that can be sent together with a message -diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c -index 8973375..cd0b81d 100644 ---- a/src/pulsecore/iochannel.c -+++ b/src/pulsecore/iochannel.c -@@ -323,6 +323,7 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l - - u = (struct ucred*) CMSG_DATA(&cmsg.hdr); - -+ /* FIXME: Check whether ucred->pid should be used */ - u->pid = getpid(); - if (ucred) { - u->uid = ucred->uid; -@@ -445,6 +446,7 @@ ssize_t pa_iochannel_read_with_ancil_data(pa_iochannel*io, void*data, size_t l, - - ancil_data->creds.gid = u.gid; - ancil_data->creds.uid = u.uid; -+ ancil_data->creds.pid = u.pid; - ancil_data->creds_valid = true; - } - else if (cmh->cmsg_type == SCM_RIGHTS) { -diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c -index 67b5c7a..a2f74a0 100644 ---- a/src/pulsecore/protocol-native.c -+++ b/src/pulsecore/protocol-native.c -@@ -2668,6 +2668,13 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta - do_shm = false; - - #ifdef HAVE_CREDS -+ { -+ const pa_creds *creds; -+ if ((creds = pa_pdispatch_creds(pd))) { -+ c->client->creds = *creds; -+ c->client->creds_valid = true; -+ } -+ } - if (do_shm) { - /* Only enable SHM if both sides are owned by the same - * user. This is a security measure because otherwise data -@@ -5631,6 +5638,7 @@ typedef struct pa_protocol_native_access_data { - } pa_protocol_native_access_data; - - static void check_access_finish_cb(pa_access_data *data, bool res) { -+ uint32_t command, tag; - pa_protocol_native_access_data *d = (pa_protocol_native_access_data *) data; - pa_native_connection *c = PA_NATIVE_CONNECTION(d->userdata); - -@@ -5639,6 +5647,11 @@ static void check_access_finish_cb(pa_access_data *data, bool res) { - goto finish; - } - -+ pa_assert_se(pa_tagstruct_getu32(d->tc, &command) >= 0); -+ pa_assert_se(pa_tagstruct_getu32(d->tc, &tag) >= 0); -+ pa_assert(command == d->command); -+ pa_assert(tag == d->tag); -+ - /* call the dispatcher again, hopefully this time, the access check will - * fail or succeed immediately */ - command_table[d->command](d->pd, d->command, d->tag, d->tc, d->userdata); diff -Nru pulseaudio-11.1/debian/patches/0410-pa-client-peer-apparmor-label.patch pulseaudio-11.1/debian/patches/0410-pa-client-peer-apparmor-label.patch --- pulseaudio-11.1/debian/patches/0410-pa-client-peer-apparmor-label.patch 1970-01-01 00:00:00.000000000 +0000 +++ pulseaudio-11.1/debian/patches/0410-pa-client-peer-apparmor-label.patch 2020-09-22 04:30:20.000000000 +0000 @@ -0,0 +1,162 @@ +From: James Henstridge +Date: Mon, 21 Sep 2020 16:56:08 +0800 +Subject: pulsecore: expose peer AppArmor label on pa_client + +Forwarded: not-needed + +This patch uses aa_getpeercon to get the AppArmor label of the peer +and store it in the pa_client struct. Only the native protocol +connection handler has been updated, as that is the only protocol with +access control hooks. +--- + configure.ac | 6 ++++++ + src/Makefile.am | 10 ++++++++++ + src/pulsecore/client.c | 3 +++ + src/pulsecore/client.h | 3 +++ + src/pulsecore/iochannel.c | 17 +++++++++++++++++ + src/pulsecore/iochannel.h | 4 ++++ + src/pulsecore/protocol-native.c | 1 + + 7 files changed, 44 insertions(+) + +--- a/configure.ac ++++ b/configure.ac +@@ -698,6 +698,12 @@ AS_IF([test "x$HAVE_LIBSAMPLERATE" = "x1 + + AS_IF([test "x$HAVE_LIBSAMPLERATE" = "x1"], AC_MSG_WARN([Support for libsamplerate is DEPRECATED])) + ++#### AppArmor support (optional) #### ++ ++PKG_CHECK_MODULES(APPARMOR, [libapparmor], [HAVE_APPARMOR=1], [HAVE_APPARMOR=0]) ++AM_CONDITIONAL([HAVE_APPARMOR], [test "x$HAVE_APPARMOR" = x1]) ++AS_IF([test "x$HAVE_APPARMOR" = x1], [AC_DEFINE([HAVE_APPARMOR], 1, [AppArmor support library is available.])]) ++ + #### Database support #### + + AC_ARG_WITH([database], +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -811,6 +811,11 @@ libpulsecommon_@PA_MAJORMINOR@_la_CFLAGS + libpulsecommon_@PA_MAJORMINOR@_la_LIBADD += $(DBUS_LIBS) + endif + ++if HAVE_APPARMOR ++libpulsecommon_@PA_MAJORMINOR@_la_CFLAGS += $(APPARMOR_CFLAGS) ++libpulsecommon_@PA_MAJORMINOR@_la_LIBADD += $(APPARMOR_LIBS) ++endif ++ + ################################### + # Client library # + ################################### +@@ -1069,6 +1074,11 @@ libpulsecore_@PA_MAJORMINOR@_la_CFLAGS + + libpulsecore_@PA_MAJORMINOR@_la_LIBADD += $(LIBSAMPLERATE_LIBS) + endif + ++if HAVE_APPARMOR ++libpulsecore_@PA_MAJORMINOR@_la_CFLAGS += $(APPARMOR_CFLAGS) ++libpulsecore_@PA_MAJORMINOR@_la_LIBADD += $(APPARMOR_LIBS) ++endif ++ + # We split the foreign code off to not be annoyed by warnings we don't care about + noinst_LTLIBRARIES += libpulsecore-foreign.la + +--- a/src/pulsecore/client.c ++++ b/src/pulsecore/client.c +@@ -49,6 +49,7 @@ void pa_client_new_data_done(pa_client_n + pa_assert(data); + + pa_proplist_free(data->proplist); ++ pa_xfree(data->apparmor_label); + } + + pa_client *pa_client_new(pa_core *core, pa_client_new_data *data) { +@@ -62,6 +63,7 @@ pa_client *pa_client_new(pa_core *core, + + c = pa_xnew0(pa_client, 1); + c->core = core; ++ c->apparmor_label = pa_xstrdup(data->apparmor_label); + c->proplist = pa_proplist_copy(data->proplist); + c->driver = pa_xstrdup(pa_path_get_filename(data->driver)); + c->module = data->module; +@@ -103,6 +105,7 @@ void pa_client_free(pa_client *c) { + + pa_proplist_free(c->proplist); + pa_xfree(c->driver); ++ pa_xfree(c->apparmor_label); + pa_xfree(c); + + pa_core_check_idle(core); +--- a/src/pulsecore/client.h ++++ b/src/pulsecore/client.h +@@ -35,6 +35,8 @@ struct pa_client { + uint32_t index; + pa_core *core; + ++ char *apparmor_label; ++ + pa_proplist *proplist; + pa_module *module; + char *driver; +@@ -53,6 +55,7 @@ typedef struct pa_client_new_data { + pa_proplist *proplist; + const char *driver; + pa_module *module; ++ char *apparmor_label; + } pa_client_new_data; + + pa_client_new_data *pa_client_new_data_init(pa_client_new_data *data); +--- a/src/pulsecore/iochannel.c ++++ b/src/pulsecore/iochannel.c +@@ -30,6 +30,10 @@ + #include + #endif + ++#ifdef HAVE_APPARMOR ++#include ++#endif ++ + #include + + #include +@@ -497,6 +501,19 @@ void pa_iochannel_socket_peer_to_string( + pa_socket_peer_to_string(io->ifd, s, l); + } + ++char *pa_iochannel_socket_get_peer_apparmor_label(pa_iochannel *io) { ++ pa_assert(io); ++ ++#ifdef HAVE_APPARMOR ++ char *label = NULL; ++ if (aa_getpeercon(io->ifd, &label, NULL) == -1) ++ return NULL; ++ return label; ++#else ++ return NULL; ++#endif ++} ++ + int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) { + pa_assert(io); + +--- a/src/pulsecore/iochannel.h ++++ b/src/pulsecore/iochannel.h +@@ -75,6 +75,10 @@ void pa_iochannel_set_callback(pa_iochan + /* In case the file descriptor is a socket, return a pretty-printed string in *s which describes the peer connected */ + void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l); + ++/* In case the file descriptor is a socket, return the apparmor label ++ * of the peer, if available. */ ++char *pa_iochannel_socket_get_peer_apparmor_label(pa_iochannel *io); ++ + /* Use setsockopt() to tune the receive and send buffers of TCP sockets */ + int pa_iochannel_socket_set_rcvbuf(pa_iochannel*io, size_t l); + int pa_iochannel_socket_set_sndbuf(pa_iochannel*io, size_t l); +--- a/src/pulsecore/protocol-native.c ++++ b/src/pulsecore/protocol-native.c +@@ -5209,6 +5209,7 @@ void pa_native_protocol_connect(pa_nativ + pa_client_new_data_init(&data); + data.module = o->module; + data.driver = __FILE__; ++ data.apparmor_label = pa_iochannel_socket_get_peer_apparmor_label(io); + pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); + pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname); + pa_proplist_sets(data.proplist, "native-protocol.peer", pname); diff -Nru pulseaudio-11.1/debian/patches/0702-add-snappy-policy-module.patch pulseaudio-11.1/debian/patches/0702-add-snappy-policy-module.patch --- pulseaudio-11.1/debian/patches/0702-add-snappy-policy-module.patch 1970-01-01 00:00:00.000000000 +0000 +++ pulseaudio-11.1/debian/patches/0702-add-snappy-policy-module.patch 2020-09-22 04:30:20.000000000 +0000 @@ -0,0 +1,308 @@ +Description: add snap policy module +Author: James Henstridge +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1895928 +Last-Update: 2020-10-08 + +--- a/configure.ac ++++ b/configure.ac +@@ -1423,13 +1423,11 @@ AS_IF([test "x$ax_pthread_ok" = "xyes"], + AC_ARG_ENABLE([snap], + AS_HELP_STRING([--enable-snap], [Enable snap support])) + +-have_apparmor=0 + have_snapd_glib=0 + AS_IF([test "x$enable_snap" != "xno"], +- [PKG_CHECK_MODULES(APPARMOR, [libapparmor], [have_apparmor=1]) +- PKG_CHECK_MODULES(SNAPD_GLIB, [snapd-glib], [have_snapd_glib=1])]) ++ [PKG_CHECK_MODULES(SNAPD_GLIB, [snapd-glib], [have_snapd_glib=1])]) + +-AS_IF([test "x$enable_snap" = "xyes" && test "x$have_apparmor" = "x0" -o "x$have-snapd_glib" = "x0"], ++AS_IF([test "x$enable_snap" = "xyes" && test "x$have-snapd_glib" = "x0"], + [AC_MSG_ERROR([*** Snap module dependencies missing])]) + + AM_CONDITIONAL([BUILD_SNAP], [test "x$enable_snap" = "xyes"]) +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -2096,8 +2096,8 @@ endif + if BUILD_SNAP + module_snap_policy_la_SOURCES = modules/module-snap-policy.c + module_snap_policy_la_LDFLAGS = $(MODULE_LDFLAGS) +-module_snap_policy_la_LIBADD = $(MODULE_LIBADD) $(APPARMOR_LIBS) $(SNAPD_GLIB_LIBS) +-module_snap_policy_la_CFLAGS = $(AM_CFLAGS) $(APPARMOR_CFLAGS) $(SNAPD_GLIB_CFLAGS) -DPA_MODULE_NAME=module_snap_policy ++module_snap_policy_la_LIBADD = $(MODULE_LIBADD) $(SNAPD_GLIB_LIBS) ++module_snap_policy_la_CFLAGS = $(AM_CFLAGS) $(SNAPD_GLIB_CFLAGS) -DPA_MODULE_NAME=module_snap_policy + endif + + # RTP modules +--- a/src/modules/module-snap-policy.c ++++ b/src/modules/module-snap-policy.c +@@ -1,7 +1,7 @@ + /*** + This file is part of PulseAudio. + +- Copyright 2018 Canonical Ltd. ++ Copyright 2020 Canonical Ltd. + Authors: + Simon Fels + James Henstridge +@@ -24,7 +24,6 @@ + #include + #endif + +-#include + #include + #include + +@@ -46,13 +45,19 @@ PA_MODULE_DESCRIPTION("Ubuntu Snap polic + 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 { +@@ -80,12 +85,12 @@ struct userdata { + + /* ---- 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); +@@ -97,7 +102,7 @@ static void get_connections_finished(GOb + { + 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; +@@ -107,7 +112,7 @@ static void get_connections_finished(GOb + 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); +@@ -119,13 +124,13 @@ static void get_connections_finished(GOb + 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, +@@ -140,13 +145,13 @@ static void get_snap_finished(GObject *s + 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; + } + +@@ -216,7 +221,7 @@ static struct per_client *per_client_new + 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; + } + +@@ -229,46 +234,34 @@ static void per_client_free(struct per_c + + static char *client_get_snap_name(pa_core *core, uint32_t client_index) { + pa_client *client; +- char *context = NULL; +- char *snap_name = NULL; ++ char *label = NULL; + char *dot; + + client = pa_idxset_get_by_index(core->clients, client_index); + pa_assert(client != NULL); +- if (!client->creds_valid) { +- pa_log_warn("Client %u has no creds, cannot authenticate", client_index); +- goto end; +- } +- +- /* If AppArmor is not enabled, then we can't identify the client */ +- if (!aa_is_enabled()) { +- goto end; +- } +- if (aa_gettaskcon(client->creds.pid, &context, NULL) < 0) { +- pa_log_error("AppArmor profile could not be retrieved."); +- goto end; ++ if (client->apparmor_label == NULL) { ++ return NULL; + } + + /* If the AppArmor context does not begin with "snap.", then this + * is not a snap */ +- if (strncmp(context, SNAP_LABEL_PREFIX, SNAP_LABEL_PREFIX_LENGTH) != 0) { +- goto end; ++ label = client->apparmor_label; ++ if (strncmp(label, SNAP_LABEL_PREFIX, SNAP_LABEL_PREFIX_LENGTH) != 0) { ++ return NULL; + } ++ label += SNAP_LABEL_PREFIX_LENGTH; + +- dot = strchr(context+SNAP_LABEL_PREFIX_LENGTH, '.'); ++ dot = strchr(label, '.'); + if (dot == NULL) { +- pa_log_warn("Malformed snapd AppArmor profile name: %s", context); +- goto end; ++ pa_log_warn("Malformed snapd AppArmor label: %s", client->apparmor_label); ++ return NULL; + } +- snap_name = pa_xstrndup(context+5, dot-context-SNAP_LABEL_PREFIX_LENGTH); +- +-end: +- free(context); +- return snap_name; ++ 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_access_hook(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; +@@ -277,7 +270,8 @@ static pa_hook_result_t connect_record_h + 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); +@@ -307,19 +301,31 @@ end: + return result; + } + ++static pa_hook_result_t require_record_access_hook(pa_core *core, ++ pa_access_data *d, ++ struct userdata *u) { ++ return check_access_hook(core, d, u, SNAP_ACCESS_RECORD); ++} ++ ++static pa_hook_result_t require_control_access_hook(pa_core *core, ++ pa_access_data *d, ++ struct userdata *u) { ++ return check_access_hook(core, d, u, SNAP_ACCESS_CONTROL); ++} ++ + static void deliver_result(struct userdata *u, struct per_client *pc) { + pa_access_data *ad; + 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); +@@ -337,22 +343,6 @@ static void check_result(pa_mainloop_api + 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); +- +- if (is_snap) { +- return PA_HOOK_STOP; +- } +- return PA_HOOK_OK; +-} +- + int pa__init(pa_module *m) { + struct userdata *u; + +@@ -373,22 +363,22 @@ int pa__init(pa_module *m) { + + 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_hook, 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_hook, 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_hook, 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_hook, 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_hook, 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_hook, u); + + /* Start glib thread and wait for it to finish initialising. */ + pa_mutex_lock(u->mutex); diff -Nru pulseaudio-11.1/debian/patches/series pulseaudio-11.1/debian/patches/series --- pulseaudio-11.1/debian/patches/series 2020-07-09 08:03:25.000000000 +0000 +++ pulseaudio-11.1/debian/patches/series 2020-09-22 04:30:20.000000000 +0000 @@ -9,9 +9,11 @@ 0406-tagstruct-add-copy-method.patch 0407-access-Add-access-control-hooks.patch 0408-protocol-native-add-access-checks.patch -0409-pa-client-peer-credentials.patch +0409-fix-arg-parsing-after-async-hook.patch +0410-pa-client-peer-apparmor-label.patch 0700-modules-add-snappy-policy-module.patch 0701-enable-snap-policy-module.patch +0702-add-snappy-policy-module.patch # Bug fixes backported from PulseAudio 12 0800-fix-lp1720684.patch