From 34f1002ba1cdb5693119c64cde504515d279d53c Mon Sep 17 00:00:00 2001 From: "u.harbuz" Date: Fri, 23 Jun 2017 11:13:39 +0200 Subject: [PATCH] Add security checking. Change-Id: I09aacf1d31af84da2c6fb37e0aad3ed908504e8d --- build/simulatordaemon/src/subdir.mk | 12 +- simulatordaemon/inc/SecurityChecker.h | 47 ++++++ simulatordaemon/inc/TEEContext.h | 7 +- simulatordaemon/inc/security.h | 53 +++++++ simulatordaemon/src/SecurityChecker.cpp | 48 ++++++ simulatordaemon/src/Session.cpp | 5 + simulatordaemon/src/SimulatorDaemonServer.cpp | 9 ++ simulatordaemon/src/TEEContext.cpp | 4 +- simulatordaemon/src/security.c | 215 ++++++++++++++++++++++++++ 9 files changed, 395 insertions(+), 5 deletions(-) create mode 100644 simulatordaemon/inc/SecurityChecker.h create mode 100644 simulatordaemon/inc/security.h create mode 100644 simulatordaemon/src/SecurityChecker.cpp create mode 100644 simulatordaemon/src/security.c diff --git a/build/simulatordaemon/src/subdir.mk b/build/simulatordaemon/src/subdir.mk index f2c0e3c..a34517c 100755 --- a/build/simulatordaemon/src/subdir.mk +++ b/build/simulatordaemon/src/subdir.mk @@ -2,12 +2,14 @@ CPP_SRCS += \ $(SIMDAEMON_SOURCE)/src/ConnectionSession.cpp \ $(SIMDAEMON_SOURCE)/src/Session.cpp \ +$(SIMDAEMON_SOURCE)/src/SecurityChecker.cpp \ $(SIMDAEMON_SOURCE)/src/SimulatorDaemon.cpp \ $(SIMDAEMON_SOURCE)/src/SimulatorDaemonServer.cpp \ $(SIMDAEMON_SOURCE)/src/TAFactory.cpp \ $(SIMDAEMON_SOURCE)/src/TAInstance.cpp \ $(SIMDAEMON_SOURCE)/src/TEEContext.cpp \ -$(SIMDAEMON_SOURCE)/src/ioService.cpp +$(SIMDAEMON_SOURCE)/src/ioService.cpp \ +$(SIMDAEMON_SOURCE)/src/security.c OBJS += \ ./src/ConnectionSession.o \ @@ -17,7 +19,9 @@ OBJS += \ ./src/TAFactory.o \ ./src/TAInstance.o \ ./src/TEEContext.o \ -./src/ioService.o +./src/ioService.o \ +./src/SecurityChecker.o \ +./src/security.o CPP_DEPS += \ ./src/ConnectionSession.d \ @@ -27,7 +31,9 @@ CPP_DEPS += \ ./src/TAFactory.d \ ./src/TAInstance.d \ ./src/TEEContext.d \ -./src/ioService.d +./src/ioService.d \ +./src/SecurityChecker.d \ +./src/security.d # Each subdirectory must supply rules for building sources it contributes diff --git a/simulatordaemon/inc/SecurityChecker.h b/simulatordaemon/inc/SecurityChecker.h new file mode 100644 index 0000000..e040afa --- /dev/null +++ b/simulatordaemon/inc/SecurityChecker.h @@ -0,0 +1,47 @@ +/* + * ===================================================================================== + * + * 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 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/TEEContext.h b/simulatordaemon/inc/TEEContext.h index ac0669f..5c70da7 100755 --- a/simulatordaemon/inc/TEEContext.h +++ b/simulatordaemon/inc/TEEContext.h @@ -31,6 +31,8 @@ #include "Session.h" #include "tee_command.h" #include "IConnectionSession.h" +#include "ConnectionSession.h" +#include "SecurityChecker.h" using namespace std; /*----------------------------------------------------------------------------- @@ -53,11 +55,14 @@ 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*/ + SecurityChecker mConnSecChecker; + /* For TA internal APIs support, dummy Context is created and for recognizing * the context as dummy isInternal member variable is used */ bool isInternal; - TEEContext(uint32_t contextID, IConnectionSession* connSession); + TEEContext(uint32_t contextID, ConnectionSession* connSession); TEEC_Result initContext(InitContextData* data); void finContext(FinalizeContextData data); TEEC_Result openSession(OpenSessionData data); diff --git a/simulatordaemon/inc/security.h b/simulatordaemon/inc/security.h new file mode 100644 index 0000000..b8153ca --- /dev/null +++ b/simulatordaemon/inc/security.h @@ -0,0 +1,53 @@ +/* + * 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 +#include +#include +#include +#include + +#define MAX_PATH_LENGTH 100 +#define MAX_TA_NAME_LENGTH 36 + +#define FILE_WAS_FOUND 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* TODO: */ +const char* system_ta_paths[]= { + "/usr/lib/optee_armtz/", +} +#define N_SYS_TA_PATHS 1 + +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/SecurityChecker.cpp b/simulatordaemon/src/SecurityChecker.cpp new file mode 100644 index 0000000..7b629a6 --- /dev/null +++ b/simulatordaemon/src/SecurityChecker.cpp @@ -0,0 +1,48 @@ +/* + * ===================================================================================== + * + * 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/Session.cpp b/simulatordaemon/src/Session.cpp index 0739089..e6340e1 100755 --- a/simulatordaemon/src/Session.cpp +++ b/simulatordaemon/src/Session.cpp @@ -102,6 +102,11 @@ TEEC_Result Session::createSession(OpenSessionData data) { string TAUUID = TABin->getUUIDAsString(data.uuid); string argvPort = TABin->getPort(TAUUID); + if(!mContext->nConnSecChecker.clientHasAccessToTa(TAUUID)){ + LOGE(SIM_DAEMON, "Client has no permission for access TA: %s ", TAUUID.c_str()); + return TEEC_ERROR_ACCESS_DENIED; + } + if (argvPort != "") { pthread_rwlock_wrlock(&TAFact->mTAInstanceMapLock); multimap::iterator itr; diff --git a/simulatordaemon/src/SimulatorDaemonServer.cpp b/simulatordaemon/src/SimulatorDaemonServer.cpp index 7d06878..42a3da5 100755 --- a/simulatordaemon/src/SimulatorDaemonServer.cpp +++ b/simulatordaemon/src/SimulatorDaemonServer.cpp @@ -20,6 +20,7 @@ * Include files *-----------------------------------------------------------------------------*/ #include "SimulatorDaemonServer.h" +#include "SecurityChecker.h" /*----------------------------------------------------------------------------- * Member functions @@ -45,6 +46,7 @@ void SimulatorDaemonServer::startAccept() { ConnectionSession::session_ptr new_session = ConnectionSession::create( acceptor.get_io_service()); + acceptor.async_accept(new_session->socket(), boost::bind(&SimulatorDaemonServer::handleAccept, this, new_session, boost::asio::placeholders::error)); @@ -58,7 +60,14 @@ void SimulatorDaemonServer::startAccept() { void SimulatorDaemonServer::handleAccept( ConnectionSession::session_ptr new_session, const boost::system::error_code& error) { + + const string privelege("http://tizen.org/privilege/account.read"); LOGD(SIM_DAEMON, "Entry"); + if (!SecurityChecker::clientHasCynaraPermission(new_session.get(), privelege)){ + LOGE("Client has no permission to use TEE"); + return; + } + if (!error) { new_session->start(); } diff --git a/simulatordaemon/src/TEEContext.cpp b/simulatordaemon/src/TEEContext.cpp index 3e352f7..f2cbea4 100755 --- a/simulatordaemon/src/TEEContext.cpp +++ b/simulatordaemon/src/TEEContext.cpp @@ -36,7 +36,9 @@ 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, ConnectionSession* connSession) + :mConnSecChecker(connSession) +{ LOGD(SIM_DAEMON, "ContextID: %d", contextID); diff --git a/simulatordaemon/src/security.c b/simulatordaemon/src/security.c new file mode 100644 index 0000000..ae73646 --- /dev/null +++ b/simulatordaemon/src/security.c @@ -0,0 +1,215 @@ +/* + * 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 "security.h" + +/* This variable is for nftw searching of ta */ +static const char* g_ta_name = NULL; + + +static bool file_exists(const char* fname){ + struct stat st; + return stat(fname, &st) == 0; +} + + +static bool get_ca_full_path_from_socket(int fd, char* path){ + /* How to get full path from pkgid? */ + 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(ca_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_name, 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){ + strcpy(ta_full_path, system_ta_paths[i]); + strcat(ta_full_path, ta_name); + + if(file_exists(ta_full_name)){ + 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_full_ca_path_from_socket(ca_fd, ca_pkg_path)){ + EMSG("Error while loading client's path"); + free(pkg_id_ca); + return false; + } + + 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; +} -- 2.7.4