#include <attr/xattr.h>
#include <linux/xattr.h>
#include <sys/capability.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/prctl.h>
+#include <sys/smack.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/smack.h>
+#include <ctime>
#include <algorithm>
#include <fstream>
+#include <poll.h>
#include <regex>
#include <string>
#include <unordered_set>
dbtest.test_db_after__app_uninstall(app_id, pkg_id, is_pkg_removed);
}
-static void install_app(const char *app_id, const char *pkg_id, uid_t uid = 0)
+static void install_app(const char *app_id, const char *pkg_id, uid_t uid = 0,
+ app_install_type type = SM_APP_INSTALL_NONE, bool check_after = true)
{
InstallRequest request;
request.setAppId(app_id);
request.setPkgId(pkg_id);
request.setUid(uid);
+ if (type != SM_APP_INSTALL_NONE)
+ request.setInstallType(type);
Api::install(request);
- check_app_after_install(app_id, pkg_id);
+ if (check_after)
+ check_app_after_install(app_id, pkg_id);
}
-static void uninstall_app(const char *app_id, const char *pkg_id, bool expect_pkg_removed)
+static void uninstall_app(const char *app_id, const char *pkg_id,
+ bool expect_pkg_removed = false, app_install_type type = SM_APP_INSTALL_NONE,
+ bool check_after = true)
{
InstallRequest request;
request.setAppId(app_id);
-
+ if (type != SM_APP_INSTALL_NONE)
+ request.setInstallType(type);
Api::uninstall(request);
- check_app_after_uninstall(app_id, pkg_id, expect_pkg_removed);
+ if (check_after)
+ check_app_after_uninstall(app_id, pkg_id, expect_pkg_removed);
}
static inline void register_current_process_as_privilege_manager(uid_t uid, bool forAdmin = false)
RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << path);
}
+RUNNER_TEST_GROUP_INIT(SECURITY_MANAGER_LABEL_MONITOR_API)
+
+struct UidGidMsg {
+ uid_t uid;
+ gid_t gid;
+};
+
+static UidGidMsg createUserSendCreds(TemporaryTestUser &testUser, int pipefd1)
+{
+ testUser.create();
+ UidGidMsg msg;
+ msg.uid = testUser.getUid();
+ msg.gid = testUser.getGid();
+ RUNNER_ASSERT_MSG(msg.uid != 0, "wrong uid of created test user");
+ ssize_t written = TEMP_FAILURE_RETRY(write(pipefd1, &msg, sizeof(UidGidMsg)));
+ RUNNER_ASSERT_MSG((written == sizeof(UidGidMsg)),"write failed");
+ return msg;
+}
+
+static UidGidMsg readCreds(int pipefd0)
+{
+ struct UidGidMsg msg;
+ ssize_t fetched = TEMP_FAILURE_RETRY(read(pipefd0, &msg, sizeof(UidGidMsg)));
+ RUNNER_ASSERT_MSG(fetched == sizeof(UidGidMsg), "read failed");
+ return msg;
+}
+
+static void setCaps(const char *cap_string)
+{
+ CapsSetsUniquePtr caps(cap_init());
+ caps.reset(cap_from_text(cap_string));
+ RUNNER_ASSERT_MSG(caps, "can't convert capabilities from text");
+ int result = cap_set_proc(caps.get());
+ RUNNER_ASSERT_MSG(result == 0, "can't set capabilities. Result: " << result);
+}
+
+static void testSetLabelForSelf(const char *app_id, bool expected_success)
+{
+ std::string label = generateAppLabel(app_id);
+ int result = smack_set_label_for_self(label.c_str());
+ if (expected_success)
+ RUNNER_ASSERT_MSG(result == 0, "smack_set_label_for_self(" << label <<
+ ") failed. Error: " << result);
+ else
+ RUNNER_ASSERT_MSG(result != 0, "smack_set_label_for_self(" << label <<
+ ") wrongly succeeded");
+}
+
+RUNNER_CHILD_TEST(security_manager_71_app_label_monitor_user_local_global) {
+
+ const char *sm_app_id_a = "sm_test_71_app_label_monitor_local";
+ const char *sm_pkg_id_a = "sm_test_71_app_label_monitor_local";
+ const char *sm_app_id_b = "sm_test_71_app_label_monitor_global";
+ const char *sm_pkg_id_b = "sm_test_71_app_label_monitor_global";
+ const std::string new_user_name = "sm_test_71";
+ int pipefd[2];
+ RUNNER_ASSERT_MSG((pipe(pipefd) != -1), "pipe failed");
+ SynchronizationPipe s_pipe;
+
+ pid_t pid = fork();
+ if (pid != 0) { //parent process
+ FdUniquePtr pipeptr(pipefd + 1);
+ close(pipefd[0]);
+ TemporaryTestUser testUser(new_user_name, GUM_USERTYPE_NORMAL, false);
+ UidGidMsg msg = createUserSendCreds(testUser, pipefd[1]);
+ int result = drop_root_privileges(msg.uid, msg.gid);
+ RUNNER_ASSERT_MSG(result == 0, "drop_root_privileges failed");
+ s_pipe.claimParentEp();
+ s_pipe.wait(); //synchronization point A1
+ install_app(sm_app_id_a, sm_pkg_id_a, msg.uid, SM_APP_INSTALL_LOCAL, false);
+ s_pipe.post(); //synchronization point A2
+ s_pipe.wait(); //synchronization point B1
+ install_app(sm_app_id_b, sm_pkg_id_b, msg.uid, SM_APP_INSTALL_GLOBAL, false);
+ s_pipe.post(); //synchronization point B2
+ s_pipe.wait(); //synchronization point C1
+ uninstall_app(sm_app_id_a, sm_app_id_a, false, SM_APP_INSTALL_LOCAL, false);
+ s_pipe.post(); //synchronization point C2
+ s_pipe.wait(); //synchronization point D1
+ uninstall_app(sm_app_id_b, sm_app_id_b, false, SM_APP_INSTALL_GLOBAL, false);
+ s_pipe.post(); //synchronization point D2
+ waitPid(pid);
+ } else { //child process
+ setCaps("cap_mac_admin+ep cap_setuid+ep cap_setgid+ep");
+ RUNNER_ASSERT_ERRNO_MSG(prctl(PR_SET_KEEPCAPS, 1, 0, 0) == 0, "prctl keeping caps failed");
+ s_pipe.claimChildEp();
+ FdUniquePtr pipeptr(pipefd);
+ close(pipefd[1]);
+ UidGidMsg msg = readCreds(pipefd[0]);
+ int result = drop_root_privileges(msg.uid, msg.gid);
+ RUNNER_ASSERT_MSG(result == 0, "drop_root_privileges failed");
+ setCaps("cap_mac_admin+ep");
+ app_labels_monitor *monitor;
+ int fd;
+ nfds_t nfds = 1;
+ struct pollfd fds[1];
+ Api::labelsMonitorInit(&monitor);
+ Api::labelsProcess(monitor);
+ Api::labelsMonitorGetFd(monitor, &fd);
+ fds[0].fd = fd;
+ fds[0].events = POLLIN;
+ for (int i = 0; i < 4; i++) { //A,B,C,D
+ s_pipe.post(); //synchronization point {A,B,C,D}1
+ s_pipe.wait(); //synchronization point {A,B,C,D}2
+ int poll_num = TEMP_FAILURE_RETRY(poll(fds, nfds, 0));
+ RUNNER_ASSERT_MSG(poll_num > 0, "Application installation was not detected");
+ RUNNER_ASSERT_MSG((fds[0].revents & POLLIN) > 0, "There is no data to read "
+ "regarding app installation");
+ }
+ Api::labelsMonitorFinish(monitor);
+ }
+}
+
+RUNNER_CHILD_TEST(security_manager_72_app_label_monitor_user_local) {
+
+ const char *sm_app_id_a = "sm_test_72_app_label_monitor_local_1";
+ const char *sm_pkg_id_a = "sm_test_72_app_label_monitor_local_1";
+ const char *sm_app_id_b = "sm_test_72_app_label_monitor_local_2";
+ const char *sm_pkg_id_b = "sm_test_72_app_label_monitor_local_2";
+ const std::string new_user_name = "sm_test_75";
+
+ int pipefd[2];
+ RUNNER_ASSERT_MSG((pipe(pipefd) != -1), "pipe failed");
+ SynchronizationPipe s_pipe;
+
+ pid_t pid = fork();
+ if (pid != 0) { //parent process
+ FdUniquePtr pipeptr(pipefd + 1);
+ close(pipefd[0]);
+ TemporaryTestUser testUser(new_user_name, GUM_USERTYPE_NORMAL, false);
+ UidGidMsg msg = createUserSendCreds(testUser, pipefd[1]);
+ int result = drop_root_privileges(msg.uid, msg.gid);
+ RUNNER_ASSERT_MSG(result == 0, "drop_root_privileges failed");
+ s_pipe.claimParentEp();
+ s_pipe.wait(); //synchronization point A1
+ install_app(sm_app_id_a, sm_pkg_id_a, msg.uid, SM_APP_INSTALL_LOCAL, false);
+ s_pipe.post(); //synchronization point A2
+ s_pipe.wait(); //synchronization point B1
+ install_app(sm_app_id_b, sm_pkg_id_b, msg.uid, SM_APP_INSTALL_LOCAL, false);
+ s_pipe.post(); //synchronization point B2
+ s_pipe.wait(); //synchronization point C1
+ uninstall_app(sm_app_id_a, sm_app_id_a, false, SM_APP_INSTALL_LOCAL, false);
+ s_pipe.post(); //synchronization point C2
+ s_pipe.wait(); //synchronization point D1
+ uninstall_app(sm_app_id_b, sm_app_id_b, false, SM_APP_INSTALL_LOCAL, false);
+ s_pipe.post(); //synchronization point D2
+ waitPid(pid);
+ } else { //child process
+ setCaps("cap_mac_admin+ep cap_setuid+ep cap_setgid+ep");
+ RUNNER_ASSERT_ERRNO_MSG(prctl(PR_SET_KEEPCAPS, 1, 0, 0) == 0, "prctl keeping caps failed");
+ s_pipe.claimChildEp();
+ FdUniquePtr pipeptr(pipefd);
+ close(pipefd[1]);
+ UidGidMsg msg = readCreds(pipefd[0]);
+ int result = drop_root_privileges(msg.uid, msg.gid);
+ RUNNER_ASSERT_MSG(result == 0, "drop_root_privileges failed");
+ setCaps("cap_mac_admin+ep");
+ app_labels_monitor *monitor;
+ int fd;
+ nfds_t nfds = 1;
+ struct pollfd fds[1];
+ Api::labelsMonitorInit(&monitor);
+ Api::labelsProcess(monitor);
+ Api::labelsMonitorGetFd(monitor, &fd);
+ fds[0].fd = fd;
+ fds[0].events = POLLIN;
+ for (int i = 0; i < 4; i++) { //A,B,C,D
+ s_pipe.post(); //synchronization point {A,B,C,D}1
+ s_pipe.wait(); //synchronization point {A,B,C,D}2
+ int poll_num = TEMP_FAILURE_RETRY(poll(fds, nfds, 0));
+ RUNNER_ASSERT_MSG(poll_num > 0, "Application installation was not detected");
+ RUNNER_ASSERT_MSG((fds[0].revents & POLLIN) > 0, "There is no data to read "
+ "regarding app installation");
+ }
+ Api::labelsMonitorFinish(monitor);
+ }
+}
+
+RUNNER_CHILD_TEST(security_manager_73_app_label_monitor_different_users) {
+
+ const char *sm_app_id_a = "sm_test_73_app_label_monitor_local_1";
+ const char *sm_pkg_id_a = "sm_test_73_app_label_monitor_local_1";
+ const char *sm_app_id_b = "sm_test_73_app_label_monitor_global_2";
+ const char *sm_pkg_id_b = "sm_test_73_app_label_monitor_global_2";
+ const std::string new_user_name_1 = "sm_test_73_1";
+ const std::string new_user_name_2 = "sm_test_73_2";
+
+ SynchronizationPipe s_pipe;
+
+ pid_t pid = fork();
+ if (pid != 0) { //parent process
+ s_pipe.claimParentEp();
+ TemporaryTestUser testUserOne(new_user_name_1, GUM_USERTYPE_NORMAL, false);
+ testUserOne.create();
+ s_pipe.post(); //synchronization point A for user creation
+ int result = drop_root_privileges(testUserOne.getUid(), testUserOne.getGid());
+ RUNNER_ASSERT_MSG(result == 0, "drop_root_privileges failed");
+ install_app(sm_app_id_a, sm_pkg_id_a, testUserOne.getUid(), SM_APP_INSTALL_LOCAL, false);
+ install_app(sm_app_id_b, sm_pkg_id_b, testUserOne.getUid(), SM_APP_INSTALL_GLOBAL, false);
+ s_pipe.post(); //synchronization point B
+ s_pipe.wait(); //synchronization point C
+ uninstall_app(sm_app_id_a, sm_app_id_a, false, SM_APP_INSTALL_LOCAL, false);
+ uninstall_app(sm_app_id_b, sm_app_id_b, false, SM_APP_INSTALL_LOCAL, false);
+ waitPid(pid);
+ } else { //child process
+ setCaps("cap_mac_admin+ep cap_setuid+ep cap_setgid+ep");
+ RUNNER_ASSERT_ERRNO_MSG(prctl(PR_SET_KEEPCAPS, 1, 0, 0) == 0, "prctl keeping caps failed");
+ s_pipe.claimChildEp();
+ s_pipe.wait(); //synchronization point A for user creation
+ TemporaryTestUser testUserTwo(new_user_name_2, GUM_USERTYPE_NORMAL, false);
+ testUserTwo.create();
+ int result = drop_root_privileges(testUserTwo.getUid(), testUserTwo.getGid());
+ RUNNER_ASSERT_MSG(result == 0, "drop_root_privileges failed");
+ setCaps("cap_mac_admin+ep");
+ app_labels_monitor *monitor;
+ Api::labelsMonitorInit(&monitor);
+ s_pipe.wait(); //B
+ Api::labelsProcess(monitor);
+ Api::labelsMonitorFinish(monitor);
+ setCaps("cap_mac_admin-eip");
+ testSetLabelForSelf(sm_app_id_a, false); // local installation by another user
+ testSetLabelForSelf(sm_app_id_b, true); // global installation by another user
+ s_pipe.post(); //C
+ }
+}
+
+RUNNER_CHILD_TEST(security_manager_74_app_label_monitor_relabel_changes_1) {
+
+ const char *sm_app_id_a = "sm_test_74_app_label_monitor_global_1";
+ const char *sm_pkg_id_a = "sm_test_74_app_label_monitor_global_1";
+ const char *sm_app_id_b = "sm_test_74_app_label_monitor_global_2";
+ const char *sm_pkg_id_b = "sm_test_74_app_label_monitor_global_2";
+ const char *sm_app_id_c = "sm_test_74_app_label_monitor_global_3";
+ const char *sm_pkg_id_c = "sm_test_74_app_label_monitor_global_3";
+ const std::string new_user_name = "sm_test_74";
+
+ int pipefd[2];
+ RUNNER_ASSERT_MSG((pipe(pipefd) != -1), "pipe failed");
+ SynchronizationPipe s_pipe;
+
+ pid_t pid = fork();
+ if (pid != 0) { //parent process
+ FdUniquePtr pipeptr(pipefd + 1);
+ close(pipefd[0]);
+ s_pipe.claimParentEp();
+ install_app(sm_app_id_a, sm_pkg_id_a, getuid(), SM_APP_INSTALL_GLOBAL);
+ TemporaryTestUser testUser(new_user_name, GUM_USERTYPE_NORMAL, false);
+ UidGidMsg msg = createUserSendCreds(testUser, pipefd[1]);
+ int result = drop_root_privileges(msg.uid, msg.gid);
+ RUNNER_ASSERT_MSG(result == 0, "drop_root_privileges failed");
+ install_app(sm_app_id_b, sm_pkg_id_b, msg.uid, SM_APP_INSTALL_GLOBAL, false);
+ install_app(sm_app_id_c, sm_pkg_id_c, msg.gid, SM_APP_INSTALL_GLOBAL, false);
+ s_pipe.post(); //Synchronization point A
+ s_pipe.wait(); //Synchronization point B
+ uninstall_app(sm_app_id_a, sm_pkg_id_a, false, SM_APP_INSTALL_GLOBAL, false);
+ uninstall_app(sm_app_id_b, sm_app_id_b, false, SM_APP_INSTALL_GLOBAL, false);
+ uninstall_app(sm_app_id_c, sm_app_id_c, false, SM_APP_INSTALL_GLOBAL, false);
+ waitPid(pid);
+ } else { //child process
+ setCaps("all=eip");
+ RUNNER_ASSERT_ERRNO_MSG(prctl(PR_SET_KEEPCAPS, 1, 0, 0) == 0, "prctl keeping caps failed");
+ s_pipe.claimChildEp();
+ FdUniquePtr pipeptr(pipefd);
+ close(pipefd[1]);
+ UidGidMsg msg = readCreds(pipefd[0]);
+ int result = drop_root_privileges(msg.uid, msg.gid);
+ RUNNER_ASSERT_MSG(result == 0, "drop_root_privileges failed");
+ setCaps("cap_mac_admin=eip");
+ app_labels_monitor *monitor;
+ Api::labelsMonitorInit(&monitor);
+ s_pipe.wait(); //A
+ Api::labelsProcess(monitor);
+ Api::labelsMonitorFinish(monitor);
+ setCaps("cap_mac_admin-eip");
+ testSetLabelForSelf(sm_app_id_a, true); // global installation (OK)
+ testSetLabelForSelf(sm_app_id_b, false); //second change
+ testSetLabelForSelf(sm_app_id_c, false); //second change
+ s_pipe.post(); //B
+ }
+}
+
+RUNNER_CHILD_TEST(security_manager_75_app_label_monitor_relabel_changes_2) {
+
+ const char *sm_app_id_a = "sm_test_75_app_label_monitor_local_1";
+ const char *sm_pkg_id_a = "sm_test_75_app_label_monitor_local_1";
+ const char *sm_app_id_b = "sm_test_75_app_label_monitor_local_2";
+ const char *sm_pkg_id_b = "sm_test_75_app_label_monitor_local_2";
+ const char *sm_app_id_c = "sm_test_75_app_label_monitor_local_3";
+ const char *sm_pkg_id_c = "sm_test_75_app_label_monitor_local_3";
+ const char *bad_seed ="Not_permitted_id";
+ const std::string new_user_name = "sm_test_75";
+
+ int pipefd[2];
+ RUNNER_ASSERT_MSG((pipe(pipefd) != -1), "pipe failed");
+ SynchronizationPipe s_pipe;
+
+ pid_t pid = fork();
+ if (pid != 0) { //parent process
+ FdUniquePtr pipeptr(pipefd + 1);
+ close(pipefd[0]);
+ s_pipe.claimParentEp();
+ TemporaryTestUser testUser(new_user_name, GUM_USERTYPE_NORMAL, false);
+ UidGidMsg msg = createUserSendCreds(testUser, pipefd[1]);
+ int result = drop_root_privileges(msg.uid, msg.gid);
+ RUNNER_ASSERT_MSG(result == 0, "drop_root_privileges failed");
+ install_app(sm_app_id_a, sm_pkg_id_a, msg.uid, SM_APP_INSTALL_LOCAL, false);
+ install_app(sm_app_id_b, sm_pkg_id_b, msg.uid, SM_APP_INSTALL_LOCAL, false);
+ install_app(sm_app_id_c, sm_pkg_id_c, msg.uid, SM_APP_INSTALL_LOCAL, false);
+ uninstall_app(sm_app_id_a, sm_pkg_id_a, false, SM_APP_INSTALL_LOCAL, false);
+ s_pipe.post(); //Synchronization A
+ s_pipe.wait(); //Synchronization B
+ uninstall_app(sm_app_id_b, sm_pkg_id_b, false, SM_APP_INSTALL_LOCAL, false);
+ uninstall_app(sm_app_id_c, sm_pkg_id_c, false, SM_APP_INSTALL_LOCAL, false);
+ waitPid(pid);
+ } else { //child process
+ setCaps("all=eip");
+ RUNNER_ASSERT_ERRNO_MSG(prctl(PR_SET_KEEPCAPS, 1, 0, 0) == 0, "prctl keeping caps failed");
+ s_pipe.claimChildEp();
+ FdUniquePtr pipeptr(pipefd);
+ close(pipefd[1]);
+ UidGidMsg msg = readCreds(pipefd[0]);
+ int result = drop_root_privileges(msg.uid, msg.gid);
+ RUNNER_ASSERT_MSG(result == 0, "drop_root_privileges failed");
+ setCaps("cap_mac_admin=eip");
+ app_labels_monitor *monitor;
+ Api::labelsMonitorInit(&monitor);
+ s_pipe.wait(); //A
+ Api::labelsProcess(monitor);
+ Api::labelsMonitorFinish(monitor);
+ setCaps("cap_mac_admin-eip");
+ testSetLabelForSelf(bad_seed, false); //not premitted
+ testSetLabelForSelf(sm_app_id_a, false); //uninstalled
+ testSetLabelForSelf(sm_app_id_b, true); //installed
+ testSetLabelForSelf(sm_app_id_c, false); //second change
+ s_pipe.post(); //B
+ }
+}
+
int main(int argc, char *argv[])
{
return DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv);