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
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2014-05-29 07:30:29 +0000
+++ CMakeLists.txt 2014-05-29 07:30:30 +0000
@@ -16,6 +16,7 @@
16)16)
17pkg_check_modules(GST gstreamer-1.0 gstreamer-pbutils-1.0 REQUIRED)17pkg_check_modules(GST gstreamer-1.0 gstreamer-pbutils-1.0 REQUIRED)
18pkg_check_modules(DBUSCPP dbus-cpp REQUIRED)18pkg_check_modules(DBUSCPP dbus-cpp REQUIRED)
19pkg_check_modules(APPARMOR libapparmor REQUIRED)
19find_package(Threads REQUIRED)20find_package(Threads REQUIRED)
20find_package(Qt5Core REQUIRED)21find_package(Qt5Core REQUIRED)
2122
2223
=== modified file 'debian/control'
--- debian/control 2014-05-29 07:30:29 +0000
+++ debian/control 2014-05-29 07:30:30 +0000
@@ -6,6 +6,7 @@
6Build-Depends: cmake,6Build-Depends: cmake,
7 dbus,7 dbus,
8 debhelper (>= 9),8 debhelper (>= 9),
9 libapparmor-dev,
9 libdbus-1-dev,10 libdbus-1-dev,
10 libdbus-cpp-dev (>= 3.0.0),11 libdbus-cpp-dev (>= 3.0.0),
11 libglib2.0-dev,12 libglib2.0-dev,
1213
=== modified file 'src/ms-dbus/CMakeLists.txt'
--- src/ms-dbus/CMakeLists.txt 2014-05-29 07:30:29 +0000
+++ src/ms-dbus/CMakeLists.txt 2014-05-29 07:30:30 +0000
@@ -1,5 +1,5 @@
1include_directories(..)1include_directories(..)
2add_definitions(${MEDIASCANNER_CFLAGS} ${DBUSCPP_CFLAGS})2add_definitions(${MEDIASCANNER_CFLAGS} ${DBUSCPP_CFLAGS} ${APPARMOR_CFLAGS})
33
4add_library(ms-dbus STATIC4add_library(ms-dbus STATIC
5 dbus-codec.cc5 dbus-codec.cc
@@ -7,7 +7,10 @@
7 service-stub.cc7 service-stub.cc
8)8)
99
10target_link_libraries(ms-dbus mediascanner ${DBUSCPP_LDFLAGS})10target_link_libraries(ms-dbus
11 mediascanner
12 ${DBUSCPP_LDFLAGS}
13 ${APPARMOR_LDFLAGS})
11# Compile with -fPIC, since this code is linked into the QML plugin.14# Compile with -fPIC, since this code is linked into the QML plugin.
12set_target_properties(ms-dbus PROPERTIES COMPILE_FLAGS "-fPIC")15set_target_properties(ms-dbus PROPERTIES COMPILE_FLAGS "-fPIC")
1316
1417
=== modified file 'src/ms-dbus/dbus-interface.hh'
--- src/ms-dbus/dbus-interface.hh 2014-05-29 07:30:29 +0000
+++ src/ms-dbus/dbus-interface.hh 2014-05-29 07:30:30 +0000
@@ -41,6 +41,13 @@
41 return s;41 return s;
42 }42 }
43 };43 };
44
45 struct Unauthorized {
46 inline static const std::string& name() {
47 static std::string s = "com.canonical.MediaScanner2.Error.Unauthorized";
48 return s;
49 }
50 };
44 };51 };
4552
46 struct Lookup {53 struct Lookup {
4754
=== modified file 'src/ms-dbus/service-skeleton.cc'
--- src/ms-dbus/service-skeleton.cc 2014-05-29 07:30:29 +0000
+++ src/ms-dbus/service-skeleton.cc 2014-05-29 07:30:30 +0000
@@ -3,6 +3,7 @@
3#include <core/dbus/message.h>3#include <core/dbus/message.h>
4#include <core/dbus/object.h>4#include <core/dbus/object.h>
5#include <core/dbus/types/object_path.h>5#include <core/dbus/types/object_path.h>
6#include <sys/apparmor.h>
67
7#include <mediascanner/Album.hh>8#include <mediascanner/Album.hh>
8#include <mediascanner/MediaFile.hh>9#include <mediascanner/MediaFile.hh>
@@ -17,6 +18,26 @@
17namespace mediascanner {18namespace mediascanner {
18namespace dbus {19namespace dbus {
1920
21struct Apparmor {
22 static const std::string &name() {
23 static std::string s = "org.freedesktop.DBus";
24 return s;
25 }
26
27 struct GetConnectionAppArmorSecurityContext {
28 typedef Apparmor Interface;
29
30 static const std::string &name() {
31 static std::string s = "GetConnectionAppArmorSecurityContext";
32 return s;
33 }
34
35 static const std::chrono::milliseconds default_timeout() {
36 return std::chrono::seconds{1};
37 }
38 };
39};
40
20struct ServiceSkeleton::Private {41struct ServiceSkeleton::Private {
21 ServiceSkeleton *impl;42 ServiceSkeleton *impl;
22 std::shared_ptr<MediaStore> store;43 std::shared_ptr<MediaStore> store;
@@ -69,7 +90,69 @@
69 std::placeholders::_1));90 std::placeholders::_1));
70 }91 }
7192
93 std::string get_client_apparmor_context(const Message::Ptr &message) {
94 if (!aa_is_enabled()) {
95 return "unconfined";
96 }
97 auto service = core::dbus::Service::use_service(
98 impl->access_bus(), "org.freedesktop.DBus");
99 auto obj = service->object_for_path(
100 core::dbus::types::ObjectPath("/org/freedesktop/DBus"));
101
102 core::dbus::Result<std::string> result;
103 try {
104 result = obj->invoke_method_synchronously<Apparmor::GetConnectionAppArmorSecurityContext, std::string>(message->sender());
105 } catch (const std::runtime_error &e) {
106 fprintf(stderr, "Error getting apparmor context: %s\n", e.what());
107 return std::string();
108 }
109 if (result.is_error()) {
110 fprintf(stderr, "Error getting apparmor context: %s\n", result.error().print().c_str());
111 return std::string();
112 }
113 return result.value();
114 }
115
116 bool does_client_have_access(const std::string &context, MediaType type) {
117 if (context.empty()) {
118 // Deny access if we don't have a context
119 return false;
120 }
121 if (context == "unconfined") {
122 // Unconfined
123 return true;
124 }
125
126 auto pos = context.find_first_of('_');
127 if (pos == std::string::npos) {
128 fprintf(stderr, "Badly formed AppArmor context: %s\n", context.c_str());
129 return false;
130 }
131 const std::string pkgname = context.substr(0, pos);
132
133 // TODO: when the trust store lands, check it to see if this
134 // app can access the index.
135 if (type == AudioMedia && pkgname == "com.ubuntu.music") {
136 return true;
137 }
138 return false;
139 }
140
141 bool check_access(const Message::Ptr &message, MediaType type) {
142 const std::string context = get_client_apparmor_context(message);
143 bool have_access = does_client_have_access(context, type);
144 if (!have_access) {
145 auto reply = Message::make_error(
146 message, MediaStoreInterface::Errors::Unauthorized::name(), "Unauthorized");
147 impl->access_bus()->send(reply);
148 }
149 return have_access;
150 }
151
72 void handle_lookup(const Message::Ptr &message) {152 void handle_lookup(const Message::Ptr &message) {
153 if (!check_access(message, AllMedia))
154 return;
155
73 std::string filename;156 std::string filename;
74 message->reader() >> filename;157 message->reader() >> filename;
75 Message::Ptr reply;158 Message::Ptr reply;
@@ -89,8 +172,11 @@
89 std::string query;172 std::string query;
90 int32_t type;173 int32_t type;
91 int32_t limit;174 int32_t limit;
92
93 message->reader() >> query >> type >> limit;175 message->reader() >> query >> type >> limit;
176
177 if (!check_access(message, (MediaType)type))
178 return;
179
94 Message::Ptr reply;180 Message::Ptr reply;
95 try {181 try {
96 auto results = store->query(query, (MediaType)type, limit);182 auto results = store->query(query, (MediaType)type, limit);
@@ -105,9 +191,11 @@
105 }191 }
106192
107 void handle_query_albums(const Message::Ptr &message) {193 void handle_query_albums(const Message::Ptr &message) {
194 if (!check_access(message, AudioMedia))
195 return;
196
108 std::string query;197 std::string query;
109 int32_t limit;198 int32_t limit;
110
111 message->reader() >> query >> limit;199 message->reader() >> query >> limit;
112 Message::Ptr reply;200 Message::Ptr reply;
113 try {201 try {
@@ -123,8 +211,10 @@
123 }211 }
124212
125 void handle_get_album_songs(const Message::Ptr &message) {213 void handle_get_album_songs(const Message::Ptr &message) {
214 if (!check_access(message, AudioMedia))
215 return;
216
126 Album album("", "");217 Album album("", "");
127
128 message->reader() >> album;218 message->reader() >> album;
129 Message::Ptr reply;219 Message::Ptr reply;
130 try {220 try {
@@ -140,6 +230,9 @@
140 }230 }
141231
142 void handle_get_etag(const Message::Ptr &message) {232 void handle_get_etag(const Message::Ptr &message) {
233 if (!check_access(message, AllMedia))
234 return;
235
143 std::string filename;236 std::string filename;
144 message->reader() >> filename;237 message->reader() >> filename;
145238
@@ -157,9 +250,11 @@
157 }250 }
158251
159 void handle_list_songs(const Message::Ptr &message) {252 void handle_list_songs(const Message::Ptr &message) {
253 if (!check_access(message, AudioMedia))
254 return;
255
160 std::string artist, album, album_artist;256 std::string artist, album, album_artist;
161 int32_t limit;257 int32_t limit;
162
163 message->reader() >> artist >> album >> album_artist >> limit;258 message->reader() >> artist >> album >> album_artist >> limit;
164 Message::Ptr reply;259 Message::Ptr reply;
165 try {260 try {
@@ -175,9 +270,11 @@
175 }270 }
176271
177 void handle_list_albums(const Message::Ptr &message) {272 void handle_list_albums(const Message::Ptr &message) {
273 if (!check_access(message, AudioMedia))
274 return;
275
178 std::string artist, album_artist;276 std::string artist, album_artist;
179 int32_t limit;277 int32_t limit;
180
181 message->reader() >> artist >> album_artist >> limit;278 message->reader() >> artist >> album_artist >> limit;
182 Message::Ptr reply;279 Message::Ptr reply;
183 try {280 try {
@@ -193,9 +290,11 @@
193 }290 }
194291
195 void handle_list_artists(const Message::Ptr &message) {292 void handle_list_artists(const Message::Ptr &message) {
293 if (!check_access(message, AudioMedia))
294 return;
295
196 bool album_artists;296 bool album_artists;
197 int32_t limit;297 int32_t limit;
198
199 message->reader() >> album_artists >> limit;298 message->reader() >> album_artists >> limit;
200 Message::Ptr reply;299 Message::Ptr reply;
201 try {300 try {
202301
=== modified file 'test/CMakeLists.txt'
--- test/CMakeLists.txt 2014-05-29 07:30:29 +0000
+++ test/CMakeLists.txt 2014-05-29 07:30:30 +0000
@@ -51,8 +51,9 @@
51qt5_use_modules(test_qml QuickTest)51qt5_use_modules(test_qml QuickTest)
52target_link_libraries(test_qml mediascanner ${DBUSCPP_LDFLAGS})52target_link_libraries(test_qml mediascanner ${DBUSCPP_LDFLAGS})
53add_test(test_qml test_qml -input ${CMAKE_CURRENT_SOURCE_DIR}/qml -import ${CMAKE_BINARY_DIR}/src/qml)53add_test(test_qml test_qml -input ${CMAKE_CURRENT_SOURCE_DIR}/qml -import ${CMAKE_BINARY_DIR}/src/qml)
54set_tests_properties(test_qml54set_tests_properties(test_qml PROPERTIES
55 PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")55 ENVIRONMENT "QT_QPA_PLATFORM=minimal"
56 TIMEOUT 600)
5657
57add_executable(test_util test_util.cc ../src/daemon/util.cc)58add_executable(test_util test_util.cc ../src/daemon/util.cc)
58target_link_libraries(test_util gtest)59target_link_libraries(test_util gtest)

Subscribers

People subscribed via source and target branches