2 * Copyright (c) 2016-2019 Samsung Electronics Co., Ltd. All rights reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <sys/smack.h>
18 #include <sys/capability.h>
19 #include <sys/prctl.h>
27 #include <dpl/test/test_runner_child.h>
28 #include <dpl/test/test_runner.h>
30 #include <app_install_helper.h>
31 #include <scoped_installer.h>
33 #include <sm_commons.h>
35 #include <tests_common.h>
37 using namespace SecurityManagerTest;
41 const size_t THREADS = 10;
43 const std::string APP_TEST_USER = "app_test_user";
45 const std::string EXTERNAL_STORAGE_PRIVILEGE = "http://tizen.org/privilege/externalstorage";
46 const std::string MEDIA_STORAGE_PRIVILEGE = "http://tizen.org/privilege/mediastorage";
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";
53 typedef std::unique_ptr<_cap_struct, decltype(&cap_free)> CapPtr;
55 std::string thread_errors;
56 std::mutex error_mutex;
58 #define THREAD_ASSERT_MSG(test, message) \
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()); \
71 void threadFn(int i, const std::string &expectedLabel)
76 THREAD_ASSERT_MSG(sigfillset(&sigset) == 0, "sigfillset failed");
77 THREAD_ASSERT_MSG(sigprocmask(SIG_BLOCK, &sigset, NULL) == 0, "sigprocmask failed");
84 THREAD_ASSERT_MSG(smack_new_label_from_self(&label) > 0, "smack_new_label_from_self failed");
85 CStringPtr labelPtr(label);
87 THREAD_ASSERT_MSG(expectedLabel.compare(label) == 0,
88 "Thread " << i << " has a wrong label: " << label);
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");
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");
112 void run(int i, const std::string &expectedLabel)
114 THREAD_ASSERT_MSG(!thread.joinable(), "Thread already started");
115 thread = std::thread(threadFn, i, expectedLabel);
121 ino_t getFileInode(const std::string &path)
124 if (stat(path.c_str(), &st) != 0)
130 std::string getTextFileContents(const std::string &path)
132 std::ifstream in(path.c_str());
134 return std::string();
135 std::stringstream ss;
140 bool isPathBound(const std::string &what, const std::string &where, pid_t pid = 1)
142 std::string mountinfoPath = std::string("/proc/") + std::to_string(pid) + "/mountinfo";
143 std::string mountinfo = getTextFileContents(mountinfoPath);
144 std::string line = what + " " + where;
146 return std::string::npos != mountinfo.find(line);
149 } // anonymous namespace
151 RUNNER_TEST_GROUP_INIT(SECURITY_MANAGER_PREPARE_APP)
153 RUNNER_CHILD_TEST(security_manager_100_synchronize_credentials_test)
155 TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
158 AppInstallHelper app("app100", tmpUser.getUid());
159 ScopedInstaller appInstall(app);
160 const std::string expectedLabel = app.generateAppLabel();
163 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
166 RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
167 Api::prepareAppCandidate();
168 ThreadWrapper threads[THREADS];
170 for (size_t i = 0; i < THREADS; i++)
171 threads[i].run(i, expectedLabel);
173 Api::prepareApp(app.getAppId().c_str());
175 RUNNER_ASSERT_MSG(thread_errors.empty(), std::endl << thread_errors);
179 Api::cleanupApp(app.getAppId().c_str(), tmpUser.getUid(), pid);
183 RUNNER_CHILD_TEST(security_manager_101_create_namespace_test_n)
185 TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
188 AppInstallHelper app("app100_n", tmpUser.getUid());
189 ScopedInstaller appInstall(app);
190 const std::string expectedLabel = app.generateAppLabel();
193 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
196 RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
197 ThreadWrapper threads[THREADS];
199 for (size_t i = 0; i < THREADS; i++)
200 threads[i].run(i, expectedLabel);
202 Api::prepareAppCandidate(SECURITY_MANAGER_ERROR_INPUT_PARAM);
204 RUNNER_ASSERT_MSG(!thread_errors.empty(), std::endl << thread_errors);
211 RUNNER_CHILD_TEST(security_manager_101_create_namespace_test)
213 TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
216 AppInstallHelper app("app101", tmpUser.getUid());
217 ScopedInstaller appInstall(app);
219 SynchronizationPipe synchPipe;
221 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
223 synchPipe.claimParentEp();
224 RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
225 Api::prepareAppCandidate();
226 Api::prepareApp(app.getAppId().c_str());
232 synchPipe.claimChildEp();
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";
240 ino_t appBindInode = getFileInode(appBindPath);
241 ino_t appProcInode = getFileInode(appProcPath);
242 ino_t launcherProcInode = getFileInode(launcherProcPath);
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");
248 RUNNER_ASSERT_ERRNO_MSG(launcherProcInode != appProcInode, "create mount namespace failed");
249 RUNNER_ASSERT_ERRNO_MSG(appBindInode == appProcInode, "bind namespace failed");
253 Api::cleanupApp(app.getAppId().c_str(), tmpUser.getUid(), pid);
257 RUNNER_CHILD_TEST(security_manager_102_check_propagation_test)
259 TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
262 AppInstallHelper app("app102", tmpUser.getUid());
263 ScopedInstaller appInstall(app);
265 SynchronizationPipe synchPipe;
267 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
269 synchPipe.claimParentEp();
270 RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
271 Api::prepareAppCandidate();
272 Api::prepareApp(app.getAppId().c_str());
278 synchPipe.claimChildEp();
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");
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");
297 Api::cleanupApp(app.getAppId().c_str(), tmpUser.getUid(), pid);
301 RUNNER_CHILD_TEST(security_manager_103_policy_change_test)
303 TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
306 AppInstallHelper app("app103", tmpUser.getUid());
307 app.addPrivilege(EXTERNAL_STORAGE_PRIVILEGE);
308 app.addPrivilege(MEDIA_STORAGE_PRIVILEGE);
309 ScopedInstaller appInstall(app);
311 SynchronizationPipe synchPipe;
313 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
315 synchPipe.claimParentEp();
316 RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
317 Api::prepareAppCandidate();
318 Api::prepareApp(app.getAppId().c_str());
324 synchPipe.claimChildEp();
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");
334 PolicyRequest policyRequest;
335 PolicyEntry policyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), EXTERNAL_STORAGE_PRIVILEGE);
336 policyEntry.setLevel("Deny");
337 policyRequest.addEntry(policyEntry);
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);
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");
351 policyEntry = PolicyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), EXTERNAL_STORAGE_PRIVILEGE);
352 policyEntry.setLevel("Allow");
353 policyRequest.addEntry(policyEntry);
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);
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");
369 Api::cleanupApp(app.getAppId().c_str(), tmpUser.getUid(), pid);