Merge lp:~jamesh/mediascanner2/dbus-apparmor into lp:mediascanner2

Proposed by James Henstridge
Status: Merged
Merged at revision: 232
Proposed branch: lp:~jamesh/mediascanner2/dbus-apparmor
Merge into: lp:mediascanner2
Prerequisite: lp:~jamesh/mediascanner2/dbus-transport
Diff against target: 276 lines (+122/-10)
6 files modified
CMakeLists.txt (+1/-0)
debian/control (+1/-0)
src/ms-dbus/CMakeLists.txt (+5/-2)
src/ms-dbus/dbus-interface.hh (+7/-0)
src/ms-dbus/service-skeleton.cc (+105/-6)
test/CMakeLists.txt (+3/-2)
To merge this branch: bzr merge lp:~jamesh/mediascanner2/dbus-apparmor
Reviewer Review Type Date Requested Status
Tyler Hicks (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Jussi Pakkanen (community) Approve
Review via email: mp+221058@code.launchpad.net

Commit message

Limit access to the MediaScanner D-Bus interface from confined processes.

The trust-store API does not exist yet, so it just hard codes support for the "com.ubuntu.music" application.

Description of the change

Limit access to the MediaScanner D-Bus interface from confined processes.

This is roughly based on the equivalent code from media-hub:

http://bazaar.launchpad.net/~phablet-team/media-hub/trunk/view/head:/src/core/media/player_skeleton.cpp#L135

The trust-store API does not exist yet, so it just hard codes support for the "com.ubuntu.music" application.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

Not a security expert, but looks fine to me.

review: Approve
257. By James Henstridge

Include a timeout on the QML test.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Tyler Hicks (tyhicks) wrote :

* AppArmor related review comments that need fixing
  - media-hub limits access for the "com.ubuntu.music" application to
    /home/phablet/{Music,Videos}
    + http://bazaar.launchpad.net/~phablet-team/media-hub/media-hub-condensed/view/head:/src/core/media/player_skeleton.cpp#L200
    + MediaScanner should probably do the same thing
    + However, note that mediahub is currently not doing this quite right since
      the path should *equal* /home/phablet/Music or /home/phablet/Vidoes,
      rather than just containing the strings Music/ or Videos/

* AppArmor related review comments that should be fixed but are non-blockers
  - You may want to make the handling of GetConnectionAppArmorSecurityContext()
    more robust
    + When AppArmor is disabled in the kernel or in dbus-daemon,
      GetConnectionAppArmorSecurityContext() will return the
      DBUS_ERROR_APPARMOR_SECURITY_CONTEXT_UNKNOWN error
    + In the current merge proposal, this will always result in the client
      being denied access
    + We may want to link against libapparmor to call aa_is_enabled() and, if
      AppArmor is disabled, always grant access before even calling
      GetConnectionAppArmorSecurityContext()
  - does_client_have_access() is very Ubuntu Touch centric
    + Some confined clients may not be Click Apps, so they may not contains '_'
      chars in their AppArmor confinement context
    + This is fine for now, but in the future we will want to handle
      applications that are applications that are confined by AppArmor but are
      not Click Apps

* Minor things that caught my eye
  - The bus variable in get_client_apparmor_context() is unused
  - The MediaType parameter in does_client_have_access() is unused
    + Because of this, the MediaType parameter of check_access is also unused

review: Needs Fixing
258. By James Henstridge

If apparmor is not enabled, treat d-bus peers as unconfined.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
James Henstridge (jamesh) wrote :

> * AppArmor related review comments that need fixing
> - media-hub limits access for the "com.ubuntu.music" application to
> /home/phablet/{Music,Videos}
> + http://bazaar.launchpad.net/~phablet-team/media-hub/media-hub-
> condensed/view/head:/src/core/media/player_skeleton.cpp#L200
> + MediaScanner should probably do the same thing
> + However, note that mediahub is currently not doing this quite right
> since
> the path should *equal* /home/phablet/Music or /home/phablet/Vidoes,
> rather than just containing the strings Music/ or Videos/

Currently the media scanner is only scanning ~/Music and ~/Videos and external media. Most of the APIs are centred around media types rather than locations though. I'm not sure what the best answer is here.

>
> * AppArmor related review comments that should be fixed but are non-blockers
> - You may want to make the handling of
> GetConnectionAppArmorSecurityContext()
> more robust
> + When AppArmor is disabled in the kernel or in dbus-daemon,
> GetConnectionAppArmorSecurityContext() will return the
> DBUS_ERROR_APPARMOR_SECURITY_CONTEXT_UNKNOWN error
> + In the current merge proposal, this will always result in the client
> being denied access
> + We may want to link against libapparmor to call aa_is_enabled() and, if
> AppArmor is disabled, always grant access before even calling
> GetConnectionAppArmorSecurityContext()
> - does_client_have_access() is very Ubuntu Touch centric
> + Some confined clients may not be Click Apps, so they may not contains
> '_'
> chars in their AppArmor confinement context
> + This is fine for now, but in the future we will want to handle
> applications that are applications that are confined by AppArmor but are
> not Click Apps

I've updated the code to call aa_is_enabled(), and treat peers as unconfined if it returns false. That seems to help get the code through Jenkins (and presumably also Launchpad's builder).

