833b9f2d8d2bd42bb0bd4e368dc6892922491d8f
[platform/core/api/libteec.git] / src / tef_libteec.c
1 /*
2  *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Krzysztof Dynowski <k.dynowski@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 #include <tef/tee_client_api.h>
20
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <dlfcn.h>
25 #include <linux/limits.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <stdlib.h>
30
31 #include "simulator/creators.h"
32 #include "optee/creators.h"
33
34 #define TEF_CONFIG_FILE "/etc/tef/tef.conf"
35 #define TEF_CONFIG_MAXLINE 1024
36 #define TEF_LIB_PATH LIB_INSTALL_DIR "/tef"
37 #define TEF_IMPLEMENTATION_SONAME "libteec.so"
38 #define TEEC_SYMBOL(lib, name) *((void**)&lib.w##name) = dlsym(lib.handle, "TEEC_" #name)
39
40 typedef struct {
41         const char *name;
42         void *handle;
43
44         void *(*createContext)();
45         void *(*createSession)();
46         void *(*createOperation)();
47         void *(*createSharedMemory)();
48         uint32_t (*paramTypes)(uint32_t);
49
50         TEEC_Result (*wInitializeContext)(const char *name, TEEC_Context *context);
51         void (*wFinalizeContext)(TEEC_Context *context);
52         TEEC_Result (*wOpenSession)(TEEC_Context *context,
53                                                                 TEEC_Session *session,
54                                                                 const TEEC_UUID *destination,
55                                                                 uint32_t connectionMethod,
56                                                                 const void *connectionData,
57                                                                 TEEC_Operation *operation,
58                                                                 uint32_t *returnOrigin);
59         void (*wCloseSession)(TEEC_Session *session);
60         TEEC_Result (*wInvokeCommand)(TEEC_Session *session,
61                                                                   uint32_t commandID,
62                                                                   TEEC_Operation *operation,
63                                                                   uint32_t *returnOrigin);
64         TEEC_Result (*wRegisterSharedMemory)(TEEC_Context *context, TEEC_SharedMemory *sharedMemory);
65         TEEC_Result (*wAllocateSharedMemory)(TEEC_Context *context, TEEC_SharedMemory *sharedMemory);
66         void (*wReleaseSharedMemory)(TEEC_SharedMemory *sharedMemory);
67         void (*wRequestCancellation)(TEEC_Operation *operation);
68 } TEF_LibraryImpl;
69
70 static TEF_LibraryImpl lib;
71
72 typedef struct {
73         void *implementation;
74         void *lastOperation;
75 } TEF_SessionImpl;
76
77 TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context)
78 {
79         if (lib.handle == NULL) {
80                 return TEEC_ERROR_NOT_IMPLEMENTED;
81         }
82         if (context == NULL) {
83                 return TEEC_ERROR_BAD_PARAMETERS;
84         }
85         context->imp = lib.createContext();
86         TEEC_Result result = lib.wInitializeContext(name, (TEEC_Context *)context->imp);
87         if (result != TEEC_SUCCESS) {
88                 free(context->imp);
89                 context->imp = NULL;
90         }
91         return result;
92 }
93
94
95 void TEEC_FinalizeContext(TEEC_Context *context)
96 {
97         if (lib.handle == NULL || context == NULL) {
98                 return;
99         }
100         lib.wFinalizeContext((TEEC_Context *)context->imp);
101         free(context->imp);
102         memset(context, 0, sizeof(*context));
103 }
104
105 static void freeSession(TEF_SessionImpl *tefSession);
106 static TEF_SessionImpl *allocSession(TEEC_Session *session)
107 {
108         TEF_SessionImpl *tefSession = (TEF_SessionImpl *)malloc(sizeof(TEF_SessionImpl));
109         if (tefSession) {
110                 tefSession->implementation = lib.createSession();
111                 tefSession->lastOperation = lib.createOperation();
112                 if (tefSession->implementation == NULL || tefSession->lastOperation == NULL) {
113                         freeSession(tefSession);
114                         return NULL;
115                 }
116                 session->imp = tefSession;
117         }
118         return tefSession;
119 }
120
121 static void freeSession(TEF_SessionImpl *tefSession)
122 {
123         if (tefSession == NULL) {
124                 return;
125         }
126         free(tefSession->lastOperation);
127         tefSession->lastOperation = NULL;
128         free(tefSession->implementation);
129         tefSession->implementation = NULL;
130         free(tefSession);
131 }
132
133 static TEEC_Operation *setOperation(TEF_SessionImpl *tefSession, TEEC_Operation *operation)
134 {
135         if (operation == NULL) {
136                 return NULL;
137         }
138
139         operation->imp = tefSession->lastOperation;
140         TEEC_Operation *op = (TEEC_Operation *)operation->imp;
141         op->started = operation->started;
142         op->paramTypes = lib.paramTypes(operation->paramTypes);
143         for (int i = 0; i < 4; ++i) {
144                 uint8_t type = TEEC_PARAM_TYPE_GET(operation->paramTypes, i);
145                 if (type >= TEEC_MEMREF_WHOLE && type <= TEEC_MEMREF_PARTIAL_INOUT) {
146                         op->params[i].memref.parent = (TEEC_SharedMemory*)operation->params[i].memref.parent->imp;
147                         op->params[i].memref.size = operation->params[i].memref.size;
148                         op->params[i].memref.offset = operation->params[i].memref.offset;
149                 } else {
150                         op->params[i] = operation->params[i];
151                 }
152         }
153         return op;
154 }
155 static void getOperation(TEEC_Operation *operation)
156 {
157         if (operation == NULL) {
158                 return;
159         }
160
161         TEEC_Operation *op = (TEEC_Operation *)operation->imp;
162         operation->started = op->started;
163         for (int i = 0; i < 4; ++i) {
164                 uint8_t type = TEEC_PARAM_TYPE_GET(operation->paramTypes, i);
165                 if (type >= TEEC_MEMREF_WHOLE && type <= TEEC_MEMREF_PARTIAL_INOUT) {
166                         operation->params[i].memref.size = op->params[i].memref.size;
167                         operation->params[i].memref.offset = op->params[i].memref.offset;
168                 } else {
169                         operation->params[i] = op->params[i];
170                 }
171         }
172 }
173
174 TEEC_Result TEEC_OpenSession(TEEC_Context *context,
175                                                          TEEC_Session *session,
176                                                          const TEEC_UUID *destination,
177                                                          uint32_t connectionMethod,
178                                                          const void *connectionData,
179                                                          TEEC_Operation *operation,
180                                                          uint32_t *returnOrigin)
181 {
182         if (returnOrigin != NULL) {
183                 *returnOrigin = TEEC_ORIGIN_API;
184         }
185         if (lib.handle == NULL) {
186                 return TEEC_ERROR_NOT_IMPLEMENTED;
187         }
188         if (context == NULL || session == NULL || context->imp == NULL) {
189                 return TEEC_ERROR_BAD_PARAMETERS;
190         }
191         TEF_SessionImpl *tefSession = allocSession(session);
192         if (tefSession == NULL) {
193                 return TEEC_ERROR_OUT_OF_MEMORY;
194         }
195         TEEC_Operation *op = setOperation(tefSession, operation);
196         TEEC_Result result = lib.wOpenSession((TEEC_Context *)context->imp,
197                                                                                   (TEEC_Session *)tefSession->implementation,
198                                                                                   destination, connectionMethod, connectionData, op, returnOrigin);
199         if (result != TEEC_SUCCESS) {
200                 freeSession(tefSession);
201                 session->imp = NULL;
202         } else {
203                 getOperation(operation);
204         }
205         return result;
206 }
207
208
209 void TEEC_CloseSession(TEEC_Session *session)
210 {
211         if (lib.handle == NULL || session == NULL) {
212                 return;
213         }
214         TEF_SessionImpl *tefSession = (TEF_SessionImpl *)session->imp;
215         if (tefSession == NULL) {
216                 return;
217         }
218         lib.wCloseSession((TEEC_Session *)tefSession->implementation);
219         freeSession(tefSession);
220         memset(session, 0, sizeof(*session));
221 }
222
223
224 TEEC_Result TEEC_InvokeCommand(TEEC_Session *session,
225                                                            uint32_t commandID,
226                                                            TEEC_Operation *operation,
227                                                            uint32_t *returnOrigin)
228 {
229         if (returnOrigin != NULL) {
230                 *returnOrigin = TEEC_ORIGIN_API;
231         }
232         if (lib.handle == NULL) {
233                 return TEEC_ERROR_NOT_IMPLEMENTED;
234         }
235         TEF_SessionImpl *tefSession = (TEF_SessionImpl *)session->imp;
236         if (tefSession == NULL) {
237                 return TEEC_ERROR_BAD_PARAMETERS;
238         }
239         TEEC_Operation *op = setOperation(tefSession, operation);
240         TEEC_Result result = lib.wInvokeCommand((TEEC_Session *)tefSession->implementation,
241                                                                                         commandID, op, returnOrigin);
242         if (result == TEEC_SUCCESS) {
243                 getOperation(operation);
244         }
245         return result;
246 }
247
248
249 TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context,
250                                                                           TEEC_SharedMemory *sharedMemory)
251 {
252         if (lib.handle == NULL) {
253                 return TEEC_ERROR_NOT_IMPLEMENTED;
254         }
255         if (sharedMemory == NULL) {
256                 return TEEC_ERROR_BAD_PARAMETERS;
257         }
258         sharedMemory->imp = lib.createSharedMemory();
259         if (sharedMemory->imp == NULL) {
260                 return TEEC_ERROR_OUT_OF_MEMORY;
261         }
262         TEEC_SharedMemory *shm = (TEEC_SharedMemory *)sharedMemory->imp;
263         shm->buffer = sharedMemory->buffer;
264         shm->size = sharedMemory->size;
265         shm->flags = sharedMemory->flags;
266         TEEC_Result result = lib.wRegisterSharedMemory((TEEC_Context *)context->imp, shm);
267         if (result != TEEC_SUCCESS) {
268                 free(sharedMemory->imp);
269                 sharedMemory->imp = NULL;
270         }
271         return result;
272 }
273
274
275 TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context,
276                                                                           TEEC_SharedMemory *sharedMemory)
277 {
278         if (lib.handle == NULL) {
279                 return TEEC_ERROR_NOT_IMPLEMENTED;
280         }
281         if (sharedMemory == NULL) {
282                 return TEEC_ERROR_BAD_PARAMETERS;
283         }
284         sharedMemory->imp = lib.createSharedMemory();
285         if (sharedMemory->imp == NULL) {
286                 return TEEC_ERROR_OUT_OF_MEMORY;
287         }
288         TEEC_SharedMemory *shm = (TEEC_SharedMemory *)sharedMemory->imp;
289         shm->buffer = NULL;
290         shm->size = sharedMemory->size;
291         shm->flags = sharedMemory->flags;
292         TEEC_Result result = lib.wAllocateSharedMemory((TEEC_Context *)context->imp, shm);
293         if (result != TEEC_SUCCESS) {
294                 free(sharedMemory->imp);
295                 sharedMemory->imp = NULL;
296         } else {
297                 sharedMemory->buffer = shm->buffer;
298         }
299         return result;
300 }
301
302
303 void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMemory)
304 {
305         if (lib.handle == NULL || sharedMemory == NULL || sharedMemory->imp == NULL) {
306                 return;
307         }
308         lib.wReleaseSharedMemory(sharedMemory->imp);
309         free(sharedMemory->imp);
310         sharedMemory->imp = NULL;
311 }
312
313
314 void TEEC_RequestCancellation(TEEC_Operation *operation)
315 {
316         if (lib.handle == NULL || operation == NULL || operation->imp == NULL) {
317                 return;
318         }
319         lib.wRequestCancellation(operation->imp);
320 }
321
322 static struct {
323         char libname[50];
324 } config;
325
326 static void configParam(const char *p)
327 {
328         if (*p == '#') {
329                 return;
330         }
331         if (strncmp(p, "lib=", 4) == 0) {
332                 const char *libname = p + 4;
333                 if (strlen(libname) > sizeof(config.libname) - 1) {
334                         fprintf(stderr, "tef-libteec: name to long '%s'\n", libname);
335                         return;
336                 }
337                 strncpy(config.libname, libname, sizeof(config.libname));
338                 config.libname[sizeof(config.libname) - 1] = '\0';
339         }
340 }
341
342 static void readConfig()
343 {
344         int fd;
345         memset(&config, 0, sizeof(config));
346         if ((fd = open(TEF_CONFIG_FILE, O_RDONLY)) < 0) {
347                 fprintf(stderr, "tef-libteec: can't read config %s\n", TEF_CONFIG_FILE);
348                 return;
349         }
350
351         char buf[TEF_CONFIG_MAXLINE];
352         ssize_t r;
353         size_t l = 0;
354         while ((r = read(fd, buf + l, sizeof(buf) - l)) > 0) {
355                 buf[l + r] = 0;
356                 char *p = strchr(buf, '\n');
357                 if (p == NULL) {
358                         fprintf(stderr, "tef-libteec: config line too long\n");
359                         break;
360                 }
361                 l = 0;
362                 do {
363                         *p = 0;
364                         configParam(buf + l);
365                         l = p - buf + 1;
366                         p = strchr(buf + l, '\n');
367                 } while (p != NULL);
368                 memcpy(buf, buf + l, r - l);
369                 l = (size_t)(r - l);
370         }
371         close(fd);
372 }
373
374 static int findLibrary(const char *name, char *libname)
375 {
376         snprintf(libname, PATH_MAX, TEF_LIB_PATH "/%s/" TEF_IMPLEMENTATION_SONAME, name);
377         return access(libname, R_OK) == 0;
378 }
379
380 static void loadLibrary(const char *name)
381 {
382         char libfile[PATH_MAX];
383         lib.name = name;
384         if (findLibrary(name, libfile)) {
385                 lib.handle = dlopen(libfile, RTLD_NOW);
386                 if (lib.handle == NULL) {
387                         fprintf(stderr, "tef-libteec: %s\n", dlerror());
388                         return;
389                 }
390         } else {
391                 fprintf(stderr, "tef-libteec: implementation '%s' not found in " TEF_LIB_PATH "\n", config.libname);
392                 lib.handle = NULL;
393                 return;
394         }
395
396         if (strcmp(name, "simulator") == 0) {
397                 lib.createContext = simulator_TEEC_Context;
398                 lib.createSession = simulator_TEEC_Session;
399                 lib.createOperation = simulator_TEEC_Operation;
400                 lib.createSharedMemory = simulator_TEEC_SharedMemory;
401                 lib.paramTypes = simulator_paramTypes;
402         } else if (strcmp(name, "optee") == 0) {
403                 lib.createContext = optee_TEEC_Context;
404                 lib.createSession = optee_TEEC_Session;
405                 lib.createOperation = optee_TEEC_Operation;
406                 lib.createSharedMemory = optee_TEEC_SharedMemory;
407                 lib.paramTypes = optee_paramTypes;
408         } else {
409                 fprintf(stderr, "tef-libteec: implementation '%s' is not supported\n", name);
410                 dlclose(lib.handle);
411                 lib.handle = NULL;
412                 return;
413         }
414
415         TEEC_SYMBOL(lib, InitializeContext);
416         TEEC_SYMBOL(lib, FinalizeContext);
417         TEEC_SYMBOL(lib, OpenSession);
418         TEEC_SYMBOL(lib, CloseSession);
419         TEEC_SYMBOL(lib, InvokeCommand);
420         TEEC_SYMBOL(lib, RegisterSharedMemory);
421         TEEC_SYMBOL(lib, AllocateSharedMemory);
422         TEEC_SYMBOL(lib, ReleaseSharedMemory);
423         TEEC_SYMBOL(lib, RequestCancellation);
424 }
425
426 // Note: _init() and _fini() are obsolete
427 void __attribute__ ((constructor))  tef_load(void)
428 {
429         //read configuration file
430         readConfig();
431
432         memset(&lib, 0, sizeof(lib));
433         if (config.libname[0]) {
434                 loadLibrary(config.libname);
435         }
436
437         if (lib.handle == NULL) { // fallback to dummy
438                 lib.name = "dummy";
439         }
440
441         fprintf(stderr, "tef-libteec: linked to %s\n", lib.name);
442 }
443 void __attribute__ ((destructor)) tef_unload(void)
444 {
445         if (lib.handle != NULL) {
446                 dlclose(lib.handle); // decrement refcount to wrapped library
447         }
448         memset(&lib, 0, sizeof(lib));
449 }