Merge lp:~thomas-voss/trust-store/fix-1518883 into lp:trust-store/15.04

Proposed by Thomas Voß
Status: Merged
Approved by: Alberto Mardegan
Approved revision: 139
Merged at revision: 138
Proposed branch: lp:~thomas-voss/trust-store/fix-1518883
Merge into: lp:trust-store/15.04
Diff against target: 439 lines (+291/-18)
10 files modified
po/de.po (+5/-5)
po/ne.po (+31/-0)
po/sr.po (+5/-5)
src/CMakeLists.txt (+3/-0)
src/core/trust/daemon.cpp (+6/-1)
src/core/trust/mir/agent.cpp (+0/-7)
src/core/trust/privilege_escalation_prevention_agent.cpp (+52/-0)
src/core/trust/privilege_escalation_prevention_agent.h (+63/-0)
tests/CMakeLists.txt (+20/-0)
tests/privilege_escalation_prevention_agent_test.cpp (+106/-0)
To merge this branch: bzr merge lp:~thomas-voss/trust-store/fix-1518883
Reviewer Review Type Date Requested Status
Alberto Mardegan (community) Approve
PS Jenkins bot continuous-integration Pending
Review via email: mp+278416@code.launchpad.net

This proposal supersedes a proposal from 2015-11-23.

Commit message

Introduce a trust::PrivilegeEscalationPreventionAgent, filtering out invalid requests. Fixes lp:#1518883.

Description of the change

Introduce a trust::PrivilegeEscalationPreventionAgent, filtering out invalid requests. Fixes lp:#1518883.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
139. By Thomas Voß

Remove obsolote check in mir::Agent.

Revision history for this message
Alberto Mardegan (mardy) wrote :

