Remove dead code related to downloadable TA
[platform/core/security/tef-simulator.git] / simulatordaemon / src / TAFactory.cpp
1 /**
2  * Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /**
18  * @file
19  * @author CHERYL (cb) (cheryl.b@samsung.com)
20  * @brief  TAFactory class
21  */
22
23
24 /*-----------------------------------------------------------------------------
25  *  Include files
26  *-----------------------------------------------------------------------------*/
27 #include "TAFactory.h"
28 #include "SecurityContext.h"
29 #include "ResponseCommands/ResMakeCommand.h"
30
31 /*-----------------------------------------------------------------------------
32  *  Globals
33  *-----------------------------------------------------------------------------*/
34 // instLock for TA Factory instance
35 pthread_mutex_t instLock;
36 // Initialize TA Factory instance as NULL
37 TAFactory *TAFactory::instance = NULL;
38
39 /*-----------------------------------------------------------------------------
40  *  Member functions
41  *-----------------------------------------------------------------------------*/
42 /**
43  * TAFactory constructer. TA Factory Instance is created
44  */
45 TAFactory::TAFactory() {
46         // Starting value for TA Instance ID set to 101
47         InstID = 101;
48
49         /* Initialize the lock for TA Instance Map (mTAInstanceMap), instance ID
50          * (instID) and TA Factory instance (instance)
51          */
52         pthread_rwlock_init(&mTAInstanceMapLock, NULL);
53         pthread_rwlock_init(&instIDLock, NULL);
54         pthread_mutex_init(&instLock, NULL);
55 }
56
57 /**
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.
60  */
61 TAFactory* TAFactory::getInstance() {
62         LOGD(SIM_DAEMON, "Entry");
63         pthread_mutex_lock(&instLock);
64
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();
69         }
70         pthread_mutex_unlock(&instLock);
71         return instance;
72 }
73
74 /**
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
78  * with it
79  */
80 TAInstancePtr TAFactory::getTAInstance(TEEC_UUID uuid, ISession* session) {
81         TAInstancePtr TAInst;
82         bool result;
83         LOGD(SIM_DAEMON, "Entry");
84
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);
89
90         // Change to upper char. TA list has upper char.
91         locale loc;
92         for (size_t i = 0; i < TAUUID.length(); ++i)
93                 TAUUID[i] = toupper(TAUUID[i], loc);
94
95
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
99                  * Instance
100                  */
101                 TAInst = createUninitalizedTAInstance(TAUUID, session);
102                 if (!TAInst == true) {
103                         LOGE(SIM_DAEMON, "Creating Trusted Application Instance FAILED");
104                         return TAInstancePtr();
105                 }
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();
112                 } else {
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()) {
117                                 TAInst = it->second;
118                                 TAInst->takeSessionMapLock();
119                                 if ((result == true)
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
123                                          */
124
125                                         if (!TAInst == true) {
126                                                 LOGE(SIM_DAEMON, "Creating Trusted Application Instance FAILED");
127                                                 TAInst->releaseSessionMapLock();
128                                                 return TAInstancePtr();
129                                         }
130                                         TAInst->releaseSessionMapLock();
131                                 } else {
132                                         LOGE(SIM_DAEMON, "TA Single Instance Single Session - "
133                                                         "multiple connections not supported");
134                                         TAInst->releaseSessionMapLock();
135                                         return TAInstancePtr();
136                                 }
137                         } else {
138                                 LOGE(SIM_DAEMON, "Trusted Application Instance not found.");
139                                 return TAInstancePtr();
140                         }
141                 }
142         } else {
143                 LOGE(SIM_DAEMON, "TA not in list");
144                 return TAInstancePtr();
145         }
146         TAInst->takeSessionMapLock();
147         // Add session to the Session Map of TA Instance
148         TAInst->insertSessionMap(session);
149         TAInst->releaseSessionMapLock();
150         return TAInst;
151 }
152
153 /**
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
157  */
158 bool TAFactory::checkIfTARunning(string TAUUID) {
159         LOGD(SIM_DAEMON, "Entry");
160         bool result = false;
161
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;
166         return result;
167 }
168
169 /**
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
173  * with it
174  */
175 TAInstancePtr TAFactory::createUninitalizedTAInstance(string TAUUID,
176                 ISession* session) {
177         LOGD(SIM_DAEMON, "Entry");
178
179         // Initialize PID to -1
180         pid_t pid = -1;
181         // Set default values for TA configuration variables
182         bool debug = false;
183         bool alive = false;
184         bool singleInst = false;
185         TEEC_Result result = TEEC_ERROR_COMMUNICATION;
186
187         TABinaryManager *TABin = TABinaryManager::getInstance();
188         pthread_rwlock_wrlock(&instIDLock);
189
190         /* Generate the endpoint name using UUID and Instance ID to be sent to
191          * TEEStub for socket connection
192          */
193         std::stringstream str;
194         str << TAUUID << "-";
195         str << InstID;
196
197         if (launchTA(TAUUID, str, debug, pid)) {
198                 // TA is launched successfully, Create a new instance of TAInstance class
199
200                 /* Check if TA is to be keep alive and accordingly set TAInstance's
201                  * member variable isKeepAlive
202                  */
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.
212                          */
213                         if (TABin->isKeepAlive(TAUUID, alive) < 0) {
214                                 LOGE(SIM_DAEMON, "TA not in list");
215                                 // Kill the launched TA
216                                 if (pid > 0) {
217                                         kill(pid, SIGKILL);
218                                         while (kill(pid, 0) != -1);
219                                         LOGD(SIM_DAEMON, "TA process exited");
220                                 }
221                                 pthread_rwlock_unlock(&instIDLock);
222                                 return TAInstancePtr();
223                         }
224                 }
225
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
229                  * Instance ID
230                  */
231
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
236                 InstID++;
237                 if (TEEC_SUCCESS != TAInst->connecttoTA(str)) {
238                         LOGE(SIM_DAEMON, "Connection to TA FAILED");
239                         TAInst->killTA();
240                         pthread_rwlock_unlock(&instIDLock);
241                         return TAInstancePtr();
242                 }
243                 // Connected to TA through socket
244
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.
249                  */
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
253                          */
254                         CreateTAEntryPointData cdata;
255                         memset(&cdata, 0, sizeof(CreateTAEntryPointData));
256                         cdata.sessionID = session->getSessionID();
257                         cdata.returnValue = TEE_ERROR_GENERIC;
258
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
265                                 TAInst->killTA();
266                                 pthread_rwlock_unlock(&instIDLock);
267                                 return TAInstancePtr();
268                         }
269                 }
270                 pthread_rwlock_unlock(&instIDLock);
271
272                 // Add the TAInstance in the TA Factory's TA Instance Map
273                 mTAInstanceMap.insert(pair<string, TAInstancePtr>(TAUUID, TAInst));
274                 return TAInst;
275         }
276         pthread_rwlock_unlock(&instIDLock);
277         return TAInstancePtr();
278 }
279
280 /**
281  * Thread routine for handling TA exit (immature/mature exit)
282  * @param pid pointer to the PID of the launched TA
283  */
284 void* TAFactory::waitForChild(void *pid) {
285         pid_t PID = *(pid_t*)pid;
286         int32_t childStatus;
287
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);
294         }
295         return NULL;
296 }
297
298 /**
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
302  */
303 void TAFactory::cleanupTAInstance(pid_t PID) {
304         LOGD(SIM_DAEMON, "Entry");
305         TAInstancePtr Inst;
306
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;
313                         break;
314                 }
315         }
316
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
321                  */
322                 Inst->cleanup();
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();
327                     ++itMap) {
328                         if (itMap->second == Inst) {
329                                 mTAInstanceMap.erase(itMap);
330                                 break;
331                         }
332                 }
333                 pthread_rwlock_unlock(&mTAInstanceMapLock);
334         }
335 }
336
337 /**
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
344  */
345 bool TAFactory::launchTA(string TAUUID, std::stringstream& str, bool debug,
346     pid_t& pid) {
347
348         int32_t result = -1;
349         pthread_t thread;
350         LOGD(SIM_DAEMON, "Entry");
351
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);
358         }
359
360         if ("" == argvPath) {
361                 LOGE(SIM_DAEMON, "Trusted Application does not exist");
362                 return false;
363         }
364         char *envp[1];
365
366         // Argument to be passed to TA main (TEEStub main)
367         string argvName = str.str().c_str();
368
369         // Get the port to be assigned to TA if TA is to be launched in debug mode
370         string argvPort = TABin->getPort(TAUUID);
371
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
375                 debug = true;
376                 char *argv[5];
377                 string argvGDB = "/usr/bin/gdbserver";
378                 string argvHost = "localhost:" + argvPort;
379
380                 argv[0] = &argvGDB[0];
381                 argv[1] = &argvHost[0];
382                 argv[2] = &argvPath[0];
383                 argv[3] = &argvName[0];
384                 argv[4] = NULL;
385
386                 // fork TA with GDB
387                 pid = fork();
388                 if (0 == pid) {
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);
393                         return false;
394                 }
395                 LOGD(SIM_DAEMON, "In Parent Process");
396         } else { //RELEASE MODE
397                 char *argv[3];
398                 argv[0] = &argvPath[0];
399                 argv[1] = &argvName[0];
400                 argv[2] = NULL;
401                 envp[0] = NULL;
402
403                 // Spawn TA
404                 result = posix_spawn(&pid, argv[0], NULL, NULL, argv, envp);
405                 if (result == 0) {
406                         LOGD(SIM_DAEMON, "TA pid: %i\n", pid);
407                         LOGD(SIM_DAEMON, "Launched Trusted Application");
408                 } else {
409                         LOGE(SIM_DAEMON, "Launching Trusted Application FAILED");
410                         pthread_mutex_unlock(&TABin->taLock);
411                         return false;
412                 }
413         }
414         pthread_mutex_unlock(&TABin->taLock);
415         // Create a thread to wait for TA exit
416         pthread_attr_t attr;
417         int s = pthread_attr_init(&attr);
418         if (s != 0)
419                 LOGE(SIM_DAEMON, "pthread_attr_init");
420         s = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
421         if (s != 0)
422                 LOGE(SIM_DAEMON, "pthread_attr_setdetachstate");
423         pthread_create(&thread, &attr, TAFactory::waitForChild, (void *)&pid);
424         return true;
425 }
426
427 TAFactory::~TAFactory() {
428         /* Destroy the locks created for TAInstance map (mTAInstanceMap), Instance
429          * Id (InstID) and TA Factory Instance (instance)
430          */
431         pthread_rwlock_destroy(&mTAInstanceMapLock);
432         pthread_rwlock_destroy(&instIDLock);
433         pthread_mutex_destroy(&instLock);
434 }