From 35af60dde5bd29042bf86b3d3ab7bed471b6a4a3 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Thu, 11 Jan 2018 16:39:44 +0100 Subject: [PATCH] Refactor security_manager_create_namespace_internal() This change reduces the number of IPCs and SQL queries needed to setup mount namespace. The goal is to reduce the application start time. Change-Id: Ib6ee820f097f07add9228346cd9a191abb16a97c --- src/client/client-security-manager.cpp | 64 ++++++++++++-------------- src/common/include/protocols.h | 2 +- src/common/include/service_impl.h | 6 ++- src/common/service_impl.cpp | 83 +++++++++++++++++++++------------- src/server/service/include/service.h | 4 +- src/server/service/service.cpp | 14 ++++-- 6 files changed, 97 insertions(+), 76 deletions(-) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index 92fad32..672bc43 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -774,25 +774,22 @@ int security_manager_drop_process_privileges(void) return SECURITY_MANAGER_SUCCESS; } -static inline int security_manager_bind_namespace_internal(const char *app_name) +static int setupMountNamespace(const std::string appName, std::vector> &privilegeStatusVector) { - using namespace SecurityManager; - return try_catch([&]() -> int { - ClientRequest request(SecurityModuleCall::APP_BIND_NAMESPACE); - return request.send(std::string(app_name)).getStatus(); - }); + ClientRequest request(SecurityModuleCall::APP_SETUP_NAMESPACE); + if (request.send(appName).failed()) + return request.getStatus(); + + request.recv(privilegeStatusVector); + return SECURITY_MANAGER_SUCCESS; } static inline int security_manager_create_namespace_internal(const char *app_name) { - int ret, result; - - if (app_name == nullptr) { - LogError("app_name is NULL"); - return SECURITY_MANAGER_ERROR_INPUT_PARAM; - } + if (!MountNS::isMountNamespaceEnabled()) + return SECURITY_MANAGER_SUCCESS; - ret = MountNS::createMountNamespace(); + int ret = MountNS::createMountNamespace(); if (ret != SECURITY_MANAGER_SUCCESS) return ret; @@ -800,33 +797,32 @@ static inline int security_manager_create_namespace_internal(const char *app_nam if (ret != SECURITY_MANAGER_SUCCESS) return ret; + std::vector> privilegeStatusVector; + ret = setupMountNamespace(app_name, privilegeStatusVector); + if (ret != SECURITY_MANAGER_SUCCESS) { + LogError("Failed to setup app namespace: " << security_manager_strerror(static_cast(ret)) << " App name:" << app_name); + return ret; + } + auto storagePrivilegePathMap = MountNS::getPrivilegePathMap(getuid()); - for (auto &it : storagePrivilegePathMap) { - ret = security_manager_app_has_privilege(app_name, it.first.c_str(), getuid(), &result); - if (ret != SECURITY_MANAGER_SUCCESS) { - LogError("Error: " << security_manager_strerror(static_cast(ret)) << " App name: " << app_name << ", " << it.first); - return ret; - } + for (auto &privilegeStatus : privilegeStatusVector) { + auto it = storagePrivilegePathMap.find(privilegeStatus.first); + if (it == storagePrivilegePathMap.end()) + continue; - for (auto &privilegePath : it.second) { + for (auto &privilegePath : it->second) { if (FS::directoryStatus(privilegePath.dstPath) == 0) { - LogWarning("Not enforcing privilege " << it.first << " for application " << app_name << " : " << - "directory " << privilegePath.dstPath << " doesn't exist"); + LogWarning("Not enforcing privilege " << it->first << " for application " << app_name << " : " << + "directory " << privilegePath.dstPath << " doesn't exist"); continue; } - ret = MountNS::applyPrivilegePath(result, privilegePath); + ret = MountNS::applyPrivilegePath(privilegeStatus.second, privilegePath); if (ret != SECURITY_MANAGER_SUCCESS) return ret; } } - ret = security_manager_bind_namespace_internal(app_name); - if (ret != SECURITY_MANAGER_SUCCESS) { - LogError("Failed to bind app namespace: " << security_manager_strerror(static_cast(ret)) << " App name:" << app_name); - return ret; - } - return SECURITY_MANAGER_SUCCESS; } @@ -847,12 +843,10 @@ int security_manager_prepare_app(const char *app_name) return ret; } - if (MountNS::isMountNamespaceEnabled()) { - ret = security_manager_create_namespace_internal(app_name); - if (ret != SECURITY_MANAGER_SUCCESS) { - LogError("Unable to setup namespace for application " << app_name); - return ret; - } + ret = security_manager_create_namespace_internal(app_name); + if (ret != SECURITY_MANAGER_SUCCESS) { + LogError("Unable to setup namespace for application " << app_name); + return ret; } ret = security_manager_sync_threads_internal(app_name); diff --git a/src/common/include/protocols.h b/src/common/include/protocols.h index dd4a29e..ad4faf7 100644 --- a/src/common/include/protocols.h +++ b/src/common/include/protocols.h @@ -126,7 +126,7 @@ enum class SecurityModuleCall GET_APP_DEFINED_PRIVILEGE_PROVIDER, GET_APP_DEFINED_PRIVILEGE_LICENSE, GET_CLIENT_PRIVILEGE_LICENSE, - APP_BIND_NAMESPACE, + APP_SETUP_NAMESPACE, APP_CLEAN_NAMESPACE, NOOP = 0x90, }; diff --git a/src/common/include/service_impl.h b/src/common/include/service_impl.h index 5a27a7c..f9b941b 100644 --- a/src/common/include/service_impl.h +++ b/src/common/include/service_impl.h @@ -293,14 +293,16 @@ public: std::string &license); /** - * Bind app namespace to file + * Setup app namespace * * @param[in] creds credentials of the requesting process * @param[in] appName application identifier + * @param[out] privilegeStatusVector returned vector of privilege-status pair * * @return API return code, as defined in protocols.h */ - int appBindNamespace(const Credentials &creds, const std::string &appName); + int appSetupNamespace(const Credentials &creds, const std::string &appName, + std::vector> &privilegeStatusVector); /** * Register channel for communication with worker process. diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp index 12f1e6b..8c669d9 100644 --- a/src/common/service_impl.cpp +++ b/src/common/service_impl.cpp @@ -1973,53 +1973,74 @@ int ServiceImpl::getClientPrivilegeLicense( return SECURITY_MANAGER_SUCCESS; } -int ServiceImpl::appBindNamespace(const Credentials &creds, const std::string &appName) +int ServiceImpl::appSetupNamespace(const Credentials &creds, const std::string &appName, + std::vector> &privilegeStatusVector) { int ret; - if (!authenticate(creds, Config::PRIVILEGE_APP_NAMESPACE)) { - LogError("Request from uid=" << creds.uid << ", Smack=" << creds.label << " for app bind denied"); + LogError("Request from uid=" << creds.uid << ", Smack=" << creds.label << " for setup app namespace denied"); return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED; } - const std::string appProcessLabel = getAppProcessLabel(appName); - const std::string appsDir = MountNS::getUserAppsMountPointsPath(creds.uid); - const std::string appFile = MountNS::getUserAppMountPointPath(creds.uid, appProcessLabel); - const std::string procFile = "/proc/" + std::to_string(creds.pid) + "/ns/mnt"; + try { + const std::string appProcessLabel = getAppProcessLabel(appName); + const std::string uidStr = std::to_string(creds.uid); + const std::string appsDir = MountNS::getUserAppsMountPointsPath(creds.uid); + const std::string appFile = MountNS::getUserAppMountPointPath(creds.uid, appProcessLabel); + const std::string procFile = "/proc/" + std::to_string(creds.pid) + "/ns/mnt"; + + if (FS::directoryStatus(appsDir) == 0) { // directory does not exist + ret = FS::createDirectory(appsDir); + if (ret != SECURITY_MANAGER_SUCCESS) + return ret; - if (FS::directoryStatus(appsDir) == 0) { // directory does not exist - ret = FS::createDirectory(appsDir); - if (ret != SECURITY_MANAGER_SUCCESS) - return ret; + ret = MountNS::bindMount(appsDir, appsDir); + if (ret != SECURITY_MANAGER_SUCCESS) { + FS::removeDirectory(appsDir); + return ret; + } - ret = MountNS::bindMount(appsDir, appsDir); - if (ret != SECURITY_MANAGER_SUCCESS) { - FS::removeDirectory(appsDir); - return ret; + ret = MountNS::makeMountPrivate(appsDir); + if (ret != SECURITY_MANAGER_SUCCESS) { + MountNS::uMount(appsDir); + FS::removeDirectory(appsDir); + return ret; + } + } + + if (FS::fileStatus(appFile) == 0) { // file does not exist + ret = FS::createFile(appFile); + if (ret != SECURITY_MANAGER_SUCCESS) + return ret; + } else { + MountNS::uMount(appFile); } - ret = MountNS::makeMountPrivate(appsDir); + ret = MountNS::bindMount(procFile, appFile); if (ret != SECURITY_MANAGER_SUCCESS) { - MountNS::uMount(appsDir); - FS::removeDirectory(appsDir); + FS::removeFile(appFile); return ret; } - } - if (FS::fileStatus(appFile) == 0) { // file does not exist - ret = FS::createFile(appFile); - if (ret != SECURITY_MANAGER_SUCCESS) - return ret; - } else { - MountNS::uMount(appFile); - } + auto storagePrivilegePathMap = MountNS::getPrivilegePathMap(creds.uid); + for (auto &it : storagePrivilegePathMap) { + bool result = m_cynara.check(appProcessLabel, it.first.c_str(), uidStr, ""); + privilegeStatusVector.push_back(make_pair(it.first, result)); + } - ret = MountNS::bindMount(procFile, appFile); - if (ret != SECURITY_MANAGER_SUCCESS) { - FS::removeFile(appFile); - return ret; + } catch (const CynaraException::Base &e) { + LogError("Error while querying Cynara for permissions: " << e.DumpToString()); + return SECURITY_MANAGER_ERROR_SERVER_ERROR; + } catch (const SmackException::InvalidLabel &e) { + LogError("Error while generating Smack labels: " << e.DumpToString()); + return SECURITY_MANAGER_ERROR_SERVER_ERROR; + } catch (const std::bad_alloc &e) { + LogError("Memory allocation failed: " << e.what()); + return SECURITY_MANAGER_ERROR_MEMORY; + } catch (...) { + LogError("Unknown exception thrown"); + return SECURITY_MANAGER_ERROR_UNKNOWN; } - return SECURITY_MANAGER_SUCCESS; } diff --git a/src/server/service/include/service.h b/src/server/service/include/service.h index 412f13c..1188935 100644 --- a/src/server/service/include/service.h +++ b/src/server/service/include/service.h @@ -231,13 +231,13 @@ private: void processGetClientPrivilegeLicense(MessageBuffer &buffer, MessageBuffer &send); /** - * Process bind namespace to file + * Process setup app namespace * * @param buffer Raw received data buffer * @param send Raw data buffer to be sent * @param creds credentials of the requesting process */ - void processAppBindNamespace(MessageBuffer &buffer, MessageBuffer &send, const Credentials &creds); + void processAppSetupNamespace(MessageBuffer &buffer, MessageBuffer &send, const Credentials &creds); /** * Process clean app namespace diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index 498d413..04dff6d 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -161,9 +161,9 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer, LogDebug("call_type: SecurityModuleCall::GET_CLIENT_PRIVILEGE_PROVIDER"); processGetClientPrivilegeLicense(buffer, send); break; - case SecurityModuleCall::APP_BIND_NAMESPACE: - LogDebug("call_type: SecurityModuleCall::APP_BIND_NAMESPACE"); - processAppBindNamespace(buffer, send, creds); + case SecurityModuleCall::APP_SETUP_NAMESPACE: + LogDebug("call_type: SecurityModuleCall::APP_SETUP_NAMESPACE"); + processAppSetupNamespace(buffer, send, creds); break; case SecurityModuleCall::APP_CLEAN_NAMESPACE: LogDebug("call_type: SecurityModuleCall::APP_CLEAN_NAMESPACE"); @@ -460,12 +460,16 @@ void Service::processGetClientPrivilegeLicense(MessageBuffer &buffer, MessageBuf Serialization::Serialize(send, license); } -void Service::processAppBindNamespace(MessageBuffer &buffer, MessageBuffer &send, const Credentials &creds) +void Service::processAppSetupNamespace(MessageBuffer &buffer, MessageBuffer &send, const Credentials &creds) { std::string appName; + std::vector> privilegeStatusVector; + Deserialization::Deserialize(buffer, appName); - int ret = serviceImpl.appBindNamespace(creds, appName); + int ret = serviceImpl.appSetupNamespace(creds, appName, privilegeStatusVector); Serialization::Serialize(send, ret); + if (ret == SECURITY_MANAGER_SUCCESS) + Serialization::Serialize(send, privilegeStatusVector); } void Service::processAppCleanNamespace(MessageBuffer &buffer, MessageBuffer &send, const Credentials &creds) -- 2.7.4