Merge branch 'security-manager' into tizen
[platform/core/test/security-tests.git] / src / security-manager-tests / test_cases_prepare_app.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include <sys/smack.h>
18 #include <sys/capability.h>
19 #include <sys/prctl.h>
20
21 #include <thread>
22 #include <string>
23 #include <memory>
24 #include <mutex>
25
26 #include <dpl/test/test_runner_child.h>
27 #include <dpl/test/test_runner.h>
28
29 #include <app_install_helper.h>
30 #include <scoped_installer.h>
31 #include <sm_api.h>
32 #include <sm_commons.h>
33 #include <memory.h>
34 #include <tests_common.h>
35
36 using namespace SecurityManagerTest;
37
38 namespace {
39 bool finish = false;
40 const size_t THREADS = 10;
41
42 const std::string APP_TEST_USER = "app_test_user";
43
44 typedef std::unique_ptr<_cap_struct, decltype(&cap_free)> CapPtr;
45
46 std::string thread_errors;
47 std::mutex error_mutex;
48
49 #define THREAD_ASSERT_MSG(test, message)                                       \
50     do                                                                         \
51     {                                                                          \
52         if (!(test))                                                           \
53         {                                                                      \
54             std::ostringstream assertMsg;                                      \
55             assertMsg << #test << " " << __FILE__ << " " << __LINE__ << " " << \
56                          message << std::endl;                                 \
57             std::lock_guard<std::mutex> guard(error_mutex);                    \
58             thread_errors.append(assertMsg.str());                             \
59         }                                                                      \
60     } while (0)
61
62 void threadFn(int i, const std::string &expectedLabel)
63 {
64     if (i % 2 == 0) {
65         // block all signals
66         sigset_t sigset;
67         THREAD_ASSERT_MSG(sigfillset(&sigset) == 0, "sigfillset failed");
68         THREAD_ASSERT_MSG(sigprocmask(SIG_BLOCK, &sigset, NULL) == 0, "sigprocmask failed");
69     }
70
71     while (!finish)
72         usleep(1000);
73
74     char* label;
75     THREAD_ASSERT_MSG(smack_new_label_from_self(&label) > 0, "smack_new_label_from_self failed");
76     CStringPtr labelPtr(label);
77
78     THREAD_ASSERT_MSG(expectedLabel.compare(label) == 0,
79                       "Thread " << i << " has a wrong label: " << label);
80
81     CapPtr expectedCaps(cap_init(), cap_free);
82     THREAD_ASSERT_MSG(expectedCaps, "cap_init() failed");
83     THREAD_ASSERT_MSG(cap_clear(expectedCaps.get()) == 0, "cap_clear() failed");
84
85     CapPtr realCaps(cap_get_proc(), cap_free);
86     THREAD_ASSERT_MSG(realCaps, "cap_get_proc() failed");
87     THREAD_ASSERT_MSG(cap_compare(realCaps.get(), expectedCaps.get()) == 0,
88                       "Thread " << i << " has wrong caps");
89 }
90
91 struct ThreadWrapper
92 {
93
94     ThreadWrapper()
95     {
96     }
97     ~ThreadWrapper()
98     {
99         finish = true;
100         thread.join();
101     }
102
103     void run(int i, const std::string &expectedLabel)
104     {
105         THREAD_ASSERT_MSG(!thread.joinable(), "Thread already started");
106         thread = std::thread(threadFn, i, expectedLabel);
107     }
108
109     std::thread thread;
110 };
111
112 int setLauncherSecurityAttributes(TemporaryTestUser &user)
113 {
114     // Add launcher capabilities (cap_dac_override, cap_setgid, cap_sys_admin, cap_mac_admin),
115     // launcher is user process, we must drop root privileges (cap_setgid, cap_setuid are needed).
116     // By default, the permitted capability set is cleared when credentials change is made
117     // (if a process drops a capability from its permitted set, it can never reacquire that capability),
118     // setting the "keep capabilities" flag prevents it from being cleared.
119     // Effective capability set is always cleared when credential change is made, we need to add them again.
120
121     setCaps("cap_dac_override+ep cap_setgid+ep cap_sys_admin+ep cap_mac_admin+ep cap_setuid+ep");
122     int ret = prctl(PR_SET_KEEPCAPS, 1, 0, 0);
123     if (ret != 0)
124         return ret;
125
126     ret = drop_root_privileges(user.getUid(), user.getGid());
127     if (ret != 0)
128         return ret;
129
130     setCaps("cap_dac_override+ep cap_setgid+ep cap_sys_admin+ep cap_mac_admin+ep");
131     return ret;
132 }
133
134 } // anonymous namespace
135
136 RUNNER_TEST_GROUP_INIT(SECURITY_MANAGER_PREPARE_APP)
137
138 RUNNER_CHILD_TEST(security_manager_100_synchronize_credentials_test)
139 {
140     TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
141     tmpUser.create();
142
143     AppInstallHelper app("app100", tmpUser.getUid());
144     ScopedInstaller appInstall(app);
145     const std::string expectedLabel = app.generateAppLabel();
146
147     pid_t pid = fork();
148     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
149     if (pid == 0) {
150         {
151             RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
152
153             ThreadWrapper threads[THREADS];
154
155             for (size_t i = 0; i < THREADS; i++)
156                 threads[i].run(i, expectedLabel);
157
158             Api::prepareApp(app.getAppId().c_str());
159         }
160         RUNNER_ASSERT_MSG(thread_errors.empty(), std::endl << thread_errors);
161         exit(0);
162     } else {
163         waitPid(pid);
164     }
165 }