2 * Copyright (c) 2016 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 int setLauncherSecurityAttributes(TemporaryTestUser &user)
123 // Add launcher capabilities (cap_dac_override, cap_setgid, cap_sys_admin, cap_mac_admin),
124 // launcher is user process, we must drop root privileges (cap_setgid, cap_setuid are needed).
125 // By default, the permitted capability set is cleared when credentials change is made
126 // (if a process drops a capability from its permitted set, it can never reacquire that capability),
127 // setting the "keep capabilities" flag prevents it from being cleared.
128 // Effective capability set is always cleared when credential change is made, we need to add them again.
130 setCaps("cap_dac_override+ep cap_setgid+ep cap_sys_admin+ep cap_mac_admin+ep cap_setuid+ep");
131 int ret = prctl(PR_SET_KEEPCAPS, 1, 0, 0);
135 ret = drop_root_privileges(user.getUid(), user.getGid());
139 setCaps("cap_dac_override+ep cap_setgid+ep cap_sys_admin+ep cap_mac_admin+ep");
143 ino_t getFileInode(const std::string &path)
146 if (stat(path.c_str(), &st) != 0)
152 std::string getTextFileContents(const std::string &path)
154 std::ifstream in(path.c_str());
156 return std::string();
157 std::stringstream ss;
162 bool isPathBound(const std::string &what, const std::string &where, pid_t pid = 1)
164 std::string mountinfoPath = std::string("/proc/") + std::to_string(pid) + "/mountinfo";
165 std::string mountinfo = getTextFileContents(mountinfoPath);
166 std::string line = what + " " + where;
168 return std::string::npos != mountinfo.find(line);
171 } // anonymous namespace
173 RUNNER_TEST_GROUP_INIT(SECURITY_MANAGER_PREPARE_APP)
175 RUNNER_CHILD_TEST(security_manager_100_synchronize_credentials_test)
177 TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
180 AppInstallHelper app("app100", tmpUser.getUid());
181 ScopedInstaller appInstall(app);
182 const std::string expectedLabel = app.generateAppLabel();
185 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
188 RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
190 ThreadWrapper threads[THREADS];
192 for (size_t i = 0; i < THREADS; i++)
193 threads[i].run(i, expectedLabel);
195 Api::prepareApp(app.getAppId().c_str());
197 RUNNER_ASSERT_MSG(thread_errors.empty(), std::endl << thread_errors);
204 RUNNER_CHILD_TEST(security_manager_101_create_namespace_test)
206 TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
209 AppInstallHelper app("app101", tmpUser.getUid());
210 ScopedInstaller appInstall(app);
212 SynchronizationPipe synchPipe;
214 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
216 synchPipe.claimParentEp();
217 RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
219 Api::prepareApp(app.getAppId().c_str());
225 synchPipe.claimChildEp();
228 std::string appBindPath = std::string("/var/run/user/") + std::to_string(tmpUser.getUid())
229 + "/apps/" + app.getAppId();
230 std::string appProcPath = std::string("/proc/") + std::to_string(pid) + "/ns/mnt";
231 std::string launcherProcPath = std::string("/proc/") + std::to_string(getpid()) + "/ns/mnt";
233 ino_t appBindInode = getFileInode(appBindPath);
234 ino_t appProcInode = getFileInode(appProcPath);
235 ino_t launcherProcInode = getFileInode(launcherProcPath);
237 RUNNER_ASSERT_ERRNO_MSG(appBindInode != 0, "get inode failed");
238 RUNNER_ASSERT_ERRNO_MSG(appProcInode != 0, "get inode failed");
239 RUNNER_ASSERT_ERRNO_MSG(launcherProcInode != 0, "get inode failed");
241 RUNNER_ASSERT_ERRNO_MSG(launcherProcInode != appProcInode, "create mount namespace failed");
242 RUNNER_ASSERT_ERRNO_MSG(appBindInode == appProcInode, "bind namespace failed");
249 RUNNER_CHILD_TEST(security_manager_102_check_propagation_test)
251 TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
254 AppInstallHelper app("app102", tmpUser.getUid());
255 ScopedInstaller appInstall(app);
257 SynchronizationPipe synchPipe;
259 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
261 synchPipe.claimParentEp();
262 RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
264 Api::prepareApp(app.getAppId().c_str());
270 synchPipe.claimChildEp();
273 bool result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
274 RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
275 result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
276 RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
277 result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
278 RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
280 result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH);
281 RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
282 result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH);
283 RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
284 result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH);
285 RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
292 RUNNER_CHILD_TEST(security_manager_103_policy_change_test)
294 TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
297 AppInstallHelper app("app103", tmpUser.getUid());
298 app.addPrivilege(EXTERNAL_STORAGE_PRIVILEGE);
299 app.addPrivilege(MEDIA_STORAGE_PRIVILEGE);
300 ScopedInstaller appInstall(app);
302 SynchronizationPipe synchPipe;
304 RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
306 synchPipe.claimParentEp();
307 RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
309 Api::prepareApp(app.getAppId().c_str());
315 synchPipe.claimChildEp();
318 bool result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
319 RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
320 result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
321 RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
322 result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
323 RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
325 PolicyRequest policyRequest;
326 PolicyEntry policyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), EXTERNAL_STORAGE_PRIVILEGE);
327 policyEntry.setLevel("Deny");
328 policyRequest.addEntry(policyEntry);
330 policyEntry = PolicyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), MEDIA_STORAGE_PRIVILEGE);
331 policyEntry.setLevel("Deny");
332 policyRequest.addEntry(policyEntry);
333 Api::sendPolicy(policyRequest);
335 result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
336 RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
337 result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
338 RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
339 result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
340 RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
342 policyEntry = PolicyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), EXTERNAL_STORAGE_PRIVILEGE);
343 policyEntry.setLevel("Allow");
344 policyRequest.addEntry(policyEntry);
346 policyEntry = PolicyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), MEDIA_STORAGE_PRIVILEGE);
347 policyEntry.setLevel("Allow");
348 policyRequest.addEntry(policyEntry);
349 Api::sendPolicy(policyRequest);
351 result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
352 RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
353 result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
354 RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
355 result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
356 RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");