#include <string>
#include <memory>
#include <mutex>
+#include <fstream>
#include <dpl/test/test_runner_child.h>
#include <dpl/test/test_runner.h>
const std::string APP_TEST_USER = "app_test_user";
+const std::string EXTERNAL_STORAGE_PRIVILEGE = "http://tizen.org/privilege/externalstorage";
+const std::string MEDIA_STORAGE_PRIVILEGE = "http://tizen.org/privilege/mediastorage";
+
+const std::string ACCESS_DENIED_DIR_PATH = "/usr/share/security-manager/dummy";
+const std::string EXTERNAL_STORAGE_DIR_PATH = "/opt/media";
+const std::string MEDIA_STORAGE_RW_DIR_PATH = "/opt/usr/media";
+const std::string MEDIA_STORAGE_RO_DIR_PATH = "/opt/usr/home/app_test_user/media";
+
typedef std::unique_ptr<_cap_struct, decltype(&cap_free)> CapPtr;
std::string thread_errors;
return ret;
}
+ino_t getFileInode(const std::string &path)
+{
+ struct stat st;
+ if (stat(path.c_str(), &st) != 0)
+ return 0;
+
+ return st.st_ino;
+}
+
+std::string getTextFileContents(const std::string &path)
+{
+ std::ifstream in(path.c_str());
+ if (in.fail())
+ return std::string();
+ std::stringstream ss;
+ ss << in.rdbuf();
+ return ss.str();
+}
+
+bool isPathBound(const std::string &what, const std::string &where, pid_t pid = 1)
+{
+ std::string mountinfoPath = std::string("/proc/") + std::to_string(pid) + "/mountinfo";
+ std::string mountinfo = getTextFileContents(mountinfoPath);
+ std::string line = what + " " + where;
+
+ return std::string::npos != mountinfo.find(line);
+}
+
} // anonymous namespace
RUNNER_TEST_GROUP_INIT(SECURITY_MANAGER_PREPARE_APP)
waitPid(pid);
}
}
+
+RUNNER_CHILD_TEST(security_manager_101_create_namespace_test)
+{
+ TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
+ tmpUser.create();
+
+ AppInstallHelper app("app101", tmpUser.getUid());
+ ScopedInstaller appInstall(app);
+
+ SynchronizationPipe synchPipe;
+ pid_t pid = fork();
+ RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
+ if (pid == 0) {
+ synchPipe.claimParentEp();
+ RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
+
+ Api::prepareApp(app.getAppId().c_str());
+ synchPipe.post();
+ synchPipe.wait();
+
+ exit(0);
+ } else {
+ synchPipe.claimChildEp();
+ synchPipe.wait();
+
+ std::string appBindPath = std::string("/var/run/user/") + std::to_string(tmpUser.getUid())
+ + "/apps/" + app.getAppId();
+ std::string appProcPath = std::string("/proc/") + std::to_string(pid) + "/ns/mnt";
+ std::string launcherProcPath = std::string("/proc/") + std::to_string(getpid()) + "/ns/mnt";
+
+ ino_t appBindInode = getFileInode(appBindPath);
+ ino_t appProcInode = getFileInode(appProcPath);
+ ino_t launcherProcInode = getFileInode(launcherProcPath);
+
+ RUNNER_ASSERT_ERRNO_MSG(appBindInode != 0, "get inode failed");
+ RUNNER_ASSERT_ERRNO_MSG(appProcInode != 0, "get inode failed");
+ RUNNER_ASSERT_ERRNO_MSG(launcherProcInode != 0, "get inode failed");
+
+ RUNNER_ASSERT_ERRNO_MSG(launcherProcInode != appProcInode, "create mount namespace failed");
+ RUNNER_ASSERT_ERRNO_MSG(appBindInode == appProcInode, "bind namespace failed");
+
+ synchPipe.post();
+ waitPid(pid);
+ }
+}
+
+RUNNER_CHILD_TEST(security_manager_102_check_propagation_test)
+{
+ TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
+ tmpUser.create();
+
+ AppInstallHelper app("app102", tmpUser.getUid());
+ ScopedInstaller appInstall(app);
+
+ SynchronizationPipe synchPipe;
+ pid_t pid = fork();
+ RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
+ if (pid == 0) {
+ synchPipe.claimParentEp();
+ RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
+
+ Api::prepareApp(app.getAppId().c_str());
+ synchPipe.post();
+ synchPipe.wait();
+
+ exit(0);
+ } else {
+ synchPipe.claimChildEp();
+ synchPipe.wait();
+
+ bool result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
+
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH);
+ RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH);
+ RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH);
+ RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
+
+ synchPipe.post();
+ waitPid(pid);
+ }
+}
+
+RUNNER_CHILD_TEST(security_manager_103_policy_change_test)
+{
+ TemporaryTestUser tmpUser(APP_TEST_USER, GUM_USERTYPE_NORMAL, false);
+ tmpUser.create();
+
+ AppInstallHelper app("app103", tmpUser.getUid());
+ app.addPrivilege(EXTERNAL_STORAGE_PRIVILEGE);
+ app.addPrivilege(MEDIA_STORAGE_PRIVILEGE);
+ ScopedInstaller appInstall(app);
+
+ SynchronizationPipe synchPipe;
+ pid_t pid = fork();
+ RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "Fork failed");
+ if (pid == 0) {
+ synchPipe.claimParentEp();
+ RUNNER_ASSERT_ERRNO_MSG(setLauncherSecurityAttributes(tmpUser) == 0, "launcher failed");
+
+ Api::prepareApp(app.getAppId().c_str());
+ synchPipe.post();
+ synchPipe.wait();
+
+ exit(0);
+ } else {
+ synchPipe.claimChildEp();
+ synchPipe.wait();
+
+ bool result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
+
+ PolicyRequest policyRequest;
+ PolicyEntry policyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), EXTERNAL_STORAGE_PRIVILEGE);
+ policyEntry.setLevel("Deny");
+ policyRequest.addEntry(policyEntry);
+
+ policyEntry = PolicyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), MEDIA_STORAGE_PRIVILEGE);
+ policyEntry.setLevel("Deny");
+ policyRequest.addEntry(policyEntry);
+ Api::sendPolicy(policyRequest);
+
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == true, "path is not bound");
+
+ policyEntry = PolicyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), EXTERNAL_STORAGE_PRIVILEGE);
+ policyEntry.setLevel("Allow");
+ policyRequest.addEntry(policyEntry);
+
+ policyEntry = PolicyEntry(app.getAppId(), std::to_string(tmpUser.getUid()), MEDIA_STORAGE_PRIVILEGE);
+ policyEntry.setLevel("Allow");
+ policyRequest.addEntry(policyEntry);
+ Api::sendPolicy(policyRequest);
+
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, EXTERNAL_STORAGE_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RW_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
+ result = isPathBound(ACCESS_DENIED_DIR_PATH, MEDIA_STORAGE_RO_DIR_PATH, pid);
+ RUNNER_ASSERT_ERRNO_MSG(result == false, "path is bound");
+
+ synchPipe.post();
+ waitPid(pid);
+ }
+}