This is an automated email from the git hooks/post-receive script. diwic-guest pushed a commit to branch ubuntu in repository pulseaudio.
commit e9f74032ae55de6f68d5ab1e1cdcc0e9b2c0416a Author: David Henningsson <[email protected]> Date: Thu Aug 27 19:10:14 2015 +0200 Add Ubuntu touch trust store patch set --- debian/changelog | 17 + debian/control | 29 + .../patches/0406-tagstruct-add-copy-method.patch | 48 ++ .../0407-access-Add-access-control-hooks.patch | 181 ++++++ .../0408-protocol-native-add-access-checks.patch | 495 ++++++++++++++++ debian/patches/0409-Trust-store-patch.patch | 627 +++++++++++++++++++++ ...-thread-to-activate-trust-store-interface.patch | 111 ++++ .../0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch | 62 ++ .../0417-increase-timeout-check-apparmor.patch | 92 +++ debian/patches/series | 10 + 10 files changed, 1672 insertions(+) diff --git a/debian/changelog b/debian/changelog index d6e7e38..31575b8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,20 @@ +pulseaudio (1:6.0-0ubuntu9) UNRELEASED; urgency=medium + + [ Alfonso Sanchez-Beato (email Canonical) ] + * debian/patches/0401-access-Add-access-control-hooks.patch + * debian/patches/0402-protocol-native-add-access-checks.patch + * debian/patches/0403-Trust-store-patch.patch + * debian/patches/0404-Add-thread-to-activate-trust-store-interface.patch + * debian/patches/0406-tagstruct-add-copy-method.patch + * debian/patches/0407-access-Add-access-control-hooks.patch + * debian/patches/0408-protocol-native-add-access-checks.patch + * debian/patches/0409-Trust-store-patch.patch + * debian/patches/0410-Add-thread-to-activate-trust-store-interface.patch + * debian/patches/0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch + Add support for trust-store in Ubuntu touch + + -- Alfonso Sanchez-Beato (email Canonical) <[email protected]> Fri, 07 Aug 2015 09:26:24 +0200 + pulseaudio (1:6.0-0ubuntu8) wily; urgency=medium * 0311-tests-add-tolerant-variation-for-comparing-the-rewin.patch: diff --git a/debian/control b/debian/control index 59a1963..8651669 100644 --- a/debian/control +++ b/debian/control @@ -13,6 +13,7 @@ Build-Depends: debhelper (>= 9), check, dh-autoreconf, intltool, + libapparmor-dev [linux-any], libasound2-dev (>= 1.0.24) [linux-any], libasyncns-dev, libatomic-ops-dev, @@ -20,6 +21,7 @@ Build-Depends: debhelper (>= 9), libbluetooth-dev (>= 4.40) [linux-any], libsbc-dev [linux-any], libcap-dev [linux-any], + libdbus-cpp-dev [armhf i386 amd64], libfftw3-dev, libgconf2-dev, libglib2.0-dev, @@ -38,6 +40,7 @@ Build-Depends: debhelper (>= 9), libssl-dev, libsystemd-dev [linux-any], libtdb-dev [!hurd-any], + libtrust-store-dev [armhf i386 amd64], libudev-dev (>= 143) [linux-any], libwebrtc-audio-processing-dev, libwrap0-dev, @@ -313,6 +316,32 @@ Description: Android Audio HAL module for PulseAudio sound server (debugging) . This package contains debugging symbols for the PulseAudio droid module. +Package: pulseaudio-module-trust-store +Architecture: armhf i386 amd64 +Priority: extra +Depends: ${shlibs:Depends}, ${misc:Depends} +Conflicts: pulseaudio (<< 0.9.14-2) +Description: trust-store module for PulseAudio sound server + PulseAudio, previously known as Polypaudio, is a sound server for POSIX and + WIN32 systems. It is a drop in replacement for the ESD sound server with + much better latency, mixing/re-sampling quality and overall architecture. + . + This module enables PulseAudio to use the trust-store in Ubuntu touch systems. + . + The module is called module-trust-store. + +Package: pulseaudio-module-trust-store-dbg +Architecture: armhf i386 amd64 +Priority: extra +Section: debug +Depends: ${misc:Depends}, pulseaudio-module-trust-store (= ${binary:Version}) +Description: trust-store module for PulseAudio sound server (debugging) + PulseAudio, previously known as Polypaudio, is a sound server for POSIX and + WIN32 systems. It is a drop in replacement for the ESD sound server with + much better latency, mixing/re-sampling quality and overall architecture. + . + This package contains debugging symbols for the PulseAudio trust-store module. + Package: pulseaudio-module-bluetooth Architecture: linux-any Priority: extra diff --git a/debian/patches/0406-tagstruct-add-copy-method.patch b/debian/patches/0406-tagstruct-add-copy-method.patch new file mode 100644 index 0000000..0ad1c6c --- /dev/null +++ b/debian/patches/0406-tagstruct-add-copy-method.patch @@ -0,0 +1,48 @@ +From 3560cafb03fc62745874077fb1153ec8d0cc59ac Mon Sep 17 00:00:00 2001 +From: David Henningsson <[email protected]> +Date: Thu, 27 Aug 2015 15:27:16 +0200 +Subject: [PATCH] Add tagstruct copy method + +Originally by Wim Taymans, backported by David Henningsson +--- + src/pulsecore/tagstruct.c | 14 ++++++++++++++ + src/pulsecore/tagstruct.h | 2 ++ + 2 files changed, 16 insertions(+) + +Index: pulseaudio/src/pulsecore/tagstruct.c +=================================================================== +--- pulseaudio.orig/src/pulsecore/tagstruct.c 2015-08-27 17:06:31.000000000 +0200 ++++ pulseaudio/src/pulsecore/tagstruct.c 2015-08-27 17:10:53.302118854 +0200 +@@ -83,6 +83,19 @@ + return p; + } + ++pa_tagstruct *pa_tagstruct_copy(pa_tagstruct*t) { ++ pa_tagstruct*tc; ++ ++ tc = pa_xnew(pa_tagstruct, 1); ++ tc->data = pa_xmemdup(t->data, t->length); ++ tc->allocated = t->length; ++ tc->length = t->length; ++ tc->rindex = 0; ++ tc->dynamic = true; ++ ++ return tc; ++} ++ + static void extend(pa_tagstruct*t, size_t l) { + pa_assert(t); + pa_assert(t->dynamic); +Index: pulseaudio/src/pulsecore/tagstruct.h +=================================================================== +--- pulseaudio.orig/src/pulsecore/tagstruct.h 2015-08-27 17:06:31.000000000 +0200 ++++ pulseaudio/src/pulsecore/tagstruct.h 2015-08-27 17:06:39.000000000 +0200 +@@ -64,6 +64,8 @@ + void pa_tagstruct_free(pa_tagstruct*t); + uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l); + ++pa_tagstruct *pa_tagstruct_copy(pa_tagstruct*t); ++ + int pa_tagstruct_eof(pa_tagstruct*t); + const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l); + diff --git a/debian/patches/0407-access-Add-access-control-hooks.patch b/debian/patches/0407-access-Add-access-control-hooks.patch new file mode 100644 index 0000000..17f3bce --- /dev/null +++ b/debian/patches/0407-access-Add-access-control-hooks.patch @@ -0,0 +1,181 @@ +From d25ec7bc401be4df1df53158ccacd5026366f38d Mon Sep 17 00:00:00 2001 +From: Alfonso Sanchez-Beato <[email protected]> +Date: Fri, 7 Aug 2015 12:19:50 +0200 +Subject: [PATCH 1/4] access: Add access control hooks + +Add hooks to core to check if certain operations are allowed. +--- + src/Makefile.am | 1 + + src/pulsecore/access.h | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ + src/pulsecore/core.c | 5 +++ + src/pulsecore/core.h | 3 ++ + 4 files changed, 111 insertions(+) + create mode 100644 src/pulsecore/access.h + +diff --git a/src/Makefile.am b/src/Makefile.am +index f96f527..f6897de 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -637,6 +637,7 @@ pkglib_LTLIBRARIES = \ + # to the existing libpulse being linked to libpulsecommon). Duplicating the + # code allows us to prevent this circular linking. + libpulsecommon_@PA_MAJORMINOR@_la_SOURCES = \ ++ pulsecore/access.h \ + pulse/client-conf.c pulse/client-conf.h \ + pulse/fork-detect.c pulse/fork-detect.h \ + pulse/format.c pulse/format.h \ +diff --git a/src/pulsecore/access.h b/src/pulsecore/access.h +new file mode 100644 +index 0000000..7cd2751 +--- /dev/null ++++ b/src/pulsecore/access.h +@@ -0,0 +1,102 @@ ++#ifndef fooaccesshfoo ++#define fooaccesshfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2004-2006 Lennart Poettering ++ 2015 Wim Taymans <[email protected]> ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of the ++ License, or (at your option) any later version. ++ ++ PulseAudio is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. ++***/ ++ ++#include <sys/types.h> ++ ++#include <pulsecore/client.h> ++ ++typedef enum pa_access_hook { ++ /* context */ ++ PA_ACCESS_HOOK_EXIT_DAEMON, ++ PA_ACCESS_HOOK_SET_DEFAULT_SINK, ++ PA_ACCESS_HOOK_SET_DEFAULT_SOURCE, ++ ++ /* introspection */ ++ PA_ACCESS_HOOK_GET_SINK_INFO, ++ PA_ACCESS_HOOK_SET_SINK_VOLUME, ++ PA_ACCESS_HOOK_SET_SINK_MUTE, ++ PA_ACCESS_HOOK_SUSPEND_SINK, ++ PA_ACCESS_HOOK_SET_SINK_PORT, ++ ++ PA_ACCESS_HOOK_GET_SOURCE_INFO, ++ PA_ACCESS_HOOK_SET_SOURCE_VOLUME, ++ PA_ACCESS_HOOK_SET_SOURCE_MUTE, ++ PA_ACCESS_HOOK_SUSPEND_SOURCE, ++ PA_ACCESS_HOOK_SET_SOURCE_PORT, ++ ++ PA_ACCESS_HOOK_GET_SERVER_INFO, ++ ++ PA_ACCESS_HOOK_GET_MODULE_INFO, ++ PA_ACCESS_HOOK_LOAD_MODULE, ++ PA_ACCESS_HOOK_UNLOAD_MODULE, ++ ++ PA_ACCESS_HOOK_GET_CLIENT_INFO, ++ PA_ACCESS_HOOK_KILL_CLIENT, ++ ++ PA_ACCESS_HOOK_GET_CARD_INFO, ++ PA_ACCESS_HOOK_SET_CARD_PROFILE, ++ PA_ACCESS_HOOK_SET_PORT_LATENCY_OFFSET, ++ ++ PA_ACCESS_HOOK_GET_SINK_INPUT_INFO, ++ PA_ACCESS_HOOK_MOVE_SINK_INPUT, ++ PA_ACCESS_HOOK_SET_SINK_INPUT_VOLUME, ++ PA_ACCESS_HOOK_SET_SINK_INPUT_MUTE, ++ PA_ACCESS_HOOK_KILL_SINK_INPUT, ++ ++ PA_ACCESS_HOOK_GET_SOURCE_OUTPUT_INFO, ++ PA_ACCESS_HOOK_MOVE_SOURCE_OUTPUT, ++ PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_VOLUME, ++ PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_MUTE, ++ PA_ACCESS_HOOK_KILL_SOURCE_OUTPUT, ++ ++ PA_ACCESS_HOOK_STAT, ++ ++ PA_ACCESS_HOOK_GET_SAMPLE_INFO, ++ /* sample cache */ ++ PA_ACCESS_HOOK_CONNECT_UPLOAD, ++ PA_ACCESS_HOOK_REMOVE_SAMPLE, ++ PA_ACCESS_HOOK_PLAY_SAMPLE, ++ /* stream */ ++ PA_ACCESS_HOOK_CONNECT_PLAYBACK, ++ PA_ACCESS_HOOK_CONNECT_RECORD, ++ /* extension */ ++ PA_ACCESS_HOOK_EXTENSION, ++ ++ PA_ACCESS_HOOK_FILTER_SUBSCRIBE_EVENT, ++ ++ PA_ACCESS_HOOK_MAX ++} pa_access_hook_t; ++ ++typedef struct pa_access_data pa_access_data; ++ ++struct pa_access_data { ++ pa_access_hook_t hook; ++ uint32_t client_index; ++ uint32_t object_index; ++ pa_subscription_event_type_t event; ++ const char *name; ++ ++ void (*async_finish_cb) (pa_access_data *data, bool res); ++}; ++ ++#endif +diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c +index 0e63bac..9135311 100644 +--- a/src/pulsecore/core.c ++++ b/src/pulsecore/core.c +@@ -151,6 +151,9 @@ pa_core* pa_core_new(pa_mainloop_api *m, bool shared, size_t shm_size) { + for (j = 0; j < PA_CORE_HOOK_MAX; j++) + pa_hook_init(&c->hooks[j], c); + ++ for (j = 0; j < PA_ACCESS_HOOK_MAX; j++) ++ pa_hook_init(&c->access[j], c); ++ + pa_random(&c->cookie, sizeof(c->cookie)); + + #ifdef SIGPIPE +@@ -222,6 +225,8 @@ static void core_free(pa_object *o) { + + for (j = 0; j < PA_CORE_HOOK_MAX; j++) + pa_hook_done(&c->hooks[j]); ++ for (j = 0; j < PA_ACCESS_HOOK_MAX; j++) ++ pa_hook_done(&c->access[j]); + + pa_xfree(c); + } +diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h +index e69a130..6e7feb4 100644 +--- a/src/pulsecore/core.h ++++ b/src/pulsecore/core.h +@@ -50,6 +50,7 @@ typedef enum pa_suspend_cause { + #include <pulsecore/source.h> + #include <pulsecore/core-subscribe.h> + #include <pulsecore/msgobject.h> ++#include <pulsecore/access.h> + + typedef enum pa_server_type { + PA_SERVER_TYPE_UNSET, +@@ -199,6 +200,8 @@ struct pa_core { + + /* hooks */ + pa_hook hooks[PA_CORE_HOOK_MAX]; ++ /* access hooks */ ++ pa_hook access[PA_ACCESS_HOOK_MAX]; + }; + + PA_DECLARE_PUBLIC_CLASS(pa_core); +-- +2.1.4 + diff --git a/debian/patches/0408-protocol-native-add-access-checks.patch b/debian/patches/0408-protocol-native-add-access-checks.patch new file mode 100644 index 0000000..282249d --- /dev/null +++ b/debian/patches/0408-protocol-native-add-access-checks.patch @@ -0,0 +1,495 @@ +From 1a7e06f33c2c7a684eaebc79ce77c6efce29af1d Mon Sep 17 00:00:00 2001 +From: Wim Taymans <[email protected]> +Date: Tue, 7 Apr 2015 17:13:16 +0200 +Subject: [PATCH 3/5] protocol-native: add access checks + +Call the hooks in various places to check if an action is allowed or +not. + +The hook can return PA_HOOK_OK to allow an action, PA_HOOK_STOP to +deny an action. + +Returning PA_HOOK_CANCEL will handle the result asynchronously. +This is implemented by saving the state of the current command and +exiting the command (going back to the mainloop) without reply. +When the access check completes, it will call async_finish_cb, which +will use the saved state to call the original command again. The access +check will eventually return OK or STOP and the command can complete +and send a reply. +--- + src/pulsecore/protocol-native.c | 219 +++++++++++++++++++++++++++++++++++++++- + 1 file changed, 217 insertions(+), 2 deletions(-) + +Index: pulseaudio/src/pulsecore/protocol-native.c +=================================================================== +--- pulseaudio.orig/src/pulsecore/protocol-native.c 2015-08-27 15:32:07.566841210 +0200 ++++ pulseaudio/src/pulsecore/protocol-native.c 2015-08-27 15:33:18.854410782 +0200 +@@ -300,6 +300,7 @@ + static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + static void command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); ++static pa_hook_result_t check_access(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata, uint32_t idx, pa_subscription_event_type_t event, const char *name); + + static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { + [PA_COMMAND_ERROR] = NULL, +@@ -2014,6 +2015,23 @@ + } \ + } while(0); + ++#define CHECK_ACCESS_STMT(c, command, tag, idx, name, async, denied) { \ ++ pa_hook_result_t res = check_access(pd, command, tag, t, userdata, idx, 0, name); \ ++ if (res == PA_HOOK_STOP) { \ ++ denied; \ ++ } else if (res == PA_HOOK_CANCEL) { \ ++ async; \ ++ } \ ++}; ++ ++#define CHECK_ACCESS_GOTO(c, command, tag, idx, name, label) \ ++ CHECK_ACCESS_STMT(c, command, tag, idx, name, \ ++ goto label, pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); goto label) ++ ++#define CHECK_ACCESS(c, command, tag, idx, name) \ ++ CHECK_ACCESS_STMT(c, command, tag, idx, name, \ ++ return, pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return) ++ + static pa_tagstruct *reply_new(uint32_t tag) { + pa_tagstruct *reply; + +@@ -2091,6 +2109,8 @@ + CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish); + CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish); + ++ CHECK_ACCESS_GOTO(c, command, tag, PA_INVALID_INDEX, NULL, finish); ++ + p = pa_proplist_new(); + + if (name) +@@ -2412,6 +2432,8 @@ + CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID, finish); + CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish); + ++ CHECK_ACCESS_GOTO(c, command, tag, PA_INVALID_INDEX, NULL, finish); ++ + p = pa_proplist_new(); + + if (name) +@@ -2617,6 +2639,7 @@ + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); ++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, NULL); + ret = pa_core_exit(c->protocol->core, false, 0); + CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS); + +@@ -2935,6 +2958,7 @@ + } + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); ++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, NULL); + + stat = pa_mempool_get_stat(c->protocol->core->mempool); + +@@ -3061,6 +3085,8 @@ + CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE); + ++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, NULL); ++ + p = pa_proplist_new(); + + if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) || +@@ -3159,6 +3185,8 @@ + + CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); + ++ CHECK_ACCESS(c, command, tag, sink->index, name); ++ + p = pa_proplist_new(); + + if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) || +@@ -3202,6 +3230,8 @@ + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + ++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, name); ++ + if (pa_scache_remove_item(c->protocol->core, name) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); + return; +@@ -3650,6 +3680,8 @@ + return; + } + ++ CHECK_ACCESS(c, command, tag, idx, name); ++ + reply = reply_new(tag); + if (sink) + sink_fill_tagstruct(c, reply, sink); +@@ -3710,6 +3742,8 @@ + + if (i) { + PA_IDXSET_FOREACH(p, i, idx) { ++ CHECK_ACCESS_STMT(c, command, tag, idx, NULL, goto async, continue); ++ + if (command == PA_COMMAND_GET_SINK_INFO_LIST) + sink_fill_tagstruct(c, reply, p); + else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) +@@ -3732,6 +3766,11 @@ + } + + pa_pstream_send_tagstruct(c->pstream, reply); ++ return; ++ ++async: ++ pa_tagstruct_free(reply); ++ return; + } + + static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +@@ -3752,6 +3791,15 @@ + + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + ++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, NULL); ++ ++ def_sink = pa_namereg_get_default_sink(c->protocol->core); ++ if (def_sink) ++ CHECK_ACCESS_STMT(c, PA_COMMAND_GET_SINK_INFO, tag, def_sink->index, NULL, return, def_sink = NULL); ++ def_source = pa_namereg_get_default_source(c->protocol->core); ++ if (def_source) ++ CHECK_ACCESS_STMT(c, PA_COMMAND_GET_SOURCE_INFO, tag, def_source->index, NULL, return, def_source = NULL); ++ + reply = reply_new(tag); + pa_tagstruct_puts(reply, PACKAGE_NAME); + pa_tagstruct_puts(reply, PACKAGE_VERSION); +@@ -3767,9 +3815,7 @@ + fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec); + pa_tagstruct_put_sample_spec(reply, &fixed_ss); + +- def_sink = pa_namereg_get_default_sink(c->protocol->core); + pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL); +- def_source = pa_namereg_get_default_source(c->protocol->core); + pa_tagstruct_puts(reply, def_source ? def_source->name : NULL); + + pa_tagstruct_putu32(reply, c->protocol->core->cookie); +@@ -3786,6 +3832,9 @@ + + pa_native_connection_assert_ref(c); + ++ if (check_access (NULL, PA_COMMAND_SUBSCRIBE_EVENT, 0, NULL, userdata, idx, e, NULL) != PA_HOOK_OK) ++ return; ++ + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT); + pa_tagstruct_putu32(t, (uint32_t) -1); +@@ -3888,6 +3937,8 @@ + + client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); + ++ CHECK_ACCESS(c, command, tag, idx, name); ++ + if (sink) { + CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID); + +@@ -3983,6 +4034,8 @@ + + CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY); + ++ CHECK_ACCESS(c, command, tag, idx, name); ++ + client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); + + if (sink) { +@@ -4446,6 +4499,7 @@ + + source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE); + CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); ++ CHECK_ACCESS(c, command, tag, source->index, s); + + pa_namereg_set_default_source(c->protocol->core, source); + } else { +@@ -4454,6 +4508,7 @@ + + sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK); + CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); ++ CHECK_ACCESS(c, command, tag, sink->index, s); + + pa_namereg_set_default_sink(c->protocol->core, sink); + } +@@ -4521,6 +4576,7 @@ + + client = pa_idxset_get_by_index(c->protocol->core->clients, idx); + CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY); ++ CHECK_ACCESS(c, command, tag, idx, NULL); + + pa_native_connection_ref(c); + pa_client_kill(client); +@@ -4530,6 +4586,7 @@ + + s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); ++ CHECK_ACCESS(c, command, tag, idx, NULL); + + pa_native_connection_ref(c); + pa_sink_input_kill(s); +@@ -4540,6 +4597,7 @@ + + s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); + CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); ++ CHECK_ACCESS(c, command, tag, idx, NULL); + + pa_native_connection_ref(c); + pa_source_output_kill(s); +@@ -4569,6 +4627,8 @@ + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID); + ++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, name); ++ + if (!(m = pa_module_load(c->protocol->core, name, argument))) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED); + return; +@@ -4597,6 +4657,8 @@ + m = pa_idxset_get_by_index(c->protocol->core->modules, idx); + CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY); + ++ CHECK_ACCESS(c, command, tag, idx, NULL); ++ + pa_module_unload_request(m, false); + pa_pstream_send_simple_ack(c->pstream, tag); + } +@@ -4635,6 +4697,7 @@ + sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK); + + CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY); ++ CHECK_ACCESS(c, command, tag, idx, sink->name); + + if (pa_sink_input_move_to(si, sink, true) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); +@@ -4654,6 +4717,7 @@ + source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE); + + CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY); ++ CHECK_ACCESS(c, command, tag, idx, source->name); + + if (pa_source_output_move_to(so, source, true) < 0) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); +@@ -4689,6 +4753,8 @@ + + if (idx == PA_INVALID_INDEX && name && !*name) { + ++ CHECK_ACCESS(c, command, tag, idx, name); ++ + pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming"); + + if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) { +@@ -4705,6 +4771,8 @@ + + CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); + ++ CHECK_ACCESS(c, command, tag, sink->index, name); ++ + pa_log_debug("%s of sink %s requested by client %" PRIu32 ".", + b ? "Suspending" : "Resuming", sink->name, c->client->index); + +@@ -4719,6 +4787,8 @@ + + if (idx == PA_INVALID_INDEX && name && !*name) { + ++ CHECK_ACCESS(c, command, tag, idx, name); ++ + pa_log_debug("%s all sources", b ? "Suspending" : "Resuming"); + + if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) { +@@ -4736,6 +4806,8 @@ + + CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); + ++ CHECK_ACCESS(c, command, tag, source->index, name); ++ + pa_log_debug("%s of source %s requested by client %" PRIu32 ".", + b ? "Suspending" : "Resuming", source->name, c->client->index); + +@@ -4779,6 +4851,8 @@ + CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION); + CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); + ++ CHECK_ACCESS(c, command, tag, m->index, name); ++ + cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m); + CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION); + +@@ -4821,6 +4895,8 @@ + + CHECK_VALIDITY(c->pstream, profile, tag, PA_ERR_NOENTITY); + ++ CHECK_ACCESS(c, command, tag, card->index, profile_name); ++ + if ((ret = pa_card_set_profile(card, profile, true)) < 0) { + pa_pstream_send_error(c->pstream, tag, -ret); + return; +@@ -4861,6 +4937,8 @@ + + CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); + ++ CHECK_ACCESS(c, command, tag, sink->index, name); ++ + if ((ret = pa_sink_set_port(sink, port, true)) < 0) { + pa_pstream_send_error(c->pstream, tag, -ret); + return; +@@ -4877,6 +4955,8 @@ + + CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); + ++ CHECK_ACCESS(c, command, tag, source->index, name); ++ + if ((ret = pa_source_set_port(source, port, true)) < 0) { + pa_pstream_send_error(c->pstream, tag, -ret); + return; +@@ -4921,6 +5001,8 @@ + port = pa_hashmap_get(card->ports, port_name); + CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_NOENTITY); + ++ CHECK_ACCESS(c, command, tag, card->index, port_name); ++ + pa_device_port_set_latency_offset(port, offset); + + pa_pstream_send_simple_ack(c->pstream, tag); +@@ -5461,3 +5543,136 @@ + + return c->client; + } ++ ++static const pa_access_hook_t map_table[PA_COMMAND_MAX] = { ++ /* CLIENT -> SERVER */ ++ [PA_COMMAND_EXIT] = PA_ACCESS_HOOK_EXIT_DAEMON, ++ [PA_COMMAND_SET_DEFAULT_SINK] = PA_ACCESS_HOOK_SET_DEFAULT_SINK, ++ [PA_COMMAND_SET_DEFAULT_SOURCE] = PA_ACCESS_HOOK_SET_DEFAULT_SOURCE, ++ ++ [PA_COMMAND_GET_SINK_INFO] = PA_ACCESS_HOOK_GET_SINK_INFO, ++ [PA_COMMAND_GET_SINK_INFO_LIST] = PA_ACCESS_HOOK_GET_SINK_INFO, ++ [PA_COMMAND_SET_SINK_VOLUME] = PA_ACCESS_HOOK_SET_SINK_VOLUME, ++ [PA_COMMAND_SET_SINK_MUTE] = PA_ACCESS_HOOK_SET_SINK_MUTE, ++ [PA_COMMAND_SUSPEND_SINK] = PA_ACCESS_HOOK_SUSPEND_SINK, ++ [PA_COMMAND_SET_SINK_PORT] = PA_ACCESS_HOOK_SET_SINK_PORT, ++ ++ [PA_COMMAND_GET_SOURCE_INFO] = PA_ACCESS_HOOK_GET_SOURCE_INFO, ++ [PA_COMMAND_GET_SOURCE_INFO_LIST] = PA_ACCESS_HOOK_GET_SOURCE_INFO, ++ [PA_COMMAND_SET_SOURCE_VOLUME] = PA_ACCESS_HOOK_SET_SOURCE_VOLUME, ++ [PA_COMMAND_SET_SOURCE_MUTE] = PA_ACCESS_HOOK_SET_SOURCE_MUTE, ++ [PA_COMMAND_SUSPEND_SOURCE] = PA_ACCESS_HOOK_SUSPEND_SOURCE, ++ [PA_COMMAND_SET_SOURCE_PORT] = PA_ACCESS_HOOK_SET_SOURCE_PORT, ++ ++ [PA_COMMAND_GET_SERVER_INFO] = PA_ACCESS_HOOK_GET_SERVER_INFO, ++ ++ [PA_COMMAND_GET_MODULE_INFO] = PA_ACCESS_HOOK_GET_MODULE_INFO, ++ [PA_COMMAND_GET_MODULE_INFO_LIST] = PA_ACCESS_HOOK_GET_MODULE_INFO, ++ [PA_COMMAND_LOAD_MODULE] = PA_ACCESS_HOOK_LOAD_MODULE, ++ [PA_COMMAND_UNLOAD_MODULE] = PA_ACCESS_HOOK_UNLOAD_MODULE, ++ ++ [PA_COMMAND_GET_CLIENT_INFO] = PA_ACCESS_HOOK_GET_CLIENT_INFO, ++ [PA_COMMAND_GET_CLIENT_INFO_LIST] = PA_ACCESS_HOOK_GET_CLIENT_INFO, ++ [PA_COMMAND_KILL_CLIENT] = PA_ACCESS_HOOK_KILL_CLIENT, ++ ++ [PA_COMMAND_GET_CARD_INFO] = PA_ACCESS_HOOK_GET_CARD_INFO, ++ [PA_COMMAND_GET_CARD_INFO_LIST] = PA_ACCESS_HOOK_GET_CARD_INFO, ++ [PA_COMMAND_SET_CARD_PROFILE] = PA_ACCESS_HOOK_SET_CARD_PROFILE, ++ [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = PA_ACCESS_HOOK_SET_PORT_LATENCY_OFFSET, ++ ++ [PA_COMMAND_GET_SINK_INPUT_INFO] = PA_ACCESS_HOOK_GET_SINK_INPUT_INFO, ++ [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = PA_ACCESS_HOOK_GET_SINK_INPUT_INFO, ++ [PA_COMMAND_MOVE_SINK_INPUT] = PA_ACCESS_HOOK_MOVE_SINK_INPUT, ++ [PA_COMMAND_SET_SINK_INPUT_VOLUME] = PA_ACCESS_HOOK_SET_SINK_INPUT_VOLUME, ++ [PA_COMMAND_SET_SINK_INPUT_MUTE] = PA_ACCESS_HOOK_SET_SINK_INPUT_MUTE, ++ [PA_COMMAND_KILL_SINK_INPUT] = PA_ACCESS_HOOK_KILL_SINK_INPUT, ++ ++ [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = PA_ACCESS_HOOK_GET_SOURCE_OUTPUT_INFO, ++ [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = PA_ACCESS_HOOK_GET_SOURCE_OUTPUT_INFO, ++ [PA_COMMAND_MOVE_SOURCE_OUTPUT] = PA_ACCESS_HOOK_MOVE_SOURCE_OUTPUT, ++ [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_VOLUME, ++ [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_MUTE, ++ [PA_COMMAND_KILL_SOURCE_OUTPUT] = PA_ACCESS_HOOK_KILL_SOURCE_OUTPUT, ++ ++ [PA_COMMAND_STAT] = PA_ACCESS_HOOK_STAT, ++ ++ [PA_COMMAND_GET_SAMPLE_INFO] = PA_ACCESS_HOOK_GET_SAMPLE_INFO, ++ [PA_COMMAND_GET_SAMPLE_INFO_LIST] = PA_ACCESS_HOOK_GET_SAMPLE_INFO, ++ ++ [PA_COMMAND_CREATE_UPLOAD_STREAM] = PA_ACCESS_HOOK_CONNECT_UPLOAD, ++ [PA_COMMAND_REMOVE_SAMPLE] = PA_ACCESS_HOOK_REMOVE_SAMPLE, ++ [PA_COMMAND_PLAY_SAMPLE] = PA_ACCESS_HOOK_PLAY_SAMPLE, ++ ++ [PA_COMMAND_CREATE_PLAYBACK_STREAM] = PA_ACCESS_HOOK_CONNECT_PLAYBACK, ++ [PA_COMMAND_CREATE_RECORD_STREAM] = PA_ACCESS_HOOK_CONNECT_RECORD, ++ ++ [PA_COMMAND_EXTENSION] = PA_ACCESS_HOOK_EXTENSION, ++ ++ /* SERVER -> CLIENT */ ++ [PA_COMMAND_SUBSCRIBE_EVENT] = PA_ACCESS_HOOK_FILTER_SUBSCRIBE_EVENT ++}; ++ ++typedef struct pa_protocol_native_access_data { ++ pa_access_data d; ++ ++ pa_pdispatch *pd; ++ uint32_t command; ++ uint32_t tag; ++ pa_tagstruct *tc; ++ void *userdata; ++} pa_protocol_native_access_data; ++ ++static void check_access_finish_cb(pa_access_data *data, bool res) { ++ pa_protocol_native_access_data *d = (pa_protocol_native_access_data *) data; ++ pa_native_connection *c = PA_NATIVE_CONNECTION(d->userdata); ++ ++ if (!res) { ++ pa_pstream_send_error(c->pstream, d->tag, PA_ERR_ACCESS); \ ++ goto finish; ++ } ++ ++ /* 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); ++ ++finish: ++ pa_xfree((char *)d->d.name); ++ if (d->pd) ++ pa_pdispatch_unref(d->pd); ++ if (d->tc) ++ pa_tagstruct_free(d->tc); ++ pa_xfree(d); ++} ++ ++static pa_hook_result_t check_access(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata, uint32_t idx, pa_subscription_event_type_t event, const char *name) { ++ pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); ++ pa_hook_result_t res; ++ ++ if (map_table[command]) { ++ pa_protocol_native_access_data *data; ++ ++ data = pa_xnew0 (pa_protocol_native_access_data, 1); ++ data->d.client_index = c->client->index; ++ data->d.object_index = idx; ++ data->d.event = event; ++ data->d.name = name; ++ data->d.hook = map_table[command]; ++ ++ res = pa_hook_fire(&c->protocol->core->access[data->d.hook], data); ++ if (res == PA_HOOK_CANCEL) { ++ /* async */ ++ data->d.name = pa_xstrdup(name); ++ data->d.async_finish_cb = check_access_finish_cb; ++ data->pd = pd ? pa_pdispatch_ref (pd) : NULL; ++ data->command = command; ++ data->tag = tag; ++ data->tc = t ? pa_tagstruct_copy (t) : NULL; ++ data->userdata = userdata; ++ } else { ++ pa_xfree(data); ++ } ++ } else ++ res = PA_HOOK_OK; ++ ++ return res; ++} diff --git a/debian/patches/0409-Trust-store-patch.patch b/debian/patches/0409-Trust-store-patch.patch new file mode 100644 index 0000000..bed2290 --- /dev/null +++ b/debian/patches/0409-Trust-store-patch.patch @@ -0,0 +1,627 @@ +From ff36148e002232842ea0f07b148e5844c5d44ceb Mon Sep 17 00:00:00 2001 +From: David Henningsson <[email protected]> +Date: Wed, 22 Jul 2015 16:37:19 +0200 +Subject: [PATCH 4/5] Trust-store patch + +...includes some fixes elsewhere as well. + +Signed-off-by: David Henningsson <[email protected]> +--- + configure.ac | 15 ++ + src/Makefile.am | 24 +++ + src/modules/trust-store/module-trust-store.c | 221 +++++++++++++++++++++++++++ + src/modules/trust-store/truststore.cc | 74 +++++++++ + src/modules/trust-store/truststore.h | 41 +++++ + src/pulsecore/client.c | 6 +- + src/pulsecore/client.h | 4 + + src/pulsecore/creds.h | 1 + + src/pulsecore/iochannel.c | 2 + + src/pulsecore/protocol-native.c | 13 ++ + src/pulsecore/tagstruct.c | 1 + + src/tests/connect-stress.c | 4 +- + 12 files changed, 399 insertions(+), 7 deletions(-) + create mode 100644 src/modules/trust-store/module-trust-store.c + create mode 100644 src/modules/trust-store/truststore.cc + create mode 100644 src/modules/trust-store/truststore.h + +Index: pulseaudio/configure.ac +=================================================================== +--- pulseaudio.orig/configure.ac 2015-08-27 15:41:43.827251983 +0200 ++++ pulseaudio/configure.ac 2015-08-27 15:41:43.815252328 +0200 +@@ -1384,6 +1384,19 @@ + [HAVE_ADRIAN_EC=1]) + AM_CONDITIONAL([HAVE_ADRIAN_EC], [test "x$HAVE_ADRIAN_EC" = "x1"]) + ++# Ubuntu touch trust store ++ ++AC_ARG_ENABLE([trust-store], ++ AS_HELP_STRING([--enable-trust-store], [Enable Ubuntu touch trust store])) ++ ++AS_IF([test "x$enable_trust_store" != "xno"], ++ [PKG_CHECK_MODULES(TRUST_STORE, [ trust-store ], [HAVE_TRUST_STORE=1], [HAVE_TRUST_STORE=0])], ++ [HAVE_WEBRTC=0]) ++ ++AS_IF([test "x$enable_trust_store" = "xyes" && test "x$HAVE_TRUST_STORE" = "x0"], ++ [AC_MSG_ERROR([*** Ubuntu touch trust store library not found])]) ++ ++AM_CONDITIONAL([HAVE_TRUST_STORE], [test "x$HAVE_TRUST_STORE" = "x1"]) + + + ################################### +@@ -1544,6 +1557,7 @@ + AS_IF([test "x$HAVE_ADRIAN_EC" = "x1"], ENABLE_ADRIAN_EC=yes, ENABLE_ADRIAN_EC=no) + AS_IF([test "x$HAVE_SPEEX" = "x1"], ENABLE_SPEEX=yes, ENABLE_SPEEX=no) + AS_IF([test "x$HAVE_WEBRTC" = "x1"], ENABLE_WEBRTC=yes, ENABLE_WEBRTC=no) ++AS_IF([test "x$HAVE_TRUST_STORE" = "x1"], ENABLE_TRUST_STORE=yes, ENABLE_TRUST_STORE=no) + AS_IF([test "x$HAVE_TDB" = "x1"], ENABLE_TDB=yes, ENABLE_TDB=no) + AS_IF([test "x$HAVE_GDBM" = "x1"], ENABLE_GDBM=yes, ENABLE_GDBM=no) + AS_IF([test "x$HAVE_SIMPLEDB" = "x1"], ENABLE_SIMPLEDB=yes, ENABLE_SIMPLEDB=no) +@@ -1606,6 +1620,7 @@ + Enable Adrian echo canceller: ${ENABLE_ADRIAN_EC} + Enable speex (resampler, AEC): ${ENABLE_SPEEX} + Enable WebRTC echo canceller: ${ENABLE_WEBRTC} ++ Enable Ubuntu trust store: ${ENABLE_TRUST_STORE} + Enable gcov coverage: ${ENABLE_GCOV} + Enable unit tests: ${ENABLE_TESTS} + Database +Index: pulseaudio/src/Makefile.am +=================================================================== +--- pulseaudio.orig/src/Makefile.am 2015-08-27 15:41:43.827251983 +0200 ++++ pulseaudio/src/Makefile.am 2015-08-27 16:41:19.000000000 +0200 +@@ -1064,6 +1064,10 @@ + modlibexec_LTLIBRARIES += libwebrtc-util.la + endif + ++if HAVE_TRUST_STORE ++modlibexec_LTLIBRARIES += libtruststore-util.la ++endif ++ + if HAVE_ESOUND + modlibexec_LTLIBRARIES += \ + libprotocol-esound.la +@@ -1188,6 +1192,11 @@ + module-filter-heuristics.la \ + module-role-ducking.la + ++if HAVE_TRUST_STORE ++modlibexec_LTLIBRARIES += \ ++ module-trust-store.la ++endif ++ + if HAVE_ESOUND + modlibexec_LTLIBRARIES += \ + module-esound-protocol-tcp.la \ +@@ -1513,6 +1522,7 @@ + module-intended-roles-symdef.h \ + module-suspend-on-idle-symdef.h \ + module-echo-cancel-symdef.h \ ++ module-trust-store-symdef.h \ + module-hal-detect-symdef.h \ + module-udev-detect-symdef.h \ + module-systemd-login-symdef.h \ +@@ -2103,6 +2113,20 @@ + module_echo_cancel_la_LIBADD += libwebrtc-util.la + endif + ++if HAVE_TRUST_STORE ++# Separate helper library to keep C and C++ code apart, like we do for webrtc ++libtruststore_util_la_SOURCES = modules/trust-store/truststore.cc ++libtruststore_util_la_CXXFLAGS = $(AM_CXXFLAGS) -std=c++11 $(SERVER_CFLAGS) $(TRUST_STORE_CFLAGS) \ ++ $(DBUS_CFLAGS) -DHAVE_TRUST_STORE=1 ++libtruststore_util_la_LIBADD = libpulsecore-@[email protected] $(TRUST_STORE_LIBS) $(DBUS_LIBS) ++libtruststore_util_la_LDFLAGS = -avoid-version ++ ++module_trust_store_la_SOURCES = modules/trust-store/module-trust-store.c ++module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS) ++module_trust_store_la_LIBADD = $(MODULE_LIBADD) libtruststore-util.la ++module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1 ++endif ++ + # RTP modules + module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c + module_rtp_send_la_LDFLAGS = $(MODULE_LDFLAGS) +Index: pulseaudio/src/modules/trust-store/module-trust-store.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ pulseaudio/src/modules/trust-store/module-trust-store.c 2015-08-27 16:47:51.491242361 +0200 +@@ -0,0 +1,225 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2015 Canonical Ltd. ++ Written by David Henningsson <[email protected]> ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. ++***/ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include <pulsecore/i18n.h> ++#include <pulsecore/core.h> ++#include <pulsecore/module.h> ++#include <pulse/xmalloc.h> ++#include <pulsecore/fdsem.h> ++#include <pulsecore/thread.h> ++#include <pulsecore/core-util.h> ++#include <pulse/mainloop-api.h> ++ ++#include "module-trust-store-symdef.h" ++ ++PA_MODULE_AUTHOR("David Henningsson"); ++PA_MODULE_DESCRIPTION("Ubuntu touch trust store integration"); ++PA_MODULE_VERSION(PACKAGE_VERSION); ++PA_MODULE_LOAD_ONCE(true); ++ ++#include "truststore.h" ++ ++#define REQUEST_GRANTED 1 ++#define REQUEST_DENIED -1 ++#define REQUEST_PENDING 0 ++ ++struct userdata; ++ ++struct per_client { ++ uint32_t index; ++ char *appname; ++ uid_t uid; ++ pid_t pid; ++ struct userdata *userdata; ++ pa_dynarray *pending_requests; ++ pa_atomic_t result; ++}; ++ ++struct userdata { ++ pa_core *core; ++ pa_trust_store *ts; ++ pa_hashmap *per_clients; ++ pa_thread *thread; ++ pa_fdsem *fdsem; ++ pa_io_event *io_event; ++ pa_hook_slot *connect_hook_slot; ++}; ++ ++static struct per_client *per_client_new(struct userdata *u, uint32_t client_index) { ++ struct per_client *pc; ++ pa_client *client = pa_idxset_get_by_index(u->core->clients, client_index); ++ ++ pa_assert(client); ++ if (!client->creds_valid) { ++ pa_log_warn("Client %d has no creds, cannot authenticate", client_index); ++ return NULL; ++ } ++ ++ pc = pa_xnew0(struct per_client, 1); ++ // TODO: Do we need something else than the application name here - ++ // the application can probably spoof it ++ pc->appname = pa_xstrdup(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)); ++ pc->index = client_index; ++ pc->uid = client->creds.uid; ++ pc->pid = client->creds.pid; ++ pc->pending_requests = pa_dynarray_new(NULL); ++ pc->userdata = u; ++ ++ pa_hashmap_put(u->per_clients, (void *) (size_t) client_index, pc); ++ ++ return pc; ++} ++ ++static void per_client_free_from_hashmap(void *data) { ++ struct per_client *pc = data; ++ if (!pc) ++ return; ++ pa_xfree(pc->appname); ++ pa_dynarray_free(pc->pending_requests); ++ pa_xfree(pc); ++} ++ ++static void thread_func(void *data) { ++ struct per_client *pc = data; ++ ++ bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid, ++ _("%1% wants to record audio.")); ++ ++ pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED); ++ pa_fdsem_post(pc->userdata->fdsem); ++} ++ ++static void check_queue(struct userdata *u) { ++ struct per_client *pc; ++ void *dummy; ++ ++ pa_log_debug("Checking queue, size: %d, thread object: %s", ++ pa_hashmap_size(u->per_clients), pa_yes_no(u->thread)); ++ if (u->thread) { ++ pa_access_data *ad; ++ unsigned i; ++ int result; ++ pc = pa_thread_get_data(u->thread); ++ result = pa_atomic_load(&pc->result); ++ if (result == REQUEST_PENDING) ++ return; /* Still processing */ ++ pa_thread_free(u->thread); ++ u->thread = NULL; ++ ++ pa_log_debug("Letting client %d (%s) know the result (%s)", ++ pc->index, pc->appname, result == REQUEST_GRANTED ? "granted" : "rejected"); ++ PA_DYNARRAY_FOREACH(ad, pc->pending_requests, i) { ++ ad->async_finish_cb(ad, result == REQUEST_GRANTED); ++ } ++ pa_hashmap_remove(u->per_clients, (void*) (size_t) pc->index); ++ } ++ ++ /* Find a client that needs asking */ ++ PA_HASHMAP_FOREACH(pc, u->per_clients, dummy) { ++ if (u->thread) ++ return; ++ pa_assert(pa_atomic_load(&pc->result) == REQUEST_PENDING); ++ pa_log_debug("Starting thread to ask about client %d (%s)", pc->index, ++ pc->appname); ++ u->thread = pa_thread_new("trust-store", thread_func, pc); ++ } ++} ++ ++static void check_fdsem(pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t ee, ++ void *userdata) { ++ struct userdata *u = userdata; ++ pa_fdsem_after_poll(u->fdsem); ++ check_queue(u); ++ pa_fdsem_before_poll(u->fdsem); ++} ++ ++static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, struct userdata *u) { ++ struct per_client *pc = pa_hashmap_get(u->per_clients, (void*) (size_t) d->client_index); ++ int r; ++ if (!pc) ++ pc = per_client_new(u, d->client_index); ++ ++ r = pa_atomic_load(&pc->result); ++ pa_log_debug("Checking permission to record for client %d (%s) ", d->client_index, ++ r == REQUEST_GRANTED ? "granted" : r != REQUEST_PENDING ? "rejected" : "unknown"); ++ if (r == REQUEST_GRANTED) return PA_HOOK_OK; ++ if (r != REQUEST_PENDING) return PA_HOOK_STOP; ++ ++ pa_dynarray_append(pc->pending_requests, d); ++ check_queue(u); ++ return PA_HOOK_CANCEL; ++} ++ ++/* Test code - remove from final product */ ++static void test(struct userdata *u) { ++ uint32_t dummy; ++ pa_client *client; ++ ++ PA_IDXSET_FOREACH(client, u->core->clients, dummy) { ++ if (client->creds_valid) ++ pa_trust_store_check(u->ts, "The evil app", client->creds.uid, ++ client->creds.pid, "%1% wants to eat your laundry."); ++ } ++} ++ ++int pa__init(pa_module *m) { ++ struct userdata *u; ++ pa_trust_store *ts = pa_trust_store_new(); ++ if (ts == NULL) ++ return -1; ++ u = pa_xnew0(struct userdata, 1); ++ u->ts = ts; ++ u->core = m->core; ++ u->per_clients = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, ++ NULL, per_client_free_from_hashmap); ++ m->userdata = u; ++ u->connect_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_assert_se(u->fdsem = pa_fdsem_new()); ++ pa_assert_se(u->io_event = m->core->mainloop->io_new(m->core->mainloop, ++ pa_fdsem_get(u->fdsem), PA_IO_EVENT_INPUT, check_fdsem, u)); ++ pa_fdsem_before_poll(u->fdsem); ++ ++ test(u); ++ return 0; ++} ++ ++void pa__done(pa_module *m) { ++ struct userdata *u = m->userdata; ++ if (u) { ++ if (u->connect_hook_slot) ++ pa_hook_slot_free(u->connect_hook_slot); ++ if (u->thread) ++ pa_thread_free(u->thread); ++ if (u->io_event) ++ m->core->mainloop->io_free(u->io_event); ++ if (u->fdsem) ++ pa_fdsem_free(u->fdsem); ++ if (u->per_clients) ++ pa_hashmap_free(u->per_clients); ++ if (u->ts) ++ pa_trust_store_free(u->ts); ++ pa_xfree(u); ++ } ++} +Index: pulseaudio/src/modules/trust-store/truststore.cc +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ pulseaudio/src/modules/trust-store/truststore.cc 2015-08-27 16:41:21.000000000 +0200 +@@ -0,0 +1,74 @@ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include <memory> ++#include <core/dbus/bus.h> ++#include <core/trust/dbus_agent.h> ++#include <core/trust/agent.h> ++ ++#include <pulse/cdecl.h> ++ ++PA_C_DECL_BEGIN ++#include <pulsecore/core-util.h> ++#include <pulse/xmalloc.h> ++#include <pulsecore/log.h> ++ ++#include "truststore.h" ++PA_C_DECL_END ++ ++class TrustStore { ++public: ++ std::shared_ptr<core::trust::Agent> agent; ++}; ++ ++pa_trust_store* pa_trust_store_new() { ++ try { ++ auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session); ++ auto agent = core::trust::dbus::create_multi_user_agent_for_bus_connection(bus, "PulseAudio"); ++ auto ts = new TrustStore(); ++ ts->agent = agent; ++ return (pa_trust_store *) ts; ++ } catch(const std::exception &e) { ++ pa_log_error("Could not create Ubuntu touch trust store connection: %s", ++ e.what()); ++ } catch(...) { ++ pa_log_error("Could not create Ubuntu touch trust store connection"); ++ return NULL; ++ } ++} ++ ++void pa_trust_store_free(pa_trust_store *t) { ++ pa_assert(t != NULL); ++ auto ts = (TrustStore*) t; ++ delete ts; ++} ++ ++bool pa_trust_store_check(pa_trust_store *t, const char *appname, ++ uid_t uid, pid_t pid, const char *description) { ++ auto ts = (TrustStore*) t; ++ try { ++ ++ core::trust::Agent::RequestParameters params { ++ core::trust::Uid{uid}, ++ core::trust::Pid{pid}, ++ appname, ++ core::trust::Feature{0}, ++ description ++ }; ++ pa_log_debug("Asking Ubuntu touch trust store for permission (app: %s)", ++ params.application.id.c_str()); ++ auto answer = ts->agent->authenticate_request_with_parameters(params); ++ if (answer == core::trust::Request::Answer::granted) { ++ pa_log_debug("Request granted."); ++ return true; ++ } ++ pa_log_info("Request denied."); ++ } catch(const std::exception &e) { ++ pa_log_error("Could not ask Ubuntu touch trust store for permission: %s", ++ e.what()); ++ } catch(...) { ++ pa_log_error("Could not ask Ubuntu touch trust store for permission"); ++ } ++ return false; ++} +Index: pulseaudio/src/modules/trust-store/truststore.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ pulseaudio/src/modules/trust-store/truststore.h 2015-08-27 15:41:43.819252213 +0200 +@@ -0,0 +1,41 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2015 Canonical Ltd. ++ Written by David Henningsson <[email protected]> ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. ++***/ ++ ++#ifndef footruststorehfoo ++#define footruststorehfoo ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include <pulsecore/creds.h> ++ ++#ifdef HAVE_TRUST_STORE ++PA_C_DECL_BEGIN ++typedef struct pa_trust_store pa_trust_store; ++ ++pa_trust_store* pa_trust_store_new(); ++void pa_trust_store_free(pa_trust_store *ts); ++bool pa_trust_store_check(pa_trust_store *ts, const char *appname, ++ uid_t uid, pid_t pid, const char *description); ++PA_C_DECL_END ++#endif ++ ++#endif +Index: pulseaudio/src/pulsecore/client.c +=================================================================== +--- pulseaudio.orig/src/pulsecore/client.c 2015-08-27 15:41:43.827251983 +0200 ++++ pulseaudio/src/pulsecore/client.c 2015-08-27 15:41:43.819252213 +0200 +@@ -60,7 +60,7 @@ + if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_NEW], data) < 0) + return NULL; + +- c = pa_xnew(pa_client, 1); ++ c = pa_xnew0(pa_client, 1); + c->core = core; + c->proplist = pa_proplist_copy(data->proplist); + c->driver = pa_xstrdup(pa_path_get_filename(data->driver)); +@@ -69,10 +69,6 @@ + c->sink_inputs = pa_idxset_new(NULL, NULL); + c->source_outputs = pa_idxset_new(NULL, NULL); + +- c->userdata = NULL; +- c->kill = NULL; +- c->send_event = NULL; +- + pa_assert_se(pa_idxset_put(core->clients, c, &c->index) >= 0); + + pa_log_info("Created %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME))); +Index: pulseaudio/src/pulsecore/client.h +=================================================================== +--- pulseaudio.orig/src/pulsecore/client.h 2015-08-27 15:41:43.827251983 +0200 ++++ pulseaudio/src/pulsecore/client.h 2015-08-27 15:41:43.819252213 +0200 +@@ -27,6 +27,7 @@ + #include <pulse/proplist.h> + #include <pulsecore/core.h> + #include <pulsecore/module.h> ++#include <pulsecore/creds.h> + + /* Every connection to the server should have a pa_client + * attached. That way the user may generate a listing of all connected +@@ -36,6 +37,9 @@ + uint32_t index; + pa_core *core; + ++ pa_creds creds; ++ bool creds_valid; ++ + pa_proplist *proplist; + pa_module *module; + char *driver; +Index: pulseaudio/src/pulsecore/creds.h +=================================================================== +--- pulseaudio.orig/src/pulsecore/creds.h 2015-08-27 15:41:43.827251983 +0200 ++++ pulseaudio/src/pulsecore/creds.h 2015-08-27 15:41:43.819252213 +0200 +@@ -41,6 +41,7 @@ + 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 +Index: pulseaudio/src/pulsecore/iochannel.c +=================================================================== +--- pulseaudio.orig/src/pulsecore/iochannel.c 2015-08-27 15:41:43.827251983 +0200 ++++ pulseaudio/src/pulsecore/iochannel.c 2015-08-27 15:41:43.819252213 +0200 +@@ -323,6 +323,7 @@ + + u = (struct ucred*) CMSG_DATA(&cmsg.hdr); + ++ /* FIXME: Check whether ucred->pid should be used */ + u->pid = getpid(); + if (ucred) { + u->uid = ucred->uid; +@@ -437,6 +438,7 @@ + + 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) { +Index: pulseaudio/src/pulsecore/protocol-native.c +=================================================================== +--- pulseaudio.orig/src/pulsecore/protocol-native.c 2015-08-27 15:41:43.827251983 +0200 ++++ pulseaudio/src/pulsecore/protocol-native.c 2015-08-27 15:41:43.823252098 +0200 +@@ -2811,6 +2811,13 @@ + 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 +@@ -5623,6 +5630,7 @@ + } 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); + +@@ -5631,6 +5639,11 @@ + 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); +Index: pulseaudio/src/tests/connect-stress.c +=================================================================== +--- pulseaudio.orig/src/tests/connect-stress.c 2015-08-27 15:41:43.827251983 +0200 ++++ pulseaudio/src/tests/connect-stress.c 2015-08-27 15:41:43.823252098 +0200 +@@ -63,7 +63,7 @@ + + static void context_state_callback(pa_context *c, void *userdata); + +-static void connect(const char *name, int *try) { ++static void connect2(const char *name, int *try) { + int ret; + pa_mainloop_api *api; + +@@ -201,7 +201,7 @@ + streams[i] = NULL; + + for (i = 0; i < NTESTS; i++) { +- connect(bname, &i); ++ connect2(bname, &i); + usleep(rand() % 500000); + disconnect(); + usleep(rand() % 500000); +Index: pulseaudio/po/POTFILES.in +=================================================================== +--- pulseaudio.orig/po/POTFILES.in 2015-08-27 10:22:25.000000000 +0200 ++++ pulseaudio/po/POTFILES.in 2015-08-27 15:55:27.000097715 +0200 +@@ -23,6 +23,7 @@ + src/modules/jack/module-jack-sink.c + src/modules/jack/module-jack-source.c + src/modules/macosx/module-coreaudio-device.c ++src/modules/trust-store/module-trust-store.c + src/modules/module-always-sink.c + src/modules/module-cli.c + src/modules/module-combine.c 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 new file mode 100644 index 0000000..5fc4249 --- /dev/null +++ b/debian/patches/0410-Add-thread-to-activate-trust-store-interface.patch @@ -0,0 +1,111 @@ +From 90dbf1d25e12b9cfc86aecbd02f14a05fd5dca8c Mon Sep 17 00:00:00 2001 +From: Alfonso Sanchez-Beato <[email protected]> +Date: Fri, 7 Aug 2015 09:08:02 +0200 +Subject: [PATCH] Add thread to activate trust-store interface + +--- + src/modules/trust-store/module-trust-store.c | 14 +------------- + src/modules/trust-store/truststore.cc | 19 +++++++++++++++++++ + 2 files changed, 20 insertions(+), 13 deletions(-) + +diff --git a/src/modules/trust-store/module-trust-store.c b/src/modules/trust-store/module-trust-store.c +index 5a3dd0b..0fb27e0 100644 +--- a/src/modules/trust-store/module-trust-store.c ++++ b/src/modules/trust-store/module-trust-store.c +@@ -27,6 +27,7 @@ + #include <pulsecore/fdsem.h> + #include <pulsecore/thread.h> + #include <pulsecore/core-util.h> ++#include <pulsecore/dynarray.h> + #include <pulse/mainloop-api.h> + + #include "module-trust-store-symdef.h" +@@ -168,18 +169,6 @@ static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, st + return PA_HOOK_CANCEL; + } + +-/* Test code - remove from final product */ +-static void test(struct userdata *u) { +- uint32_t dummy; +- pa_client *client; +- +- PA_IDXSET_FOREACH(client, u->core->clients, dummy) { +- if (client->creds_valid) +- pa_trust_store_check(u->ts, "The evil app", client->creds.uid, +- client->creds.pid, "%1% wants to eat your laundry."); +- } +-} +- + int pa__init(pa_module *m) { + struct userdata *u; + pa_trust_store *ts = pa_trust_store_new(); +@@ -199,7 +188,6 @@ int pa__init(pa_module *m) { + pa_fdsem_get(u->fdsem), PA_IO_EVENT_INPUT, check_fdsem, u)); + pa_fdsem_before_poll(u->fdsem); + +- test(u); + return 0; + } + +diff --git a/src/modules/trust-store/truststore.cc b/src/modules/trust-store/truststore.cc +index ee09038..8645ce5 100644 +--- a/src/modules/trust-store/truststore.cc ++++ b/src/modules/trust-store/truststore.cc +@@ -4,6 +4,7 @@ + + #include <memory> + #include <core/dbus/bus.h> ++#include <core/dbus/asio/executor.h> + #include <core/trust/dbus_agent.h> + #include <core/trust/agent.h> + +@@ -13,6 +14,7 @@ PA_C_DECL_BEGIN + #include <pulsecore/core-util.h> + #include <pulse/xmalloc.h> + #include <pulsecore/log.h> ++#include <pulsecore/thread.h> + + #include "truststore.h" + PA_C_DECL_END +@@ -20,14 +22,27 @@ PA_C_DECL_END + class TrustStore { + public: + std::shared_ptr<core::trust::Agent> agent; ++ std::shared_ptr<core::dbus::Bus> bus; ++ pa_thread *thread; + }; + ++static void thread_func(void *data) { ++ class TrustStore *ts = (class TrustStore *) data; ++ ++ ts->bus->run(); ++} ++ + pa_trust_store* pa_trust_store_new() { + try { + auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session); ++ bus->install_executor(core::dbus::asio::make_executor(bus)); ++ + auto agent = core::trust::dbus::create_multi_user_agent_for_bus_connection(bus, "PulseAudio"); + auto ts = new TrustStore(); + ts->agent = agent; ++ ts->bus = bus; ++ ts->thread = pa_thread_new("trust-store-bus", thread_func, ts); ++ + return (pa_trust_store *) ts; + } catch(const std::exception &e) { + pa_log_error("Could not create Ubuntu touch trust store connection: %s", +@@ -41,6 +56,10 @@ pa_trust_store* pa_trust_store_new() { + void pa_trust_store_free(pa_trust_store *t) { + pa_assert(t != NULL); + auto ts = (TrustStore*) t; ++ if (ts->thread) { ++ ts->bus->stop(); ++ pa_thread_free(ts->thread); ++ } + delete ts; + } + +-- +2.1.4 + diff --git a/debian/patches/0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch b/debian/patches/0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch new file mode 100644 index 0000000..459d9a8 --- /dev/null +++ b/debian/patches/0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch @@ -0,0 +1,62 @@ +From 360cb6550e6558606091ac8c64028ed9872ba6f9 Mon Sep 17 00:00:00 2001 +From: Tanu Kaskinen <[email protected]> +Date: Wed, 7 Jan 2015 16:56:50 +0200 +Subject: [PATCH 4/4] dynarray: Add PA_DYNARRAY_FOREACH + +The PA_DYNARRAY_FOREACH macro requires that pa_dynarray_get() returns +NULL if the index is out of bounds. +--- + src/pulsecore/dynarray.c | 4 +++- + src/pulsecore/dynarray.h | 5 +++++ + src/pulsecore/tokenizer.c | 3 --- + 3 files changed, 8 insertions(+), 4 deletions(-) + +Index: pulseaudio/src/pulsecore/dynarray.c +=================================================================== +--- pulseaudio.orig/src/pulsecore/dynarray.c 2015-08-27 17:22:56.068175130 +0200 ++++ pulseaudio/src/pulsecore/dynarray.c 2015-08-27 17:22:56.060175027 +0200 +@@ -72,7 +72,9 @@ + + void *pa_dynarray_get(pa_dynarray *array, unsigned i) { + pa_assert(array); +- pa_assert(i < array->n_entries); ++ ++ if (i >= array->n_entries) ++ return NULL; + + return array->data[i]; + } +Index: pulseaudio/src/pulsecore/dynarray.h +=================================================================== +--- pulseaudio.orig/src/pulsecore/dynarray.h 2015-08-27 17:22:56.068175130 +0200 ++++ pulseaudio/src/pulsecore/dynarray.h 2015-08-27 17:22:56.060175027 +0200 +@@ -46,6 +46,8 @@ + void pa_dynarray_free(pa_dynarray *array); + + void pa_dynarray_append(pa_dynarray *array, void *p); ++ ++/* Returns the element at index i, or NULL if i is out of bounds. */ + void *pa_dynarray_get(pa_dynarray *array, unsigned i); + + /* Returns the removed item, or NULL if the array is empty. */ +@@ -53,4 +55,7 @@ + + unsigned pa_dynarray_size(pa_dynarray *array); + ++#define PA_DYNARRAY_FOREACH(elem, array, idx) \ ++ for ((idx) = 0; ((elem) = pa_dynarray_get(array, idx)); (idx)++) ++ + #endif +Index: pulseaudio/src/pulsecore/tokenizer.c +=================================================================== +--- pulseaudio.orig/src/pulsecore/tokenizer.c 2015-08-27 17:22:56.068175130 +0200 ++++ pulseaudio/src/pulsecore/tokenizer.c 2015-08-27 17:22:56.060175027 +0200 +@@ -78,8 +78,5 @@ + + pa_assert(a); + +- if (i >= pa_dynarray_size(a)) +- return NULL; +- + return pa_dynarray_get(a, i); + } diff --git a/debian/patches/0417-increase-timeout-check-apparmor.patch b/debian/patches/0417-increase-timeout-check-apparmor.patch new file mode 100644 index 0000000..5dd2c8a --- /dev/null +++ b/debian/patches/0417-increase-timeout-check-apparmor.patch @@ -0,0 +1,92 @@ +--- a/src/modules/trust-store/module-trust-store.c ++++ b/src/modules/trust-store/module-trust-store.c +@@ -31,6 +31,8 @@ + #include <pulsecore/dynarray.h> + #include <pulse/mainloop-api.h> + ++#include <sys/apparmor.h> ++ + #include "module-trust-store-symdef.h" + + PA_MODULE_AUTHOR("David Henningsson"); +@@ -76,9 +78,37 @@ + } + + pc = pa_xnew0(struct per_client, 1); +- // TODO: Do we need something else than the application name here - +- // the application can probably spoof it +- pc->appname = pa_xstrdup(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)); ++ ++ pa_log_info("Client application name is: '%s'", pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)); ++ ++ // ask apparmor about the context of the client, later this will be used to decide if the ++ // app should be or not using the trust store ++ ++ if (aa_is_enabled()) { ++ char *context = NULL; ++ char *mode = NULL; ++ ++ /* XXX: The mode string is *NOT* be freed since it forms ++ * part of the allocation returned in context. ++ * ++ * See aa_gettaskcon(2) for details. ++ */ ++ if (aa_gettaskcon (client->creds.pid, &context, &mode) >= 0) { ++ pc->appname = pa_xstrdup(context); ++ pa_log_info("Client apparmor profile is: '%s'", context); ++ } else { ++ pa_log_error("AppArmo profile could not be retrieved."); ++ } ++ ++ if (context) ++ free(context); ++ ++ } else { ++ // while we do leave the appname as empty if we fail, if apparmor is not present we should ++ // assume that the app is not confined ++ pc->appname = pa_xstrdup("unconfined"); ++ } ++ + pc->index = client_index; + pc->uid = client->creds.uid; + pc->pid = client->creds.pid; +@@ -102,10 +132,25 @@ + static void thread_func(void *data) { + struct per_client *pc = data; + +- bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid, +- _("%1% wants to record audio.")); ++ // there are 3 possible values for the app name that we will consider at this point ++ // * empty string: there was an error when retrieving the value and therefore we will ++ // automatically deny access ++ // * uncofined: the app is unconfined and therefore we will automatically grant access ++ // * appname: we need the user to decide what to do. ++ ++ if (pc->appname == NULL) { ++ pa_log_info("Client apparmor could not retrieved."); ++ pa_atomic_store(&pc->result, REQUEST_DENIED); ++ } else if (pa_streq(pc->appname, "unconfined")) { ++ pa_log_info("Conected client is unconfined."); ++ pa_atomic_store(&pc->result, REQUEST_GRANTED); ++ } else { ++ pa_log_info("User needs to authorize the application.."); ++ bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid, ++ _("%1% wants to record audio.")); ++ pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED); ++ } + +- pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED); + pa_fdsem_post(pc->userdata->fdsem); + } + +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -2122,7 +2122,7 @@ + libtruststore_util_la_LDFLAGS = -avoid-version + + module_trust_store_la_SOURCES = modules/trust-store/module-trust-store.c +-module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS) ++module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS) -lapparmor + module_trust_store_la_LIBADD = $(MODULE_LIBADD) libtruststore-util.la + module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1 + endif diff --git a/debian/patches/series b/debian/patches/series index 373b53c..f14c4ca 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -30,3 +30,13 @@ 0309-resampler-Allow-disabling-the-LFE-filter-by-setting-.patch 0310-resampler-Rename-lfe_filter_required-to-lfe_remixed.patch 0311-tests-add-tolerant-variation-for-comparing-the-rewin.patch + +# Ubuntu touch: support for trust-store +0406-tagstruct-add-copy-method.patch +0407-access-Add-access-control-hooks.patch +0408-protocol-native-add-access-checks.patch +0409-Trust-store-patch.patch +0410-Add-thread-to-activate-trust-store-interface.patch +0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch +0417-increase-timeout-check-apparmor.patch + -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-pulseaudio/pulseaudio.git _______________________________________________ pkg-pulseaudio-devel mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-pulseaudio-devel

