2 * Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 * @author CHERYL (cb) (cheryl.b@samsung.com)
20 * @brief TAFactory class
24 /*-----------------------------------------------------------------------------
26 *-----------------------------------------------------------------------------*/
27 #include "TAFactory.h"
28 #include "SecurityContext.h"
29 #include "ResponseCommands/ResMakeCommand.h"
31 /*-----------------------------------------------------------------------------
33 *-----------------------------------------------------------------------------*/
34 // instLock for TA Factory instance
35 pthread_mutex_t instLock;
36 // Initialize TA Factory instance as NULL
37 TAFactory *TAFactory::instance = NULL;
39 /*-----------------------------------------------------------------------------
41 *-----------------------------------------------------------------------------*/
43 * TAFactory constructer. TA Factory Instance is created
45 TAFactory::TAFactory() {
46 // Starting value for TA Instance ID set to 101
49 /* Initialize the lock for TA Instance Map (mTAInstanceMap), instance ID
50 * (instID) and TA Factory instance (instance)
52 pthread_rwlock_init(&mTAInstanceMapLock, NULL);
53 pthread_rwlock_init(&instIDLock, NULL);
54 pthread_mutex_init(&instLock, NULL);
58 * Get TA Factory Instance. If called for first time then create a TA Factory
59 * instance and return the instance else return the already created instance.
61 TAFactory* TAFactory::getInstance() {
62 LOGD(SIM_DAEMON, "Entry");
63 pthread_mutex_lock(&instLock);
65 // Check if the instance is not yet craeted
66 if (NULL == instance) {
67 // Create a new instance of TA Factory
68 instance = new TAFactory();
70 pthread_mutex_unlock(&instLock);
75 * Get a TA Instance for the UUID sent as the argument
76 * @param uuid TEEC_UUID for the TA instance to be returned
77 * @param session Session which requested the TA Instance to be associated
80 TAInstancePtr TAFactory::getTAInstance(TEEC_UUID uuid, ISession* session) {
83 LOGD(SIM_DAEMON, "Entry");
85 // Get TA Binary Manager instance
86 TABinaryManager *TABin = TABinaryManager::getInstance();
87 // Get TEEC_UUID format uuid converted to string form
88 string TAUUID = TABin->getUUIDAsString(uuid);
90 // Change to upper char. TA list has upper char.
92 for (size_t i = 0; i < TAUUID.length(); ++i)
93 TAUUID[i] = toupper(TAUUID[i], loc);
96 if ((!checkIfTARunning(TAUUID))
97 || ((TABin->isSingleInstance(TAUUID, result) == 0) && (result == false))) {
98 /* TA instance is not already alive or is Multi Instance, Create a new TA
101 TAInst = createUninitalizedTAInstance(TAUUID, session);
102 if (!TAInst == true) {
103 LOGE(SIM_DAEMON, "Creating Trusted Application Instance FAILED");
104 return TAInstancePtr();
106 } else if ((TABin->isSingleInstance(TAUUID, result) == 0)
107 && (result == true)) {
108 // TA is Single Instance and alive
109 if (TABin->isMultipleSession(TAUUID, result) < 0) {
110 LOGE(SIM_DAEMON, "TA not in list");
111 return TAInstancePtr();
113 multimap<string, TAInstancePtr>::iterator it;
114 // Find alive TA Instance in TA Factory's Instance Map
115 it = mTAInstanceMap.find(TAUUID);
116 if (it != mTAInstanceMap.end()) {
118 TAInst->takeSessionMapLock();
120 || ((result == false) && (it->second->getSessionMapSize() == 0))) {
121 /* TA is alive Single Instance and either it is MultiSession or
122 * has no session associated to it
125 if (!TAInst == true) {
126 LOGE(SIM_DAEMON, "Creating Trusted Application Instance FAILED");
127 TAInst->releaseSessionMapLock();
128 return TAInstancePtr();
130 TAInst->releaseSessionMapLock();
132 LOGE(SIM_DAEMON, "TA Single Instance Single Session - "
133 "multiple connections not supported");
134 TAInst->releaseSessionMapLock();
135 return TAInstancePtr();
138 LOGE(SIM_DAEMON, "Trusted Application Instance not found.");
139 return TAInstancePtr();
143 LOGE(SIM_DAEMON, "TA not in list");
144 return TAInstancePtr();
146 TAInst->takeSessionMapLock();
147 // Add session to the Session Map of TA Instance
148 TAInst->insertSessionMap(session);
149 TAInst->releaseSessionMapLock();
154 * Check if TA already alive. Return true if it is present in the TA Instance
155 * Map else return false
156 * @param TAUUID TA UUID in string form
158 bool TAFactory::checkIfTARunning(string TAUUID) {
159 LOGD(SIM_DAEMON, "Entry");
162 // Find TA UUID in the TA Instance Map
163 multimap<string, TAInstancePtr>::iterator itr;
164 itr = mTAInstanceMap.find(TAUUID);
165 if (itr != mTAInstanceMap.end()) result = true;
170 * Create a new TA Instance by launching the TA specified by TA UUID
171 * @param TAUUID TA UUID in string form
172 * @param session Session which requested the TA Instance to be associated
175 TAInstancePtr TAFactory::createUninitalizedTAInstance(string TAUUID,
177 LOGD(SIM_DAEMON, "Entry");
179 // Initialize PID to -1
181 // Set default values for TA configuration variables
184 bool singleInst = false;
185 TEEC_Result result = TEEC_ERROR_COMMUNICATION;
187 TABinaryManager *TABin = TABinaryManager::getInstance();
188 pthread_rwlock_wrlock(&instIDLock);
190 /* Generate the endpoint name using UUID and Instance ID to be sent to
191 * TEEStub for socket connection
193 std::stringstream str;
194 str << TAUUID << "-";
197 if (launchTA(TAUUID, str, debug, pid)) {
198 // TA is launched successfully, Create a new instance of TAInstance class
200 /* Check if TA is to be keep alive and accordingly set TAInstance's
201 * member variable isKeepAlive
203 if (TABin->isSingleInstance(TAUUID, singleInst) < 0) {
204 LOGE(SIM_DAEMON, "TA not in list");
205 pthread_rwlock_unlock(&instIDLock);
206 return TAInstancePtr();
207 } else if (singleInst == true) {
208 /* If TA is single Instance and KeepAlive then set TAInstance's member
209 * variable isKeepAlive to true.
210 * Even if TA is KeepAlive but MultiInstance, set TAInstance's member
211 * variable isKeepAlive to false.
213 if (TABin->isKeepAlive(TAUUID, alive) < 0) {
214 LOGE(SIM_DAEMON, "TA not in list");
215 // Kill the launched TA
218 while (kill(pid, 0) != -1);
219 LOGD(SIM_DAEMON, "TA process exited");
221 pthread_rwlock_unlock(&instIDLock);
222 return TAInstancePtr();
226 /* Update TAInstance's member variable isDebug according to the property
227 * set in manifest file for TA
228 * Update TAInstance's member variable mTAInstanceID with the assigned
232 // Update TAInstance member variable mPID with the launched TA PID
233 TAInstancePtr TAInst;
234 TAInst = TAInstancePtr(new TAInstance(pid, alive, debug, InstID, ioService::getInstance()));
235 // Increment the Instance ID variable for assigning to next TA Instance
237 if (TEEC_SUCCESS != TAInst->connecttoTA(str)) {
238 LOGE(SIM_DAEMON, "Connection to TA FAILED");
240 pthread_rwlock_unlock(&instIDLock);
241 return TAInstancePtr();
243 // Connected to TA through socket
245 /* Check if TAInstance is newly created or an old instance is being re-used.
246 * If new instance then send CREATE command to the TA.
247 * TaInstance member variable isCreated is used to find if the TAInstance is
248 * newly created or re-used.
250 if (TAInst->getCreated() == false) {
251 /* TA is launched uninitialised and CreateTAEntryPoint has not been
252 * called yet for this TA Instance, send request for CreateTAEntryPoint
254 CreateTAEntryPointData cdata;
255 memset(&cdata, 0, sizeof(CreateTAEntryPointData));
256 cdata.sessionID = session->getSessionID();
257 cdata.returnValue = TEE_ERROR_GENERIC;
259 // Send CREATE command to TA
260 result = TAInst->sendRequestToTA(CREATE, (void*)&cdata,
261 sizeof(CreateTAEntryPointData));
262 if (result != TEEC_SUCCESS) {
263 LOGE(SIM_DAEMON, "Create sendRequestToTA FAILED\n");
264 // Kill the launched TA
266 pthread_rwlock_unlock(&instIDLock);
267 return TAInstancePtr();
270 pthread_rwlock_unlock(&instIDLock);
272 // Add the TAInstance in the TA Factory's TA Instance Map
273 mTAInstanceMap.insert(pair<string, TAInstancePtr>(TAUUID, TAInst));
276 pthread_rwlock_unlock(&instIDLock);
277 return TAInstancePtr();
281 * Thread routine for handling TA exit (immature/mature exit)
282 * @param pid pointer to the PID of the launched TA
284 void* TAFactory::waitForChild(void *pid) {
285 pid_t PID = *(pid_t*)pid;
288 // Wait for PID to exit
289 waitpid(PID, &childStatus, 0);
290 LOGD(SIM_DAEMON, "PID %d exited", PID);
291 if (instance != NULL) {
292 // Clean (handle immature termination of) TA
293 instance->cleanupTAInstance(PID);
299 * Clean (handle immature termination of) TA by sending response for all the
300 * pending commands for the TA and deleting the TA instance
301 * @param pid pointer to the PID of the exited TA
303 void TAFactory::cleanupTAInstance(pid_t PID) {
304 LOGD(SIM_DAEMON, "Entry");
307 // Find the TA instance associated with the argument PID
308 multimap<string, TAInstancePtr>::iterator itInstanceMap;
309 for (itInstanceMap = mTAInstanceMap.begin();
310 itInstanceMap != mTAInstanceMap.end(); itInstanceMap++) {
311 if (itInstanceMap->second->getPID() == PID) {
312 Inst = itInstanceMap->second;
317 if (!Inst == false) {
318 /* TA instance is found for the PID argument.
319 * Check if there are any commands pending for TA response and send the
320 * failure response back to CA if the response is pending and TA has exited
323 // Remove the TA Instance from the TA Instance Map maintained in TA Factory
324 pthread_rwlock_wrlock(&mTAInstanceMapLock);
325 multimap<string, TAInstancePtr>::iterator itMap;
326 for (itMap = mTAInstanceMap.begin(); itMap != mTAInstanceMap.end();
328 if (itMap->second == Inst) {
329 mTAInstanceMap.erase(itMap);
333 pthread_rwlock_unlock(&mTAInstanceMapLock);
338 * Launch the TA instance
339 * @param TAUUID TA UUID is string format
340 * @param str string containing the endpoint name to be passed as an argument
341 * to TA while launching
342 * @param debug debug flag
343 * @param pid PID to be update for launched TA
345 bool TAFactory::launchTA(string TAUUID, std::stringstream& str, bool debug,
350 LOGD(SIM_DAEMON, "Entry");
352 // Get TABinaryManager instance
353 TABinaryManager *TABin = TABinaryManager::getInstance();
354 // Get TA Image path for launching
355 string argvPath = "";
356 if (TABin->initTA(TAUUID)) {
357 argvPath = TABin->getImagePath(TAUUID);
360 if ("" == argvPath) {
361 LOGE(SIM_DAEMON, "Trusted Application does not exist");
366 // Argument to be passed to TA main (TEEStub main)
367 string argvName = str.str().c_str();
369 // Get the port to be assigned to TA if TA is to be launched in debug mode
370 string argvPort = TABin->getPort(TAUUID);
372 pthread_mutex_lock(&TABin->taLock);
373 //Check if the TA is to be launched in debug mode or release mode
374 if (argvPort != "") { // DEBUG MODE
377 string argvGDB = "/usr/bin/gdbserver";
378 string argvHost = "localhost:" + argvPort;
380 argv[0] = &argvGDB[0];
381 argv[1] = &argvHost[0];
382 argv[2] = &argvPath[0];
383 argv[3] = &argvName[0];
389 LOGD(SIM_DAEMON, "In Child Process");
390 execv(argv[0], argv);
391 LOGE(SIM_DAEMON, "Launching Trusted Application FAILED");
392 pthread_mutex_unlock(&TABin->taLock);
395 LOGD(SIM_DAEMON, "In Parent Process");
396 } else { //RELEASE MODE
398 argv[0] = &argvPath[0];
399 argv[1] = &argvName[0];
404 result = posix_spawn(&pid, argv[0], NULL, NULL, argv, envp);
406 LOGD(SIM_DAEMON, "TA pid: %i\n", pid);
407 LOGD(SIM_DAEMON, "Launched Trusted Application");
409 LOGE(SIM_DAEMON, "Launching Trusted Application FAILED");
410 pthread_mutex_unlock(&TABin->taLock);
414 pthread_mutex_unlock(&TABin->taLock);
415 // Create a thread to wait for TA exit
417 int s = pthread_attr_init(&attr);
419 LOGE(SIM_DAEMON, "pthread_attr_init");
420 s = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
422 LOGE(SIM_DAEMON, "pthread_attr_setdetachstate");
423 pthread_create(&thread, &attr, TAFactory::waitForChild, (void *)&pid);
427 TAFactory::~TAFactory() {
428 /* Destroy the locks created for TAInstance map (mTAInstanceMap), Instance
429 * Id (InstID) and TA Factory Instance (instance)
431 pthread_rwlock_destroy(&mTAInstanceMapLock);
432 pthread_rwlock_destroy(&instIDLock);
433 pthread_mutex_destroy(&instLock);