Merge ~jamesh/pulseaudio:module-snap-policy into ~ubuntu-audio-dev/pulseaudio:ubuntu
- Git
- lp:~jamesh/pulseaudio
- module-snap-policy
- Merge into ubuntu
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | c3261bbec962194c4e62b40874fbc0fe7f9b6a55 | ||||
Proposed branch: | ~jamesh/pulseaudio:module-snap-policy | ||||
Merge into: | ~ubuntu-audio-dev/pulseaudio:ubuntu | ||||
Prerequisite: | ~ubuntu-audio-dev/pulseaudio:ubuntu-pulse12.2-proposed | ||||
Diff against target: |
1555 lines (+504/-215) 9 files modified
debian/changelog (+12/-0) debian/control (+1/-0) debian/patches/0409-pa-client-peer-credentials.patch (+104/-0) debian/patches/0700-modules-add-snappy-policy-module.patch (+357/-105) debian/patches/0701-enable-snap-policy-module.patch (+25/-0) debian/patches/series (+3/-6) debian/pulseaudio.install (+1/-1) debian/rules (+1/-1) dev/null (+0/-102) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ken VanDine | Approve | ||
Daniel van Vugt | Needs Fixing | ||
Review via email: mp+352558@code.launchpad.net |
Commit message
Update snap policy to make access to audio recording conditional on plugging the "pulseaudio" or "audio-record" interfaces.
Description of the change
The current snap policy module cannot be enabled on desktop Ubuntu systems because it blocks audio recording to all snap confined applications, which breaks many of the snaps available on the store (e.g. Skype is not particularly useful if it can't access the microphone).
On the snapd side, the plan is to introduce new "audio-playback" and "audio-record" interfaces so we can identify apps that actually require microphone access.
On the PulseAudio side, the snap policy module needs to check what interfaces the client has plugged. We use snapd-glib to check whether either of the legacy "pulseaudio" or "audio-record" interfaces are plugged.
The implementation is complicated by the fact that snapd-glib depends on the GLib main loop, while pulse audio has its own incompatible event loop. So we instead run the GLib main loop in a separate thread and pass messages back and forward as needed.
I've also updated the default configuration file to actually enable the module too, since it should now function correctly.
Daniel van Vugt (vanvugt) wrote : | # |
(4) Just make sure module-snap-policy doesn't affect deb users negatively at all.
James Henstridge (jamesh) wrote : | # |
As discussed on IRC, I've dropped the trust-store specific patches (which haven't been built since February according to bug 1739469), keeping the patches necessary for the snap policy module to hook in.
Daniel van Vugt (vanvugt) wrote : | # |
(5) changelog needs to now mention the removal of trust store patches :)
Ken VanDine (ken-vandine) wrote : | # |
jamesh had fixed the changelog, it's been uploaded and merged
Preview Diff
1 | diff --git a/debian/changelog b/debian/changelog | |||
2 | index c797d51..e68a037 100644 | |||
3 | --- a/debian/changelog | |||
4 | +++ b/debian/changelog | |||
5 | @@ -1,3 +1,15 @@ | |||
6 | 1 | pulseaudio (1:12.2-0ubuntu2) UNRELEASED; urgency=medium | ||
7 | 2 | |||
8 | 3 | * Update snap policy to make access to audio recording conditional on | ||
9 | 4 | plugging the "pulseaudio" or "audio-record" interfaces (LP: #1781428): | ||
10 | 5 | - 0700-modules-add-snappy-policy-module.patch: rewrite to query | ||
11 | 6 | snapd for the client's plugged interfaces. | ||
12 | 7 | - 0701-enable-snap-policy-module.patch: enable the module in the | ||
13 | 8 | default configuration. | ||
14 | 9 | - Build depend on libsnapd-glib-dev. | ||
15 | 10 | |||
16 | 11 | -- James Henstridge <james.henstridge@canonical.com> Tue, 07 Aug 2018 17:01:22 +0800 | ||
17 | 12 | |||
18 | 1 | pulseaudio (1:12.2-0ubuntu1) cosmic; urgency=medium | 13 | pulseaudio (1:12.2-0ubuntu1) cosmic; urgency=medium |
19 | 2 | 14 | ||
20 | 3 | * New upstream release 12.2 (LP: #1785551): | 15 | * New upstream release 12.2 (LP: #1785551): |
21 | diff --git a/debian/control b/debian/control | |||
22 | index 3b2a1f4..e724169 100644 | |||
23 | --- a/debian/control | |||
24 | +++ b/debian/control | |||
25 | @@ -33,6 +33,7 @@ Build-Depends: debhelper (>= 10), | |||
26 | 33 | libltdl-dev, | 33 | libltdl-dev, |
27 | 34 | liborc-0.4-dev, | 34 | liborc-0.4-dev, |
28 | 35 | libsamplerate0-dev, | 35 | libsamplerate0-dev, |
29 | 36 | libsnapd-glib-dev, | ||
30 | 36 | libsndfile1-dev, | 37 | libsndfile1-dev, |
31 | 37 | libsoxr-dev (>= 0.1.1), | 38 | libsoxr-dev (>= 0.1.1), |
32 | 38 | libspeexdsp-dev (>= 1.2~rc1), | 39 | libspeexdsp-dev (>= 1.2~rc1), |
33 | diff --git a/debian/patches/0409-Trust-store-patch.patch b/debian/patches/0409-Trust-store-patch.patch | |||
34 | 39 | deleted file mode 100644 | 40 | deleted file mode 100644 |
35 | index 1607c62..0000000 | |||
36 | --- a/debian/patches/0409-Trust-store-patch.patch | |||
37 | +++ /dev/null | |||
38 | @@ -1,572 +0,0 @@ | |||
39 | 1 | From ff36148e002232842ea0f07b148e5844c5d44ceb Mon Sep 17 00:00:00 2001 | ||
40 | 2 | From: David Henningsson <david.henningsson@canonical.com> | ||
41 | 3 | Date: Wed, 22 Jul 2015 16:37:19 +0200 | ||
42 | 4 | Subject: [PATCH 4/5] Trust-store patch | ||
43 | 5 | |||
44 | 6 | ...includes some fixes elsewhere as well. | ||
45 | 7 | |||
46 | 8 | Signed-off-by: David Henningsson <david.henningsson@canonical.com> | ||
47 | 9 | --- | ||
48 | 10 | configure.ac | 15 ++ | ||
49 | 11 | src/Makefile.am | 24 +++ | ||
50 | 12 | src/modules/trust-store/module-trust-store.c | 221 +++++++++++++++++++++++++++ | ||
51 | 13 | src/modules/trust-store/truststore.cc | 74 +++++++++ | ||
52 | 14 | src/modules/trust-store/truststore.h | 41 +++++ | ||
53 | 15 | src/pulsecore/client.h | 4 + | ||
54 | 16 | src/pulsecore/creds.h | 1 + | ||
55 | 17 | src/pulsecore/iochannel.c | 2 + | ||
56 | 18 | src/pulsecore/protocol-native.c | 13 ++ | ||
57 | 19 | src/pulsecore/tagstruct.c | 1 + | ||
58 | 20 | 12 files changed, 399 insertions(+), 7 deletions(-) | ||
59 | 21 | create mode 100644 src/modules/trust-store/module-trust-store.c | ||
60 | 22 | create mode 100644 src/modules/trust-store/truststore.cc | ||
61 | 23 | create mode 100644 src/modules/trust-store/truststore.h | ||
62 | 24 | |||
63 | 25 | Index: pulseaudio/configure.ac | ||
64 | 26 | =================================================================== | ||
65 | 27 | --- pulseaudio.orig/configure.ac | ||
66 | 28 | +++ pulseaudio/configure.ac | ||
67 | 29 | @@ -1447,6 +1447,19 @@ AS_IF([test "x$ax_pthread_ok" = "xyes"], | ||
68 | 30 | AC_DEFINE([_POSIX_PTHREAD_SEMANTICS], 1, [Needed on Solaris])) | ||
69 | 31 | |||
70 | 32 | |||
71 | 33 | +# Ubuntu touch trust store | ||
72 | 34 | + | ||
73 | 35 | +AC_ARG_ENABLE([trust-store], | ||
74 | 36 | + AS_HELP_STRING([--enable-trust-store], [Enable Ubuntu touch trust store])) | ||
75 | 37 | + | ||
76 | 38 | +AS_IF([test "x$enable_trust_store" != "xno"], | ||
77 | 39 | + [PKG_CHECK_MODULES(TRUST_STORE, [ trust-store ], [HAVE_TRUST_STORE=1], [HAVE_TRUST_STORE=0])], | ||
78 | 40 | + [HAVE_WEBRTC=0]) | ||
79 | 41 | + | ||
80 | 42 | +AS_IF([test "x$enable_trust_store" = "xyes" && test "x$HAVE_TRUST_STORE" = "x0"], | ||
81 | 43 | + [AC_MSG_ERROR([*** Ubuntu touch trust store library not found])]) | ||
82 | 44 | + | ||
83 | 45 | +AM_CONDITIONAL([HAVE_TRUST_STORE], [test "x$HAVE_TRUST_STORE" = "x1"]) | ||
84 | 46 | |||
85 | 47 | ################################### | ||
86 | 48 | # Output # | ||
87 | 49 | @@ -1619,6 +1632,7 @@ AS_IF([test "x$HAVE_ADRIAN_EC" = "x1"], | ||
88 | 50 | AS_IF([test "x$HAVE_SPEEX" = "x1"], ENABLE_SPEEX=yes, ENABLE_SPEEX=no) | ||
89 | 51 | AS_IF([test "x$HAVE_SOXR" = "x1"], ENABLE_SOXR=yes, ENABLE_SOXR=no) | ||
90 | 52 | AS_IF([test "x$HAVE_WEBRTC" = "x1"], ENABLE_WEBRTC=yes, ENABLE_WEBRTC=no) | ||
91 | 53 | +AS_IF([test "x$HAVE_TRUST_STORE" = "x1"], ENABLE_TRUST_STORE=yes, ENABLE_TRUST_STORE=no) | ||
92 | 54 | AS_IF([test "x$HAVE_TDB" = "x1"], ENABLE_TDB=yes, ENABLE_TDB=no) | ||
93 | 55 | AS_IF([test "x$HAVE_GDBM" = "x1"], ENABLE_GDBM=yes, ENABLE_GDBM=no) | ||
94 | 56 | AS_IF([test "x$HAVE_SIMPLEDB" = "x1"], ENABLE_SIMPLEDB=yes, ENABLE_SIMPLEDB=no) | ||
95 | 57 | @@ -1683,6 +1697,7 @@ echo " | ||
96 | 58 | Enable speex (resampler, AEC): ${ENABLE_SPEEX} | ||
97 | 59 | Enable soxr (resampler): ${ENABLE_SOXR} | ||
98 | 60 | Enable WebRTC echo canceller: ${ENABLE_WEBRTC} | ||
99 | 61 | + Enable Ubuntu trust store: ${ENABLE_TRUST_STORE} | ||
100 | 62 | Enable gcov coverage: ${ENABLE_GCOV} | ||
101 | 63 | Enable unit tests: ${ENABLE_TESTS} | ||
102 | 64 | Database | ||
103 | 65 | Index: pulseaudio/src/Makefile.am | ||
104 | 66 | =================================================================== | ||
105 | 67 | --- pulseaudio.orig/src/Makefile.am | ||
106 | 68 | +++ pulseaudio/src/Makefile.am | ||
107 | 69 | @@ -1105,6 +1105,10 @@ if HAVE_WEBRTC | ||
108 | 70 | modlibexec_LTLIBRARIES += libwebrtc-util.la | ||
109 | 71 | endif | ||
110 | 72 | |||
111 | 73 | +if HAVE_TRUST_STORE | ||
112 | 74 | +modlibexec_LTLIBRARIES += libtruststore-util.la | ||
113 | 75 | +endif | ||
114 | 76 | + | ||
115 | 77 | if HAVE_ESOUND | ||
116 | 78 | modlibexec_LTLIBRARIES += \ | ||
117 | 79 | libprotocol-esound.la | ||
118 | 80 | @@ -1235,6 +1239,11 @@ modlibexec_LTLIBRARIES += \ | ||
119 | 81 | module-role-ducking.la \ | ||
120 | 82 | module-allow-passthrough.la | ||
121 | 83 | |||
122 | 84 | +if HAVE_TRUST_STORE | ||
123 | 85 | +modlibexec_LTLIBRARIES += \ | ||
124 | 86 | + module-trust-store.la | ||
125 | 87 | +endif | ||
126 | 88 | + | ||
127 | 89 | if HAVE_ESOUND | ||
128 | 90 | modlibexec_LTLIBRARIES += \ | ||
129 | 91 | module-esound-protocol-tcp.la \ | ||
130 | 92 | @@ -2025,6 +2034,20 @@ module_echo_cancel_la_CFLAGS += -DHAVE_W | ||
131 | 93 | module_echo_cancel_la_LIBADD += libwebrtc-util.la | ||
132 | 94 | endif | ||
133 | 95 | |||
134 | 96 | +if HAVE_TRUST_STORE | ||
135 | 97 | +# Separate helper library to keep C and C++ code apart, like we do for webrtc | ||
136 | 98 | +libtruststore_util_la_SOURCES = modules/trust-store/truststore.cc | ||
137 | 99 | +libtruststore_util_la_CXXFLAGS = $(AM_CXXFLAGS) -std=c++11 $(SERVER_CFLAGS) $(TRUST_STORE_CFLAGS) \ | ||
138 | 100 | + $(DBUS_CFLAGS) -DHAVE_TRUST_STORE=1 | ||
139 | 101 | +libtruststore_util_la_LIBADD = libpulsecore-@PA_MAJORMINOR@.la $(TRUST_STORE_LIBS) $(DBUS_LIBS) | ||
140 | 102 | +libtruststore_util_la_LDFLAGS = -avoid-version | ||
141 | 103 | + | ||
142 | 104 | +module_trust_store_la_SOURCES = modules/trust-store/module-trust-store.c | ||
143 | 105 | +module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS) | ||
144 | 106 | +module_trust_store_la_LIBADD = $(MODULE_LIBADD) libtruststore-util.la | ||
145 | 107 | +module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1 | ||
146 | 108 | +endif | ||
147 | 109 | + | ||
148 | 110 | # RTP modules | ||
149 | 111 | module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c | ||
150 | 112 | module_rtp_send_la_LDFLAGS = $(MODULE_LDFLAGS) | ||
151 | 113 | Index: pulseaudio/src/modules/trust-store/module-trust-store.c | ||
152 | 114 | =================================================================== | ||
153 | 115 | --- /dev/null | ||
154 | 116 | +++ pulseaudio/src/modules/trust-store/module-trust-store.c | ||
155 | 117 | @@ -0,0 +1,226 @@ | ||
156 | 118 | +/*** | ||
157 | 119 | + This file is part of PulseAudio. | ||
158 | 120 | + | ||
159 | 121 | + Copyright 2015 Canonical Ltd. | ||
160 | 122 | + Written by David Henningsson <david.henningsson@canonical.com> | ||
161 | 123 | + | ||
162 | 124 | + PulseAudio is free software; you can redistribute it and/or modify | ||
163 | 125 | + it under the terms of the GNU Lesser General Public License as published | ||
164 | 126 | + by the Free Software Foundation; either version 2.1 of the License, | ||
165 | 127 | + or (at your option) any later version. | ||
166 | 128 | + | ||
167 | 129 | + PulseAudio is distributed in the hope that it will be useful, but | ||
168 | 130 | + WITHOUT ANY WARRANTY; without even the implied warranty of | ||
169 | 131 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
170 | 132 | + General Public License for more details. | ||
171 | 133 | + | ||
172 | 134 | + You should have received a copy of the GNU Lesser General Public License | ||
173 | 135 | + along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. | ||
174 | 136 | +***/ | ||
175 | 137 | +#ifdef HAVE_CONFIG_H | ||
176 | 138 | +#include <config.h> | ||
177 | 139 | +#endif | ||
178 | 140 | + | ||
179 | 141 | +#include <pulsecore/i18n.h> | ||
180 | 142 | +#include <pulsecore/core.h> | ||
181 | 143 | +#include <pulsecore/module.h> | ||
182 | 144 | +#include <pulse/xmalloc.h> | ||
183 | 145 | +#include <pulsecore/fdsem.h> | ||
184 | 146 | +#include <pulsecore/thread.h> | ||
185 | 147 | +#include <pulsecore/core-util.h> | ||
186 | 148 | +#include <pulse/mainloop-api.h> | ||
187 | 149 | + | ||
188 | 150 | +PA_MODULE_AUTHOR("David Henningsson"); | ||
189 | 151 | +PA_MODULE_DESCRIPTION("Ubuntu touch trust store integration"); | ||
190 | 152 | +PA_MODULE_VERSION(PACKAGE_VERSION); | ||
191 | 153 | +PA_MODULE_LOAD_ONCE(true); | ||
192 | 154 | + | ||
193 | 155 | +#include "truststore.h" | ||
194 | 156 | + | ||
195 | 157 | +#define REQUEST_GRANTED 1 | ||
196 | 158 | +#define REQUEST_DENIED -1 | ||
197 | 159 | +#define REQUEST_PENDING 0 | ||
198 | 160 | + | ||
199 | 161 | +struct userdata; | ||
200 | 162 | + | ||
201 | 163 | +struct per_client { | ||
202 | 164 | + uint32_t index; | ||
203 | 165 | + char *appname; | ||
204 | 166 | + uid_t uid; | ||
205 | 167 | + pid_t pid; | ||
206 | 168 | + struct userdata *userdata; | ||
207 | 169 | + pa_dynarray *pending_requests; | ||
208 | 170 | + pa_atomic_t result; | ||
209 | 171 | +}; | ||
210 | 172 | + | ||
211 | 173 | +struct userdata { | ||
212 | 174 | + pa_core *core; | ||
213 | 175 | + pa_trust_store *ts; | ||
214 | 176 | + pa_hashmap *per_clients; | ||
215 | 177 | + pa_thread *thread; | ||
216 | 178 | + pa_fdsem *fdsem; | ||
217 | 179 | + pa_io_event *io_event; | ||
218 | 180 | + pa_hook_slot *connect_hook_slot; | ||
219 | 181 | +}; | ||
220 | 182 | + | ||
221 | 183 | +static struct per_client *per_client_new(struct userdata *u, uint32_t client_index) { | ||
222 | 184 | + struct per_client *pc; | ||
223 | 185 | + pa_client *client = pa_idxset_get_by_index(u->core->clients, client_index); | ||
224 | 186 | + | ||
225 | 187 | + pa_assert(client); | ||
226 | 188 | + if (!client->creds_valid) { | ||
227 | 189 | + pa_log_warn("Client %d has no creds, cannot authenticate", client_index); | ||
228 | 190 | + return NULL; | ||
229 | 191 | + } | ||
230 | 192 | + | ||
231 | 193 | + pc = pa_xnew0(struct per_client, 1); | ||
232 | 194 | + // TODO: Do we need something else than the application name here - | ||
233 | 195 | + // the application can probably spoof it | ||
234 | 196 | + pc->appname = pa_xstrdup(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)); | ||
235 | 197 | + pc->index = client_index; | ||
236 | 198 | + pc->uid = client->creds.uid; | ||
237 | 199 | + pc->pid = client->creds.pid; | ||
238 | 200 | + pc->pending_requests = pa_dynarray_new(NULL); | ||
239 | 201 | + pc->userdata = u; | ||
240 | 202 | + | ||
241 | 203 | + pa_hashmap_put(u->per_clients, (void *) (size_t) client_index, pc); | ||
242 | 204 | + | ||
243 | 205 | + return pc; | ||
244 | 206 | +} | ||
245 | 207 | + | ||
246 | 208 | +static void per_client_free_from_hashmap(void *data) { | ||
247 | 209 | + struct per_client *pc = data; | ||
248 | 210 | + if (!pc) | ||
249 | 211 | + return; | ||
250 | 212 | + pa_xfree(pc->appname); | ||
251 | 213 | + pa_dynarray_free(pc->pending_requests); | ||
252 | 214 | + pa_xfree(pc); | ||
253 | 215 | +} | ||
254 | 216 | + | ||
255 | 217 | +static void thread_func(void *data) { | ||
256 | 218 | + struct per_client *pc = data; | ||
257 | 219 | + | ||
258 | 220 | + bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid, | ||
259 | 221 | + /// TRANSLATORS: The app icon and name appears above this string. If the phrase | ||
260 | 222 | + /// can't be translated in this language, translate the whole sentence | ||
261 | 223 | + /// 'This app wants to record audio.' | ||
262 | 224 | + _("wants to record audio.")); | ||
263 | 225 | + | ||
264 | 226 | + pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED); | ||
265 | 227 | + pa_fdsem_post(pc->userdata->fdsem); | ||
266 | 228 | +} | ||
267 | 229 | + | ||
268 | 230 | +static void check_queue(struct userdata *u) { | ||
269 | 231 | + struct per_client *pc; | ||
270 | 232 | + void *dummy; | ||
271 | 233 | + | ||
272 | 234 | + pa_log_debug("Checking queue, size: %d, thread object: %s", | ||
273 | 235 | + pa_hashmap_size(u->per_clients), pa_yes_no(u->thread)); | ||
274 | 236 | + if (u->thread) { | ||
275 | 237 | + pa_access_data *ad; | ||
276 | 238 | + unsigned i; | ||
277 | 239 | + int result; | ||
278 | 240 | + pc = pa_thread_get_data(u->thread); | ||
279 | 241 | + result = pa_atomic_load(&pc->result); | ||
280 | 242 | + if (result == REQUEST_PENDING) | ||
281 | 243 | + return; /* Still processing */ | ||
282 | 244 | + pa_thread_free(u->thread); | ||
283 | 245 | + u->thread = NULL; | ||
284 | 246 | + | ||
285 | 247 | + pa_log_debug("Letting client %d (%s) know the result (%s)", | ||
286 | 248 | + pc->index, pc->appname, result == REQUEST_GRANTED ? "granted" : "rejected"); | ||
287 | 249 | + PA_DYNARRAY_FOREACH(ad, pc->pending_requests, i) { | ||
288 | 250 | + ad->async_finish_cb(ad, result == REQUEST_GRANTED); | ||
289 | 251 | + } | ||
290 | 252 | + pa_hashmap_remove(u->per_clients, (void*) (size_t) pc->index); | ||
291 | 253 | + } | ||
292 | 254 | + | ||
293 | 255 | + /* Find a client that needs asking */ | ||
294 | 256 | + PA_HASHMAP_FOREACH(pc, u->per_clients, dummy) { | ||
295 | 257 | + if (u->thread) | ||
296 | 258 | + return; | ||
297 | 259 | + pa_assert(pa_atomic_load(&pc->result) == REQUEST_PENDING); | ||
298 | 260 | + pa_log_debug("Starting thread to ask about client %d (%s)", pc->index, | ||
299 | 261 | + pc->appname); | ||
300 | 262 | + u->thread = pa_thread_new("trust-store", thread_func, pc); | ||
301 | 263 | + } | ||
302 | 264 | +} | ||
303 | 265 | + | ||
304 | 266 | +static void check_fdsem(pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t ee, | ||
305 | 267 | + void *userdata) { | ||
306 | 268 | + struct userdata *u = userdata; | ||
307 | 269 | + pa_fdsem_after_poll(u->fdsem); | ||
308 | 270 | + check_queue(u); | ||
309 | 271 | + pa_fdsem_before_poll(u->fdsem); | ||
310 | 272 | +} | ||
311 | 273 | + | ||
312 | 274 | +static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, struct userdata *u) { | ||
313 | 275 | + struct per_client *pc = pa_hashmap_get(u->per_clients, (void*) (size_t) d->client_index); | ||
314 | 276 | + int r; | ||
315 | 277 | + if (!pc) | ||
316 | 278 | + pc = per_client_new(u, d->client_index); | ||
317 | 279 | + | ||
318 | 280 | + r = pa_atomic_load(&pc->result); | ||
319 | 281 | + pa_log_debug("Checking permission to record for client %d (%s) ", d->client_index, | ||
320 | 282 | + r == REQUEST_GRANTED ? "granted" : r != REQUEST_PENDING ? "rejected" : "unknown"); | ||
321 | 283 | + if (r == REQUEST_GRANTED) return PA_HOOK_OK; | ||
322 | 284 | + if (r != REQUEST_PENDING) return PA_HOOK_STOP; | ||
323 | 285 | + | ||
324 | 286 | + pa_dynarray_append(pc->pending_requests, d); | ||
325 | 287 | + check_queue(u); | ||
326 | 288 | + return PA_HOOK_CANCEL; | ||
327 | 289 | +} | ||
328 | 290 | + | ||
329 | 291 | +/* Test code - remove from final product */ | ||
330 | 292 | +static void test(struct userdata *u) { | ||
331 | 293 | + uint32_t dummy; | ||
332 | 294 | + pa_client *client; | ||
333 | 295 | + | ||
334 | 296 | + PA_IDXSET_FOREACH(client, u->core->clients, dummy) { | ||
335 | 297 | + if (client->creds_valid) | ||
336 | 298 | + pa_trust_store_check(u->ts, "The evil app", client->creds.uid, | ||
337 | 299 | + client->creds.pid, "%1% wants to eat your laundry."); | ||
338 | 300 | + } | ||
339 | 301 | +} | ||
340 | 302 | + | ||
341 | 303 | +int pa__init(pa_module *m) { | ||
342 | 304 | + struct userdata *u; | ||
343 | 305 | + pa_trust_store *ts = pa_trust_store_new(); | ||
344 | 306 | + if (ts == NULL) | ||
345 | 307 | + return -1; | ||
346 | 308 | + u = pa_xnew0(struct userdata, 1); | ||
347 | 309 | + u->ts = ts; | ||
348 | 310 | + u->core = m->core; | ||
349 | 311 | + u->per_clients = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, | ||
350 | 312 | + NULL, per_client_free_from_hashmap); | ||
351 | 313 | + m->userdata = u; | ||
352 | 314 | + u->connect_hook_slot = pa_hook_connect(&m->core->access[PA_ACCESS_HOOK_CONNECT_RECORD], | ||
353 | 315 | + PA_HOOK_NORMAL, (pa_hook_cb_t) connect_record_hook, u); | ||
354 | 316 | + | ||
355 | 317 | + pa_assert_se(u->fdsem = pa_fdsem_new()); | ||
356 | 318 | + pa_assert_se(u->io_event = m->core->mainloop->io_new(m->core->mainloop, | ||
357 | 319 | + pa_fdsem_get(u->fdsem), PA_IO_EVENT_INPUT, check_fdsem, u)); | ||
358 | 320 | + pa_fdsem_before_poll(u->fdsem); | ||
359 | 321 | + | ||
360 | 322 | + test(u); | ||
361 | 323 | + return 0; | ||
362 | 324 | +} | ||
363 | 325 | + | ||
364 | 326 | +void pa__done(pa_module *m) { | ||
365 | 327 | + struct userdata *u = m->userdata; | ||
366 | 328 | + if (u) { | ||
367 | 329 | + if (u->connect_hook_slot) | ||
368 | 330 | + pa_hook_slot_free(u->connect_hook_slot); | ||
369 | 331 | + if (u->thread) | ||
370 | 332 | + pa_thread_free(u->thread); | ||
371 | 333 | + if (u->io_event) | ||
372 | 334 | + m->core->mainloop->io_free(u->io_event); | ||
373 | 335 | + if (u->fdsem) | ||
374 | 336 | + pa_fdsem_free(u->fdsem); | ||
375 | 337 | + if (u->per_clients) | ||
376 | 338 | + pa_hashmap_free(u->per_clients); | ||
377 | 339 | + if (u->ts) | ||
378 | 340 | + pa_trust_store_free(u->ts); | ||
379 | 341 | + pa_xfree(u); | ||
380 | 342 | + } | ||
381 | 343 | +} | ||
382 | 344 | Index: pulseaudio/src/modules/trust-store/truststore.cc | ||
383 | 345 | =================================================================== | ||
384 | 346 | --- /dev/null | ||
385 | 347 | +++ pulseaudio/src/modules/trust-store/truststore.cc | ||
386 | 348 | @@ -0,0 +1,74 @@ | ||
387 | 349 | +#ifdef HAVE_CONFIG_H | ||
388 | 350 | +#include <config.h> | ||
389 | 351 | +#endif | ||
390 | 352 | + | ||
391 | 353 | +#include <memory> | ||
392 | 354 | +#include <core/dbus/bus.h> | ||
393 | 355 | +#include <core/trust/dbus_agent.h> | ||
394 | 356 | +#include <core/trust/agent.h> | ||
395 | 357 | + | ||
396 | 358 | +#include <pulse/cdecl.h> | ||
397 | 359 | + | ||
398 | 360 | +PA_C_DECL_BEGIN | ||
399 | 361 | +#include <pulsecore/core-util.h> | ||
400 | 362 | +#include <pulse/xmalloc.h> | ||
401 | 363 | +#include <pulsecore/log.h> | ||
402 | 364 | + | ||
403 | 365 | +#include "truststore.h" | ||
404 | 366 | +PA_C_DECL_END | ||
405 | 367 | + | ||
406 | 368 | +class TrustStore { | ||
407 | 369 | +public: | ||
408 | 370 | + std::shared_ptr<core::trust::Agent> agent; | ||
409 | 371 | +}; | ||
410 | 372 | + | ||
411 | 373 | +pa_trust_store* pa_trust_store_new() { | ||
412 | 374 | + try { | ||
413 | 375 | + auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session); | ||
414 | 376 | + auto agent = core::trust::dbus::create_multi_user_agent_for_bus_connection(bus, "PulseAudio"); | ||
415 | 377 | + auto ts = new TrustStore(); | ||
416 | 378 | + ts->agent = agent; | ||
417 | 379 | + return (pa_trust_store *) ts; | ||
418 | 380 | + } catch(const std::exception &e) { | ||
419 | 381 | + pa_log_error("Could not create Ubuntu touch trust store connection: %s", | ||
420 | 382 | + e.what()); | ||
421 | 383 | + } catch(...) { | ||
422 | 384 | + pa_log_error("Could not create Ubuntu touch trust store connection"); | ||
423 | 385 | + return NULL; | ||
424 | 386 | + } | ||
425 | 387 | +} | ||
426 | 388 | + | ||
427 | 389 | +void pa_trust_store_free(pa_trust_store *t) { | ||
428 | 390 | + pa_assert(t != NULL); | ||
429 | 391 | + auto ts = (TrustStore*) t; | ||
430 | 392 | + delete ts; | ||
431 | 393 | +} | ||
432 | 394 | + | ||
433 | 395 | +bool pa_trust_store_check(pa_trust_store *t, const char *appname, | ||
434 | 396 | + uid_t uid, pid_t pid, const char *description) { | ||
435 | 397 | + auto ts = (TrustStore*) t; | ||
436 | 398 | + try { | ||
437 | 399 | + | ||
438 | 400 | + core::trust::Agent::RequestParameters params { | ||
439 | 401 | + core::trust::Uid{uid}, | ||
440 | 402 | + core::trust::Pid{pid}, | ||
441 | 403 | + appname, | ||
442 | 404 | + core::trust::Feature{0}, | ||
443 | 405 | + description | ||
444 | 406 | + }; | ||
445 | 407 | + pa_log_debug("Asking Ubuntu touch trust store for permission (app: %s)", | ||
446 | 408 | + params.application.id.c_str()); | ||
447 | 409 | + auto answer = ts->agent->authenticate_request_with_parameters(params); | ||
448 | 410 | + if (answer == core::trust::Request::Answer::granted) { | ||
449 | 411 | + pa_log_debug("Request granted."); | ||
450 | 412 | + return true; | ||
451 | 413 | + } | ||
452 | 414 | + pa_log_info("Request denied."); | ||
453 | 415 | + } catch(const std::exception &e) { | ||
454 | 416 | + pa_log_error("Could not ask Ubuntu touch trust store for permission: %s", | ||
455 | 417 | + e.what()); | ||
456 | 418 | + } catch(...) { | ||
457 | 419 | + pa_log_error("Could not ask Ubuntu touch trust store for permission"); | ||
458 | 420 | + } | ||
459 | 421 | + return false; | ||
460 | 422 | +} | ||
461 | 423 | Index: pulseaudio/src/modules/trust-store/truststore.h | ||
462 | 424 | =================================================================== | ||
463 | 425 | --- /dev/null | ||
464 | 426 | +++ pulseaudio/src/modules/trust-store/truststore.h | ||
465 | 427 | @@ -0,0 +1,41 @@ | ||
466 | 428 | +/*** | ||
467 | 429 | + This file is part of PulseAudio. | ||
468 | 430 | + | ||
469 | 431 | + Copyright 2015 Canonical Ltd. | ||
470 | 432 | + Written by David Henningsson <david.henningsson@canonical.com> | ||
471 | 433 | + | ||
472 | 434 | + PulseAudio is free software; you can redistribute it and/or modify | ||
473 | 435 | + it under the terms of the GNU Lesser General Public License as published | ||
474 | 436 | + by the Free Software Foundation; either version 2.1 of the License, | ||
475 | 437 | + or (at your option) any later version. | ||
476 | 438 | + | ||
477 | 439 | + PulseAudio is distributed in the hope that it will be useful, but | ||
478 | 440 | + WITHOUT ANY WARRANTY; without even the implied warranty of | ||
479 | 441 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
480 | 442 | + General Public License for more details. | ||
481 | 443 | + | ||
482 | 444 | + You should have received a copy of the GNU Lesser General Public License | ||
483 | 445 | + along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. | ||
484 | 446 | +***/ | ||
485 | 447 | + | ||
486 | 448 | +#ifndef footruststorehfoo | ||
487 | 449 | +#define footruststorehfoo | ||
488 | 450 | + | ||
489 | 451 | +#ifdef HAVE_CONFIG_H | ||
490 | 452 | +#include <config.h> | ||
491 | 453 | +#endif | ||
492 | 454 | + | ||
493 | 455 | +#include <pulsecore/creds.h> | ||
494 | 456 | + | ||
495 | 457 | +#ifdef HAVE_TRUST_STORE | ||
496 | 458 | +PA_C_DECL_BEGIN | ||
497 | 459 | +typedef struct pa_trust_store pa_trust_store; | ||
498 | 460 | + | ||
499 | 461 | +pa_trust_store* pa_trust_store_new(); | ||
500 | 462 | +void pa_trust_store_free(pa_trust_store *ts); | ||
501 | 463 | +bool pa_trust_store_check(pa_trust_store *ts, const char *appname, | ||
502 | 464 | + uid_t uid, pid_t pid, const char *description); | ||
503 | 465 | +PA_C_DECL_END | ||
504 | 466 | +#endif | ||
505 | 467 | + | ||
506 | 468 | +#endif | ||
507 | 469 | Index: pulseaudio/src/pulsecore/client.h | ||
508 | 470 | =================================================================== | ||
509 | 471 | --- pulseaudio.orig/src/pulsecore/client.h | ||
510 | 472 | +++ pulseaudio/src/pulsecore/client.h | ||
511 | 473 | @@ -26,6 +26,7 @@ | ||
512 | 474 | #include <pulse/proplist.h> | ||
513 | 475 | #include <pulsecore/core.h> | ||
514 | 476 | #include <pulsecore/module.h> | ||
515 | 477 | +#include <pulsecore/creds.h> | ||
516 | 478 | |||
517 | 479 | /* Every connection to the server should have a pa_client | ||
518 | 480 | * attached. That way the user may generate a listing of all connected | ||
519 | 481 | @@ -35,6 +36,9 @@ struct pa_client { | ||
520 | 482 | uint32_t index; | ||
521 | 483 | pa_core *core; | ||
522 | 484 | |||
523 | 485 | + pa_creds creds; | ||
524 | 486 | + bool creds_valid; | ||
525 | 487 | + | ||
526 | 488 | pa_proplist *proplist; | ||
527 | 489 | pa_module *module; | ||
528 | 490 | char *driver; | ||
529 | 491 | Index: pulseaudio/src/pulsecore/creds.h | ||
530 | 492 | =================================================================== | ||
531 | 493 | --- pulseaudio.orig/src/pulsecore/creds.h | ||
532 | 494 | +++ pulseaudio/src/pulsecore/creds.h | ||
533 | 495 | @@ -41,6 +41,7 @@ typedef struct pa_cmsg_ancil_data pa_cms | ||
534 | 496 | struct pa_creds { | ||
535 | 497 | gid_t gid; | ||
536 | 498 | uid_t uid; | ||
537 | 499 | + pid_t pid; | ||
538 | 500 | }; | ||
539 | 501 | |||
540 | 502 | /* Struct for handling ancillary data, i e, extra data that can be sent together with a message | ||
541 | 503 | Index: pulseaudio/src/pulsecore/iochannel.c | ||
542 | 504 | =================================================================== | ||
543 | 505 | --- pulseaudio.orig/src/pulsecore/iochannel.c | ||
544 | 506 | +++ pulseaudio/src/pulsecore/iochannel.c | ||
545 | 507 | @@ -323,6 +323,7 @@ ssize_t pa_iochannel_write_with_creds(pa | ||
546 | 508 | |||
547 | 509 | u = (struct ucred*) CMSG_DATA(&cmsg.hdr); | ||
548 | 510 | |||
549 | 511 | + /* FIXME: Check whether ucred->pid should be used */ | ||
550 | 512 | u->pid = getpid(); | ||
551 | 513 | if (ucred) { | ||
552 | 514 | u->uid = ucred->uid; | ||
553 | 515 | @@ -445,6 +446,7 @@ ssize_t pa_iochannel_read_with_ancil_dat | ||
554 | 516 | |||
555 | 517 | ancil_data->creds.gid = u.gid; | ||
556 | 518 | ancil_data->creds.uid = u.uid; | ||
557 | 519 | + ancil_data->creds.pid = u.pid; | ||
558 | 520 | ancil_data->creds_valid = true; | ||
559 | 521 | } | ||
560 | 522 | else if (cmh->cmsg_type == SCM_RIGHTS) { | ||
561 | 523 | Index: pulseaudio/src/pulsecore/protocol-native.c | ||
562 | 524 | =================================================================== | ||
563 | 525 | --- pulseaudio.orig/src/pulsecore/protocol-native.c | ||
564 | 526 | +++ pulseaudio/src/pulsecore/protocol-native.c | ||
565 | 527 | @@ -2668,6 +2668,13 @@ static void command_auth(pa_pdispatch *p | ||
566 | 528 | do_shm = false; | ||
567 | 529 | |||
568 | 530 | #ifdef HAVE_CREDS | ||
569 | 531 | + { | ||
570 | 532 | + const pa_creds *creds; | ||
571 | 533 | + if ((creds = pa_pdispatch_creds(pd))) { | ||
572 | 534 | + c->client->creds = *creds; | ||
573 | 535 | + c->client->creds_valid = true; | ||
574 | 536 | + } | ||
575 | 537 | + } | ||
576 | 538 | if (do_shm) { | ||
577 | 539 | /* Only enable SHM if both sides are owned by the same | ||
578 | 540 | * user. This is a security measure because otherwise data | ||
579 | 541 | @@ -5631,6 +5638,7 @@ typedef struct pa_protocol_native_access | ||
580 | 542 | } pa_protocol_native_access_data; | ||
581 | 543 | |||
582 | 544 | static void check_access_finish_cb(pa_access_data *data, bool res) { | ||
583 | 545 | + uint32_t command, tag; | ||
584 | 546 | pa_protocol_native_access_data *d = (pa_protocol_native_access_data *) data; | ||
585 | 547 | pa_native_connection *c = PA_NATIVE_CONNECTION(d->userdata); | ||
586 | 548 | |||
587 | 549 | @@ -5639,6 +5647,11 @@ static void check_access_finish_cb(pa_ac | ||
588 | 550 | goto finish; | ||
589 | 551 | } | ||
590 | 552 | |||
591 | 553 | + pa_assert_se(pa_tagstruct_getu32(d->tc, &command) >= 0); | ||
592 | 554 | + pa_assert_se(pa_tagstruct_getu32(d->tc, &tag) >= 0); | ||
593 | 555 | + pa_assert(command == d->command); | ||
594 | 556 | + pa_assert(tag == d->tag); | ||
595 | 557 | + | ||
596 | 558 | /* call the dispatcher again, hopefully this time, the access check will | ||
597 | 559 | * fail or succeed immediately */ | ||
598 | 560 | command_table[d->command](d->pd, d->command, d->tag, d->tc, d->userdata); | ||
599 | 561 | Index: pulseaudio/po/POTFILES.in | ||
600 | 562 | =================================================================== | ||
601 | 563 | --- pulseaudio.orig/po/POTFILES.in | ||
602 | 564 | +++ pulseaudio/po/POTFILES.in | ||
603 | 565 | @@ -23,6 +23,7 @@ src/modules/jack/module-jack-sink.c | ||
604 | 566 | src/modules/jack/module-jack-source.c | ||
605 | 567 | src/modules/macosx/module-coreaudio-device.c | ||
606 | 568 | src/modules/module-allow-passthrough.c | ||
607 | 569 | +src/modules/trust-store/module-trust-store.c | ||
608 | 570 | src/modules/module-always-sink.c | ||
609 | 571 | src/modules/module-always-source.c | ||
610 | 572 | src/modules/module-cli.c | ||
611 | diff --git a/debian/patches/0409-pa-client-peer-credentials.patch b/debian/patches/0409-pa-client-peer-credentials.patch | |||
612 | 573 | new file mode 100644 | 0 | new file mode 100644 |
613 | index 0000000..d6d7ff6 | |||
614 | --- /dev/null | |||
615 | +++ b/debian/patches/0409-pa-client-peer-credentials.patch | |||
616 | @@ -0,0 +1,104 @@ | |||
617 | 1 | From: David Henningsson <david.henningsson@canonical.com> | ||
618 | 2 | Date: Wed, 22 Jul 2015 16:37:19 +0200 | ||
619 | 3 | Subject: [PATCH 4/5] Expose peer credentials on pa_client | ||
620 | 4 | |||
621 | 5 | Signed-off-by: David Henningsson <david.henningsson@canonical.com> | ||
622 | 6 | --- | ||
623 | 7 | src/pulsecore/client.h | 4 ++++ | ||
624 | 8 | src/pulsecore/creds.h | 1 + | ||
625 | 9 | src/pulsecore/iochannel.c | 2 ++ | ||
626 | 10 | src/pulsecore/protocol-native.c | 13 +++++++++++++ | ||
627 | 11 | 4 files changed, 20 insertions(+) | ||
628 | 12 | |||
629 | 13 | diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h | ||
630 | 14 | index eb8173d..a038a0c 100644 | ||
631 | 15 | --- a/src/pulsecore/client.h | ||
632 | 16 | +++ b/src/pulsecore/client.h | ||
633 | 17 | @@ -26,6 +26,7 @@ | ||
634 | 18 | #include <pulse/proplist.h> | ||
635 | 19 | #include <pulsecore/core.h> | ||
636 | 20 | #include <pulsecore/module.h> | ||
637 | 21 | +#include <pulsecore/creds.h> | ||
638 | 22 | |||
639 | 23 | /* Every connection to the server should have a pa_client | ||
640 | 24 | * attached. That way the user may generate a listing of all connected | ||
641 | 25 | @@ -35,6 +36,9 @@ struct pa_client { | ||
642 | 26 | uint32_t index; | ||
643 | 27 | pa_core *core; | ||
644 | 28 | |||
645 | 29 | + pa_creds creds; | ||
646 | 30 | + bool creds_valid; | ||
647 | 31 | + | ||
648 | 32 | pa_proplist *proplist; | ||
649 | 33 | pa_module *module; | ||
650 | 34 | char *driver; | ||
651 | 35 | diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h | ||
652 | 36 | index 9fdbb4f..8bcf636 100644 | ||
653 | 37 | --- a/src/pulsecore/creds.h | ||
654 | 38 | +++ b/src/pulsecore/creds.h | ||
655 | 39 | @@ -41,6 +41,7 @@ typedef struct pa_cmsg_ancil_data pa_cmsg_ancil_data; | ||
656 | 40 | struct pa_creds { | ||
657 | 41 | gid_t gid; | ||
658 | 42 | uid_t uid; | ||
659 | 43 | + pid_t pid; | ||
660 | 44 | }; | ||
661 | 45 | |||
662 | 46 | /* Struct for handling ancillary data, i e, extra data that can be sent together with a message | ||
663 | 47 | diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c | ||
664 | 48 | index e25824b..3c83092 100644 | ||
665 | 49 | --- a/src/pulsecore/iochannel.c | ||
666 | 50 | +++ b/src/pulsecore/iochannel.c | ||
667 | 51 | @@ -323,6 +323,7 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l | ||
668 | 52 | |||
669 | 53 | u = (struct ucred*) CMSG_DATA(&cmsg.hdr); | ||
670 | 54 | |||
671 | 55 | + /* FIXME: Check whether ucred->pid should be used */ | ||
672 | 56 | u->pid = getpid(); | ||
673 | 57 | if (ucred) { | ||
674 | 58 | u->uid = ucred->uid; | ||
675 | 59 | @@ -445,6 +446,7 @@ ssize_t pa_iochannel_read_with_ancil_data(pa_iochannel*io, void*data, size_t l, | ||
676 | 60 | |||
677 | 61 | ancil_data->creds.gid = u.gid; | ||
678 | 62 | ancil_data->creds.uid = u.uid; | ||
679 | 63 | + ancil_data->creds.pid = u.pid; | ||
680 | 64 | ancil_data->creds_valid = true; | ||
681 | 65 | } | ||
682 | 66 | else if (cmh->cmsg_type == SCM_RIGHTS) { | ||
683 | 67 | diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c | ||
684 | 68 | index f7dc338..baaa952 100644 | ||
685 | 69 | --- a/src/pulsecore/protocol-native.c | ||
686 | 70 | +++ b/src/pulsecore/protocol-native.c | ||
687 | 71 | @@ -2668,6 +2668,13 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta | ||
688 | 72 | do_shm = false; | ||
689 | 73 | |||
690 | 74 | #ifdef HAVE_CREDS | ||
691 | 75 | + { | ||
692 | 76 | + const pa_creds *creds; | ||
693 | 77 | + if ((creds = pa_pdispatch_creds(pd))) { | ||
694 | 78 | + c->client->creds = *creds; | ||
695 | 79 | + c->client->creds_valid = true; | ||
696 | 80 | + } | ||
697 | 81 | + } | ||
698 | 82 | if (do_shm) { | ||
699 | 83 | /* Only enable SHM if both sides are owned by the same | ||
700 | 84 | * user. This is a security measure because otherwise data | ||
701 | 85 | @@ -5631,6 +5638,7 @@ typedef struct pa_protocol_native_access_data { | ||
702 | 86 | } pa_protocol_native_access_data; | ||
703 | 87 | |||
704 | 88 | static void check_access_finish_cb(pa_access_data *data, bool res) { | ||
705 | 89 | + uint32_t command, tag; | ||
706 | 90 | pa_protocol_native_access_data *d = (pa_protocol_native_access_data *) data; | ||
707 | 91 | pa_native_connection *c = PA_NATIVE_CONNECTION(d->userdata); | ||
708 | 92 | |||
709 | 93 | @@ -5639,6 +5647,11 @@ static void check_access_finish_cb(pa_access_data *data, bool res) { | ||
710 | 94 | goto finish; | ||
711 | 95 | } | ||
712 | 96 | |||
713 | 97 | + pa_assert_se(pa_tagstruct_getu32(d->tc, &command) >= 0); | ||
714 | 98 | + pa_assert_se(pa_tagstruct_getu32(d->tc, &tag) >= 0); | ||
715 | 99 | + pa_assert(command == d->command); | ||
716 | 100 | + pa_assert(tag == d->tag); | ||
717 | 101 | + | ||
718 | 102 | /* call the dispatcher again, hopefully this time, the access check will | ||
719 | 103 | * fail or succeed immediately */ | ||
720 | 104 | command_table[d->command](d->pd, d->command, d->tag, d->tc, d->userdata); | ||
721 | diff --git a/debian/patches/0410-Add-thread-to-activate-trust-store-interface.patch b/debian/patches/0410-Add-thread-to-activate-trust-store-interface.patch | |||
722 | 0 | deleted file mode 100644 | 105 | deleted file mode 100644 |
723 | index 721ce11..0000000 | |||
724 | --- a/debian/patches/0410-Add-thread-to-activate-trust-store-interface.patch | |||
725 | +++ /dev/null | |||
726 | @@ -1,108 +0,0 @@ | |||
727 | 1 | From 90dbf1d25e12b9cfc86aecbd02f14a05fd5dca8c Mon Sep 17 00:00:00 2001 | ||
728 | 2 | From: Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com> | ||
729 | 3 | Date: Fri, 7 Aug 2015 09:08:02 +0200 | ||
730 | 4 | Subject: [PATCH] Add thread to activate trust-store interface | ||
731 | 5 | |||
732 | 6 | --- | ||
733 | 7 | src/modules/trust-store/module-trust-store.c | 14 +------------- | ||
734 | 8 | src/modules/trust-store/truststore.cc | 19 +++++++++++++++++++ | ||
735 | 9 | 2 files changed, 20 insertions(+), 13 deletions(-) | ||
736 | 10 | |||
737 | 11 | Index: pulseaudio/src/modules/trust-store/module-trust-store.c | ||
738 | 12 | =================================================================== | ||
739 | 13 | --- pulseaudio.orig/src/modules/trust-store/module-trust-store.c | ||
740 | 14 | +++ pulseaudio/src/modules/trust-store/module-trust-store.c | ||
741 | 15 | @@ -28,6 +28,7 @@ | ||
742 | 16 | #include <pulsecore/fdsem.h> | ||
743 | 17 | #include <pulsecore/thread.h> | ||
744 | 18 | #include <pulsecore/core-util.h> | ||
745 | 19 | +#include <pulsecore/dynarray.h> | ||
746 | 20 | #include <pulse/mainloop-api.h> | ||
747 | 21 | |||
748 | 22 | PA_MODULE_AUTHOR("David Henningsson"); | ||
749 | 23 | @@ -171,18 +172,6 @@ static pa_hook_result_t connect_record_h | ||
750 | 24 | return PA_HOOK_CANCEL; | ||
751 | 25 | } | ||
752 | 26 | |||
753 | 27 | -/* Test code - remove from final product */ | ||
754 | 28 | -static void test(struct userdata *u) { | ||
755 | 29 | - uint32_t dummy; | ||
756 | 30 | - pa_client *client; | ||
757 | 31 | - | ||
758 | 32 | - PA_IDXSET_FOREACH(client, u->core->clients, dummy) { | ||
759 | 33 | - if (client->creds_valid) | ||
760 | 34 | - pa_trust_store_check(u->ts, "The evil app", client->creds.uid, | ||
761 | 35 | - client->creds.pid, "%1% wants to eat your laundry."); | ||
762 | 36 | - } | ||
763 | 37 | -} | ||
764 | 38 | - | ||
765 | 39 | int pa__init(pa_module *m) { | ||
766 | 40 | struct userdata *u; | ||
767 | 41 | pa_trust_store *ts = pa_trust_store_new(); | ||
768 | 42 | @@ -202,7 +191,6 @@ int pa__init(pa_module *m) { | ||
769 | 43 | pa_fdsem_get(u->fdsem), PA_IO_EVENT_INPUT, check_fdsem, u)); | ||
770 | 44 | pa_fdsem_before_poll(u->fdsem); | ||
771 | 45 | |||
772 | 46 | - test(u); | ||
773 | 47 | return 0; | ||
774 | 48 | } | ||
775 | 49 | |||
776 | 50 | Index: pulseaudio/src/modules/trust-store/truststore.cc | ||
777 | 51 | =================================================================== | ||
778 | 52 | --- pulseaudio.orig/src/modules/trust-store/truststore.cc | ||
779 | 53 | +++ pulseaudio/src/modules/trust-store/truststore.cc | ||
780 | 54 | @@ -4,6 +4,7 @@ | ||
781 | 55 | |||
782 | 56 | #include <memory> | ||
783 | 57 | #include <core/dbus/bus.h> | ||
784 | 58 | +#include <core/dbus/asio/executor.h> | ||
785 | 59 | #include <core/trust/dbus_agent.h> | ||
786 | 60 | #include <core/trust/agent.h> | ||
787 | 61 | |||
788 | 62 | @@ -13,6 +14,7 @@ PA_C_DECL_BEGIN | ||
789 | 63 | #include <pulsecore/core-util.h> | ||
790 | 64 | #include <pulse/xmalloc.h> | ||
791 | 65 | #include <pulsecore/log.h> | ||
792 | 66 | +#include <pulsecore/thread.h> | ||
793 | 67 | |||
794 | 68 | #include "truststore.h" | ||
795 | 69 | PA_C_DECL_END | ||
796 | 70 | @@ -20,14 +22,27 @@ PA_C_DECL_END | ||
797 | 71 | class TrustStore { | ||
798 | 72 | public: | ||
799 | 73 | std::shared_ptr<core::trust::Agent> agent; | ||
800 | 74 | + std::shared_ptr<core::dbus::Bus> bus; | ||
801 | 75 | + pa_thread *thread; | ||
802 | 76 | }; | ||
803 | 77 | |||
804 | 78 | +static void thread_func(void *data) { | ||
805 | 79 | + class TrustStore *ts = (class TrustStore *) data; | ||
806 | 80 | + | ||
807 | 81 | + ts->bus->run(); | ||
808 | 82 | +} | ||
809 | 83 | + | ||
810 | 84 | pa_trust_store* pa_trust_store_new() { | ||
811 | 85 | try { | ||
812 | 86 | auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session); | ||
813 | 87 | + bus->install_executor(core::dbus::asio::make_executor(bus)); | ||
814 | 88 | + | ||
815 | 89 | auto agent = core::trust::dbus::create_multi_user_agent_for_bus_connection(bus, "PulseAudio"); | ||
816 | 90 | auto ts = new TrustStore(); | ||
817 | 91 | ts->agent = agent; | ||
818 | 92 | + ts->bus = bus; | ||
819 | 93 | + ts->thread = pa_thread_new("trust-store-bus", thread_func, ts); | ||
820 | 94 | + | ||
821 | 95 | return (pa_trust_store *) ts; | ||
822 | 96 | } catch(const std::exception &e) { | ||
823 | 97 | pa_log_error("Could not create Ubuntu touch trust store connection: %s", | ||
824 | 98 | @@ -41,6 +56,10 @@ pa_trust_store* pa_trust_store_new() { | ||
825 | 99 | void pa_trust_store_free(pa_trust_store *t) { | ||
826 | 100 | pa_assert(t != NULL); | ||
827 | 101 | auto ts = (TrustStore*) t; | ||
828 | 102 | + if (ts->thread) { | ||
829 | 103 | + ts->bus->stop(); | ||
830 | 104 | + pa_thread_free(ts->thread); | ||
831 | 105 | + } | ||
832 | 106 | delete ts; | ||
833 | 107 | } | ||
834 | 108 | |||
835 | diff --git a/debian/patches/0417-increase-timeout-check-apparmor.patch b/debian/patches/0417-increase-timeout-check-apparmor.patch | |||
836 | 109 | deleted file mode 100644 | 0 | deleted file mode 100644 |
837 | index 2c746f7..0000000 | |||
838 | --- a/debian/patches/0417-increase-timeout-check-apparmor.patch | |||
839 | +++ /dev/null | |||
840 | @@ -1,102 +0,0 @@ | |||
841 | 1 | Index: pulseaudio/src/modules/trust-store/module-trust-store.c | ||
842 | 2 | =================================================================== | ||
843 | 3 | --- pulseaudio.orig/src/modules/trust-store/module-trust-store.c | ||
844 | 4 | +++ pulseaudio/src/modules/trust-store/module-trust-store.c | ||
845 | 5 | @@ -31,6 +31,8 @@ | ||
846 | 6 | #include <pulsecore/dynarray.h> | ||
847 | 7 | #include <pulse/mainloop-api.h> | ||
848 | 8 | |||
849 | 9 | +#include <sys/apparmor.h> | ||
850 | 10 | + | ||
851 | 11 | PA_MODULE_AUTHOR("David Henningsson"); | ||
852 | 12 | PA_MODULE_DESCRIPTION("Ubuntu touch trust store integration"); | ||
853 | 13 | PA_MODULE_VERSION(PACKAGE_VERSION); | ||
854 | 14 | @@ -75,9 +77,37 @@ static struct per_client *per_client_new | ||
855 | 15 | } | ||
856 | 16 | |||
857 | 17 | pc = pa_xnew0(struct per_client, 1); | ||
858 | 18 | - // TODO: Do we need something else than the application name here - | ||
859 | 19 | - // the application can probably spoof it | ||
860 | 20 | - pc->appname = pa_xstrdup(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)); | ||
861 | 21 | + | ||
862 | 22 | + pa_log_info("Client application name is: '%s'", pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)); | ||
863 | 23 | + | ||
864 | 24 | + // ask apparmor about the context of the client, later this will be used to decide if the | ||
865 | 25 | + // app should be or not using the trust store | ||
866 | 26 | + | ||
867 | 27 | + if (aa_is_enabled()) { | ||
868 | 28 | + char *context = NULL; | ||
869 | 29 | + char *mode = NULL; | ||
870 | 30 | + | ||
871 | 31 | + /* XXX: The mode string is *NOT* be freed since it forms | ||
872 | 32 | + * part of the allocation returned in context. | ||
873 | 33 | + * | ||
874 | 34 | + * See aa_gettaskcon(2) for details. | ||
875 | 35 | + */ | ||
876 | 36 | + if (aa_gettaskcon (client->creds.pid, &context, &mode) >= 0) { | ||
877 | 37 | + pc->appname = pa_xstrdup(context); | ||
878 | 38 | + pa_log_info("Client apparmor profile is: '%s'", context); | ||
879 | 39 | + } else { | ||
880 | 40 | + pa_log_error("AppArmo profile could not be retrieved."); | ||
881 | 41 | + } | ||
882 | 42 | + | ||
883 | 43 | + if (context) | ||
884 | 44 | + free(context); | ||
885 | 45 | + | ||
886 | 46 | + } else { | ||
887 | 47 | + // while we do leave the appname as empty if we fail, if apparmor is not present we should | ||
888 | 48 | + // assume that the app is not confined | ||
889 | 49 | + pc->appname = pa_xstrdup("unconfined"); | ||
890 | 50 | + } | ||
891 | 51 | + | ||
892 | 52 | pc->index = client_index; | ||
893 | 53 | pc->uid = client->creds.uid; | ||
894 | 54 | pc->pid = client->creds.pid; | ||
895 | 55 | @@ -101,13 +131,28 @@ static void per_client_free_from_hashmap | ||
896 | 56 | static void thread_func(void *data) { | ||
897 | 57 | struct per_client *pc = data; | ||
898 | 58 | |||
899 | 59 | - bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid, | ||
900 | 60 | - /// TRANSLATORS: The app icon and name appears above this string. If the phrase | ||
901 | 61 | - /// can't be translated in this language, translate the whole sentence | ||
902 | 62 | - /// 'This app wants to record audio.' | ||
903 | 63 | - _("wants to record audio.")); | ||
904 | 64 | + // there are 3 possible values for the app name that we will consider at this point | ||
905 | 65 | + // * empty string: there was an error when retrieving the value and therefore we will | ||
906 | 66 | + // automatically deny access | ||
907 | 67 | + // * unconfined: the app is unconfined and therefore we will automatically grant access | ||
908 | 68 | + // * appname: we need the user to decide what to do. | ||
909 | 69 | + | ||
910 | 70 | + if (pc->appname == NULL) { | ||
911 | 71 | + pa_log_info("Client apparmor could not retrieved."); | ||
912 | 72 | + pa_atomic_store(&pc->result, REQUEST_DENIED); | ||
913 | 73 | + } else if (pa_streq(pc->appname, "unconfined")) { | ||
914 | 74 | + pa_log_info("Connected client is unconfined."); | ||
915 | 75 | + pa_atomic_store(&pc->result, REQUEST_GRANTED); | ||
916 | 76 | + } else { | ||
917 | 77 | + pa_log_info("User needs to authorize the application.."); | ||
918 | 78 | + bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid, | ||
919 | 79 | + /// TRANSLATORS: The app icon and name appears above this string. If the phrase | ||
920 | 80 | + /// can't be translated in this language, translate the whole sentence | ||
921 | 81 | + /// 'This app wants to record audio.' | ||
922 | 82 | + _("wants to record audio.")); | ||
923 | 83 | + pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED); | ||
924 | 84 | + } | ||
925 | 85 | |||
926 | 86 | - pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED); | ||
927 | 87 | pa_fdsem_post(pc->userdata->fdsem); | ||
928 | 88 | } | ||
929 | 89 | |||
930 | 90 | Index: pulseaudio/src/Makefile.am | ||
931 | 91 | =================================================================== | ||
932 | 92 | --- pulseaudio.orig/src/Makefile.am | ||
933 | 93 | +++ pulseaudio/src/Makefile.am | ||
934 | 94 | @@ -2043,7 +2043,7 @@ libtruststore_util_la_LIBADD = libpulsec | ||
935 | 95 | libtruststore_util_la_LDFLAGS = -avoid-version | ||
936 | 96 | |||
937 | 97 | module_trust_store_la_SOURCES = modules/trust-store/module-trust-store.c | ||
938 | 98 | -module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS) | ||
939 | 99 | +module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS) -lapparmor | ||
940 | 100 | module_trust_store_la_LIBADD = $(MODULE_LIBADD) libtruststore-util.la | ||
941 | 101 | module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1 | ||
942 | 102 | endif | ||
943 | diff --git a/debian/patches/0700-modules-add-snappy-policy-module.patch b/debian/patches/0700-modules-add-snappy-policy-module.patch | |||
944 | index 2425ec7..6ac2da7 100644 | |||
945 | --- a/debian/patches/0700-modules-add-snappy-policy-module.patch | |||
946 | +++ b/debian/patches/0700-modules-add-snappy-policy-module.patch | |||
947 | @@ -1,56 +1,101 @@ | |||
952 | 1 | From a430ebc2271f5a07389ee25631a8ba5524371764 Mon Sep 17 00:00:00 2001 | 1 | From: James Henstridge <james.henstridge@canonical.com> |
953 | 2 | From: Simon Fels <simon.fels@canonical.com> | 2 | Date: Tue, 7 Aug 2018 12:40:59 +0800 |
954 | 3 | Date: Tue, 17 May 2016 17:29:31 +0200 | 3 | Subject: [PATCH] modules: add snap policy module |
951 | 4 | Subject: [PATCH] modules: add snappy policy module | ||
955 | 5 | 4 | ||
956 | 5 | Co-authored-by: Simon Fels <simon.fels@canonical.com> | ||
957 | 6 | --- | 6 | --- |
963 | 7 | configure.ac | 18 +++++++- | 7 | configure.ac | 17 ++ |
964 | 8 | src/Makefile.am | 18 ++++++++ | 8 | src/Makefile.am | 13 ++ |
965 | 9 | src/modules/module-snappy-policy.c | 94 ++++++++++++++++++++++++++++++++++++++ | 9 | src/modules/module-snap-policy.c | 347 +++++++++++++++++++++++++++++++++++++++ |
966 | 10 | 3 files changed, 129 insertions(+), 1 deletion(-) | 10 | 3 files changed, 377 insertions(+) |
967 | 11 | create mode 100644 src/modules/module-snappy-policy.c | 11 | create mode 100644 src/modules/module-snap-policy.c |
968 | 12 | 12 | ||
974 | 13 | Index: pulseaudio/src/Makefile.am | 13 | diff --git a/configure.ac b/configure.ac |
975 | 14 | =================================================================== | 14 | index c9c414f..97c2d9d 100644 |
976 | 15 | --- pulseaudio.orig/src/Makefile.am | 15 | --- a/configure.ac |
977 | 16 | +++ pulseaudio/src/Makefile.am | 16 | +++ b/configure.ac |
978 | 17 | @@ -1250,6 +1250,11 @@ modlibexec_LTLIBRARIES += \ | 17 | @@ -1446,6 +1446,21 @@ AS_IF([test "x$os_is_win32" != "x1"], |
979 | 18 | AS_IF([test "x$ax_pthread_ok" = "xyes"], | ||
980 | 19 | AC_DEFINE([_POSIX_PTHREAD_SEMANTICS], 1, [Needed on Solaris])) | ||
981 | 20 | |||
982 | 21 | +# Snappy support | ||
983 | 22 | + | ||
984 | 23 | +AC_ARG_ENABLE([snap], | ||
985 | 24 | + AS_HELP_STRING([--enable-snap], [Enable snap support])) | ||
986 | 25 | + | ||
987 | 26 | +have_apparmor=0 | ||
988 | 27 | +have_snapd_glib=0 | ||
989 | 28 | +AS_IF([test "x$enable_snap" != "xno"], | ||
990 | 29 | + [PKG_CHECK_MODULES(APPARMOR, [libapparmor], [have_apparmor=1]) | ||
991 | 30 | + PKG_CHECK_MODULES(SNAPD_GLIB, [snapd-glib], [have_snapd_glib=1])]) | ||
992 | 31 | + | ||
993 | 32 | +AS_IF([test "x$enable_snap" = "xyes" && test "x$have_apparmor" = "x0" -o "x$have-snapd_glib" = "x0"], | ||
994 | 33 | + [AC_MSG_ERROR([*** Snap module dependencies missing])]) | ||
995 | 34 | + | ||
996 | 35 | +AM_CONDITIONAL([BUILD_SNAP], [test "x$enable_snap" = "xyes"]) | ||
997 | 36 | |||
998 | 37 | |||
999 | 38 | ################################### | ||
1000 | 39 | @@ -1627,6 +1642,7 @@ AS_IF([test "x$HAVE_ESOUND" = "x1" -a "x$USE_PER_USER_ESOUND_SOCKET" = "x1"], EN | ||
1001 | 40 | AS_IF([test "x$HAVE_GCOV" = "x1"], ENABLE_GCOV=yes, ENABLE_GCOV=no) | ||
1002 | 41 | AS_IF([test "x$HAVE_LIBCHECK" = "x1"], ENABLE_TESTS=yes, ENABLE_TESTS=no) | ||
1003 | 42 | AS_IF([test "x$enable_legacy_database_entry_format" != "xno"], ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=yes, ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=no) | ||
1004 | 43 | +AS_IF([test "x$enable_snap" != "xno"], ENABLE_SNAP=yes, ENABLE_SNAP=no) | ||
1005 | 44 | |||
1006 | 45 | echo " | ||
1007 | 46 | ---{ $PACKAGE_NAME $VERSION }--- | ||
1008 | 47 | @@ -1683,6 +1699,7 @@ echo " | ||
1009 | 48 | Enable speex (resampler, AEC): ${ENABLE_SPEEX} | ||
1010 | 49 | Enable soxr (resampler): ${ENABLE_SOXR} | ||
1011 | 50 | Enable WebRTC echo canceller: ${ENABLE_WEBRTC} | ||
1012 | 51 | + Enable Snap support: ${ENABLE_SNAP} | ||
1013 | 52 | Enable gcov coverage: ${ENABLE_GCOV} | ||
1014 | 53 | Enable unit tests: ${ENABLE_TESTS} | ||
1015 | 54 | Database | ||
1016 | 55 | diff --git a/src/Makefile.am b/src/Makefile.am | ||
1017 | 56 | index d623d0a..16b4d5d 100644 | ||
1018 | 57 | --- a/src/Makefile.am | ||
1019 | 58 | +++ b/src/Makefile.am | ||
1020 | 59 | @@ -1240,6 +1240,11 @@ modlibexec_LTLIBRARIES += \ | ||
1021 | 18 | module-esound-sink.la | 60 | module-esound-sink.la |
1022 | 19 | endif | 61 | endif |
1023 | 20 | 62 | ||
1025 | 21 | +if HAVE_APPARMOR | 63 | +if BUILD_SNAP |
1026 | 22 | +modlibexec_LTLIBRARIES += \ | 64 | +modlibexec_LTLIBRARIES += \ |
1028 | 23 | + module-snappy-policy.la | 65 | + module-snap-policy.la |
1029 | 24 | +endif | 66 | +endif |
1030 | 25 | + | 67 | + |
1031 | 26 | # See comment at librtp.la above | 68 | # See comment at librtp.la above |
1032 | 27 | if !OS_IS_WIN32 | 69 | if !OS_IS_WIN32 |
1033 | 28 | modlibexec_LTLIBRARIES += \ | 70 | modlibexec_LTLIBRARIES += \ |
1036 | 29 | @@ -2048,6 +2053,14 @@ module_trust_store_la_LIBADD = $(MODULE_ | 71 | @@ -2024,6 +2029,14 @@ module_echo_cancel_la_CFLAGS += -DHAVE_WEBRTC=1 |
1037 | 30 | module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1 | 72 | module_echo_cancel_la_LIBADD += libwebrtc-util.la |
1038 | 31 | endif | 73 | endif |
1039 | 32 | 74 | ||
1040 | 33 | +# Snappy | 75 | +# Snappy |
1046 | 34 | +if HAVE_APPARMOR | 76 | +if BUILD_SNAP |
1047 | 35 | +module_snappy_policy_la_SOURCES = modules/module-snappy-policy.c | 77 | +module_snap_policy_la_SOURCES = modules/module-snap-policy.c |
1048 | 36 | +module_snappy_policy_la_LDFLAGS = $(MODULE_LDFLAGS) -lapparmor | 78 | +module_snap_policy_la_LDFLAGS = $(MODULE_LDFLAGS) |
1049 | 37 | +module_snappy_policy_la_LIBADD = $(MODULE_LIBADD) | 79 | +module_snap_policy_la_LIBADD = $(MODULE_LIBADD) $(APPARMOR_LIBS) $(SNAPD_GLIB_LIBS) |
1050 | 38 | +module_snappy_policy_la_CFLAGS = $(AM_CFLAGS) -DHAVE_SNAPPY=1 | 80 | +module_snap_policy_la_CFLAGS = $(AM_CFLAGS) $(APPARMOR_CFLAGS) $(SNAPD_GLIB_CFLAGS) -DPA_MODULE_NAME=module_snap_policy |
1051 | 39 | +endif | 81 | +endif |
1052 | 40 | + | 82 | + |
1053 | 41 | # RTP modules | 83 | # RTP modules |
1054 | 42 | module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c | 84 | module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c |
1055 | 43 | module_rtp_send_la_LDFLAGS = $(MODULE_LDFLAGS) | 85 | module_rtp_send_la_LDFLAGS = $(MODULE_LDFLAGS) |
1058 | 44 | Index: pulseaudio/src/modules/module-snappy-policy.c | 86 | diff --git a/src/modules/module-snap-policy.c b/src/modules/module-snap-policy.c |
1059 | 45 | =================================================================== | 87 | new file mode 100644 |
1060 | 88 | index 0000000..8660476 | ||
1061 | 46 | --- /dev/null | 89 | --- /dev/null |
1064 | 47 | +++ pulseaudio/src/modules/module-snappy-policy.c | 90 | +++ b/src/modules/module-snap-policy.c |
1065 | 48 | @@ -0,0 +1,96 @@ | 91 | @@ -0,0 +1,347 @@ |
1066 | 49 | +/*** | 92 | +/*** |
1067 | 50 | + This file is part of PulseAudio. | 93 | + This file is part of PulseAudio. |
1068 | 51 | + | 94 | + |
1071 | 52 | + Copyright 2016 Canonical Ltd. | 95 | + Copyright 2018 Canonical Ltd. |
1072 | 53 | + Written by Simon Fels <simon.fels@canonical.com> | 96 | + Authors: |
1073 | 97 | + Simon Fels <simon.fels@canonical.com> | ||
1074 | 98 | + James Henstridge <james.henstridge@canonical.com> | ||
1075 | 54 | + | 99 | + |
1076 | 55 | + PulseAudio is free software; you can redistribute it and/or modify | 100 | + PulseAudio is free software; you can redistribute it and/or modify |
1077 | 56 | + it under the terms of the GNU Lesser General Public License as published | 101 | + it under the terms of the GNU Lesser General Public License as published |
1078 | @@ -71,116 +116,323 @@ Index: pulseaudio/src/modules/module-snappy-policy.c | |||
1079 | 71 | +#endif | 116 | +#endif |
1080 | 72 | + | 117 | + |
1081 | 73 | +#include <sys/apparmor.h> | 118 | +#include <sys/apparmor.h> |
1083 | 74 | +#include <errno.h> | 119 | +#include <glib.h> |
1084 | 120 | +#include <snapd-glib/snapd-glib.h> | ||
1085 | 75 | + | 121 | + |
1087 | 76 | +#include <pulsecore/i18n.h> | 122 | +#include <pulsecore/asyncq.h> |
1088 | 77 | +#include <pulsecore/core.h> | 123 | +#include <pulsecore/core.h> |
1089 | 124 | +#include <pulsecore/idxset.h> | ||
1090 | 125 | +#include <pulsecore/hashmap.h> | ||
1091 | 78 | +#include <pulsecore/module.h> | 126 | +#include <pulsecore/module.h> |
1094 | 79 | +#include <pulse/xmalloc.h> | 127 | +#include <pulsecore/mutex.h> |
1093 | 80 | +#include <pulsecore/fdsem.h> | ||
1095 | 81 | +#include <pulsecore/thread.h> | 128 | +#include <pulsecore/thread.h> |
1096 | 82 | +#include <pulsecore/core-util.h> | ||
1097 | 83 | +#include <pulse/mainloop-api.h> | 129 | +#include <pulse/mainloop-api.h> |
1098 | 130 | +#include <pulse/xmalloc.h> | ||
1099 | 84 | + | 131 | + |
1100 | 85 | +#define SNAP_LABEL_PREFIX "snap." | 132 | +#define SNAP_LABEL_PREFIX "snap." |
1101 | 86 | +#define SNAP_LABEL_PREFIX_LENGTH 5 | 133 | +#define SNAP_LABEL_PREFIX_LENGTH 5 |
1102 | 87 | + | 134 | + |
1105 | 88 | +PA_MODULE_AUTHOR("Simon Fels"); | 135 | +PA_MODULE_AUTHOR("Canonical Ltd"); |
1106 | 89 | +PA_MODULE_DESCRIPTION("Ubuntu Snappy policy management"); | 136 | +PA_MODULE_DESCRIPTION("Ubuntu Snap policy management"); |
1107 | 90 | +PA_MODULE_VERSION(PACKAGE_VERSION); | 137 | +PA_MODULE_VERSION(PACKAGE_VERSION); |
1108 | 91 | +PA_MODULE_LOAD_ONCE(true); | 138 | +PA_MODULE_LOAD_ONCE(true); |
1109 | 92 | + | 139 | + |
1110 | 140 | +struct per_client { | ||
1111 | 141 | + struct userdata *userdata; | ||
1112 | 142 | + uint32_t index; | ||
1113 | 143 | + char *snap_name; | ||
1114 | 144 | + pa_dynarray *pending_requests; /* of pa_access_data */ | ||
1115 | 145 | + bool completed; | ||
1116 | 146 | + bool grant_access; | ||
1117 | 147 | +}; | ||
1118 | 148 | + | ||
1119 | 93 | +struct userdata { | 149 | +struct userdata { |
1121 | 94 | + pa_core *core; | 150 | + pa_io_event *io_event; |
1122 | 95 | + pa_hook_slot *connect_hook_slot; | 151 | + pa_hook_slot *connect_hook_slot; |
1123 | 152 | + | ||
1124 | 153 | + pa_thread *thread; | ||
1125 | 154 | + pa_mutex *mutex; | ||
1126 | 155 | + pa_cond *cond; | ||
1127 | 156 | + | ||
1128 | 157 | + pa_hashmap *clients; /* int => struct per_client */ | ||
1129 | 158 | + pa_asyncq *results; /* of struct per_client */ | ||
1130 | 159 | + | ||
1131 | 160 | + /* Data owned by glib thread */ | ||
1132 | 161 | + GMainContext *main_context; | ||
1133 | 162 | + GMainLoop *main_loop; | ||
1134 | 163 | + GCancellable *cancellable; | ||
1135 | 164 | + SnapdClient *snapd; | ||
1136 | 96 | +}; | 165 | +}; |
1137 | 97 | + | 166 | + |
1149 | 98 | +static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, struct userdata *u) { | 167 | +/* ---- Code running in glib thread ---- */ |
1150 | 99 | + pa_client *client = pa_idxset_get_by_index(u->core->clients, d->client_index); | 168 | + |
1151 | 100 | + if (!client) | 169 | +static void check_interfaces_finish(GObject *source_object, |
1152 | 101 | + return PA_HOOK_OK; | 170 | + GAsyncResult *result, |
1153 | 102 | + | 171 | + gpointer user_data) |
1154 | 103 | + char *label = NULL; | 172 | +{ |
1155 | 104 | + char *mode = NULL; | 173 | + struct per_client *pc = user_data; |
1156 | 105 | + if (aa_gettaskcon(client->creds.pid, &label, &mode) < 0) { | 174 | + struct userdata *u = pc->userdata; |
1157 | 106 | + pa_log_warn("Failed to retrieve apparmor security label for pid %u: %s", | 175 | + g_autoptr(GError) error = NULL; |
1158 | 107 | + client->creds.pid, strerror(-errno)); | 176 | + g_autoptr(GPtrArray) plugs = NULL; |
1159 | 108 | + return PA_HOOK_OK; | 177 | + unsigned i; |
1160 | 178 | + | ||
1161 | 179 | + pa_mutex_lock(u->mutex); | ||
1162 | 180 | + | ||
1163 | 181 | + if (!snapd_client_get_interfaces_finish(u->snapd, result, &plugs, NULL, &error)) { | ||
1164 | 182 | + pa_log_warn("snapd_client_get_interfaces failed: %s", error->message); | ||
1165 | 183 | + goto end; | ||
1166 | 184 | + } | ||
1167 | 185 | + | ||
1168 | 186 | + /* determine pc->grant_access */ | ||
1169 | 187 | + for (i = 0; i < plugs->len; i++) { | ||
1170 | 188 | + SnapdPlug *plug = plugs->pdata[i]; | ||
1171 | 189 | + const char *snap_name = snapd_plug_get_snap(plug); | ||
1172 | 190 | + const char *iface = snapd_plug_get_interface(plug); | ||
1173 | 191 | + const bool connected = snapd_plug_get_connections(plug)->len != 0; | ||
1174 | 192 | + | ||
1175 | 193 | + /* We are only interested in connected plugs of our snap */ | ||
1176 | 194 | + if (!connected || strcmp(snap_name, pc->snap_name) != 0) { | ||
1177 | 195 | + continue; | ||
1178 | 196 | + } | ||
1179 | 197 | + if (!strcmp(iface, "pulseaudio") || !strcmp(iface, "audio-record")) { | ||
1180 | 198 | + pc->grant_access = true; | ||
1181 | 199 | + break; | ||
1182 | 200 | + } | ||
1183 | 201 | + } | ||
1184 | 202 | + | ||
1185 | 203 | +end: | ||
1186 | 204 | + pc->completed = true; | ||
1187 | 205 | + pa_asyncq_push(u->results, pc, true); | ||
1188 | 206 | + pa_mutex_unlock(u->mutex); | ||
1189 | 207 | +} | ||
1190 | 208 | + | ||
1191 | 209 | +static gboolean check_interfaces(void *data) | ||
1192 | 210 | +{ | ||
1193 | 211 | + struct per_client *pc = data; | ||
1194 | 212 | + struct userdata *u = pc->userdata; | ||
1195 | 213 | + | ||
1196 | 214 | + snapd_client_get_interfaces_async(u->snapd, u->cancellable, | ||
1197 | 215 | + check_interfaces_finish, pc); | ||
1198 | 216 | + return G_SOURCE_REMOVE; | ||
1199 | 217 | +} | ||
1200 | 218 | + | ||
1201 | 219 | + | ||
1202 | 220 | +static void thread_main(void *data) { | ||
1203 | 221 | + struct userdata *u = data; | ||
1204 | 222 | + | ||
1205 | 223 | + pa_mutex_lock(u->mutex); | ||
1206 | 224 | + | ||
1207 | 225 | + u->main_context = g_main_context_new(); | ||
1208 | 226 | + g_main_context_push_thread_default(u->main_context); | ||
1209 | 227 | + u->main_loop = g_main_loop_new(u->main_context, false); | ||
1210 | 228 | + u->cancellable = g_cancellable_new(); | ||
1211 | 229 | + u->snapd = snapd_client_new(); | ||
1212 | 230 | + | ||
1213 | 231 | + /* Signal main thread that we've finished initialisation */ | ||
1214 | 232 | + pa_cond_signal(u->cond, false); | ||
1215 | 233 | + pa_mutex_unlock(u->mutex); | ||
1216 | 234 | + | ||
1217 | 235 | + pa_log_info("Starting GLib main loop"); | ||
1218 | 236 | + g_main_loop_run(u->main_loop); | ||
1219 | 237 | + pa_log_info("GLib main loop exited"); | ||
1220 | 238 | + | ||
1221 | 239 | + g_cancellable_cancel(u->cancellable); | ||
1222 | 240 | + | ||
1223 | 241 | + g_clear_object(&u->snapd); | ||
1224 | 242 | + g_clear_object(&u->cancellable); | ||
1225 | 243 | + g_main_context_pop_thread_default(u->main_context); | ||
1226 | 244 | + g_clear_pointer(&u->main_loop, g_main_loop_unref); | ||
1227 | 245 | + g_clear_pointer(&u->main_context, g_main_context_unref); | ||
1228 | 246 | +} | ||
1229 | 247 | + | ||
1230 | 248 | +static gboolean thread_quit(void *data) | ||
1231 | 249 | +{ | ||
1232 | 250 | + struct userdata *u = data; | ||
1233 | 251 | + | ||
1234 | 252 | + g_main_loop_quit(u->main_loop); | ||
1235 | 253 | + return G_SOURCE_REMOVE; | ||
1236 | 254 | +} | ||
1237 | 255 | + | ||
1238 | 256 | +/* ---- Code running in main thread ---- */ | ||
1239 | 257 | + | ||
1240 | 258 | +static struct per_client *per_client_new(struct userdata *u, | ||
1241 | 259 | + uint32_t client_index, | ||
1242 | 260 | + char *snap_name) { | ||
1243 | 261 | + struct per_client *pc = pa_xnew0(struct per_client, 1); | ||
1244 | 262 | + pc->userdata = u; | ||
1245 | 263 | + pc->index = client_index; | ||
1246 | 264 | + pc->snap_name = snap_name; | ||
1247 | 265 | + pc->pending_requests = pa_dynarray_new(NULL); | ||
1248 | 266 | + pc->completed = false; | ||
1249 | 267 | + pc->grant_access = false; | ||
1250 | 268 | + return pc; | ||
1251 | 269 | +} | ||
1252 | 270 | + | ||
1253 | 271 | +static void per_client_free(struct per_client *pc) { | ||
1254 | 272 | + if (!pc) return; | ||
1255 | 273 | + pa_xfree(pc->snap_name); | ||
1256 | 274 | + pa_dynarray_free(pc->pending_requests); | ||
1257 | 275 | + pa_xfree(pc); | ||
1258 | 276 | +} | ||
1259 | 277 | + | ||
1260 | 278 | +static char *client_get_snap_name(pa_core *core, uint32_t client_index) { | ||
1261 | 279 | + pa_client *client; | ||
1262 | 280 | + char *context = NULL; | ||
1263 | 281 | + char *snap_name = NULL; | ||
1264 | 282 | + char *dot; | ||
1265 | 283 | + | ||
1266 | 284 | + client = pa_idxset_get_by_index(core->clients, client_index); | ||
1267 | 285 | + pa_assert(client != NULL); | ||
1268 | 286 | + if (!client->creds_valid) { | ||
1269 | 287 | + pa_log_warn("Client %u has no creds, cannot authenticate", client_index); | ||
1270 | 288 | + goto end; | ||
1271 | 289 | + } | ||
1272 | 290 | + | ||
1273 | 291 | + /* If AppArmor is not enabled, then we can't identify the client */ | ||
1274 | 292 | + if (!aa_is_enabled()) { | ||
1275 | 293 | + goto end; | ||
1276 | 294 | + } | ||
1277 | 295 | + if (aa_gettaskcon(client->creds.pid, &context, NULL) < 0) { | ||
1278 | 296 | + pa_log_error("AppArmor profile could not be retrieved."); | ||
1279 | 297 | + goto end; | ||
1280 | 109 | + } | 298 | + } |
1281 | 110 | + | 299 | + |
1283 | 111 | + pa_hook_result_t decision = PA_HOOK_OK; | 300 | + /* If the AppArmor context does not begin with "snap.", then this |
1284 | 301 | + * is not a snap */ | ||
1285 | 302 | + if (strncmp(context, SNAP_LABEL_PREFIX, SNAP_LABEL_PREFIX_LENGTH) != 0) { | ||
1286 | 303 | + goto end; | ||
1287 | 304 | + } | ||
1288 | 112 | + | 305 | + |
1295 | 113 | + // We only cancel the attempt of the client to start audio recording | 306 | + dot = strchr(context+SNAP_LABEL_PREFIX_LENGTH, '.'); |
1296 | 114 | + // when we could successfully determine that the request is coming | 307 | + if (dot == NULL) { |
1297 | 115 | + // from an app which is part of a snap. Otherwise we continue to | 308 | + pa_log_warn("Malformed snapd AppArmor profile name: %s", context); |
1298 | 116 | + // work as normal. | 309 | + goto end; |
1299 | 117 | + if (label && strncmp(SNAP_LABEL_PREFIX, label, SNAP_LABEL_PREFIX_LENGTH) == 0) | 310 | + } |
1300 | 118 | + decision = PA_HOOK_CANCEL; | 311 | + snap_name = pa_xstrndup(context+5, dot-context-SNAP_LABEL_PREFIX_LENGTH); |
1301 | 119 | + | 312 | + |
1303 | 120 | + free(label); | 313 | +end: |
1304 | 314 | + free(context); | ||
1305 | 315 | + return snap_name; | ||
1306 | 316 | +} | ||
1307 | 317 | + | ||
1308 | 318 | +static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, | ||
1309 | 319 | + struct userdata *u) { | ||
1310 | 320 | + pa_hook_result_t result = PA_HOOK_STOP; | ||
1311 | 321 | + struct per_client *pc = NULL; | ||
1312 | 322 | + char *snap_name = NULL; | ||
1313 | 323 | + | ||
1314 | 324 | + pa_mutex_lock(u->mutex); | ||
1315 | 325 | + pc = pa_hashmap_get(u->clients, (void *)(size_t)d->client_index); | ||
1316 | 326 | + if (pc) { | ||
1317 | 327 | + if (pc->completed) { | ||
1318 | 328 | + result = pc->grant_access ? PA_HOOK_OK : PA_HOOK_STOP; | ||
1319 | 329 | + } else { | ||
1320 | 330 | + /* A permission check for this snap is currently in progress */ | ||
1321 | 331 | + pa_dynarray_append(pc->pending_requests, d); | ||
1322 | 332 | + result = PA_HOOK_CANCEL; | ||
1323 | 333 | + } | ||
1324 | 334 | + goto end; | ||
1325 | 335 | + } | ||
1326 | 121 | + | 336 | + |
1328 | 122 | + return decision; | 337 | + snap_name = client_get_snap_name(core, d->client_index); |
1329 | 338 | + if (!snap_name) { | ||
1330 | 339 | + /* Not a snap, so allow access */ | ||
1331 | 340 | + result = PA_HOOK_OK; | ||
1332 | 341 | + goto end; | ||
1333 | 342 | + } | ||
1334 | 343 | + | ||
1335 | 344 | + /* create new per client struct, and submit to glib thread */ | ||
1336 | 345 | + pc = per_client_new(u, d->client_index, snap_name); | ||
1337 | 346 | + pa_dynarray_append(pc->pending_requests, d); | ||
1338 | 347 | + pa_hashmap_put(u->clients, (void *) (size_t) d->client_index, pc); | ||
1339 | 348 | + pa_log_info("Checking access for client %d (%s)", pc->index, pc->snap_name); | ||
1340 | 349 | + g_main_context_invoke(u->main_context, check_interfaces, pc); | ||
1341 | 350 | + | ||
1342 | 351 | + result = PA_HOOK_CANCEL; | ||
1343 | 352 | + | ||
1344 | 353 | +end: | ||
1345 | 354 | + pa_mutex_unlock(u->mutex); | ||
1346 | 355 | + return result; | ||
1347 | 356 | +} | ||
1348 | 357 | + | ||
1349 | 358 | +static void deliver_result(struct userdata *u, struct per_client *pc) { | ||
1350 | 359 | + pa_access_data *ad; | ||
1351 | 360 | + unsigned i; | ||
1352 | 361 | + | ||
1353 | 362 | + pa_log_info("Access check for client %u (%s): %d", | ||
1354 | 363 | + pc->index, pc->snap_name, pc->grant_access); | ||
1355 | 364 | + | ||
1356 | 365 | + /* Call the hooks without holding the mutex, since this will | ||
1357 | 366 | + * recurse into connect_record_hook. Access to pending_requests | ||
1358 | 367 | + * should be safe here, since connect_record_hook wont alter the | ||
1359 | 368 | + * array when the access check is complete. */ | ||
1360 | 369 | + PA_DYNARRAY_FOREACH(ad, pc->pending_requests, i) { | ||
1361 | 370 | + ad->async_finish_cb(ad, pc->grant_access); | ||
1362 | 371 | + } | ||
1363 | 372 | + pa_mutex_lock(u->mutex); | ||
1364 | 373 | + pa_hashmap_remove_and_free(u->clients, (void *) (size_t) pc->index); | ||
1365 | 374 | + pa_mutex_unlock(u->mutex); | ||
1366 | 375 | +} | ||
1367 | 376 | + | ||
1368 | 377 | +static void check_result(pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { | ||
1369 | 378 | + struct userdata *u = userdata; | ||
1370 | 379 | + struct per_client *pc; | ||
1371 | 380 | + | ||
1372 | 381 | + pa_asyncq_read_after_poll(u->results); | ||
1373 | 382 | + while ((pc = pa_asyncq_pop(u->results, false)) != NULL) { | ||
1374 | 383 | + deliver_result(u, pc); | ||
1375 | 384 | + } | ||
1376 | 385 | + pa_asyncq_read_before_poll(u->results); | ||
1377 | 123 | +} | 386 | +} |
1378 | 124 | + | 387 | + |
1379 | 125 | +int pa__init(pa_module *m) { | 388 | +int pa__init(pa_module *m) { |
1380 | 126 | + struct userdata *u; | 389 | + struct userdata *u; |
1381 | 127 | + u = pa_xnew0(struct userdata, 1); | ||
1382 | 128 | + u->core = m->core; | ||
1383 | 129 | + | 390 | + |
1384 | 391 | + u = pa_xnew0(struct userdata, 1); | ||
1385 | 130 | + m->userdata = u; | 392 | + m->userdata = u; |
1388 | 131 | + u->connect_hook_slot = pa_hook_connect(&m->core->access[PA_ACCESS_HOOK_CONNECT_RECORD], | 393 | + u->mutex = pa_mutex_new(false, false); |
1389 | 132 | + PA_HOOK_NORMAL, (pa_hook_cb_t) connect_record_hook, u); | 394 | + u->cond = pa_cond_new(); |
1390 | 395 | + | ||
1391 | 396 | + u->clients = pa_hashmap_new_full(pa_idxset_trivial_hash_func, | ||
1392 | 397 | + pa_idxset_trivial_compare_func, | ||
1393 | 398 | + NULL, (pa_free_cb_t) per_client_free); | ||
1394 | 399 | + | ||
1395 | 400 | + u->results = pa_asyncq_new(0); | ||
1396 | 401 | + u->io_event = m->core->mainloop->io_new( | ||
1397 | 402 | + m->core->mainloop, pa_asyncq_read_fd(u->results), PA_IO_EVENT_INPUT, | ||
1398 | 403 | + check_result, u); | ||
1399 | 404 | + pa_asyncq_read_before_poll(u->results); | ||
1400 | 405 | + | ||
1401 | 406 | + u->connect_hook_slot = pa_hook_connect( | ||
1402 | 407 | + &m->core->access[PA_ACCESS_HOOK_CONNECT_RECORD], PA_HOOK_NORMAL, | ||
1403 | 408 | + (pa_hook_cb_t) connect_record_hook, u); | ||
1404 | 409 | + | ||
1405 | 410 | + /* Start glib thread and wait for it to finish initialising. */ | ||
1406 | 411 | + pa_mutex_lock(u->mutex); | ||
1407 | 412 | + u->thread = pa_thread_new("snapd-glib", thread_main, u); | ||
1408 | 413 | + pa_cond_wait(u->cond, u->mutex); | ||
1409 | 414 | + pa_mutex_unlock(u->mutex); | ||
1410 | 133 | + | 415 | + |
1411 | 134 | + return 0; | 416 | + return 0; |
1412 | 135 | +} | 417 | +} |
1413 | 136 | + | 418 | + |
1414 | 137 | +void pa__done(pa_module *m) { | 419 | +void pa__done(pa_module *m) { |
1415 | 138 | + struct userdata *u = m->userdata; | 420 | + struct userdata *u = m->userdata; |
1431 | 139 | + if (u) { | 421 | + if (!u) return; |
1417 | 140 | + if (u->connect_hook_slot) | ||
1418 | 141 | + pa_hook_slot_free(u->connect_hook_slot); | ||
1419 | 142 | + pa_xfree(u); | ||
1420 | 143 | + } | ||
1421 | 144 | +} | ||
1422 | 145 | Index: pulseaudio/configure.ac | ||
1423 | 146 | =================================================================== | ||
1424 | 147 | --- pulseaudio.orig/configure.ac | ||
1425 | 148 | +++ pulseaudio/configure.ac | ||
1426 | 149 | @@ -1446,6 +1446,19 @@ AS_IF([test "x$os_is_win32" != "x1"], | ||
1427 | 150 | AS_IF([test "x$ax_pthread_ok" = "xyes"], | ||
1428 | 151 | AC_DEFINE([_POSIX_PTHREAD_SEMANTICS], 1, [Needed on Solaris])) | ||
1429 | 152 | |||
1430 | 153 | +# Snappy support | ||
1432 | 154 | + | 422 | + |
1435 | 155 | +AC_ARG_ENABLE([snappy], | 423 | + pa_hook_slot_free(u->connect_hook_slot); |
1436 | 156 | + AS_HELP_STRING([--enable-snappy], [Enable snappy support])) | 424 | + m->core->mainloop->io_free(u->io_event); |
1437 | 157 | + | 425 | + |
1441 | 158 | +AS_IF([test "x$enable_snappy" != "xno"], | 426 | + /* Stop the glib thread and wait for it to exit */ |
1442 | 159 | + [PKG_CHECK_MODULES(APPARMOR, [libapparmor], [HAVE_APPARMOR=1], [HAVE_APPARMOR=0])], | 427 | + g_main_context_invoke(u->main_context, thread_quit, u); |
1443 | 160 | + [HAVE_APPARMOR=0]) | 428 | + pa_thread_join(u->thread); |
1444 | 429 | + pa_thread_free(u->thread); | ||
1445 | 161 | + | 430 | + |
1448 | 162 | +AS_IF([test "x$enable_snappy" = "xyes" && test "x$HAVE_APPARMOR" = "x0"], | 431 | + pa_asyncq_free(u->results, NULL); /* items in queue owned by u->clients */ |
1449 | 163 | + [AC_MSG_ERROR([*** Apparmor library not found])]) | 432 | + g_clear_pointer(&u->clients, pa_hashmap_free); |
1450 | 164 | + | 433 | + |
1473 | 165 | +AM_CONDITIONAL([HAVE_APPARMOR], [test "x$HAVE_APPARMOR" = "x1"]) | 434 | + g_clear_pointer(&u->cond, pa_cond_free); |
1474 | 166 | 435 | + g_clear_pointer(&u->mutex, pa_mutex_free); | |
1475 | 167 | # Ubuntu touch trust store | 436 | + |
1476 | 168 | 437 | + pa_xfree(u); | |
1477 | 169 | @@ -1641,6 +1654,8 @@ AS_IF([test "x$HAVE_ESOUND" = "x1" -a "x | 438 | +} |
1456 | 170 | AS_IF([test "x$HAVE_GCOV" = "x1"], ENABLE_GCOV=yes, ENABLE_GCOV=no) | ||
1457 | 171 | AS_IF([test "x$HAVE_LIBCHECK" = "x1"], ENABLE_TESTS=yes, ENABLE_TESTS=no) | ||
1458 | 172 | AS_IF([test "x$enable_legacy_database_entry_format" != "xno"], ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=yes, ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=no) | ||
1459 | 173 | +AS_IF([test "x$enable_snappy" = "x1"], ENABLE_SNAPPY=yes, ENABLE_SNAPPY=no) | ||
1460 | 174 | +AS_IF([test "x$HAVE_APPARMOR" = "x1"], ENABLE_APPARMOR=yes, ENABLE_APPARMOR=no) | ||
1461 | 175 | |||
1462 | 176 | echo " | ||
1463 | 177 | ---{ $PACKAGE_NAME $VERSION }--- | ||
1464 | 178 | @@ -1698,6 +1713,8 @@ echo " | ||
1465 | 179 | Enable soxr (resampler): ${ENABLE_SOXR} | ||
1466 | 180 | Enable WebRTC echo canceller: ${ENABLE_WEBRTC} | ||
1467 | 181 | Enable Ubuntu trust store: ${ENABLE_TRUST_STORE} | ||
1468 | 182 | + Enable Snappy support: ${ENABLE_SNAPPY} | ||
1469 | 183 | + Enable Apparmor: ${ENABLE_APPARMOR} | ||
1470 | 184 | Enable gcov coverage: ${ENABLE_GCOV} | ||
1471 | 185 | Enable unit tests: ${ENABLE_TESTS} | ||
1472 | 186 | Database | ||
1478 | diff --git a/debian/patches/0701-enable-snap-policy-module.patch b/debian/patches/0701-enable-snap-policy-module.patch | |||
1479 | 187 | new file mode 100644 | 439 | new file mode 100644 |
1480 | index 0000000..233671b | |||
1481 | --- /dev/null | |||
1482 | +++ b/debian/patches/0701-enable-snap-policy-module.patch | |||
1483 | @@ -0,0 +1,25 @@ | |||
1484 | 1 | From: James Henstridge <james.henstridge@canonical.com> | ||
1485 | 2 | Date: Tue, 7 Aug 2018 16:54:00 +0800 | ||
1486 | 3 | Subject: daemon: enable module-snap-policy module | ||
1487 | 4 | |||
1488 | 5 | --- | ||
1489 | 6 | src/daemon/default.pa.in | 6 ++++++ | ||
1490 | 7 | 1 file changed, 6 insertions(+) | ||
1491 | 8 | |||
1492 | 9 | diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in | ||
1493 | 10 | index 78c42a1..633e0f0 100755 | ||
1494 | 11 | --- a/src/daemon/default.pa.in | ||
1495 | 12 | +++ b/src/daemon/default.pa.in | ||
1496 | 13 | @@ -171,6 +171,12 @@ load-module module-position-event-sounds | ||
1497 | 14 | ### Cork music/video streams when a phone stream is active | ||
1498 | 15 | load-module module-role-cork | ||
1499 | 16 | |||
1500 | 17 | +### Block audio recording for snap confined packages unless they have | ||
1501 | 18 | +### the "pulseaudio" or "audio-record" interfaces plugged. | ||
1502 | 19 | +.ifexists module-snap-policy@PA_SOEXT@ | ||
1503 | 20 | +load-module module-snap-policy | ||
1504 | 21 | +.endif | ||
1505 | 22 | + | ||
1506 | 23 | ### Modules to allow autoloading of filters (such as echo cancellation) | ||
1507 | 24 | ### on demand. module-filter-heuristics tries to determine what filters | ||
1508 | 25 | ### make sense, and module-filter-apply does the heavy-lifting of | ||
1509 | diff --git a/debian/patches/series b/debian/patches/series | |||
1510 | index 52c106a..16de29a 100644 | |||
1511 | --- a/debian/patches/series | |||
1512 | +++ b/debian/patches/series | |||
1513 | @@ -7,13 +7,10 @@ | |||
1514 | 7 | memfd-glibc2.27.patch | 7 | memfd-glibc2.27.patch |
1515 | 8 | 0050-disable-volume-test.patch | 8 | 0050-disable-volume-test.patch |
1516 | 9 | 9 | ||
1518 | 10 | # Ubuntu touch: support for trust-store | 10 | # Ubuntu Snap policy support |
1519 | 11 | 0406-tagstruct-add-copy-method.patch | 11 | 0406-tagstruct-add-copy-method.patch |
1520 | 12 | 0407-access-Add-access-control-hooks.patch | 12 | 0407-access-Add-access-control-hooks.patch |
1521 | 13 | 0408-protocol-native-add-access-checks.patch | 13 | 0408-protocol-native-add-access-checks.patch |
1527 | 14 | 0409-Trust-store-patch.patch | 14 | 0409-pa-client-peer-credentials.patch |
1523 | 15 | 0410-Add-thread-to-activate-trust-store-interface.patch | ||
1524 | 16 | 0417-increase-timeout-check-apparmor.patch | ||
1525 | 17 | |||
1526 | 18 | # Ubuntu Snappy | ||
1528 | 19 | 0700-modules-add-snappy-policy-module.patch | 15 | 0700-modules-add-snappy-policy-module.patch |
1529 | 16 | 0701-enable-snap-policy-module.patch | ||
1530 | diff --git a/debian/pulseaudio.install b/debian/pulseaudio.install | |||
1531 | index 59419ae..0756e46 100755 | |||
1532 | --- a/debian/pulseaudio.install | |||
1533 | +++ b/debian/pulseaudio.install | |||
1534 | @@ -78,7 +78,7 @@ usr/lib/pulse-*/modules/module-virtual-sink.so | |||
1535 | 78 | usr/lib/pulse-*/modules/module-virtual-source.so | 78 | usr/lib/pulse-*/modules/module-virtual-source.so |
1536 | 79 | usr/lib/pulse-*/modules/module-switch-on-port-available.so | 79 | usr/lib/pulse-*/modules/module-switch-on-port-available.so |
1537 | 80 | usr/lib/pulse-*/modules/module-virtual-surround-sink.so | 80 | usr/lib/pulse-*/modules/module-virtual-surround-sink.so |
1539 | 81 | usr/lib/pulse-*/modules/module-snappy-policy.so | 81 | usr/lib/pulse-*/modules/module-snap-policy.so |
1540 | 82 | usr/lib/pulse-*/modules/module-x11*.so | 82 | usr/lib/pulse-*/modules/module-x11*.so |
1541 | 83 | usr/lib/pulse-*/modules/module-allow-passthrough.so | 83 | usr/lib/pulse-*/modules/module-allow-passthrough.so |
1542 | 84 | [linux-any] usr/lib/pulse-*/modules/module-systemd-login.so | 84 | [linux-any] usr/lib/pulse-*/modules/module-systemd-login.so |
1543 | diff --git a/debian/rules b/debian/rules | |||
1544 | index f92f0b2..697e3cc 100755 | |||
1545 | --- a/debian/rules | |||
1546 | +++ b/debian/rules | |||
1547 | @@ -22,7 +22,7 @@ DEB_CONFIGURE_EXTRA_FLAGS = --enable-x11 --disable-hal-compat \ | |||
1548 | 22 | --with-zsh-completion-dir=\$${datadir}/zsh/vendor-completions \ | 22 | --with-zsh-completion-dir=\$${datadir}/zsh/vendor-completions \ |
1549 | 23 | --with-bash-completion-dir=\$${datadir}/bash-completion/completions \ | 23 | --with-bash-completion-dir=\$${datadir}/bash-completion/completions \ |
1550 | 24 | --with-systemduserunitdir=\$${prefix}/lib/systemd/user \ | 24 | --with-systemduserunitdir=\$${prefix}/lib/systemd/user \ |
1552 | 25 | --enable-snappy \ | 25 | --enable-snap \ |
1553 | 26 | --disable-bluez4 \ | 26 | --disable-bluez4 \ |
1554 | 27 | --enable-gsettings \ | 27 | --enable-gsettings \ |
1555 | 28 | --disable-gconf | 28 | --disable-gconf |
(1) You can drop the prereq branch if it's convenient. It doesn't exist any more because 'ubuntu' is identical.
(2) I get a build failure using this branch:
modules/ module- snap-policy. c: In function ‘module_ snap_policy_ LTX_pa_ _done’: glib-2. 0/glib/ gmem.h: 120:7: error: too few arguments to function ‘pa_asyncq_free’ module- snap-policy. c:340:5: note: in expansion of macro ‘g_clear_pointer’ clear_pointer( &u->results, pa_asyncq_free); ~~~~~~~ ~~~~~~ module- snap-policy. c:31: asyncq. h:44:6: note: declared here free(pa_ asyncq* q, pa_free_cb_t free_cb); ~~~~~~~ ~~~~~~
/usr/include/
(destroy) (_ptr); \
^
modules/
g_
^~
In file included from modules/
./pulsecore/
void pa_asyncq_
^
(3) You're now a member of ~ubuntu-audio-dev so no need to ask for a review next time.