From: Rafal Krypa Date: Tue, 19 Apr 2016 12:26:44 +0000 (+0200) Subject: TemporaryTestUser: encapsulate communication with gumd in separate process X-Git-Tag: security-manager_5.5_testing~104 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5ac95b6b464af0fbd701aac7182e99a1c5c79c70;p=platform%2Fcore%2Ftest%2Fsecurity-tests.git TemporaryTestUser: encapsulate communication with gumd in separate process Gumd interface libgum has nasty side effects on the calling process. On the first call to gumd service it allocates persistent resources in the calling thread that are not freed and are used for subsequent calls to gumd. These resources include a new thread, socket connection and two eventfds. This doesn't play well with process that changes it's Smack label and DAC credentials back and forth. It also breaks encapsulation between test cases, leading to nasty "gumd timeout" issues. This patch attempts to fix this issue by dedicated a separate process for calling libgum functions. The TemporaryTestUser class will no longer call libgum directly, but delegate the calls to the dedicated process. Change-Id: Id111d5ef79d65135e3b378582a220f168f8a2284 Signed-off-by: Rafal Krypa --- diff --git a/src/common/temp_test_user.cpp b/src/common/temp_test_user.cpp index f6aa6c1d..198645c8 100644 --- a/src/common/temp_test_user.cpp +++ b/src/common/temp_test_user.cpp @@ -17,43 +17,191 @@ /* * @file temp_test_user.cpp * @author Jan Cybulski (j.cybulski@partner.samsung.com) + * @author Rafal Krypa (j.cybulski@samsung.com) * @version 1.0 * @brief File with class for users management */ +#include +#include #include #include #include +#include +#include +#include +#include +#include + void TemporaryTestUser::create(void) { - if (m_guser) { + if (m_uid != 0) remove(); - }; - - m_guser = gum_user_create_sync (m_offline); - RUNNER_ASSERT_MSG(m_guser != nullptr, "Failed to create gumd user object"); - g_object_set(G_OBJECT(m_guser), "usertype", m_userType, NULL); - g_object_set(G_OBJECT(m_guser), "username", m_userName.c_str(), NULL); - gboolean added = gum_user_add_sync(m_guser); - RUNNER_ASSERT_MSG(added, "Failed to add user"); - g_object_get(G_OBJECT(m_guser), "uid", &m_uid, NULL); + + bool ret = m_runner.userCreate(m_userName, m_userType, m_offline, m_uid, m_gid); + RUNNER_ASSERT_MSG(ret, "Failed to add user"); RUNNER_ASSERT_MSG(m_uid != 0, "Something strange happened during user creation. uid == 0."); - g_object_get(G_OBJECT(m_guser), "gid", &m_gid, NULL); RUNNER_ASSERT_MSG(m_gid != 0, "Something strange happened during user creation. gid == 0."); } void TemporaryTestUser::remove(void) { - if(m_guser){ - gum_user_delete_sync(m_guser, TRUE); - g_object_unref(m_guser); - m_guser = nullptr; - } + if (m_uid == 0) + return; + + m_runner.userRemove(m_uid, m_offline); + m_uid = m_gid = 0; } TemporaryTestUser::~TemporaryTestUser() { this->remove(); } + +TemporaryTestUser::GumdRunner TemporaryTestUser::m_runner = TemporaryTestUser::GumdRunner(); + +TemporaryTestUser::GumdRunner::GumdRunner() +{ + int sock[2]; + int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); + RUNNER_ASSERT_MSG(ret != -1, "socketpair() failed"); + + pid_t pid = fork(); + RUNNER_ASSERT_MSG(pid != -1, "fork() failed"); + if (pid) { // parent + m_sock = sock[0]; + close(sock[1]); + return; + } else { // child + m_sock = sock[1]; + close(sock[0]); + prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // Don't outlive parent process + run(); // Never returns + } +} + +TemporaryTestUser::GumdRunner::~GumdRunner() +{ + close(m_sock); +} + +bool TemporaryTestUser::GumdRunner::userCreate(std::string userName, + GumUserType userType, bool offline, uid_t &uid, gid_t &gid) +{ + put(static_cast(opType::USER_CREATE)); + put(userName.size()); + put(userName.c_str(), userName.size()); + put(userType); + put(offline); + + bool ret = get(); + if (ret) { + uid = get(); + gid = get(); + } + return ret; +} + +bool TemporaryTestUser::GumdRunner::userRemove(uid_t uid, bool offline) +{ + put(static_cast(opType::USER_REMOVE)); + put(uid); + put(offline); + return get(); +} + + +void TemporaryTestUser::GumdRunner::run() +{ + DEFINE_SMARTPTR(g_object_unref, GumUser, GumUserPtr); + + while (true) { + switch(static_cast(get())) { + case opType::USER_CREATE: + { + size_t userNameLen = get(); + std::unique_ptr userNamePtr(new char[userNameLen + 1]); + get(userNamePtr.get(), userNameLen); + userNamePtr[userNameLen] = '\0'; + GumUserType userType = get(); + bool offline = get(); + + bool result = false; + uid_t uid; + gid_t gid; + + GumUserPtr userPtr(gum_user_create_sync(offline)); + if (userPtr) { + g_object_set(G_OBJECT(userPtr.get()), + "username", userNamePtr.get(), + "usertype", userType, + nullptr); + gboolean ret = gum_user_add_sync(userPtr.get()); + if (ret == TRUE) { + g_object_get(G_OBJECT(userPtr.get()), "uid", &uid, nullptr); + g_object_get(G_OBJECT(userPtr.get()), "gid", &gid, nullptr); + result = true; + } + } + + put(result); + if (result) { + put(uid); + put(gid); + } + } + break; + + case opType::USER_REMOVE: + { + uid_t uid = get(); + bool offline = get(); + bool result = false; + + GumUserPtr userPtr(gum_user_get_sync(uid, offline)); + if (userPtr) { + gboolean ret = gum_user_delete_sync(userPtr.get(), TRUE); + result = (ret == TRUE); + } + put(static_cast(result)); + } + break; + } + } +} + +void TemporaryTestUser::GumdRunner::get(void *buf, size_t cnt) +{ + int ret; + for (size_t pos = 0; pos < cnt; pos += ret) { + ret = TEMP_FAILURE_RETRY( + read(m_sock, static_cast(buf) + pos, cnt - pos)); + RUNNER_ASSERT_MSG(ret != -1, "read() failed"); + } +} + +void TemporaryTestUser::GumdRunner::put(const void *buf, size_t cnt) +{ + int ret; + for (size_t pos = 0; pos < cnt; pos += ret) { + ret = TEMP_FAILURE_RETRY( + write(m_sock, static_cast(buf) + pos, cnt - pos)); + RUNNER_ASSERT_MSG(ret != -1, "write() failed"); + } +} + +template +T TemporaryTestUser::GumdRunner::get() +{ + T x; + get(&x, sizeof(x)); + return std::move(x); +} + +template +void TemporaryTestUser::GumdRunner::put(const T x) +{ + put(&x, sizeof(x)); +} diff --git a/src/common/temp_test_user.h b/src/common/temp_test_user.h index 120b21b8..72e74089 100644 --- a/src/common/temp_test_user.h +++ b/src/common/temp_test_user.h @@ -30,7 +30,6 @@ public: m_gid(0), m_userName(userName), m_userType(userType), - m_guser(nullptr), m_offline(offline) {}; ~TemporaryTestUser(); @@ -41,12 +40,32 @@ public: void getUidString(std::string& uidstr) const {uidstr = std::to_string(static_cast(m_uid));} const std::string& getUserName() const {return m_userName;} GumUserType getUserType() const {return m_userType;} + private: + class GumdRunner { + public: + GumdRunner(); + ~GumdRunner(); + bool userCreate(std::string userName, GumUserType userType, bool offline, + uid_t &uid, gid_t &gid); + bool userRemove(uid_t uid, bool offline); + + private: + enum class opType {USER_CREATE, USER_REMOVE}; + int m_sock; + + void run(); + void get(void *buf, size_t count); + void put(const void *buf, size_t count); + template T get(); + template void put(const T x); + }; + + static GumdRunner m_runner; uid_t m_uid; uid_t m_gid; std::string m_userName; GumUserType m_userType; - GumUser *m_guser; bool m_offline; };