LGTM!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'po/de.po'
--- po/de.po 2015-09-03 05:40:47 +0000
+++ po/de.po 2015-11-27 12:18:10 +0000
@@ -6,20 +6,20 @@
6"Project-Id-Version: trust-store\n"6"Project-Id-Version: trust-store\n"
7"Report-Msgid-Bugs-To: \n"7"Report-Msgid-Bugs-To: \n"
8"POT-Creation-Date: 2015-08-20 13:41-0400\n"8"POT-Creation-Date: 2015-08-20 13:41-0400\n"
9"PO-Revision-Date: 2015-09-02 16:46+0000\n"9"PO-Revision-Date: 2015-11-07 21:39+0000\n"
10"Last-Translator: Tobias Bannert <Unknown>\n"10"Last-Translator: Niklas Wenzel <nikwen.developer@gmail.com>\n"
11"Language-Team: \n"11"Language-Team: \n"
12"MIME-Version: 1.0\n"12"MIME-Version: 1.0\n"
13"Content-Type: text/plain; charset=UTF-8\n"13"Content-Type: text/plain; charset=UTF-8\n"
14"Content-Transfer-Encoding: 8bit\n"14"Content-Transfer-Encoding: 8bit\n"
15"X-Launchpad-Export-Date: 2015-09-03 05:40+0000\n"15"X-Launchpad-Export-Date: 2015-11-08 05:46+0000\n"
16"X-Generator: Launchpad (build 17706)\n"16"X-Generator: Launchpad (build 17838)\n"
17"Language: de\n"17"Language: de\n"
1818
19#: /tmp/trust-store-i18n/src/core/trust/daemon.cpp:26519#: /tmp/trust-store-i18n/src/core/trust/daemon.cpp:265
20#, boost-format20#, boost-format
21msgid "Application %1% is trying to access"21msgid "Application %1% is trying to access"
22msgstr "Anwendung %1% versucht zugreifen"22msgstr "Anwendung »%1%« versucht, zuzugreifen auf"
2323
24#: /tmp/trust-store-i18n/src/core/trust/mir/prompt_main.qml:4224#: /tmp/trust-store-i18n/src/core/trust/mir/prompt_main.qml:42
25msgid "Deny"25msgid "Deny"
2626
=== added file 'po/ne.po'
--- po/ne.po 1970-01-01 00:00:00 +0000
+++ po/ne.po 2015-11-27 12:18:10 +0000
@@ -0,0 +1,31 @@
1# Nepali translation for trust-store
2# Copyright (c) 2015 Rosetta Contributors and Canonical Ltd 2015
3# This file is distributed under the same license as the trust-store package.
4# FIRST AUTHOR <EMAIL@ADDRESS>, 2015.
5#
6msgid ""
7msgstr ""
8"Project-Id-Version: trust-store\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2015-08-20 13:41-0400\n"
11"PO-Revision-Date: 2015-11-04 15:47+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Language-Team: Nepali <ne@li.org>\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2015-11-05 05:46+0000\n"
18"X-Generator: Launchpad (build 17838)\n"
19
20#: /tmp/trust-store-i18n/src/core/trust/daemon.cpp:265
21#, boost-format
22msgid "Application %1% is trying to access"
23msgstr ""
24
25#: /tmp/trust-store-i18n/src/core/trust/mir/prompt_main.qml:42
26msgid "Deny"
27msgstr ""
28
29#: /tmp/trust-store-i18n/src/core/trust/mir/prompt_main.qml:49
30msgid "Allow"
31msgstr ""
032
=== modified file 'po/sr.po'
--- po/sr.po 2015-08-22 05:53:55 +0000
+++ po/sr.po 2015-11-27 12:18:10 +0000
@@ -8,19 +8,19 @@
8"Project-Id-Version: trust-store\n"8"Project-Id-Version: trust-store\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2015-08-20 13:41-0400\n"10"POT-Creation-Date: 2015-08-20 13:41-0400\n"
11"PO-Revision-Date: 2014-11-07 04:09+0000\n"11"PO-Revision-Date: 2015-10-26 21:49+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"12"Last-Translator: Данило Шеган <Unknown>\n"
13"Language-Team: Serbian <sr@li.org>\n"13"Language-Team: Serbian <sr@li.org>\n"
14"MIME-Version: 1.0\n"14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2015-08-22 05:53+0000\n"17"X-Launchpad-Export-Date: 2015-10-28 05:56+0000\n"
18"X-Generator: Launchpad (build 17690)\n"18"X-Generator: Launchpad (build 17833)\n"
1919
20#: /tmp/trust-store-i18n/src/core/trust/daemon.cpp:26520#: /tmp/trust-store-i18n/src/core/trust/daemon.cpp:265
21#, boost-format21#, boost-format
22msgid "Application %1% is trying to access"22msgid "Application %1% is trying to access"
23msgstr ""23msgstr "Програм %1% покушава да приступи"
2424
25#: /tmp/trust-store-i18n/src/core/trust/mir/prompt_main.qml:4225#: /tmp/trust-store-i18n/src/core/trust/mir/prompt_main.qml:42
26msgid "Deny"26msgid "Deny"
2727
=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 2015-08-31 13:16:20 +0000
+++ src/CMakeLists.txt 2015-11-27 12:18:10 +0000
@@ -43,6 +43,9 @@
43 core/trust/app_id_formatting_trust_agent.h43 core/trust/app_id_formatting_trust_agent.h
44 core/trust/app_id_formatting_trust_agent.cpp44 core/trust/app_id_formatting_trust_agent.cpp
4545
46 # An agent implementation preventing privilege escalation attacks.
47 core/trust/privilege_escalation_prevention_agent.cpp
48
46 # An agent-implementation that allows for selectively whitelisting app ids49 # An agent-implementation that allows for selectively whitelisting app ids
47 core/trust/white_listing_agent.cpp50 core/trust/white_listing_agent.cpp
48 # An agent-implementation using a store instance to cache user replies.51 # An agent-implementation using a store instance to cache user replies.
4952
=== modified file 'src/core/trust/daemon.cpp'
--- src/core/trust/daemon.cpp 2015-08-31 14:00:41 +0000
+++ src/core/trust/daemon.cpp 2015-11-27 12:18:10 +0000
@@ -22,6 +22,7 @@
22#include <core/trust/cached_agent.h>22#include <core/trust/cached_agent.h>
23#include <core/trust/expose.h>23#include <core/trust/expose.h>
24#include <core/trust/i18n.h>24#include <core/trust/i18n.h>
25#include <core/trust/privilege_escalation_prevention_agent.h>
25#include <core/trust/store.h>26#include <core/trust/store.h>
26#include <core/trust/white_listing_agent.h>27#include <core/trust/white_listing_agent.h>
2728
@@ -375,6 +376,10 @@
375 }, cached_agent);376 }, cached_agent);
376377
377 auto formatting_agent = std::make_shared<core::trust::AppIdFormattingTrustAgent>(whitelisting_agent);378 auto formatting_agent = std::make_shared<core::trust::AppIdFormattingTrustAgent>(whitelisting_agent);
379
380 auto privilege_escalation_prevention_agent = std::make_shared<core::trust::PrivilegeEscalationPreventionAgent>(
381 core::trust::PrivilegeEscalationPreventionAgent::default_user_id_functor(),
382 formatting_agent);
378383
379 auto remote_agent = remote_agent_factory(service_name, formatting_agent, dict);384 auto remote_agent = remote_agent_factory(service_name, formatting_agent, dict);
380385
@@ -382,7 +387,7 @@
382 {387 {
383 service_name,388 service_name,
384 bus_from_name(vm[Parameters::StoreBus::name].as<std::string>()),389 bus_from_name(vm[Parameters::StoreBus::name].as<std::string>()),
385 {local_store, formatting_agent},390 {local_store, privilege_escalation_prevention_agent},
386 {remote_agent}391 {remote_agent}
387 };392 };
388}393}
389394
=== modified file 'src/core/trust/mir/agent.cpp'
--- src/core/trust/mir/agent.cpp 2015-08-31 13:16:20 +0000
+++ src/core/trust/mir/agent.cpp 2015-11-27 12:18:10 +0000
@@ -236,13 +236,6 @@
236// From core::trust::Agent:236// From core::trust::Agent:
237core::trust::Request::Answer mir::Agent::authenticate_request_with_parameters(const core::trust::Agent::RequestParameters& parameters)237core::trust::Request::Answer mir::Agent::authenticate_request_with_parameters(const core::trust::Agent::RequestParameters& parameters)
238{238{
239 // We assume that the agent implementation runs under the same user id as
240 // the requesting app to prevent from cross-user attacks.
241 if (core::trust::Uid{::getuid()} != parameters.application.uid) throw std::logic_error
242 {
243 "mir::Agent::prompt_user_for_request: current user id does not match requesting app's user id"
244 };
245
246 // We initialize our callback context with an invalid child-process for setup239 // We initialize our callback context with an invalid child-process for setup
247 // purposes. Later on, once we have acquired a pre-authenticated fd for the240 // purposes. Later on, once we have acquired a pre-authenticated fd for the
248 // prompt provider, we exec the actual provider in a child process and replace the241 // prompt provider, we exec the actual provider in a child process and replace the
249242
=== added file 'src/core/trust/privilege_escalation_prevention_agent.cpp'
--- src/core/trust/privilege_escalation_prevention_agent.cpp 1970-01-01 00:00:00 +0000
+++ src/core/trust/privilege_escalation_prevention_agent.cpp 2015-11-27 12:18:10 +0000
@@ -0,0 +1,52 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Thomas Voß <thomas.voss@canonical.com>
17 */
18
19#include <core/trust/privilege_escalation_prevention_agent.h>
20
21#include <unistd.h>
22#include <sys/types.h>
23
24core::trust::PrivilegeEscalationPreventionAgent::Error::Error() : std::runtime_error{"Potential privilege escalation attack detected."}
25{
26}
27
28core::trust::PrivilegeEscalationPreventionAgent::UserIdFunctor core::trust::PrivilegeEscalationPreventionAgent::default_user_id_functor()
29{
30 return []()
31 {
32 return core::trust::Uid{::getuid()};
33 };
34}
35
36core::trust::PrivilegeEscalationPreventionAgent::PrivilegeEscalationPreventionAgent(
37 const UserIdFunctor& uid_functor,
38 const std::shared_ptr<core::trust::Agent>& impl)
39 : uid_functor{uid_functor},
40 impl{impl}
41{
42 if (not impl) throw std::runtime_error
43 {
44 "Missing agent implementation."
45 };
46}
47
48core::trust::Request::Answer core::trust::PrivilegeEscalationPreventionAgent::authenticate_request_with_parameters(const core::trust::Agent::RequestParameters& parameters)
49{
50 if (uid_functor() != parameters.application.uid) throw Error{};
51 return impl->authenticate_request_with_parameters(parameters);
52}
053
=== added file 'src/core/trust/privilege_escalation_prevention_agent.h'
--- src/core/trust/privilege_escalation_prevention_agent.h 1970-01-01 00:00:00 +0000
+++ src/core/trust/privilege_escalation_prevention_agent.h 2015-11-27 12:18:10 +0000
@@ -0,0 +1,63 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Thomas Voß <thomas.voss@canonical.com>
17 */
18
19#ifndef CORE_TRUST_PRIVILEGE_ESCALATION_PREVENTION_AGENT_H_
20#define CORE_TRUST_PRIVILEGE_ESCALATION_PREVENTION_AGENT_H_
21
22#include <core/trust/agent.h>
23
24#include <stdexcept>
25
26namespace core
27{
28namespace trust
29{
30// A PrivilegeEscalationPreventionAgent ensures that requests originating from an application
31// running under a different user than the current one are rejected immediately, thereby preventing
32// from privilege escalation issues.
33class CORE_TRUST_DLL_PUBLIC PrivilegeEscalationPreventionAgent : public core::trust::Agent
34{
35public:
36 // An Error is thrown if a potential privilege escalation attack has been detected.
37 struct Error : public std::runtime_error
38 {
39 // Error creates an instance, providing details about the escalation issue.
40 Error();
41 };
42
43 // A UserIdFunctor queries the user id under which the current process runs.
44 typedef std::function<Uid()> UserIdFunctor;
45
46 // default_user_id_functor returns a UserIdFunctor querying the current user id from the system.
47 static UserIdFunctor default_user_id_functor();
48
49 // PrivilegeEscalationPreventionAgent creates a new instance that queries the current user,
50 // forwarding valid requests to impl.
51 PrivilegeEscalationPreventionAgent(const UserIdFunctor& uid_functor, const std::shared_ptr<Agent>& impl);
52
53 // From core::trust::Agent
54 Request::Answer authenticate_request_with_parameters(const RequestParameters& parameters) override;
55
56private:
57 UserIdFunctor uid_functor;
58 std::shared_ptr<Agent> impl;
59};
60}
61}
62
63#endif // CORE_TRUST_PRIVILEGE_ESCALATION_PREVENTION_AGENT_H_
064
=== modified file 'tests/CMakeLists.txt'
--- tests/CMakeLists.txt 2014-11-14 12:17:24 +0000
+++ tests/CMakeLists.txt 2015-11-27 12:18:10 +0000
@@ -59,6 +59,11 @@
59)59)
6060
61add_executable(61add_executable(
62 privilege_escalation_prevention_agent_test
63 privilege_escalation_prevention_agent_test.cpp
64)
65
66add_executable(
62 cached_agent_test67 cached_agent_test
63 cached_agent_test.cpp68 cached_agent_test.cpp
64)69)
@@ -166,6 +171,20 @@
166)171)
167172
168target_link_libraries(173target_link_libraries(
174 privilege_escalation_prevention_agent_test
175
176 trust-store
177
178 gmock
179
180 gtest
181 gtest_main
182
183 ${PROCESS_CPP_LIBRARIES}
184)
185
186
187target_link_libraries(
169 cached_agent_test188 cached_agent_test
170189
171 trust-store190 trust-store
@@ -226,6 +245,7 @@
226add_test(app_id_formatting_trust_agent_test ${CMAKE_CURRENT_BINARY_DIR}/app_id_formatting_trust_agent_test)245add_test(app_id_formatting_trust_agent_test ${CMAKE_CURRENT_BINARY_DIR}/app_id_formatting_trust_agent_test)
227add_test(cached_agent_test ${CMAKE_CURRENT_BINARY_DIR}/cached_agent_test)246add_test(cached_agent_test ${CMAKE_CURRENT_BINARY_DIR}/cached_agent_test)
228add_test(white_listing_agent_test ${CMAKE_CURRENT_BINARY_DIR}/white_listing_agent_test)247add_test(white_listing_agent_test ${CMAKE_CURRENT_BINARY_DIR}/white_listing_agent_test)
248add_test(privilege_escalation_prevention_agent_test ${CMAKE_CURRENT_BINARY_DIR}/privilege_escalation_prevention_agent_test)
229# TODO(tvoss) Re-enable daemon tests once CI issues are resolved.249# TODO(tvoss) Re-enable daemon tests once CI issues are resolved.
230# add_test(daemon_test ${CMAKE_CURRENT_BINARY_DIR}/daemon_test)250# add_test(daemon_test ${CMAKE_CURRENT_BINARY_DIR}/daemon_test)
231add_test(dbus_test ${CMAKE_CURRENT_BINARY_DIR}/dbus_test)251add_test(dbus_test ${CMAKE_CURRENT_BINARY_DIR}/dbus_test)
232252
=== added file 'tests/privilege_escalation_prevention_agent_test.cpp'
--- tests/privilege_escalation_prevention_agent_test.cpp 1970-01-01 00:00:00 +0000
+++ tests/privilege_escalation_prevention_agent_test.cpp 2015-11-27 12:18:10 +0000
@@ -0,0 +1,106 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Thomas Voß <thomas.voss@canonical.com>
17 */
18
19#include <core/trust/privilege_escalation_prevention_agent.h>
20
21#include "mock_agent.h"
22#include "the.h"
23
24#include <gmock/gmock.h>
25
26namespace
27{
28std::shared_ptr<testing::NiceMock<MockAgent>> a_mocked_agent()
29{
30 return std::make_shared<testing::NiceMock<MockAgent>>();
31}
32
33struct MockUserIdFunctor
34{
35 core::trust::PrivilegeEscalationPreventionAgent::UserIdFunctor to_functional()
36 {
37 return [this]()
38 {
39 return get_uid();
40 };
41 }
42
43 MOCK_METHOD0(get_uid, core::trust::Uid());
44};
45}
46
47TEST(PrivilegeEscalationPreventionAgent, ctor_throws_for_null_agent)
48{
49 EXPECT_ANY_THROW(core::trust::PrivilegeEscalationPreventionAgent
50 (
51 core::trust::PrivilegeEscalationPreventionAgent::default_user_id_functor(),
52 std::shared_ptr<core::trust::Agent>()
53 ));
54}
55
56TEST(PrivilegeEscalationPreventionAgent, queries_user_id_for_incoming_request_and_dispatches_to_impl_if_no_privilege_escalation_detected)
57{
58 using namespace ::testing;
59
60 auto mock_agent = a_mocked_agent();
61
62 auto params = the::default_request_parameters_for_testing();
63 params.application.id = params.application.id + std::string{"_app"} + std::string{"_1.2.3"};
64
65 MockUserIdFunctor uif;
66 EXPECT_CALL(uif, get_uid())
67 .Times(1)
68 .WillRepeatedly(Return(params.application.uid));
69
70 EXPECT_CALL(*mock_agent, authenticate_request_with_parameters(params))
71 .Times(1)
72 .WillRepeatedly(Return(core::trust::Request::Answer::denied));
73
74 core::trust::PrivilegeEscalationPreventionAgent agent{uif.to_functional(), mock_agent};
75
76 EXPECT_EQ(core::trust::Request::Answer::denied,
77 agent.authenticate_request_with_parameters(params));
78}
79
80TEST(PrivilegeEscalationPreventionAgent, invokes_user_id_functor_for_incoming_request_and_throws_if_privilege_escalation_detected)
81{
82 using namespace ::testing;
83
84 auto mock_agent = a_mocked_agent();
85
86 auto params = the::default_request_parameters_for_testing();
87 params.application.id = params.application.id + std::string{"_app"} + std::string{"_1.2.3"};
88
89 MockUserIdFunctor uif;
90 EXPECT_CALL(uif, get_uid())
91 .Times(1)
92 .WillRepeatedly(Return(core::trust::Uid{12}));
93
94 EXPECT_CALL(*mock_agent, authenticate_request_with_parameters(params))
95 .Times(0);
96
97 core::trust::PrivilegeEscalationPreventionAgent agent{uif.to_functional(), mock_agent};
98
99 EXPECT_THROW(agent.authenticate_request_with_parameters(params), core::trust::PrivilegeEscalationPreventionAgent::Error);
100}
101
102TEST(PrivilegeEscalationPreventionAgentDefaultUserIdFunctor, returns_current_user_id)
103{
104 auto f = core::trust::PrivilegeEscalationPreventionAgent::default_user_id_functor();
105 EXPECT_EQ(core::trust::Uid(::getuid()), f());
106}

Subscribers

People subscribed via source and target branches