I agree that it would be good to externalise the security policy, but this seems to be the kind of thing media-hub is also doing for now. I'd be happy to change this once we've got an idea of how to do that.

>
> * Minor things that caught my eye
> - The bus variable in get_client_apparmor_context() is unused
> - The MediaType parameter in does_client_have_access() is unused
> + Because of this, the MediaType parameter of check_access is also unused

I've switched the policy over to allowing com.ubuntu.music to access AudioMedia, so the MediaType parameter is now used (I guess I missed this when I got distracted by the Jenkins failure). I've removed the unused bus variable in get_client_apparmor_context().

Revision history for this message
Tyler Hicks (tyhicks) wrote :

Everything looks good to me. Thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-05-29 07:30:29 +0000
3+++ CMakeLists.txt 2014-05-29 07:30:30 +0000
4@@ -16,6 +16,7 @@
5 )
6 pkg_check_modules(GST gstreamer-1.0 gstreamer-pbutils-1.0 REQUIRED)
7 pkg_check_modules(DBUSCPP dbus-cpp REQUIRED)
8+pkg_check_modules(APPARMOR libapparmor REQUIRED)
9 find_package(Threads REQUIRED)
10 find_package(Qt5Core REQUIRED)
11
12
13=== modified file 'debian/control'
14--- debian/control 2014-05-29 07:30:29 +0000
15+++ debian/control 2014-05-29 07:30:30 +0000
16@@ -6,6 +6,7 @@
17 Build-Depends: cmake,
18 dbus,
19 debhelper (>= 9),
20+ libapparmor-dev,
21 libdbus-1-dev,
22 libdbus-cpp-dev (>= 3.0.0),
23 libglib2.0-dev,
24
25=== modified file 'src/ms-dbus/CMakeLists.txt'
26--- src/ms-dbus/CMakeLists.txt 2014-05-29 07:30:29 +0000
27+++ src/ms-dbus/CMakeLists.txt 2014-05-29 07:30:30 +0000
28@@ -1,5 +1,5 @@
29 include_directories(..)
30-add_definitions(${MEDIASCANNER_CFLAGS} ${DBUSCPP_CFLAGS})
31+add_definitions(${MEDIASCANNER_CFLAGS} ${DBUSCPP_CFLAGS} ${APPARMOR_CFLAGS})
32
33 add_library(ms-dbus STATIC
34 dbus-codec.cc
35@@ -7,7 +7,10 @@
36 service-stub.cc
37 )
38
39-target_link_libraries(ms-dbus mediascanner ${DBUSCPP_LDFLAGS})
40+target_link_libraries(ms-dbus
41+ mediascanner
42+ ${DBUSCPP_LDFLAGS}
43+ ${APPARMOR_LDFLAGS})
44 # Compile with -fPIC, since this code is linked into the QML plugin.
45 set_target_properties(ms-dbus PROPERTIES COMPILE_FLAGS "-fPIC")
46
47
48=== modified file 'src/ms-dbus/dbus-interface.hh'
49--- src/ms-dbus/dbus-interface.hh 2014-05-29 07:30:29 +0000
50+++ src/ms-dbus/dbus-interface.hh 2014-05-29 07:30:30 +0000
51@@ -41,6 +41,13 @@
52 return s;
53 }
54 };
55+
56+ struct Unauthorized {
57+ inline static const std::string& name() {
58+ static std::string s = "com.canonical.MediaScanner2.Error.Unauthorized";
59+ return s;
60+ }
61+ };
62 };
63
64 struct Lookup {
65
66=== modified file 'src/ms-dbus/service-skeleton.cc'
67--- src/ms-dbus/service-skeleton.cc 2014-05-29 07:30:29 +0000
68+++ src/ms-dbus/service-skeleton.cc 2014-05-29 07:30:30 +0000
69@@ -3,6 +3,7 @@
70 #include <core/dbus/message.h>
71 #include <core/dbus/object.h>
72 #include <core/dbus/types/object_path.h>
73+#include <sys/apparmor.h>
74
75 #include <mediascanner/Album.hh>
76 #include <mediascanner/MediaFile.hh>
77@@ -17,6 +18,26 @@
78 namespace mediascanner {
79 namespace dbus {
80
81+struct Apparmor {
82+ static const std::string &name() {
83+ static std::string s = "org.freedesktop.DBus";
84+ return s;
85+ }
86+
87+ struct GetConnectionAppArmorSecurityContext {
88+ typedef Apparmor Interface;
89+
90+ static const std::string &name() {
91+ static std::string s = "GetConnectionAppArmorSecurityContext";
92+ return s;
93+ }
94+
95+ static const std::chrono::milliseconds default_timeout() {
96+ return std::chrono::seconds{1};
97+ }
98+ };
99+};
100+
101 struct ServiceSkeleton::Private {
102 ServiceSkeleton *impl;
103 std::shared_ptr<MediaStore> store;
104@@ -69,7 +90,69 @@
105 std::placeholders::_1));
106 }
107
108+ std::string get_client_apparmor_context(const Message::Ptr &message) {
109+ if (!aa_is_enabled()) {
110+ return "unconfined";
111+ }
112+ auto service = core::dbus::Service::use_service(
113+ impl->access_bus(), "org.freedesktop.DBus");
114+ auto obj = service->object_for_path(
115+ core::dbus::types::ObjectPath("/org/freedesktop/DBus"));
116+
117+ core::dbus::Result<std::string> result;
118+ try {
119+ result = obj->invoke_method_synchronously<Apparmor::GetConnectionAppArmorSecurityContext, std::string>(message->sender());
120+ } catch (const std::runtime_error &e) {
121+ fprintf(stderr, "Error getting apparmor context: %s\n", e.what());
122+ return std::string();
123+ }
124+ if (result.is_error()) {
125+ fprintf(stderr, "Error getting apparmor context: %s\n", result.error().print().c_str());
126+ return std::string();
127+ }
128+ return result.value();
129+ }
130+
131+ bool does_client_have_access(const std::string &context, MediaType type) {
132+ if (context.empty()) {
133+ // Deny access if we don't have a context
134+ return false;
135+ }
136+ if (context == "unconfined") {
137+ // Unconfined
138+ return true;
139+ }
140+
141+ auto pos = context.find_first_of('_');
142+ if (pos == std::string::npos) {
143+ fprintf(stderr, "Badly formed AppArmor context: %s\n", context.c_str());
144+ return false;
145+ }
146+ const std::string pkgname = context.substr(0, pos);
147+
148+ // TODO: when the trust store lands, check it to see if this
149+ // app can access the index.
150+ if (type == AudioMedia && pkgname == "com.ubuntu.music") {
151+ return true;
152+ }
153+ return false;
154+ }
155+
156+ bool check_access(const Message::Ptr &message, MediaType type) {
157+ const std::string context = get_client_apparmor_context(message);
158+ bool have_access = does_client_have_access(context, type);
159+ if (!have_access) {
160+ auto reply = Message::make_error(
161+ message, MediaStoreInterface::Errors::Unauthorized::name(), "Unauthorized");
162+ impl->access_bus()->send(reply);
163+ }
164+ return have_access;
165+ }
166+
167 void handle_lookup(const Message::Ptr &message) {
168+ if (!check_access(message, AllMedia))
169+ return;
170+
171 std::string filename;
172 message->reader() >> filename;
173 Message::Ptr reply;
174@@ -89,8 +172,11 @@
175 std::string query;
176 int32_t type;
177 int32_t limit;
178-
179 message->reader() >> query >> type >> limit;
180+
181+ if (!check_access(message, (MediaType)type))
182+ return;
183+
184 Message::Ptr reply;
185 try {
186 auto results = store->query(query, (MediaType)type, limit);
187@@ -105,9 +191,11 @@
188 }
189
190 void handle_query_albums(const Message::Ptr &message) {
191+ if (!check_access(message, AudioMedia))
192+ return;
193+
194 std::string query;
195 int32_t limit;
196-
197 message->reader() >> query >> limit;
198 Message::Ptr reply;
199 try {
200@@ -123,8 +211,10 @@
201 }
202
203 void handle_get_album_songs(const Message::Ptr &message) {
204+ if (!check_access(message, AudioMedia))
205+ return;
206+
207 Album album("", "");
208-
209 message->reader() >> album;
210 Message::Ptr reply;
211 try {
212@@ -140,6 +230,9 @@
213 }
214
215 void handle_get_etag(const Message::Ptr &message) {
216+ if (!check_access(message, AllMedia))
217+ return;
218+
219 std::string filename;
220 message->reader() >> filename;
221
222@@ -157,9 +250,11 @@
223 }
224
225 void handle_list_songs(const Message::Ptr &message) {
226+ if (!check_access(message, AudioMedia))
227+ return;
228+
229 std::string artist, album, album_artist;
230 int32_t limit;
231-
232 message->reader() >> artist >> album >> album_artist >> limit;
233 Message::Ptr reply;
234 try {
235@@ -175,9 +270,11 @@
236 }
237
238 void handle_list_albums(const Message::Ptr &message) {
239+ if (!check_access(message, AudioMedia))
240+ return;
241+
242 std::string artist, album_artist;
243 int32_t limit;
244-
245 message->reader() >> artist >> album_artist >> limit;
246 Message::Ptr reply;
247 try {
248@@ -193,9 +290,11 @@
249 }
250
251 void handle_list_artists(const Message::Ptr &message) {
252+ if (!check_access(message, AudioMedia))
253+ return;
254+
255 bool album_artists;
256 int32_t limit;
257-
258 message->reader() >> album_artists >> limit;
259 Message::Ptr reply;
260 try {
261
262=== modified file 'test/CMakeLists.txt'
263--- test/CMakeLists.txt 2014-05-29 07:30:29 +0000
264+++ test/CMakeLists.txt 2014-05-29 07:30:30 +0000
265@@ -51,8 +51,9 @@
266 qt5_use_modules(test_qml QuickTest)
267 target_link_libraries(test_qml mediascanner ${DBUSCPP_LDFLAGS})
268 add_test(test_qml test_qml -input ${CMAKE_CURRENT_SOURCE_DIR}/qml -import ${CMAKE_BINARY_DIR}/src/qml)
269-set_tests_properties(test_qml
270- PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
271+set_tests_properties(test_qml PROPERTIES
272+ ENVIRONMENT "QT_QPA_PLATFORM=minimal"
273+ TIMEOUT 600)
274
275 add_executable(test_util test_util.cc ../src/daemon/util.cc)
276 target_link_libraries(test_util gtest)

Subscribers

People subscribed via source and target branches