From: u.harbuz Date: Thu, 24 Aug 2017 07:49:18 +0000 (+0200) Subject: Implement checking of Tizen policies X-Git-Tag: submit/tizen/20170914.115510~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c2d33223c2ecb17ccab5a6412f49ffa89840ff33;p=platform%2Fcore%2Fsecurity%2Ftef-simulator.git Implement checking of Tizen policies Change-Id: I18d2ef26f63d17b3d97d5af9fbeab0f0db4bc3e1 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c8ff86..4afbe25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ ADD_DEFINITIONS("-Werror") # Make all warnings into errors. #ADD_DEFINITIONS("-Wall") # Generate all warnings #ADD_DEFINITIONS("-Wextra") # Generate even more extra warnings +ADD_DEFINITIONS("-D_CYNARA_INTEGRATION") IF (CMAKE_BUILD_TYPE MATCHES "DEBUG") ADD_DEFINITIONS("-DTIZEN_DEBUG_ENABLE") diff --git a/packaging/tef-simulator.spec b/packaging/tef-simulator.spec index d2e8b61..d28dc76 100644 --- a/packaging/tef-simulator.spec +++ b/packaging/tef-simulator.spec @@ -10,6 +10,7 @@ BuildRequires: boost-devel BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(openssl) BuildRequires: pkgconfig(cynara-client) +BuildRequires: pkgconfig(cynara-session) BuildRequires: pkgconfig(cynara-creds-socket) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: pkgconfig(security-manager) diff --git a/pkgconfig/tef-simulator-devkit.pc.in b/pkgconfig/tef-simulator-devkit.pc.in index 04ee70a..50a74ae 100644 --- a/pkgconfig/tef-simulator-devkit.pc.in +++ b/pkgconfig/tef-simulator-devkit.pc.in @@ -7,5 +7,5 @@ Name: tef-simulator-devkit Description: TEF Simulator TA development kit Version: @PKGCFG_VERSION@ Requires: boost dlog openssl -Libs: -L${libdir} -lTEEStub -ltef-simulator-ssflib -ltef-simulator-log -lboost_thread -lboost_system -ldlog +Libs: -L${libdir} -lTEEStub -ltef-simulator-ssflib -ltef-simulator-log -lboost_thread -lboost_filesystem -lboost_system -ldlog Cflags: -I${includedir}/ diff --git a/simulatordaemon/CMakeLists.txt b/simulatordaemon/CMakeLists.txt index e79bf6a..1c76541 100644 --- a/simulatordaemon/CMakeLists.txt +++ b/simulatordaemon/CMakeLists.txt @@ -19,9 +19,11 @@ PKG_CHECK_MODULES(DAEMON_DEPS REQUIRED cynara-client + cynara-session cynara-creds-socket security-manager libsystemd-daemon + libtzplatform-config ) FIND_PACKAGE(Threads REQUIRED) @@ -29,10 +31,7 @@ FIND_PACKAGE(Threads REQUIRED) SET(DAEMON_SOURCES ${DAEMON_PATH}/src/ConnectionSession.cpp ${DAEMON_PATH}/src/ioService.cpp - # TODO change Security to cpp module - #${DAEMON_PATH}/src/security.c - # TODO lots of circular dependecies are within SecurityChecker, refactor - #${DAEMON_PATH}/src/SecurityChecker.cpp + ${DAEMON_PATH}/src/SecurityContext.cpp ${DAEMON_PATH}/src/Session.cpp ${DAEMON_PATH}/src/SimulatorDaemon.cpp ${DAEMON_PATH}/src/SimulatorDaemonServer.cpp @@ -62,7 +61,6 @@ SET(DAEMON_SOURCES ${DAEMON_PATH}/src/TABinaryManager/TAUnpack.cpp ) - ADD_EXECUTABLE(${TARGET_TEF_SIMULATOR_DAEMON} ${DAEMON_SOURCES} ) @@ -93,7 +91,7 @@ TARGET_LINK_LIBRARIES(${TARGET_TEF_SIMULATOR_DAEMON} ${DAEMON_DEPS_LIBRARIES} ${TARGET_TEF_SIMULATOR_LOG} ${TARGET_TEF_SIMULATOR_OSAL} - boost_system + boost_system boost_filesystem ) INSTALL(TARGETS ${TARGET_TEF_SIMULATOR_DAEMON} DESTINATION ${BIN_DIR}) diff --git a/simulatordaemon/inc/ConnectionSession.h b/simulatordaemon/inc/ConnectionSession.h index 53e02c3..9d253dd 100644 --- a/simulatordaemon/inc/ConnectionSession.h +++ b/simulatordaemon/inc/ConnectionSession.h @@ -33,6 +33,7 @@ #include "ClientCommands/MakeCommand.h" #include "TEEContext.h" #include "IConnectionSession.h" +#include "SecurityContext.h" using namespace std; @@ -66,6 +67,7 @@ public: } void start(); TEEC_Result write(TEE_CMD command, char* data, size_t size); + SecurityContext getSecurityContext(); ~ConnectionSession(); private: TEEContext *TEECtx; @@ -73,6 +75,8 @@ private: size_t bytes_transferred); // The socket used to communicate with the client. stream_protocol::socket clientSocket; + // Security context of Connection. + SecurityContext secContext; // Buffer used to store data received from the client. boost::array clientData; states currentState; diff --git a/simulatordaemon/inc/IConnectionSession.h b/simulatordaemon/inc/IConnectionSession.h index 046a69b..f7664ae 100644 --- a/simulatordaemon/inc/IConnectionSession.h +++ b/simulatordaemon/inc/IConnectionSession.h @@ -23,6 +23,7 @@ * Include files *-----------------------------------------------------------------------------*/ #include "tee_command.h" +#include "SecurityContext.h" /*----------------------------------------------------------------------------- * Class definitions @@ -30,6 +31,7 @@ class IConnectionSession { public: virtual TEEC_Result write(TEE_CMD command, char* data, size_t size) = 0; + virtual SecurityContext getSecurityContext() = 0; virtual ~IConnectionSession() {} }; diff --git a/simulatordaemon/inc/ISession.h b/simulatordaemon/inc/ISession.h index 766c719..cf05546 100644 --- a/simulatordaemon/inc/ISession.h +++ b/simulatordaemon/inc/ISession.h @@ -26,6 +26,7 @@ #include "tee_command.h" #include "teestub_command_data.h" #include "ITAInstance.h" +#include "SecurityContext.h" /*----------------------------------------------------------------------------- * Class definitions @@ -40,6 +41,7 @@ public: virtual bool checkInternal() = 0; virtual uint32_t getContextID() = 0; virtual uint32_t getSessionID() = 0; + virtual SecurityContext getSecurityContext() = 0; virtual TAInstancePtr getTAInstance() = 0; virtual TEEC_Result writeResponse(TEE_CMD command, char* data, size_t size) = 0; virtual void detachFromContext() = 0; diff --git a/simulatordaemon/inc/SecurityChecker.h b/simulatordaemon/inc/SecurityChecker.h deleted file mode 100644 index a030d72..0000000 --- a/simulatordaemon/inc/SecurityChecker.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * ===================================================================================== - * - * Filename: SecurityChecker.h - * - * Description: Class to check if client application has access to TEE - * - * Version: 1.0 - * Created: 19 June 2017 14:00:03 IST - * Revision: Original - * Compiler: gcc - * - * Author: Uladzislau Harbuz, u.harbuz@samsung.com - * Organization: Samsung Electronics - * - * ===================================================================================== - */ - -#ifndef SECURITYCHECKER_H -#define SECURITYCHECKER_H - -#include -#include "ConnectionSession.h" -#include "log.h" -#include "security.h" - - -using std::string; -class ConnectionSession; - -class SecurityChecker { -private: - ConnectionSession* mConnSess; - -public: - - SecurityChecker(ConnectionSession* ses); - - static bool clientHasAccessToTa(ConnectionSession *ses, string taName); - static bool clientHasCynaraPermission(ConnectionSession *ses, string privelege); - - bool clientHasAccessToTa(string taName); - bool clientHasCynaraPermission(string privelege); - - ~SecurityChecker(); - -}; -#endif /* SECURITYCHECKER_H */ diff --git a/simulatordaemon/inc/SecurityContext.h b/simulatordaemon/inc/SecurityContext.h new file mode 100644 index 0000000..a012752 --- /dev/null +++ b/simulatordaemon/inc/SecurityContext.h @@ -0,0 +1,71 @@ +/* + * SecurityContext.h + * + * Copyright (C) 2017 Samsung Electronics + * Uladzislau Harbuz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SECURITYCONTEXT_H +#define SECURITYCONTEXT_H + +#include +#include "log.h" +#include "config.h" +#include + +#define TA_LOCAL_PATH "/res/tee" + +class SecurityContext { +private: + int connFd; + + static constexpr const size_t CYNARA_CACHE_SIZE = 100U; + + static cynara* initCynara(); + static cynara* _cynara; + + static constexpr const char* sysTaPaths[] = { + TEE_TASTORE_ROOT, + }; + + static std::string getCaFullPathFromPkgId(char*); + +public: + SecurityContext(); + SecurityContext(int connFd); + ~SecurityContext(); + +/** + * This function tries to find TA by name in directories, + * which are allowed for CA according to security policies + * + * @param taName Name of ta to connect for. + * @param allowedPath Out parameter, if function returns true, it + * contains found path to TA with given name, + * otherwise it's empty. + * @return true if TA was found, otherwise false. + */ + bool findRequestedTa(const std::string &taName, std::string& allowedPath); + +/** + * Check if client has Tizen permission for use TEE. + * + * @param privilege Privilege to be checked for client. + * @return true if client has permission, otherwise false. + */ + bool clientHasCynaraPermission(const std::string &privilege); +}; + +#endif /*SECURITYCONTEXT_H*/ diff --git a/simulatordaemon/inc/Session.h b/simulatordaemon/inc/Session.h index 8569059..2c95de0 100644 --- a/simulatordaemon/inc/Session.h +++ b/simulatordaemon/inc/Session.h @@ -49,6 +49,7 @@ public: bool checkInternal(); uint32_t getContextID(); uint32_t getSessionID(); + SecurityContext getSecurityContext(); TAInstancePtr getTAInstance(); TEEC_Result writeResponse(TEE_CMD command, char* data, size_t size); void detachFromContext(); diff --git a/simulatordaemon/inc/TAFactory.h b/simulatordaemon/inc/TAFactory.h index e3916c3..ed6b453 100644 --- a/simulatordaemon/inc/TAFactory.h +++ b/simulatordaemon/inc/TAFactory.h @@ -50,7 +50,7 @@ private: TAFactory(); bool checkIfTARunning(string TAUUID); TAInstancePtr createUninitalizedTAInstance(string TAUUID, ISession* session); - bool launchTA(string TAUUID, std::stringstream& str, bool debug, pid_t& pid); + bool launchTA(string TAPath, string TAUUID, std::stringstream& str, bool debug, pid_t& pid); static void* waitForChild(void *pid); void cleanupTAInstance(pid_t PID); ~TAFactory(); diff --git a/simulatordaemon/inc/TEEContext.h b/simulatordaemon/inc/TEEContext.h index 79212de..5b35f02 100644 --- a/simulatordaemon/inc/TEEContext.h +++ b/simulatordaemon/inc/TEEContext.h @@ -31,6 +31,7 @@ #include "Session.h" #include "tee_command.h" #include "IConnectionSession.h" +#include "SecurityContext.h" using namespace std; /*----------------------------------------------------------------------------- @@ -53,9 +54,8 @@ public: IConnectionSession* mConnSess; // ContextID assigned to the instance uint32_t mContextID; - /* Security checker wich can tell us if client has different Tizen's policy permissions*/ - // TODO refactor SecurityChecker - //SecurityChecker mConnSecChecker; + /* Security context wich stores info about low-level connection data*/ + SecurityContext secContext; /* For TA internal APIs support, dummy Context is created and for recognizing * the context as dummy isInternal member variable is used diff --git a/simulatordaemon/inc/security.h b/simulatordaemon/inc/security.h deleted file mode 100644 index 695cc7c..0000000 --- a/simulatordaemon/inc/security.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * security.h - * - * Copyright (C) 2017 Samsung Electronics - * Uladzislau Harbuz - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef SECURITY_H -#define SECURITY_H - -#include - -#define MAX_PATH_LENGTH 100 -#define MAX_OPENED_FD 5 - -#ifdef __cplusplus -extern "C" { -#endif - -bool ca_has_access_to_ta(int ca_fd, const char* ta_name); -bool client_has_cynara_permission(int ca_fd, const char* privelege); - -#ifdef __cplusplus -} -#endif - - -#endif /* SECURITY_H */ diff --git a/simulatordaemon/src/ConnectionSession.cpp b/simulatordaemon/src/ConnectionSession.cpp index 759eab4..4c0c958 100644 --- a/simulatordaemon/src/ConnectionSession.cpp +++ b/simulatordaemon/src/ConnectionSession.cpp @@ -40,6 +40,18 @@ uint32_t ctxID = 21; void ConnectionSession::start() { LOGD(SIM_DAEMON, "Entry"); + // init SecurityContext of current session after initializing socket + this->secContext = SecurityContext(clientSocket.native()); + +#ifdef _CYNARA_INTEGRATION + /* Check if client has cynara permission */ + const string privilege("http://tizen.org/privilege/tee.client"); + if (! secContext.clientHasCynaraPermission(privilege)) { + LOGE(SIM_DAEMON, "Client has no permission to use TEE"); + return; + } +#endif /* _CYNARA_INTEGRATION */ + // Create a new Context pthread_rwlock_wrlock(&ctxIDLock); TEECtx = new TEEContext(ctxID, this); @@ -48,6 +60,7 @@ void ConnectionSession::start() { if (ctxID == 0) ctxID++; pthread_rwlock_unlock(&ctxIDLock); currentState = CMD_READ; + // read exactly 1 byte to identify the command and execute callback when // command is received boost::asio::async_read(clientSocket, boost::asio::buffer(clientData), @@ -200,6 +213,10 @@ TEEC_Result ConnectionSession::write(TEE_CMD cmd, char* data, size_t size) { return result; } +SecurityContext ConnectionSession::getSecurityContext(){ + return secContext; +} + ConnectionSession::~ConnectionSession() { LOGD(SIM_DAEMON, "Entry"); // Destory the lock for write (connLock) diff --git a/simulatordaemon/src/SecurityChecker.cpp b/simulatordaemon/src/SecurityChecker.cpp deleted file mode 100644 index c9b6b12..0000000 --- a/simulatordaemon/src/SecurityChecker.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * ===================================================================================== - * - * Filename: SecurityChecker.cpp - * - * Description: Class to check if client application has access to TEE - * - * Version: 1.0 - * Created: 19 June 2017 14:37:03 IST - * Revision: Original - * Compiler: gcc - * - * Author: Uladzislau Harbuz, u.harbuz@samsung.com - * Organization: Samsung Electronics - * - * ===================================================================================== - */ - -#include "SecurityChecker.h" - - -SecurityChecker(ConnectionSession* ses){ - mConnSess = ses; -} - - -bool SecurityChecker::clientHasAccessToTa(ConnectionSession *ses, string taName) { - return ca_has_access_to_ta(ses->socket().native(), taName.c_str()); -} - - -bool SecurityChecker::clientHasCynaraPermission(ConnectionSession *ses, string privelege) { - return client_has_cynara_permission(ses->socket().native(), privelege.c_str()); -} - - -bool SecurityChecker::clientHasCynaraPermission(string privelege) { - return SecurityChecker::clientHasCynaraPermission(mConnSess, privelege); -} - - -bool SecurityChecker::clientHasAccessToTa(string taName) { - return SecurityChecker::clientHasAccessToTa(mConnSess, taName); -} - - -~SecurityChecker(){ -} diff --git a/simulatordaemon/src/SecurityContext.cpp b/simulatordaemon/src/SecurityContext.cpp new file mode 100644 index 0000000..0160962 --- /dev/null +++ b/simulatordaemon/src/SecurityContext.cpp @@ -0,0 +1,235 @@ +/* + * SecurityContext.cpp + * + * Copyright (C) 2017 Samsung Electronics + * Uladzislau Harbuz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SecurityContext.h" +#include +#include +#include +#include +#include "log.h" +#include +#include +#include +#include +#include + +using p_char = std::unique_ptr>; +using p_cynara_conf = std::unique_ptr>; +using p_tzplatform_context= std::unique_ptr>; + +namespace fs = boost::filesystem; + +constexpr const char* SecurityContext::sysTaPaths[]; + +cynara* SecurityContext::_cynara = SecurityContext::initCynara(); + +pthread_mutex_t cynara_mutex = PTHREAD_MUTEX_INITIALIZER; + +#define FILE_WAS_FOUND 1 +#define MAX_OPENED_FD 5 +#define MAX_PATH_LENGTH 100 +#define BOOST_FILESYSTEM_VERSION 3 +#define RETURN_UNLOCK(ret, mtx) {pthread_mutex_unlock(&mtx); return ret;} + +/* TODO: this function needs to be tested. + */ +std::string SecurityContext::getCaFullPathFromPkgId(char* pkgid) { + + std::string path; + + tzplatform_variable ids[3] = {TZ_USER_APP, TZ_SYS_RW_APP, TZ_SYS_RO_APP}; + tzplatform_context *ctx; + if (! tzplatform_context_create(&ctx)) { + LOGE(SIM_DAEMON, "Can't create tizen context"); + return path; + } + + p_tzplatform_context p_ctx(ctx, &free); + + if (! tzplatform_context_set_user(p_ctx.get(), getuid())) { + LOGE(SIM_DAEMON, "Can not set user for context"); + return path; + } + + for (auto &id : ids) { + path = std::move(tzplatform_context_getenv(p_ctx.get(), id)); + LOGD(SIM_DAEMON, "Path is : %s", path.c_str()); + if (! path.empty()) break; + } + + path = fs::read_symlink(fs::path(path)).parent_path().string(); + + if (path.empty()) { + LOGE(SIM_DAEMON, "Bad CA path. Does this directory exist: %s ?", path.c_str()); + } + + path += "/" + std::string(pkgid) + TA_LOCAL_PATH; + LOGD(SIM_DAEMON, "Path::::: &s", path.c_str()); + + return path; +} + + +bool SecurityContext::findRequestedTa(const std::string &ta_name, std::string &allowed_path) { + int ret; + char* pkg_id_ca; + + LOGD(SIM_DAEMON, "Entry"); + ret = security_manager_identify_app_from_socket(connFd, &pkg_id_ca, NULL); + + if (ret == SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT) { + LOGD(SIM_DAEMON, "Owner of socket has no pkgid"); + + std::string ta_full_path; + + /* Check if any of system ta directories contains our ta */ + for (const std::string& path : sysTaPaths) { + ta_full_path = path + ta_name; + + if (fs::exists(ta_full_path)){ + allowed_path = path; + return true; + } + } + + return false; + } + + if (ret != SECURITY_MANAGER_SUCCESS) { + LOGE(SIM_DAEMON, "security_manager_identify_app_from_socket failed with CA"); + return false; + } + + /* We can free it only if security_manager_identify_app_from_socket return success */ + p_char p_pkg_id_ca(pkg_id_ca, &free); + + std::string ca_pkg_path = getCaFullPathFromPkgId(pkg_id_ca); + if (ca_pkg_path.empty()) { + LOGE(SIM_DAEMON, "Error while loading client's path"); + return false; + } + +/* Now it searches client’s TA recursively in subdirectories of it. Maybe + * in future we will know exact predefined subdirectories or even + * map Client <-> allowed directories for it*/ + for(fs::recursive_directory_iterator end, dir(ca_pkg_path); dir != end; ++dir){ + std::string ta_full_path = dir->path().filename().string() + "/" + ta_name; + if(fs::exists(ta_full_path)){ + allowed_path = dir->path().filename().string(); + return true; + } + } + + return false; +} + + +bool SecurityContext::clientHasCynaraPermission(const std::string &privelege) { + int ret = -1; + + pthread_mutex_lock(&cynara_mutex); + + char *label = nullptr; + ret = cynara_creds_socket_get_client(connFd, CLIENT_METHOD_SMACK, &label); + if (ret != CYNARA_API_SUCCESS) { + LOGE(SIM_DAEMON, "Couldn't get smack label of the client. Error code: %d", ret); + RETURN_UNLOCK(false, cynara_mutex); + } + p_char p_label(label, &free); + + pid_t ca_pid = -1; + ret = cynara_creds_socket_get_pid(connFd, &ca_pid); + if (ret != CYNARA_API_SUCCESS) { + LOGE(SIM_DAEMON, "Couldn't get pid of the client. Error code: %d", ret); + RETURN_UNLOCK(false, cynara_mutex); + } + + char *session = nullptr; + session = cynara_session_from_pid(ca_pid); + if (!session) { + LOGE(SIM_DAEMON, "Couldn't get client's cynara session."); + RETURN_UNLOCK(false, cynara_mutex); + } + p_char p_session(session, &free); + + char *user = nullptr; + ret = cynara_creds_socket_get_user(connFd, USER_METHOD_DEFAULT, &user); + if (ret != CYNARA_API_SUCCESS) { + LOGE(SIM_DAEMON, "Couldn't get user. Error code: %d", ret); + RETURN_UNLOCK(false, cynara_mutex); + } + p_char p_user(user, &free); + + ret = cynara_check(_cynara, p_label.get(), p_session.get(), p_user.get(), privelege.c_str()); + + if (ret == CYNARA_API_ACCESS_DENIED) { + LOGE(SIM_DAEMON, "Cynara access denied."); + RETURN_UNLOCK(false, cynara_mutex); + } + if (ret != CYNARA_API_ACCESS_ALLOWED) { + LOGE(SIM_DAEMON, "Error during cynara_check(). Error code: %d", ret); + RETURN_UNLOCK(false, cynara_mutex); + } + + RETURN_UNLOCK(true, cynara_mutex); +} + + +cynara* SecurityContext::initCynara() { + int ret = -1; + cynara_configuration *p_conf = nullptr; + cynara* result = nullptr; + + ret = cynara_configuration_create(&p_conf); + if (ret != CYNARA_API_SUCCESS) { + LOGE(SIM_DAEMON, "Cynara configuration creation failed"); + return nullptr; + } + + p_cynara_conf conf(p_conf, &cynara_configuration_destroy); + + ret = cynara_configuration_set_cache_size(p_conf, CYNARA_CACHE_SIZE); + if (ret != CYNARA_API_SUCCESS) { + LOGE(SIM_DAEMON, "Set cynara cache size failed"); + return nullptr; + } + + ret = cynara_initialize(&result, conf.get()); + if (ret != CYNARA_API_SUCCESS) { + LOGE(SIM_DAEMON, "Cynara initialize failed"); + return nullptr; + } + + return result; +} + + +SecurityContext::SecurityContext(): + SecurityContext(-1) { +} + + +SecurityContext::SecurityContext(int connFd): + connFd(connFd) { + if (_cynara == nullptr) throw std::runtime_error("Cynara is not initialized"); +} + + +SecurityContext::~SecurityContext() { +} diff --git a/simulatordaemon/src/Session.cpp b/simulatordaemon/src/Session.cpp index f2c71df..39f73ce 100644 --- a/simulatordaemon/src/Session.cpp +++ b/simulatordaemon/src/Session.cpp @@ -58,6 +58,10 @@ TAInstancePtr Session::getTAInstance() { return mTAInstance; } +SecurityContext Session::getSecurityContext() { + return mContext->secContext; +} + void Session::detachFromContext() { /* Find the Session instance in the session map */ map::iterator it; @@ -102,12 +106,8 @@ TEEC_Result Session::createSession(OpenSessionData data) { string TAUUID = TABin->getUUIDAsString(data.uuid); string argvPort = TABin->getPort(TAUUID); - /*string TAName(TAUUID); + string TAName(TAUUID); std::transform(TAName.begin(), TAName.end(), TAName.begin(), ::toupper); - if(!mContext->mConnSecChecker.clientHasAccessToTa(TAUUID)){ - LOGE(SIM_DAEMON, "Client has no permission for access TA: %s ", TAName.c_str()); - return TEEC_ERROR_ACCESS_DENIED; - }*/ if (argvPort != "") { pthread_rwlock_wrlock(&TAFact->mTAInstanceMapLock); diff --git a/simulatordaemon/src/SimulatorDaemonServer.cpp b/simulatordaemon/src/SimulatorDaemonServer.cpp index e9f04f7..767fc53 100644 --- a/simulatordaemon/src/SimulatorDaemonServer.cpp +++ b/simulatordaemon/src/SimulatorDaemonServer.cpp @@ -20,6 +20,7 @@ * Include files *-----------------------------------------------------------------------------*/ #include "SimulatorDaemonServer.h" +#include "SecurityContext.h" /*----------------------------------------------------------------------------- * Member functions @@ -67,14 +68,6 @@ void SimulatorDaemonServer::handleAccept( ConnectionSession::session_ptr session, const boost::system::error_code& error) { - const string privelege("http://tizen.org/privilege/account.read"); - LOGD(SIM_DAEMON, "Entry"); - // TODO reenable after refactor - /*if (!SecurityChecker::clientHasCynaraPermission(new_session.get(), privelege)){ - LOGE("Client has no permission to use TEE"); - return; - }*/ - if (!error) { session->start(); } diff --git a/simulatordaemon/src/TABinaryManager/TABinaryManager.cpp b/simulatordaemon/src/TABinaryManager/TABinaryManager.cpp index b035dd9..27723a8 100644 --- a/simulatordaemon/src/TABinaryManager/TABinaryManager.cpp +++ b/simulatordaemon/src/TABinaryManager/TABinaryManager.cpp @@ -153,12 +153,42 @@ TABinaryManager* TABinaryManager::getInstance() { return instance; } +/** + * This function add TA at given path to BinaryManager if it exists. + * @return On successful completion of above operations returns true else false. + */ +bool TABinaryManager::initTAatPath(const string &path, const string &uuid) { + LOGD(SIM_DAEMON, ""); + + pthread_rwlock_wrlock(&binaryMapLock); + map::iterator it = binaryMap.find(uuid); + StructBinaryInfo value; + bool res = false; + StructBinaryInfo info; + + if (it != binaryMap.end()) { + pthread_mutex_lock(&taLock); + try { + if (unpackBinary(uuid, path, info)) { + binaryMap[uuid] = info; + res = true; + } + } catch (...) { + res = false; + } + pthread_mutex_unlock(&taLock); + } + pthread_rwlock_unlock(&binaryMapLock); + return res; +} + /** * This function reads UUID list file and unpacks files to their respective * locations. * @return On successful completion of above operations returns true else false. * It is very important to check for return value from this function. */ + bool TABinaryManager::readUUIDList() { LOGD(SIM_DAEMON, ""); string line; @@ -221,7 +251,7 @@ bool TABinaryManager::readUUIDList() { } pthread_mutex_lock(&taLock); - if (unpackBinary(uuid, info)) { + if (unpackBinary(uuid, TA_STORE_PATH, info)) { binaryMap[uuid] = info; } pthread_mutex_unlock(&taLock); @@ -309,15 +339,16 @@ void TABinaryManager::decryptImage(StructBinaryInfo& info) { * @return On successful completion of above operations returns true else false. * It is very important to check for return value from this function. */ -bool TABinaryManager::unpackBinary(const string &uuid, StructBinaryInfo& info) { + +bool TABinaryManager::unpackBinary(const string &uuid, const string &path, StructBinaryInfo& info) { TAUnpack* unpacker = TAUnpack::getInstance(); bool ret = false; LOGE(SIM_DAEMON, "Unpacking TA"); - if (0 == unpacker->unpackTA(string(TA_STORE_PATH), uuid)) { + if (0 == unpacker->unpackTA(path, uuid)) { LOGE(SIM_DAEMON, "Unpacked, filling info"); // 1. Set binary info - info.path = string(TA_STORE_PATH) + uuid; - info.extractpath = string(TA_STORE_PATH) + uuid + "-ext/"; + info.path = path + uuid; + info.extractpath = path + uuid + "-ext/"; info.imagePath = info.extractpath + uuid + ".image"; info.manifestPath = info.extractpath + uuid + ".manifest"; // 2. Parse manifest and store results diff --git a/simulatordaemon/src/TABinaryManager/TABinaryManager.h b/simulatordaemon/src/TABinaryManager/TABinaryManager.h index 00cfb90..5d6dde1 100644 --- a/simulatordaemon/src/TABinaryManager/TABinaryManager.h +++ b/simulatordaemon/src/TABinaryManager/TABinaryManager.h @@ -63,7 +63,7 @@ private: time_t lastModTimeUUIDList; TABinaryManager(); bool readUUIDList(); - bool unpackBinary(const string &uuid, StructBinaryInfo& info); + bool unpackBinary(const string &uuid, const string &path, StructBinaryInfo& info); template std::string IntToHex(T i, int width = sizeof(T) * 2) { std::stringstream stream; @@ -86,6 +86,7 @@ public: pthread_mutex_t taLock; static TABinaryManager* getInstance(); bool initBinaryManager(); + bool initTAatPath(const string &path, const string &uuid); /* * Query functions on Binary Manager diff --git a/simulatordaemon/src/TAFactory.cpp b/simulatordaemon/src/TAFactory.cpp index 6379144..67b66f9 100644 --- a/simulatordaemon/src/TAFactory.cpp +++ b/simulatordaemon/src/TAFactory.cpp @@ -20,6 +20,7 @@ * Include files *-----------------------------------------------------------------------------*/ #include "TAFactory.h" +#include "SecurityContext.h" #include "ResponseCommands/ResMakeCommand.h" /*----------------------------------------------------------------------------- @@ -202,7 +203,12 @@ TAInstancePtr TAFactory::createUninitalizedTAInstance(string TAUUID, str << TAUUID << "-"; str << InstID; - if (launchTA(TAUUID, str, debug, pid)) { + string allowedTAPath; + if(!session->getSecurityContext().findRequestedTa(TAUUID, allowedTAPath)) { + LOGE(SIM_DAEMON, "Access for TA %s forbidden", TAUUID.c_str()); + return TAInstancePtr(); + } + if (launchTA(allowedTAPath, TAUUID, str, debug, pid)) { // TA is launched successfully, Create a new instance of TAInstance class /* Check if TA is to be keep alive and accordingly set TAInstance's @@ -352,7 +358,7 @@ void TAFactory::cleanupTAInstance(pid_t PID) { * @param debug debug flag * @param pid PID to be update for launched TA */ -bool TAFactory::launchTA(string TAUUID, std::stringstream& str, bool debug, +bool TAFactory::launchTA(string path, string TAUUID, std::stringstream& str, bool debug, pid_t& pid) { int32_t result = -1; @@ -362,8 +368,10 @@ bool TAFactory::launchTA(string TAUUID, std::stringstream& str, bool debug, // Get TABinaryManager instance TABinaryManager *TABin = TABinaryManager::getInstance(); // Get TA Image path for launching - LOGD(SIM_DAEMON, TAUUID.c_str()); - string argvPath = TABin->getImagePath(TAUUID); + string argvPath = ""; + if (TABin->initTAatPath(path, TAUUID)) { + argvPath = TABin->getImagePath(TAUUID); + } if ("" == argvPath) { LOGE(SIM_DAEMON, "Trusted Application does not exist"); return false; diff --git a/simulatordaemon/src/TEEContext.cpp b/simulatordaemon/src/TEEContext.cpp index 51ccd4f..f20bbb5 100644 --- a/simulatordaemon/src/TEEContext.cpp +++ b/simulatordaemon/src/TEEContext.cpp @@ -37,7 +37,8 @@ uint32_t sessID = 51; * @param contextID ID for Context reference * @param connSession ConnectionSession instance associated with the context */ -TEEContext::TEEContext(uint32_t contextID, IConnectionSession* connSession) { +TEEContext::TEEContext(uint32_t contextID, IConnectionSession* connSession): + secContext(connSession->getSecurityContext()) { LOGD(SIM_DAEMON, "ContextID: %d", contextID); diff --git a/simulatordaemon/src/security.c b/simulatordaemon/src/security.c deleted file mode 100644 index bf47072..0000000 --- a/simulatordaemon/src/security.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * security.c - * - * Copyright (C) 2017 Samsung Electronics - * Uladzislau Harbuz - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "security.h" - -/* This variable is for nftw searching of ta */ -static const char* g_ta_name = NULL; - -#define FILE_WAS_FOUND 1 - -#define N_SYS_TA_PATHS 1 -static const char* system_ta_paths[N_SYS_TA_PATHS]={ - "/usr/lib/optee_armtz/", -}; - - -static bool file_exists(const char* fname) { - struct stat st; - return stat(fname, &st) == 0; -} - - -/* TODO: need we get path of CA from its pkgid or we need traverse some - * predefined directories with CA which contain its TA, or will installator of - * it store some paired CA-TA pathces? Now it is not good mechanism for searcing - * CA path from pid. - */ -static bool get_ca_full_path_from_socket(int fd, char* path) { - - pid_t ca_pid = -1; - cynara *cynara = NULL; - int ret = -1; - - ret = cynara_initialize(&cynara, NULL); - if(ret != CYNARA_API_SUCCESS) { - EMSG("Cynara initialization failed with error code %d", ret); - return false; - } - - ret = cynara_creds_socket_get_pid(fd, &ca_pid); - if(ret != CYNARA_API_SUCCESS) { - EMSG("Couldn't get pid of the client. Error code: %d", ret); - cynara_finish(cynara); - return false; - } - - char ca_path[MAX_PATH_LENGTH] = {0}; - snprintf(ca_path, MAX_PATH_LENGTH, "/proc/%d/exe", ca_pid); - ret = readlink(ca_path, path, MAX_PATH_LENGTH); - - if(ret == -1) { - EMSG("readlink() failed"); - cynara_finish(cynara); - return false; - } - - cynara_finish(cynara); - - return true; -} - - -static int cmp_ta_name(const char *fpath, const struct stat *sb, - int tflag, struct FTW *ftwbuf) { - if(tflag == FTW_D) { - char ta_full_path[MAX_PATH_LENGTH] = {0}; - snprintf(ta_full_path, MAX_PATH_LENGTH, "%s/%s", fpath, g_ta_name); - - if(file_exists(ta_full_path)) { - return FILE_WAS_FOUND; - } - } - - return 0; -} - - -bool ca_has_access_to_ta(int ca_fd, const char* ta_name) { - int ret; - g_ta_name = ta_name; - - char *pkg_id_ca; - - ret = security_manager_identify_app_from_socket(ca_fd, &pkg_id_ca, NULL); - if(ret == SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT) { - DMSG("Owner of socket has no pkgid"); - - char ta_full_path[MAX_PATH_LENGTH] = {0}; - - /* Check if any of system ta directories contains our ta */ - for(int i = 0; i < N_SYS_TA_PATHS; ++i){ - snprintf(ta_full_path, MAX_PATH_LENGTH, "%s/%s", system_ta_paths[i], ta_name); - - if(file_exists(ta_full_path)){ - return true; - } - - memset(ta_full_path, 0, MAX_PATH_LENGTH); - } - - return false; - } - - if(ret != SECURITY_MANAGER_SUCCESS) { - EMSG("security_manager_identify_app_from_cynara_client() failed with CA"); - return false; - } - - char ca_pkg_path[MAX_PATH_LENGTH]; - if(!get_ca_full_path_from_socket(ca_fd, ca_pkg_path)) { - EMSG("Error while loading client's path"); - free(pkg_id_ca); - return false; - } - -/* Now it searches TA of client recursively in subdirectories of it. Maybe - * in future we will know koncrete predefined subdirectories or even - * map Client <-> allowed directories for it*/ - ret = nftw(ca_pkg_path, cmp_ta_name, MAX_OPENED_FD, 0); - if(ret == FILE_WAS_FOUND) { - free(pkg_id_ca); - return true; - } - - free(pkg_id_ca); - return false; -} - - -bool client_has_cynara_permission(int ca_fd, const char *privelege) { - cynara *cynara = NULL; - int ret = -1; - char *user; - char *session = NULL; - char *label; - pid_t ca_pid = -1; - - ret = cynara_initialize(&cynara, NULL); - if(ret != CYNARA_API_SUCCESS) { - EMSG("Cynara initialization failed with error code %d", ret); - return false; - } - - ret = cynara_creds_socket_get_client(ca_fd, CLIENT_METHOD_SMACK, &label); - if(ret != CYNARA_API_SUCCESS) { - EMSG("Couldn't get smack label of the client. Error code: %d", ret); - goto exit_error3; - } - - ret = cynara_creds_socket_get_pid(ca_fd, &ca_pid); - if(ret != CYNARA_API_SUCCESS) { - EMSG("Couldn't get pid of the client. Error code: %d", ret); - goto exit_error2; - } - - session = cynara_session_from_pid(ca_pid); - if(!session) { - EMSG("Couldn't get client's cynara session."); - goto exit_error2; - } - - ret = cynara_creds_socket_get_user(ca_fd, CLIENT_METHOD_SMACK, &user); - if(ret != CYNARA_API_SUCCESS) { - EMSG("Couldn't get user. Error code: %d", ret); - goto exit_error1; - } - - ret = cynara_check(cynara, label, session, user, privelege); - if(ret == CYNARA_API_ACCESS_DENIED) { - EMSG("Cynara access denied."); - goto exit_error0; - } - else if(ret != CYNARA_API_ACCESS_ALLOWED) { - EMSG("Error during cynara_check(). Error code: %d", ret); - goto exit_error0; - } - - - ret = cynara_finish(cynara); - if(ret != CYNARA_API_SUCCESS) { - EMSG("Cynara finish failed with error code %d", ret); - } - - free(session); - free(label); - free(user); - - return true; - - -exit_error0: - free(user); - -exit_error1: - free(session); - -exit_error2: - free(label); - -exit_error3: - ret = cynara_finish(cynara); - if(ret != CYNARA_API_SUCCESS) { - EMSG("Cynara finish failed with error code %d", ret); - } - - return false; -}