ee386061f6d554fd08659f09ca1ddbb838130016
[platform/core/test/security-tests.git] / src / security-manager-tests / test_cases_prepare_app.cpp
1 /*
2  * Copyright (c) 2016-2019 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 #include <fstream>
26
27 #include <dpl/test/test_runner_child.h>
28 #include <dpl/test/test_runner.h>
29
30 #include <app_install_helper.h>
31 #include <scoped_installer.h>
32 #include <sm_api.h>
33 #include <sm_commons.h>
34 #include <memory.h>
35 #include <tests_common.h>
36
37 using namespace SecurityManagerTest;
38
39 namespace {
40 bool finish = false;
41 const size_t THREADS = 10;
42
43 const std::string APP_TEST_USER = "app_test_user";
44
45 const std::string EXTERNAL_STORAGE_PRIVILEGE = "http://tizen.org/privilege/externalstorage";
46 const std::string MEDIA_STORAGE_PRIVILEGE = "http://tizen.org/privilege/mediastorage";
47
48 const std::string ACCESS_DENIED_DIR_PATH = "/usr/share/security-manager/dummy";
49 const std::string EXTERNAL_STORAGE_DIR_PATH = "/opt/media";
50 const std::string MEDIA_STORAGE_RW_DIR_PATH = "/opt/usr/media";
51 const std::string MEDIA_STORAGE_RO_DIR_PATH = "/opt/usr/home/app_test_user/media";
52
53 typedef std::unique_ptr<_cap_struct, decltype(&cap_free)> CapPtr;
54
55 std::string thread_errors;
56 std::mutex error_mutex;
57
58 #define THREAD_ASSERT_MSG(test, message)                                       \
59     do                                                                         \
60     {                                                                          \
61         if (!(test))                                                           \
62         {                                                                      \
63             std::ostringstream assertMsg;                                      \
64             assertMsg << #test << " " << __FILE__ << " " << __LINE__ << " " << \
65                          message << std::endl;                                 \
66             std::lock_guard<std::mutex> guard(error_mutex);                    \
67             thread_errors.append(assertMsg.str());                             \
68         }                                                                      \
69     } while (0)
70
71 void threadFn(int i, const std::string &expectedLabel)
72 {
73     if (i % 2 == 0) {
74         // block all signals
75         sigset_t sigset;
76         THREAD_ASSERT_MSG(sigfillset(&sigset) == 0, "sigfillset failed");
77         THREAD_ASSERT_MSG(sigprocmask(SIG_BLOCK, &sigset, NULL) == 0, "sigprocmask failed");
78     }
79
80     while (!finish)
81         usleep(1000);
82
83     char* label;
84     THREAD_ASSERT_MSG(smack_new_label_from_self(&label) > 0, "smack_new_label_from_self failed");
85     CStringPtr labelPtr(label);
86
87     THREAD_ASSERT_MSG(expectedLabel.compare(label) == 0,
88                       "Thread " << i << " has a wrong label: " << label);
89
90     CapPtr expectedCaps(cap_init(), cap_free);
91     THREAD_ASSERT_MSG(expectedCaps, "cap_init() failed");
92     THREAD_ASSERT_MSG(cap_clear(expectedCaps.get()) == 0, "cap_clear() failed");
93
94     CapPtr realCaps(cap_get_proc(), cap_free);
95     THREAD_ASSERT_MSG(realCaps, "cap_get_proc() failed");
96     THREAD_ASSERT_MSG(cap_compare(realCaps.get(), expectedCaps.get()) == 0,
97                       "Thread " << i << " has wrong caps");
98 }
99
100 struct ThreadWrapper
101 {
102
103     ThreadWrapper()
104     {
105     }
106     ~ThreadWrapper()
107     {
108         finish = true;
109         thread.join();
110     }
111
112     void run(int i, const std::string &expectedLabel)
113     {
114         THREAD_ASSERT_MSG(!thread.joinable(), "Thread already started");
115         thread = std::thread(threadFn, i, expectedLabel);
116     }
117
118     std::thread thread;
119 };
120
121 ino_t getFileInode(const std::string &path)
122 {
123     struct stat st;
124     if (stat(path.c_str(), &st) != 0)
125         return 0;
126
127     return st.st_ino;
128 }
129
130 std::string getTextFileContents(const std::string &path)
131 {
132     std::ifstream in(path.c_str());
133     if (in.fail())
134         return std::string();
135     std::stringstream ss;
136     ss << in.rdbuf();
137     return ss.str();
138 }
139
140 bool isPathBound(const std::string &what, const std::string &where, pid_t pid = 1)
141 {
142     std::string mountinfoPath = std::string("/proc/") + std::to_string(pid) + "/mountinfo";
143     std::string mountinfo = getTextFileContents(mountinfoPath);
144     std::string line = what + " " + where;
145
146     return std::string::npos != mountinfo.find(line);
147 }
148
149 } // anonymous namespace
150
151 RUNNER_TEST_GROUP_INIT(SECURITY_MANAGER_PREPARE_APP)
152
153 RUNNER_CHILD_TEST(security_manager_100_synchronize_credentials_test)
154 {
155     TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
156     tmpUser.create();
157
158     AppInstallHelper app("app100", tmpUser.getUid());
159     ScopedInstaller appInstall(app);
160     const std::string expectedLabel = app.generateAppLabel();
161
162     pid_t pid = fork();
163     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
164     if (pid == 0) {
165         {
166             RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
167             Api::prepareAppCandidate();
168             ThreadWrapper threads[THREADS];
169
170             for (size_t i = 0; i < THREADS; i++)
171                 threads[i].run(i, expectedLabel);
172
173             Api::prepareApp(app.getAppId().c_str());
174         }
175         RUNNER_ASSERT_MSG(thread_errors.empty(), std::endl << thread_errors);
176         exit(0);
177     } else {
178         waitPid(pid);
179         Api::cleanupApp(app.getAppId().c_str(), tmpUser.getUid(), pid);
180     }
181 }
182
183 RUNNER_CHILD_TEST(security_manager_101_create_namespace_test_n)
184 {
185     TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
186     tmpUser.create();
187
188     AppInstallHelper app("app100_n", tmpUser.getUid());
189     ScopedInstaller appInstall(app);
190     const std::string expectedLabel = app.generateAppLabel();
191
192     pid_t pid = fork();
193     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
194     if (pid == 0) {
195         {
196             RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
197             ThreadWrapper threads[THREADS];
198
199             for (size_t i = 0; i < THREADS; i++)
200                 threads[i].run(i, expectedLabel);
201
202             Api::prepareAppCandidate(SECURITY_MANAGER_ERROR_INPUT_PARAM);
203         }
204         RUNNER_ASSERT_MSG(!thread_errors.empty(), std::endl << thread_errors);
205         exit(0);
206     } else {
207         waitPid(pid);
208     }
209 }
210
211 RUNNER_CHILD_TEST(security_manager_101_create_namespace_test)
212 {
213     TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
214     tmpUser.create();
215
216     AppInstallHelper app("app101", tmpUser.getUid());
217     ScopedInstaller appInstall(app);
218
219     SynchronizationPipe synchPipe;
220     pid_t pid = fork();
221     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
222     if (pid == 0) {
223         synchPipe.claimParentEp();
224         RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
225         Api::prepareAppCandidate();
226         Api::prepareApp(app.getAppId().c_str());
227         synchPipe.post();
228         synchPipe.wait();
229
230         exit(0);
231     } else {
232         synchPipe.claimChildEp();
233         synchPipe.wait();
234
235         std::string appBindPath = std::string("/var/run/user/") + std::to_string(tmpUser.getUid())
236                                   + "/apps/" + app.generateAppLabel() + "/" + std::to_string(pid);
237         std::string appProcPath = std::string("/proc/") + std::to_string(pid) + "/ns/mnt";
238         std::string launcherProcPath = std::string("/proc/") + std::to_string(getpid()) + "/ns/mnt";
239
240         ino_t appBindInode = getFileInode(appBindPath);
241         ino_t appProcInode = getFileInode(appProcPath);
242         ino_t launcherProcInode = getFileInode(launcherProcPath);
243
244         RUNNER_ASSERT_ERRNO_MSG(appBindInode != 0, "get inode failed");
245         RUNNER_ASSERT_ERRNO_MSG(appProcInode != 0, "get inode failed");
246         RUNNER_ASSERT_ERRNO_MSG(launcherProcInode != 0, "get inode failed");
247
248         RUNNER_ASSERT_ERRNO_MSG(launcherProcInode != appProcInode, "create mount namespace failed");
249         RUNNER_ASSERT_ERRNO_MSG(appBindInode == appProcInode, "bind namespace failed");
250
251         synchPipe.post();
252         waitPid(pid);
253         Api::cleanupApp(app.getAppId().c_str(), tmpUser.getUid(), pid);
254     }
255 }
256
257 RUNNER_CHILD_TEST(security_manager_102_check_propagation_test)
258 {
259     TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
260     tmpUser.create();
261
262     AppInstallHelper app("app102", tmpUser.getUid());
263     ScopedInstaller appInstall(app);
264
265     SynchronizationPipe synchPipe;
266     pid_t pid = fork();
267     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
268     if (pid == 0) {
269         synchPipe.claimParentEp();
270         RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
271         Api::prepareAppCandidate();
272         Api::prepareApp(app.getAppId().c_str());
273         synchPipe.post();
274         synchPipe.wait();
275
276         exit(0);
277     } else {
278         synchPipe.claimChildEp();
279         synchPipe.wait();
280
281         bool result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
282         RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
283         result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
284         RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
285         result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
286         RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
287
288         result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH);
289         RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
290         result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH);
291         RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
292         result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH);
293         RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
294
295         synchPipe.post();
296         waitPid(pid);
297         Api::cleanupApp(app.getAppId().c_str(), tmpUser.getUid(), pid);
298     }
299 }
300
301 RUNNER_CHILD_TEST(security_manager_103_policy_change_test)
302 {
303     TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
304     tmpUser.create();
305
306     AppInstallHelper app("app103", tmpUser.getUid());
307     app.addPrivilege(EXTERNAL_STORAGE_PRIVILEGE);
308     app.addPrivilege(MEDIA_STORAGE_PRIVILEGE);
309     ScopedInstaller appInstall(app);
310
311     SynchronizationPipe synchPipe;
312     pid_t pid = fork();
313     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
314     if (pid == 0) {
315         synchPipe.claimParentEp();
316         RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
317         Api::prepareAppCandidate();
318         Api::prepareApp(app.getAppId().c_str());
319         synchPipe.post();
320         synchPipe.wait();
321
322         exit(0);
323     } else {
324         synchPipe.claimChildEp();
325         synchPipe.wait();
326
327         bool result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
328         RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
329         result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
330         RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
331         result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
332         RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
333
334         PolicyRequest policyRequest;
335         PolicyEntry policyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), EXTERNAL_STORAGE_PRIVILEGE);
336         policyEntry.setLevel("Deny");
337         policyRequest.addEntry(policyEntry);
338
339         policyEntry = PolicyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), MEDIA_STORAGE_PRIVILEGE);
340         policyEntry.setLevel("Deny");
341         policyRequest.addEntry(policyEntry);
342         Api::sendPolicy(policyRequest);
343
344         result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
345         RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
346         result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
347         RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
348         result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
349         RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
350
351         policyEntry = PolicyEntry(app.getAppId(),  std::to_string(tmpUser.getUid()), EXTERNAL_STORAGE_PRIVILEGE);
352         policyEntry.setLevel("Allow");
353         policyRequest.addEntry(policyEntry);
354
355         policyEntry = PolicyEntry(app.getAppId(),  std::to_string(tmpUser.getUid()), MEDIA_STORAGE_PRIVILEGE);
356         policyEntry.setLevel("Allow");
357         policyRequest.addEntry(policyEntry);
358         Api::sendPolicy(policyRequest);
359
360         result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
361         RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
362         result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
363         RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
364         result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
365         RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
366
367         synchPipe.post();
368         waitPid(pid);
369         Api::cleanupApp(app.getAppId().c_str(), tmpUser.getUid(), pid);
370     }
371 }