1 /**
2  * Copyright(c) 2011 Trusted Logic.   All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *  * Neither the name Trusted Logic nor the names of its
15  *    contributors may be used to endorse or promote products derived
16  *    from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #if defined(ANDROID)
32 #include <stddef.h>
33 #endif
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 /*
39  * When porting to a new OS, insert here the appropriate include files
40  */
41 #include <sys/stat.h>
42 #include <errno.h>
43 #include <sys/types.h>
44 #include <fcntl.h>
45 
46 #if defined(LINUX) || defined(ANDROID)
47 #include <unistd.h>
48 #include <sys/resource.h>
49 
50 
51 #if defined(ANDROID)
52 /* fdatasync does not exist on Android */
53 #define fdatasync fsync
54 #else
55 /*
56  * http://linux.die.net/man/2/fsync
57  * The function fdatasync seems to be absent of the header file
58  * in some distributions
59  */
60 int fdatasync(int fd);
61 #endif /* ANDROID */
62 #include <syslog.h>
63 #include <sys/types.h>
64 #include <sys/stat.h>
65 #include <pthread.h>
66 #include <semaphore.h>
67 #define PATH_SEPARATOR '/'
68 #endif /* LINUX || ANDROID */
69 
70 #ifdef WIN32
71 #include <windows.h>
72 #include <io.h>
73 #define PATH_SEPARATOR '\\'
74 #endif
75 
76 #ifdef __SYMBIAN32__
77 #include <unistd.h>
78 #include "os_symbian.h"
79 #define PATH_SEPARATOR '\\'
80 #endif
81 
82 #include <stdarg.h>
83 #include <assert.h>
84 
85 #include "service_delegation_protocol.h"
86 
87 #include "s_version.h"
88 #include "s_error.h"
89 #include "tee_client_api.h"
90 
91 /* You can define the preprocessor constant SUPPORT_DELEGATION_EXTENSION
92    if you want to pass extended options in a configuration file (option '-c').
93    It is up to you to define the format of this configuration file and the
94    extended option in the source file delegation_client_extension.c. You can
95    use extended options, e.g., to control the name of each partition file. */
96 #ifdef SUPPORT_DELEGATION_EXTENSION
97 #include "delegation_client_extension.h"
98 #endif
99 
100 #ifdef TFSW_FDM_ANDROID
101 #include <android/log.h>
102 #endif
103 
104 /*----------------------------------------------------------------------------
105  * Design notes
106  * ============
107  *
108  * This implementation of the delegation daemon supports the protocol
109  * specified in the Product Reference Manual ("Built-in Services Protocols Specification")
110  *
111  *----------------------------------------------------------------------------*/
112 
113 /*----------------------------------------------------------------------------
114  * Defines and structures
115  *----------------------------------------------------------------------------*/
116 #define ECHANGE_BUFFER_INSTRUCTIONS_NB 1000
117 
118 #define DEFAULT_WORKSPACE_SIZE (128*1024)
119 
120 /* A single shared memory block is used to contain the administrative data, the
121    instruction buffer and the workspace. The size of the instruction buffer is
122    fixed, but the size of workspace can be configured using the "-workspaceSize"
123    command-line option. */
124 typedef struct
125 {
126    DELEGATION_ADMINISTRATIVE_DATA sAdministrativeData;
127    uint32_t                       sInstructions[ECHANGE_BUFFER_INSTRUCTIONS_NB];
128    uint8_t                        sWorkspace[1/*g_nWorkspaceSize*/];
129 } DELEGATION_EXCHANGE_BUFFER;
130 
131 #ifdef SUPPORT_RPMB_PARTITION
132 typedef struct
133 {
134    uint8_t pDummy[196];
135    uint8_t pMAC[32];
136    uint8_t pData[256];
137    uint8_t pNonce[16];
138    uint32_t nMC;
139    uint16_t nAddr;
140    uint16_t nBlockCount;
141    uint16_t nResult;
142    uint16_t nReqOrResp;
143 } DELEGATION_RPMB_MESSAGE;
144 #endif
145 
146 #define MD_VAR_NOT_USED(variable)  do{(void)(variable);}while(0);
147 
148 #define MD_INLINE __inline
149 
150 /* ----------------------------------------------
151    Traces and logs
152 
153    On Linux, traces and logs go either to the console (stderr) or to the syslog.
154    When the daemon is started, the logs go to the console. Once and if the daemon
155    is detached, the logs go to syslog.
156 
157    On other systems, traces and logs go systematically to stderr
158 
159    The difference between traces and logs is that traces are compiled out
160    in release builds whereas logs are visible to the customer.
161 
162    -----------------------------------------------*/
163 #if defined(LINUX) || (defined ANDROID)
164 
165 static bool bDetached = false;
166 
LogError(const char * format,...)167 static MD_INLINE void LogError(const char* format, ...)
168 {
169    va_list ap;
170    va_start(ap, format);
171    if (bDetached)
172    {
173       vsyslog(LOG_ERR, format, ap);
174    }
175    else
176    {
177 #ifdef TFSW_FDM_ANDROID
178 	   __android_log_vprint(ANDROID_LOG_ERROR   , "TF Daemon", format, ap);
179 #else
180       fprintf(stderr, "ERROR: ");
181       vfprintf(stderr, format, ap);
182       fprintf(stderr, "\n");
183 #endif
184    }
185    va_end(ap);
186 }
187 
LogWarning(const char * format,...)188 static MD_INLINE void LogWarning(const char* format, ...)
189 {
190    va_list ap;
191    va_start(ap, format);
192    if (bDetached)
193    {
194       vsyslog(LOG_WARNING, format, ap);
195    }
196    else
197    {
198 #ifdef TFSW_FDM_ANDROID
199 	   __android_log_vprint(ANDROID_LOG_WARN   , "TF Daemon", format, ap);
200 #else
201       fprintf(stderr, "WARNING: ");
202       vfprintf(stderr, format, ap);
203       fprintf(stderr, "\n");
204 #endif
205    }
206    va_end(ap);
207 }
LogInfo(const char * format,...)208 static MD_INLINE void LogInfo(const char* format, ...)
209 {
210    va_list ap;
211    va_start(ap, format);
212    if (bDetached)
213    {
214       vsyslog(LOG_INFO, format, ap);
215    }
216    else
217    {
218 #ifdef TFSW_FDM_ANDROID
219 	   __android_log_vprint(ANDROID_LOG_INFO   , "TF Daemon", format, ap);
220 #else
221       vfprintf(stderr, format, ap);
222       fprintf(stderr, "\n");
223 #endif
224    }
225    va_end(ap);
226 }
227 
TRACE_ERROR(const char * format,...)228 static MD_INLINE void TRACE_ERROR(const char* format, ...)
229 {
230 #ifndef NDEBUG
231    va_list ap;
232    va_start(ap, format);
233    if (bDetached)
234    {
235       vsyslog(LOG_ERR, format, ap);
236    }
237    else
238    {
239 #ifdef TFSW_FDM_ANDROID
240 	   __android_log_vprint(ANDROID_LOG_ERROR   , "TF Daemon", format, ap);
241 #else
242       fprintf(stderr, "TRACE: ERROR: ");
243       vfprintf(stderr, format, ap);
244       fprintf(stderr, "\n");
245 #endif
246    }
247    va_end(ap);
248 #else
249    MD_VAR_NOT_USED(format);
250 #endif /* NDEBUG */
251 }
252 
TRACE_WARNING(const char * format,...)253 static MD_INLINE void TRACE_WARNING(const char* format, ...)
254 {
255 #ifndef NDEBUG
256    va_list ap;
257    va_start(ap, format);
258    if (bDetached)
259    {
260       vsyslog(LOG_WARNING, format, ap);
261    }
262    else
263    {
264 #ifdef TFSW_FDM_ANDROID
265 	   __android_log_vprint(ANDROID_LOG_WARN   , "TF Daemon", format, ap);
266 #else
267       fprintf(stderr, "TRACE: WARNING: ");
268       vfprintf(stderr, format, ap);
269       fprintf(stderr, "\n");
270 #endif
271    }
272    va_end(ap);
273 #else
274    MD_VAR_NOT_USED(format);
275 #endif /* NDEBUG */
276 }
277 
TRACE_INFO(const char * format,...)278 static MD_INLINE void TRACE_INFO(const char* format, ...)
279 {
280 #ifndef NDEBUG
281    va_list ap;
282    va_start(ap, format);
283    if (bDetached)
284    {
285       vsyslog(LOG_DEBUG, format, ap);
286    }
287    else
288    {
289 #ifdef TFSW_FDM_ANDROID
290 	   __android_log_vprint(ANDROID_LOG_INFO   , "TF Daemon", format, ap);
291 #else
292       fprintf(stderr, "TRACE: ");
293       vfprintf(stderr, format, ap);
294       fprintf(stderr, "\n");
295 #endif
296    }
297    va_end(ap);
298 #else
299    MD_VAR_NOT_USED(format);
300 #endif /* NDEBUG */
301 }
302 #elif defined __SYMBIAN32__
303 /* defined in os_symbian.h */
304 
305 #elif defined NO_LOG_NO_TRACE
LogError(const char * format,...)306 static MD_INLINE void LogError(const char* format, ...)
307 {
308    MD_VAR_NOT_USED(format);
309 }
LogWarning(const char * format,...)310 static MD_INLINE void LogWarning(const char* format, ...)
311 {
312    MD_VAR_NOT_USED(format);
313 }
LogInfo(const char * format,...)314 static MD_INLINE void LogInfo(const char* format, ...)
315 {
316    MD_VAR_NOT_USED(format);
317 }
318 
TRACE_ERROR(const char * format,...)319 static MD_INLINE void TRACE_ERROR(const char* format, ...)
320 {
321    MD_VAR_NOT_USED(format);
322 }
323 
TRACE_WARNING(const char * format,...)324 static MD_INLINE void TRACE_WARNING(const char* format, ...)
325 {
326    MD_VAR_NOT_USED(format);
327 }
328 
TRACE_INFO(const char * format,...)329 static MD_INLINE void TRACE_INFO(const char* format, ...)
330 {
331    MD_VAR_NOT_USED(format);
332 }
333 
334 #else
335 /* !defined(LINUX) || !defined(ANDROID) */
336 
LogError(const char * format,...)337 static MD_INLINE void LogError(const char* format, ...)
338 {
339    va_list ap;
340    va_start(ap, format);
341    fprintf(stderr, "ERROR: ");
342    vfprintf(stderr, format, ap);
343    fprintf(stderr, "\n");
344    va_end(ap);
345 }
LogWarning(const char * format,...)346 static MD_INLINE void LogWarning(const char* format, ...)
347 {
348    va_list ap;
349    va_start(ap, format);
350    fprintf(stderr, "WARNING: ");
351    vfprintf(stderr, format, ap);
352    fprintf(stderr, "\n");
353    va_end(ap);
354 }
LogInfo(const char * format,...)355 static MD_INLINE void LogInfo(const char* format, ...)
356 {
357    va_list ap;
358    va_start(ap, format);
359    vfprintf(stderr, format, ap);
360    fprintf(stderr, "\n");
361    va_end(ap);
362 }
363 
TRACE_ERROR(const char * format,...)364 static MD_INLINE void TRACE_ERROR(const char* format, ...)
365 {
366 #ifndef NDEBUG
367    va_list ap;
368    va_start(ap, format);
369    fprintf(stderr, "TRACE: ERROR: ");
370    vfprintf(stderr, format, ap);
371    fprintf(stderr, "\n");
372    va_end(ap);
373 #else
374    MD_VAR_NOT_USED(format);
375 #endif /* NDEBUG */
376 }
377 
TRACE_WARNING(const char * format,...)378 static MD_INLINE void TRACE_WARNING(const char* format, ...)
379 {
380 #ifndef NDEBUG
381    va_list ap;
382    va_start(ap, format);
383    fprintf(stderr, "TRACE: WARNING: ");
384    vfprintf(stderr, format, ap);
385    fprintf(stderr, "\n");
386    va_end(ap);
387 #else
388    MD_VAR_NOT_USED(format);
389 #endif /* NDEBUG */
390 }
391 
TRACE_INFO(const char * format,...)392 static MD_INLINE void TRACE_INFO(const char* format, ...)
393 {
394 #ifndef NDEBUG
395    va_list ap;
396    va_start(ap, format);
397    fprintf(stderr, "TRACE: ");
398    vfprintf(stderr, format, ap);
399    fprintf(stderr, "\n");
400    va_end(ap);
401 #else
402    MD_VAR_NOT_USED(format);
403 #endif /* NDEBUG */
404 }
405 #endif /* defined(LINUX) || defined(ANDROID) */
406 
407 /*----------------------------------------------------------------------------
408  * Globals
409  *----------------------------------------------------------------------------*/
410 /* The sector size */
411 static uint32_t g_nSectorSize;
412 
413 /* The workspace size */
414 static uint32_t g_nWorkspaceSize = DEFAULT_WORKSPACE_SIZE;
415 
416 /* UUID of the delegation service */
417 static const TEEC_UUID g_sServiceId = SERVICE_DELEGATION_UUID;
418 
419 /* pWorkspaceBuffer points to the workspace buffer shared with the secure
420    world to transfer the sectors in the READ and WRITE instructions  */
421 static uint8_t* g_pWorkspaceBuffer;
422 static DELEGATION_EXCHANGE_BUFFER * g_pExchangeBuffer;
423 TEEC_SharedMemory sExchangeSharedMem;
424 /*
425    The absolute path name for each of the 16 possible partitions.
426  */
427 static char* g_pPartitionNames[16];
428 
429 /* The file context for each of the 16 possible partitions. An entry
430    in this array is NULL if the corresponding partition is currently not opened
431  */
432 static FILE* g_pPartitionFiles[16];
433 
434 /*----------------------------------------------------------------------------
435  * Utilities functions
436  *----------------------------------------------------------------------------*/
printUsage(void)437 static void printUsage(void)
438 {
439    LogInfo("usage : tf_daemon [options]");
440    LogInfo("where [options] are:");
441    LogInfo("-h --help  Display help.");
442 #ifdef SUPPORT_DELEGATION_EXTENSION
443    LogInfo("-c <conf>  Configuration file path.");
444 #else
445    /* If the compilation parameter SUPPORT_DELEGATION_EXTENSION is not set, each
446       partition is stored as a file within the base dir */
447    LogInfo("-storageDir <baseDir>  Set the directory where the data will be stored; this directory");
448    LogInfo("           must be writable and executable (this parameter is mandatory)");
449 #endif
450    LogInfo("-d         Turns on debug mode.  If not specified, the daemon will fork itself");
451    LogInfo("           and get detached from the console.");
452 #ifndef SUPPORT_DELEGATION_EXTENSION
453    LogInfo("-workspaceSize <integer>  Set the size in bytes of the workspace. Must be greater or equal to 8 sectors.");
454    LogInfo("           (default is 128KB)");
455 #endif
456 }
457 
errno2serror(void)458 static TEEC_Result errno2serror(void)
459 {
460    switch (errno)
461    {
462    case EINVAL:
463       return S_ERROR_BAD_PARAMETERS;
464    case EMFILE:
465       return S_ERROR_NO_MORE_HANDLES;
466    case ENOENT:
467       return S_ERROR_ITEM_NOT_FOUND;
468    case EEXIST:
469       return S_ERROR_ITEM_EXISTS;
470    case ENOSPC:
471       return S_ERROR_STORAGE_NO_SPACE;
472    case ENOMEM:
473       return S_ERROR_OUT_OF_MEMORY;
474    case EBADF:
475    case EACCES:
476    default:
477       return S_ERROR_STORAGE_UNREACHABLE;
478    }
479 }
480 
481 /*
482  * Check if the directory in parameter exists with Read/Write access
483  * Return 0 in case of success and 1 otherwise.
484  */
static_checkStorageDirAndAccessRights(char * directoryName)485 int static_checkStorageDirAndAccessRights(char * directoryName)
486 {
487 #ifdef __SYMBIAN32__
488    /* it looks like stat is not working properly on Symbian
489       Create and remove dummy file to check access rights */
490    FILE *stream;
491    char *checkAccess = NULL;
492 
493    if (directoryName == NULL)
494    {
495       LogError("Directory Name is NULL");
496       return 1;
497    }
498 
499    checkAccess = malloc(strlen(directoryName)+1/* \ */ +1 /* a */ + 1 /* 0 */);
500    if (!checkAccess)
501    {
502       LogError("storageDir '%s' allocation error", directoryName);
503       return 1;
504    }
505    sprintf(checkAccess,"%s\\a",directoryName);
506    stream = fopen(checkAccess, "w+b");
507    if (!stream)
508    {
509       LogError("storageDir '%s' is incorrect or cannot be reached", directoryName);
510       return 1;
511    }
512    fclose(stream);
513    unlink(checkAccess);
514 #else
515    /* Non-Symbian OS: use stat */
516    struct stat buf;
517    int result = 0;
518 
519    if (directoryName == NULL)
520    {
521       LogError("Directory Name is NULL");
522       return 1;
523    }
524 
525    result = stat(directoryName, &buf);
526    if (result == 0)
527    {
528       /* Storage dir exists. Check access rights */
529 #if defined(LINUX) || (defined ANDROID)
530       if ((buf.st_mode & (S_IXUSR | S_IWUSR)) != (S_IXUSR | S_IWUSR))
531       {
532          LogError("storageDir '%s' does not have read-write access", directoryName);
533          return 1;
534       }
535 #endif
536    }
537    else if (errno == ENOENT)
538    {
539       LogError("storageDir '%s' does not exist", directoryName);
540       return 1;
541    }
542    else
543    {
544       /* Another error */
545       LogError("storageDir '%s' is incorrect or cannot be reached", directoryName);
546       return 1;
547    }
548 #endif
549    return 0;
550 }
551 
552 
553 
554 /*----------------------------------------------------------------------------
555  * Instructions
556  *----------------------------------------------------------------------------*/
557 
558 /**
559  * This function executes the DESTROY_PARTITION instruction
560  *
561  * @param nPartitionID: the partition identifier
562  **/
partitionDestroy(uint32_t nPartitionID)563 static TEEC_Result partitionDestroy(uint32_t nPartitionID)
564 {
565    TEEC_Result  nError = S_SUCCESS;
566 
567    if (g_pPartitionFiles[nPartitionID] != NULL)
568    {
569       /* The partition must not be currently opened */
570       LogError("g_pPartitionFiles not NULL");
571       return S_ERROR_BAD_STATE;
572    }
573 
574    /* Try to erase the file */
575 #if defined(LINUX) || (defined ANDROID) || defined (__SYMBIAN32__)
576    if (unlink(g_pPartitionNames[nPartitionID]) != 0)
577 #endif
578 #ifdef WIN32
579    if (_unlink(g_pPartitionNames[nPartitionID]) != 0)
580 #endif
581    {
582       /* File in use or OS didn't allow the operation */
583       nError = errno2serror();
584    }
585 
586    return nError;
587 }
588 
589 /**
590  * This function executes the CREATE_PARTITION instruction. When successful,
591  * it fills the g_pPartitionFiles[nPartitionID] slot.
592  *
593  * @param nPartitionID: the partition identifier
594  **/
partitionCreate(uint32_t nPartitionID)595 static TEEC_Result partitionCreate(uint32_t nPartitionID)
596 {
597    uint32_t nError = S_SUCCESS;
598 
599    if (g_pPartitionFiles[nPartitionID] != NULL)
600    {
601       /* The partition is already opened */
602       LogError("g_pPartitionFiles not NULL");
603       return S_ERROR_BAD_STATE;
604    }
605 
606    /* Create the file unconditionnally */
607    LogInfo("Create storage file \"%s\"", g_pPartitionNames[nPartitionID]);
608    g_pPartitionFiles[nPartitionID] = fopen(g_pPartitionNames[nPartitionID], "w+b");
609 
610    if (g_pPartitionFiles[nPartitionID] == NULL)
611    {
612       LogError("Cannot create storage file \"%s\"", g_pPartitionNames[nPartitionID]);
613       nError = errno2serror();
614       return nError;
615    }
616 
617    return nError;
618 }
619 
620 /**
621  * This function executes the OPEN_PARTITION instruction. When successful,
622  * it fills the g_pPartitionFiles[nPartitionID] slot and writes the partition
623  * size in hResultEncoder
624  *
625  * @param nPartitionID: the partition identifier
626  * @param pnPartitionSize: filled with the number of sectors in the partition
627  **/
partitionOpen(uint32_t nPartitionID,uint32_t * pnPartitionSize)628 static TEEC_Result partitionOpen(uint32_t nPartitionID, uint32_t* pnPartitionSize)
629 {
630    uint32_t nError = S_SUCCESS;
631 
632    if (g_pPartitionFiles[nPartitionID] != NULL)
633    {
634       /* No partition must be currently opened in the session */
635       LogError("g_pPartitionFiles not NULL");
636       return S_ERROR_BAD_STATE;
637    }
638 
639    /* Open the file */
640    g_pPartitionFiles[nPartitionID] = fopen(g_pPartitionNames[nPartitionID], "r+b");
641    if (g_pPartitionFiles[nPartitionID] == NULL)
642    {
643       if (errno == ENOENT)
644       {
645          /* File does not exist */
646          LogError("Storage file \"%s\" does not exist", g_pPartitionNames[nPartitionID]);
647          nError = S_ERROR_ITEM_NOT_FOUND;
648          return nError;
649       }
650       else
651       {
652          LogError("cannot open storage file \"%s\"", g_pPartitionNames[nPartitionID]);
653          nError = errno2serror();
654          return nError;
655       }
656    }
657    /* Determine the current number of sectors */
658    fseek(g_pPartitionFiles[nPartitionID], 0L, SEEK_END);
659    *pnPartitionSize = ftell(g_pPartitionFiles[nPartitionID]) / g_nSectorSize;
660 
661    LogInfo("storage file \"%s\" successfully opened (size = %d KB (%d bytes))",
662       g_pPartitionNames[nPartitionID],
663       ((*pnPartitionSize) * g_nSectorSize) / 1024,
664       ((*pnPartitionSize) * g_nSectorSize));
665 
666    return nError;
667 }
668 
669 
670 /**
671  * This function executes the CLOSE_PARTITION instruction.
672  * It closes the partition file.
673  *
674  * @param nPartitionID: the partition identifier
675  **/
partitionClose(uint32_t nPartitionID)676 static TEEC_Result partitionClose(uint32_t nPartitionID)
677 {
678    if (g_pPartitionFiles[nPartitionID] == NULL)
679    {
680       /* The partition is currently not opened */
681       return S_ERROR_BAD_STATE;
682    }
683    fclose(g_pPartitionFiles[nPartitionID]);
684    g_pPartitionFiles[nPartitionID] = NULL;
685    return S_SUCCESS;
686 }
687 
688 /**
689  * This function executes the READ instruction.
690  *
691  * @param nPartitionID: the partition identifier
692  * @param nSectorIndex: the index of the sector to read
693  * @param nWorkspaceOffset: the offset in the workspace where the sector must be written
694  **/
partitionRead(uint32_t nPartitionID,uint32_t nSectorIndex,uint32_t nWorkspaceOffset)695 static TEEC_Result partitionRead(uint32_t nPartitionID, uint32_t nSectorIndex, uint32_t nWorkspaceOffset)
696 {
697    FILE* pFile;
698 
699    TRACE_INFO(">Partition %1X: read sector 0x%08X into workspace at offset 0x%08X",
700       nPartitionID, nSectorIndex, nWorkspaceOffset);
701 
702    pFile = g_pPartitionFiles[nPartitionID];
703 
704    if (pFile == NULL)
705    {
706       /* The partition is not opened */
707       return S_ERROR_BAD_STATE;
708    }
709 
710    if (fseek(pFile, nSectorIndex*g_nSectorSize, SEEK_SET) != 0)
711    {
712       LogError("fseek error: %s", strerror(errno));
713       return errno2serror();
714    }
715 
716    if (fread(g_pWorkspaceBuffer + nWorkspaceOffset,
717              g_nSectorSize, 1,
718              pFile) != 1)
719    {
720       if (feof(pFile))
721       {
722          LogError("fread error: End-Of-File detected");
723          return S_ERROR_ITEM_NOT_FOUND;
724       }
725       LogError("fread error: %s", strerror(errno));
726       return errno2serror();
727    }
728 
729    return S_SUCCESS;
730 }
731 
732 #ifdef SUPPORT_RPMB_PARTITION
rpmbRead(DELEGATION_RPMB_INSTRUCTION * pInstruction)733 static TEEC_Result rpmbRead(DELEGATION_RPMB_INSTRUCTION *pInstruction)
734 {
735    DELEGATION_RPMB_MESSAGE* pMessages;
736    uint32_t nNbMsg, nIndex;
737 
738    nNbMsg = g_nSectorSize >> 8;
739    pMessages = (DELEGATION_RPMB_MESSAGE*)malloc(nNbMsg * sizeof(DELEGATION_RPMB_MESSAGE));
740    if (pMessages == NULL)
741    {
742       return S_ERROR_OUT_OF_MEMORY;
743    }
744    memset(pMessages,0,nNbMsg * sizeof(DELEGATION_RPMB_MESSAGE));
745 
746    for (nIndex=0;nIndex<nNbMsg;nIndex++)
747    {
748       memcpy(pMessages[nIndex].pNonce , pInstruction->pNonce, 16);
749       pMessages[nIndex].nAddr = pInstruction->nAddr;
750       pMessages[nIndex].nBlockCount = pInstruction->nBlockCount;
751       pMessages[nIndex].nReqOrResp = 0x0004;
752    }
753    memcpy(pMessages[nNbMsg-1].pMAC,pInstruction->nMAC,32);
754 
755    /* TODO: send to the RPMB driver */
756 
757    memcpy(pInstruction->pNonce,pMessages[0].pNonce , 16);
758    pInstruction->nAddr = pMessages[0].nAddr;
759    pInstruction->nBlockCount = pMessages[0].nBlockCount;
760    for (nIndex=0;nIndex<nNbMsg;nIndex++)
761    {
762       memcpy(g_pWorkspaceBuffer + pInstruction->nWorkspaceOffset[nIndex],pMessages[nIndex].pData,256);
763    }
764    memcpy(pInstruction->nMAC, pMessages[nNbMsg-1].pMAC,32);
765    pInstruction->nResult=pMessages[nNbMsg-1].nResult;
766 
767    free(pMessages);
768 
769    return S_SUCCESS;
770 }
771 #endif
772 /**
773  * This function executes the WRITE instruction.
774  *
775  * @param nPartitionID: the partition identifier
776  * @param nSectorIndex: the index of the sector to read
777  * @param nWorkspaceOffset: the offset in the workspace where the sector must be read
778  **/
partitionWrite(uint32_t nPartitionID,uint32_t nSectorIndex,uint32_t nWorkspaceOffset)779 static TEEC_Result partitionWrite(uint32_t nPartitionID, uint32_t nSectorIndex, uint32_t nWorkspaceOffset)
780 {
781    FILE* pFile;
782 
783    TRACE_INFO(">Partition %1X: write sector 0x%X from workspace at offset 0x%X",
784       nPartitionID, nSectorIndex, nWorkspaceOffset);
785 
786    pFile = g_pPartitionFiles[nPartitionID];
787 
788    if (pFile == NULL)
789    {
790       /* The partition is not opened */
791       return S_ERROR_BAD_STATE;
792    }
793 
794    if (fseek(pFile, nSectorIndex*g_nSectorSize, SEEK_SET) != 0)
795    {
796       LogError("fseek error: %s", strerror(errno));
797       return errno2serror();
798    }
799 
800    if (fwrite(g_pWorkspaceBuffer + nWorkspaceOffset,
801               g_nSectorSize, 1,
802               pFile) != 1)
803    {
804       LogError("fread error: %s", strerror(errno));
805       return errno2serror();
806    }
807    return S_SUCCESS;
808 }
809 
810 #ifdef SUPPORT_RPMB_PARTITION
rpmbWrite(DELEGATION_RPMB_INSTRUCTION * pInstruction)811 static TEEC_Result rpmbWrite(DELEGATION_RPMB_INSTRUCTION *pInstruction)
812 {
813    DELEGATION_RPMB_MESSAGE* pMessages;
814    uint32_t nNbMsg, nIndex;
815 
816    nNbMsg = g_nSectorSize >> 8;
817    pMessages = (DELEGATION_RPMB_MESSAGE*)malloc(nNbMsg * sizeof(DELEGATION_RPMB_MESSAGE));
818    if (pMessages == NULL)
819    {
820       return S_ERROR_OUT_OF_MEMORY;
821    }
822    memset(pMessages,0,nNbMsg * sizeof(DELEGATION_RPMB_MESSAGE));
823 
824    for (nIndex=0;nIndex<nNbMsg;nIndex++)
825    {
826       memcpy(pMessages[nIndex].pData,g_pWorkspaceBuffer + pInstruction->nWorkspaceOffset[nIndex],256);
827       pMessages[nIndex].nMC = pInstruction->nMC;
828       pMessages[nIndex].nAddr = pInstruction->nAddr;
829       pMessages[nIndex].nBlockCount = pInstruction->nBlockCount;
830       pMessages[nIndex].nReqOrResp = 0x0003;
831    }
832    memcpy(pMessages[nNbMsg-1].pMAC,pInstruction->nMAC,32);
833 
834    /* TODO: send to the RPMB driver */
835 
836    pInstruction->nAddr = pMessages[0].nAddr;
837    pInstruction->nMC = pMessages[0].nMC;
838    memcpy(pInstruction->nMAC, pMessages[nNbMsg-1].pMAC,32);
839    pInstruction->nResult=pMessages[nNbMsg-1].nResult;
840 
841    free(pMessages);
842 
843    return S_SUCCESS;
844 }
845 #endif
846 /**
847  * This function executes the SET_SIZE instruction.
848  *
849  * @param nPartitionID: the partition identifier
850  * @param nNewSectorCount: the new sector count
851  **/
partitionSetSize(uint32_t nPartitionID,uint32_t nNewSectorCount)852 static TEEC_Result partitionSetSize(uint32_t nPartitionID, uint32_t nNewSectorCount)
853 {
854    FILE* pFile;
855    uint32_t nCurrentSectorCount;
856 
857    pFile = g_pPartitionFiles[nPartitionID];
858 
859    if (pFile==NULL)
860    {
861       /* The partition is not opened */
862       return S_ERROR_BAD_STATE;
863    }
864 
865    /* Determine the current size of the partition */
866    if (fseek(pFile, 0, SEEK_END) != 0)
867    {
868       LogError("fseek error: %s", strerror(errno));
869       return errno2serror();
870    }
871    nCurrentSectorCount = ftell(pFile) / g_nSectorSize;
872 
873    if (nNewSectorCount > nCurrentSectorCount)
874    {
875       uint32_t nAddedBytesCount;
876       /* Enlarge the partition file. Make sure we actually write
877          some non-zero data into the new sectors. Otherwise, some file-system
878          might not really reserve the storage space but use a
879          sparse representation. In this case, a subsequent write instruction
880          could fail due to out-of-space, which we want to avoid. */
881       nAddedBytesCount = (nNewSectorCount-nCurrentSectorCount)*g_nSectorSize;
882       while (nAddedBytesCount)
883       {
884          if (fputc(0xA5, pFile)!=0xA5)
885          {
886             return errno2serror();
887          }
888          nAddedBytesCount--;
889       }
890    }
891    else if (nNewSectorCount < nCurrentSectorCount)
892    {
893       int result = 0;
894       /* Truncate the partition file */
895 #if defined(LINUX) || (defined ANDROID)
896       result = ftruncate(fileno(pFile),nNewSectorCount * g_nSectorSize);
897 #endif
898 #if defined (__SYMBIAN32__)
899 	  LogError("No truncate available in Symbian C API");
900 #endif
901 #ifdef WIN32
902       result = _chsize(_fileno(pFile),nNewSectorCount * g_nSectorSize);
903 #endif
904       if (result)
905       {
906          return errno2serror();
907       }
908    }
909    return S_SUCCESS;
910 }
911 
912 /**
913  * This function executes the SYNC instruction.
914  *
915  * @param pPartitionID: the partition identifier
916  **/
partitionSync(uint32_t nPartitionID)917 static TEEC_Result partitionSync(uint32_t nPartitionID)
918 {
919    TEEC_Result nError = S_SUCCESS;
920    int result;
921 
922    FILE* pFile = g_pPartitionFiles[nPartitionID];
923 
924    if (pFile == NULL)
925    {
926       /* The partition is not currently opened */
927       return S_ERROR_BAD_STATE;
928    }
929 
930    /* First make sure that the data in the stdio buffers
931       is flushed to the file descriptor */
932    result=fflush(pFile);
933    if (result)
934    {
935       nError=errno2serror();
936       goto end;
937    }
938    /* Then synchronize the file descriptor with the file-system */
939 
940 #if defined(LINUX) || (defined ANDROID)
941    result=fdatasync(fileno(pFile));
942 #endif
943 #if defined (__SYMBIAN32__)
944    result=fsync(fileno(pFile));
945 #endif
946 #ifdef WIN32
947    result=_commit(_fileno(pFile));
948 #endif
949    if (result)
950    {
951       nError=errno2serror();
952    }
953 
954 end:
955    return nError;
956 }
957 
958 /**
959  * This function executes the NOTIFY instruction.
960  *
961  * @param pMessage the message string
962  * @param nMessageType the type of messages
963  **/
notify(const wchar_t * pMessage,uint32_t nMessageType)964 static void notify(const wchar_t* pMessage, uint32_t nMessageType)
965 {
966    switch (nMessageType)
967    {
968    case DELEGATION_NOTIFY_TYPE_ERROR:
969       LogError("%ls", pMessage);
970       break;
971    case DELEGATION_NOTIFY_TYPE_WARNING:
972       LogWarning("%ls", pMessage);
973       break;
974    case DELEGATION_NOTIFY_TYPE_DEBUG:
975       LogInfo("DEBUG: %ls", pMessage);
976       break;
977    case DELEGATION_NOTIFY_TYPE_INFO:
978    default:
979       LogInfo("%ls", pMessage);
980       break;
981    }
982 }
983 
984 /*----------------------------------------------------------------------------
985  * Session main function
986  *----------------------------------------------------------------------------*/
987 
988 /*
989  * This function runs a session opened on the delegation service. It fetches
990  * instructions and execute them in a loop. It never returns, but may call
991  * exit when instructed to shutdown by the service
992  */
runSession(TEEC_Context * pContext,TEEC_Session * pSession,TEEC_Operation * pOperation)993 static int runSession(TEEC_Context* pContext, TEEC_Session* pSession, TEEC_Operation* pOperation)
994 {
995    memset(&g_pExchangeBuffer->sAdministrativeData, 0x00, sizeof(g_pExchangeBuffer->sAdministrativeData));
996 
997    while (true)
998    {
999       S_RESULT    nError;
1000       TEEC_Result                      nTeeError;
1001       uint32_t                         nInstructionsIndex;
1002       uint32_t                         nInstructionsBufferSize = sizeof(g_pExchangeBuffer->sInstructions);
1003 
1004       pOperation->paramTypes = TEEC_PARAM_TYPES(
1005          TEEC_MEMREF_PARTIAL_INPUT,
1006          TEEC_MEMREF_PARTIAL_OUTPUT,
1007          TEEC_MEMREF_PARTIAL_INOUT,
1008          TEEC_NONE);
1009       pOperation->params[0].memref.parent = &sExchangeSharedMem;
1010       pOperation->params[0].memref.offset = offsetof(DELEGATION_EXCHANGE_BUFFER, sAdministrativeData);
1011       pOperation->params[0].memref.size   = sizeof(g_pExchangeBuffer->sAdministrativeData);
1012 
1013       pOperation->params[1].memref.parent = &sExchangeSharedMem;
1014       pOperation->params[1].memref.offset = offsetof(DELEGATION_EXCHANGE_BUFFER, sInstructions);
1015       pOperation->params[1].memref.size   = sizeof(g_pExchangeBuffer->sInstructions);
1016 
1017       pOperation->params[2].memref.parent = &sExchangeSharedMem;
1018       pOperation->params[2].memref.offset = offsetof(DELEGATION_EXCHANGE_BUFFER, sWorkspace);
1019       pOperation->params[2].memref.size   = g_nWorkspaceSize;
1020 
1021       nTeeError = TEEC_InvokeCommand(pSession,
1022                                   SERVICE_DELEGATION_GET_INSTRUCTIONS,   /* commandID */
1023                                   pOperation,     /* IN OUT operation */
1024                                   NULL             /* OUT errorOrigin, optional */
1025                                  );
1026 
1027       if (nTeeError != TEEC_SUCCESS)
1028       {
1029          LogError("TEEC_InvokeCommand error: 0x%08X", nTeeError);
1030          LogError("Daemon exits");
1031          exit(2);
1032       }
1033 
1034       if (pOperation->params[1].tmpref.size >  nInstructionsBufferSize)
1035       {
1036          /* Should not happen, probably an error from the service */
1037          pOperation->params[1].tmpref.size = 0;
1038       }
1039 
1040       /* Reset the operation results */
1041       nError = TEEC_SUCCESS;
1042       g_pExchangeBuffer->sAdministrativeData.nSyncExecuted = 0;
1043       memset(g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates, 0x00, sizeof(g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates));
1044       memset(g_pExchangeBuffer->sAdministrativeData.nPartitionOpenSizes, 0x00, sizeof(g_pExchangeBuffer->sAdministrativeData.nPartitionOpenSizes));
1045 
1046       /* Execute the instructions */
1047       nInstructionsIndex = 0;
1048       nInstructionsBufferSize = pOperation->params[1].tmpref.size;
1049       while (true)
1050       {
1051          DELEGATION_INSTRUCTION * pInstruction;
1052          uint32_t nInstructionID;
1053          pInstruction = (DELEGATION_INSTRUCTION *)(&g_pExchangeBuffer->sInstructions[nInstructionsIndex/4]);
1054          if (nInstructionsIndex + 4 <= nInstructionsBufferSize)
1055          {
1056             nInstructionID = pInstruction->sGeneric.nInstructionID;
1057             nInstructionsIndex+=4;
1058          }
1059          else
1060          {
1061             goto instruction_parse_end;
1062          }
1063          if ((nInstructionID & 0x0F) == 0)
1064          {
1065             /* Partition-independent instruction */
1066             switch (nInstructionID)
1067             {
1068             case DELEGATION_INSTRUCTION_SHUTDOWN:
1069                {
1070                   exit(0);
1071                   /* The implementation of the TF Client API will automatically
1072                      destroy the context and release any associated resource */
1073                }
1074             case DELEGATION_INSTRUCTION_NOTIFY:
1075                {
1076                   /* Parse the instruction parameters */
1077                   wchar_t  pMessage[100];
1078                   uint32_t nMessageType;
1079                   uint32_t nMessageSize;
1080                   memset(pMessage, 0, 100*sizeof(wchar_t));
1081 
1082                   if (nInstructionsIndex + 8 <= nInstructionsBufferSize)
1083                   {
1084                      nMessageType = pInstruction->sNotify.nMessageType;
1085                      nMessageSize = pInstruction->sNotify.nMessageSize;
1086                      nInstructionsIndex+=8;
1087                   }
1088                   else
1089                   {
1090                      goto instruction_parse_end;
1091                   }
1092                   if (nMessageSize > (99)*sizeof(wchar_t))
1093                   {
1094                      /* How to handle the error correctly in this case ? */
1095                      goto instruction_parse_end;
1096                   }
1097                   if (nInstructionsIndex + nMessageSize <= nInstructionsBufferSize)
1098                   {
1099                      memcpy(pMessage, &pInstruction->sNotify.nMessage[0], nMessageSize);
1100                      nInstructionsIndex+=nMessageSize;
1101                   }
1102                   else
1103                   {
1104                      goto instruction_parse_end;
1105                   }
1106                   /* Align the pInstructionsIndex on 4 bytes */
1107                   nInstructionsIndex = (nInstructionsIndex+3)&~3;
1108                   notify(pMessage, nMessageType);
1109                   break;
1110                }
1111             default:
1112                LogError("Unknown instruction identifier: %02X", nInstructionID);
1113                nError = S_ERROR_BAD_PARAMETERS;
1114                break;
1115             }
1116          }
1117          else
1118          {
1119             /* Partition-specific instruction */
1120             uint32_t nPartitionID = (nInstructionID & 0xF0) >> 4;
1121             if (g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates[nPartitionID] == S_SUCCESS)
1122             {
1123                /* Execute the instruction only if there is currently no
1124                   error on the partition */
1125                switch (nInstructionID & 0x0F)
1126                {
1127                case DELEGATION_INSTRUCTION_PARTITION_CREATE:
1128                   nError = partitionCreate(nPartitionID);
1129 #ifdef SUPPORT_RPMB_PARTITION
1130                   if (nPartitionID == RPMB_PARTITION_ID)
1131                   {
1132                      /* TODO: get the Write counter */
1133                      pInstruction->sAuthRW.nMC = 0;
1134                   }
1135 #endif
1136                   TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError);
1137                   break;
1138                case DELEGATION_INSTRUCTION_PARTITION_OPEN:
1139                   {
1140                      uint32_t nPartitionSize = 0;
1141                      nError = partitionOpen(nPartitionID, &nPartitionSize);
1142                      TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d pSize=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nPartitionSize, nError);
1143                      if (nError == S_SUCCESS)
1144                      {
1145                         g_pExchangeBuffer->sAdministrativeData.nPartitionOpenSizes[nPartitionID] = nPartitionSize;
1146                      }
1147 #ifdef SUPPORT_RPMB_PARTITION
1148                      if (nPartitionID == RPMB_PARTITION_ID)
1149                      {
1150                         /* TODO: get the Write counter */
1151                         pInstruction->sAuthRW.nMC = 0;
1152                      }
1153 #endif
1154                      break;
1155                   }
1156                case DELEGATION_INSTRUCTION_PARTITION_READ:
1157 #ifdef SUPPORT_RPMB_PARTITION
1158                   if (nPartitionID == RPMB_PARTITION_ID)
1159                   {
1160                      if (nInstructionsIndex + sizeof(DELEGATION_RPMB_INSTRUCTION)-sizeof(uint32_t) <= nInstructionsBufferSize)
1161                      {
1162                         nInstructionsIndex+=sizeof(DELEGATION_RPMB_INSTRUCTION)-sizeof(uint32_t);
1163                      }
1164                      else
1165                      {
1166                         goto instruction_parse_end;
1167                      }
1168                      nError = rpmbRead(&pInstruction->sAuthRW);
1169                      TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError);
1170                      break;
1171                   }
1172                   else
1173 #endif
1174                   {
1175                      /* Parse parameters */
1176                      uint32_t nSectorID;
1177                      uint32_t nWorkspaceOffset;
1178                      if (nInstructionsIndex + 8 <= nInstructionsBufferSize)
1179                      {
1180                         nSectorID        = pInstruction->sReadWrite.nSectorID;
1181                         nWorkspaceOffset = pInstruction->sReadWrite.nWorkspaceOffset;
1182                         nInstructionsIndex+=8;
1183                      }
1184                      else
1185                      {
1186                         goto instruction_parse_end;
1187                      }
1188                      nError = partitionRead(nPartitionID, nSectorID, nWorkspaceOffset);
1189                      TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d sid=%d woff=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nSectorID, nWorkspaceOffset, nError);
1190                      break;
1191                   }
1192                case DELEGATION_INSTRUCTION_PARTITION_WRITE:
1193 #ifdef SUPPORT_RPMB_PARTITION
1194                   if (nPartitionID == RPMB_PARTITION_ID)
1195                   {
1196                      if (nInstructionsIndex + sizeof(DELEGATION_RPMB_INSTRUCTION)-sizeof(uint32_t) <= nInstructionsBufferSize)
1197                      {
1198                         nInstructionsIndex+=sizeof(DELEGATION_RPMB_INSTRUCTION)-sizeof(uint32_t);
1199                      }
1200                      else
1201                      {
1202                         goto instruction_parse_end;
1203                      }
1204                      nError = rpmbWrite(&pInstruction->sAuthRW);
1205                      TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError);
1206                      break;
1207                   }
1208                   else
1209 #endif
1210                   {
1211                      /* Parse parameters */
1212                      uint32_t nSectorID;
1213                      uint32_t nWorkspaceOffset;
1214                      if (nInstructionsIndex + 8 <= nInstructionsBufferSize)
1215                      {
1216                         nSectorID        = pInstruction->sReadWrite.nSectorID;
1217                         nWorkspaceOffset = pInstruction->sReadWrite.nWorkspaceOffset;
1218                         nInstructionsIndex+=8;
1219                      }
1220                      else
1221                      {
1222                         goto instruction_parse_end;
1223                      }
1224                      nError = partitionWrite(nPartitionID, nSectorID, nWorkspaceOffset);
1225                      TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d sid=%d woff=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nSectorID, nWorkspaceOffset, nError);
1226                      break;
1227                   }
1228                case DELEGATION_INSTRUCTION_PARTITION_SYNC:
1229                   nError = partitionSync(nPartitionID);
1230                   TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError);
1231                   if (nError == S_SUCCESS)
1232                   {
1233                      g_pExchangeBuffer->sAdministrativeData.nSyncExecuted++;
1234                   }
1235                   break;
1236                case DELEGATION_INSTRUCTION_PARTITION_SET_SIZE:
1237                   {
1238                      uint32_t nNewSize;
1239                      if (nInstructionsIndex + 4 <= nInstructionsBufferSize)
1240                      {
1241                         nNewSize = pInstruction->sSetSize.nNewSize;
1242                         nInstructionsIndex+=4;
1243                      }
1244                      else
1245                      {
1246                         goto instruction_parse_end;
1247                      }
1248                      nError = partitionSetSize(nPartitionID, nNewSize);
1249                      TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d nNewSize=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nNewSize, nError);
1250                      break;
1251                   }
1252                case DELEGATION_INSTRUCTION_PARTITION_CLOSE:
1253                   nError = partitionClose(nPartitionID);
1254                   TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError);
1255                   break;
1256                case DELEGATION_INSTRUCTION_PARTITION_DESTROY:
1257                   nError = partitionDestroy(nPartitionID);
1258                   TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError);
1259                   break;
1260                }
1261                g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates[nPartitionID] = nError;
1262             }
1263          }
1264       }
1265 instruction_parse_end:
1266       memset(pOperation, 0, sizeof(TEEC_Operation));
1267    }
1268 }
1269 
1270 /**
1271  * This function opens a new session to the delegation service.
1272  **/
createSession(TEEC_Context * pContext,TEEC_Session * pSession,TEEC_Operation * pOperation)1273 static int createSession(TEEC_Context* pContext, TEEC_Session* pSession, TEEC_Operation* pOperation)
1274 {
1275    TEEC_Result nError;
1276    uint32_t nExchangeBufferSize;
1277 
1278    memset(pOperation, 0, sizeof(TEEC_Operation));
1279    pOperation->paramTypes = TEEC_PARAM_TYPES(
1280       TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
1281    nError = TEEC_OpenSession(pContext,
1282                              pSession,                /* OUT session */
1283                              &g_sServiceId,           /* destination UUID */
1284                              TEEC_LOGIN_PRIVILEGED,   /* connectionMethod */
1285                              NULL,                    /* connectionData */
1286                              pOperation,              /* IN OUT operation */
1287                              NULL                     /* OUT errorOrigin, optional */
1288                              );
1289    if (nError != TEEC_SUCCESS)
1290    {
1291       LogError("Error on TEEC_OpenSession : 0x%x", nError);
1292       exit(2);
1293    }
1294    /* Read sector size */
1295    g_nSectorSize = pOperation->params[0].value.a;
1296    LogInfo("Sector Size: %d bytes", g_nSectorSize);
1297 
1298    /* Check sector size */
1299    if (!(g_nSectorSize == 512 || g_nSectorSize == 1024 || g_nSectorSize == 2048 || g_nSectorSize == 4096))
1300    {
1301       LogError("Incorrect sector size: terminating...");
1302       exit(2);
1303    }
1304 
1305    /* Check workspace size */
1306    if (g_nWorkspaceSize < 8 * g_nSectorSize)
1307    {
1308       g_nWorkspaceSize = 8 * g_nSectorSize;
1309       LogWarning("Workspace size too small, automatically set to %d bytes", g_nWorkspaceSize);
1310    }
1311    /* Compute the size of the exchange buffer */
1312    nExchangeBufferSize = sizeof(DELEGATION_EXCHANGE_BUFFER)-1+g_nWorkspaceSize;
1313    g_pExchangeBuffer  = (DELEGATION_EXCHANGE_BUFFER*)malloc(nExchangeBufferSize);
1314 	 if (g_pExchangeBuffer == NULL)
1315    {
1316       LogError("Cannot allocate exchange buffer of %d bytes", nExchangeBufferSize);
1317       LogError("Now exiting...");
1318       exit(2);
1319    }
1320    g_pWorkspaceBuffer = (uint8_t*)g_pExchangeBuffer->sWorkspace;
1321    memset(g_pExchangeBuffer, 0x00, nExchangeBufferSize);
1322    memset(g_pPartitionFiles,0,16*sizeof(FILE*));
1323 
1324    /* Register the exchange buffer as a shared memory block */
1325    sExchangeSharedMem.buffer = g_pExchangeBuffer;
1326    sExchangeSharedMem.size   = nExchangeBufferSize;
1327    sExchangeSharedMem.flags  = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
1328    nError = TEEC_RegisterSharedMemory(pContext, &sExchangeSharedMem);
1329    if (nError != TEEC_SUCCESS)
1330    {
1331       LogError("Error on TEEC_RegisterSharedMemory : 0x%x", nError);
1332       free(g_pExchangeBuffer);
1333       exit(2);
1334    }
1335    LogInfo("Daemon now connected");
1336    return 0;
1337 }
1338 
1339 
1340 /*----------------------------------------------------------------------------
1341  * Main
1342  *----------------------------------------------------------------------------*/
1343 
1344 #ifdef INCLUDE_CLIENT_DELEGATION
delegation_main(int argc,char * argv[])1345 int delegation_main(int argc, char* argv[])
1346 #else
1347 int main(int argc, char* argv[])
1348 #endif
1349 {
1350    TEEC_Result    nError;
1351    TEEC_Context   sContext;
1352    TEEC_Session   sSession;
1353    TEEC_Operation sOperation;
1354    bool        debug = false;
1355 
1356 #ifndef SUPPORT_DELEGATION_EXTENSION
1357    char * baseDir = NULL;
1358 
1359    LogInfo("TFSW Normal-World Daemon");
1360 #else
1361    LogInfo("TFSW Normal-World Ext Daemon");
1362 #endif
1363    LogInfo(S_VERSION_STRING);
1364    LogInfo("");
1365 
1366    /* Skip program name */
1367    argv++;
1368    argc--;
1369 
1370    while (argc != 0)
1371    {
1372       if (strcmp(argv[0], "-d") == 0)
1373       {
1374          debug = true;
1375       }
1376 #ifdef SUPPORT_DELEGATION_EXTENSION
1377       else if (strcmp(argv[0], "-c") == 0)
1378       {
1379          int error;
1380          argc--;
1381          argv++;
1382          if (argc == 0)
1383          {
1384             printUsage();
1385             return 1;
1386          }
1387          /* Note that the function parseCommandLineExtension can modify the
1388             content of the g_partitionNames array */
1389          error = parseCommandLineExtension(argv[0], g_pPartitionNames);
1390          if ( error != 0 )
1391          {
1392             printUsage();
1393             return error;
1394          }
1395       }
1396 #else
1397       else if (strcmp(argv[0], "-storageDir") == 0)
1398       {
1399          uint32_t i = 0;
1400          argc--;
1401          argv++;
1402          if (argc == 0)
1403          {
1404             printUsage();
1405             return 1;
1406          }
1407          if (baseDir != NULL)
1408          {
1409             LogError("Only one storage directory may be specified");
1410             return 1;
1411          }
1412          baseDir = malloc(strlen(argv[0])+1); /* Zero-terminated string */
1413          if (baseDir == NULL)
1414          {
1415              LogError("Out of memory");
1416              return 2;
1417          }
1418 
1419          strcpy(baseDir, argv[0]);
1420 
1421          /* Set default names to the partitions */
1422          for ( i=0; i<16 ;i++ )
1423          {
1424             g_pPartitionNames[i] = NULL;
1425             g_pPartitionNames[i] = malloc(strlen(baseDir) + 1 /* separator */ + sizeof("Store_X.tf"));
1426             if (g_pPartitionNames[i] != NULL)
1427             {
1428                sprintf(g_pPartitionNames[i], "%s%cStore_%1X.tf", baseDir, PATH_SEPARATOR, i);
1429             }
1430             else
1431             {
1432                free(baseDir);
1433                i=0;
1434                while(g_pPartitionNames[i] != NULL) free(g_pPartitionNames[i++]);
1435                LogError("Out of memory");
1436                return 2;
1437             }
1438          }
1439       }
1440       else if (strcmp(argv[0], "-workspaceSize") == 0)
1441       {
1442          argc--;
1443          argv++;
1444          if (argc == 0)
1445          {
1446             printUsage();
1447             return 1;
1448          }
1449          g_nWorkspaceSize=atol(argv[0]);
1450       }
1451 #endif /* ! SUPPORT_DELEGATION_EXTENSION */
1452       /*****************************************/
1453       else if (strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "-h") == 0)
1454       {
1455          printUsage();
1456          return 0;
1457       }
1458       else
1459       {
1460          printUsage();
1461          return 1;
1462       }
1463       argc--;
1464       argv++;
1465    }
1466 
1467 #ifndef SUPPORT_DELEGATION_EXTENSION
1468    if (baseDir == NULL)
1469    {
1470       LogError("-storageDir option is mandatory");
1471       return 1;
1472    }
1473    else
1474    {
1475       if (static_checkStorageDirAndAccessRights(baseDir) != 0)
1476       {
1477          return 1;
1478       }
1479    }
1480 #endif /* #ifndef SUPPORT_DELEGATION_EXTENSION */
1481 
1482    /*
1483     * Detach the daemon from the console
1484     */
1485 
1486 #if defined(LINUX) || (defined ANDROID)
1487    {
1488       /*
1489        * Turns this application into a daemon => fork off parent process, setup logging, ...
1490        */
1491 
1492       /* Our process ID and Session ID */
1493       pid_t pid, sid;
1494 
1495       if (!debug)
1496       {
1497          LogInfo("tf_daemon is detaching from console... Further traces go to syslog");
1498          /* Fork off the parent process */
1499          pid = fork();
1500          if (pid < 0)
1501          {
1502             LogError("daemon forking failed");
1503             return 1;
1504          }
1505 
1506          if (pid > 0)
1507          {
1508             /* parent */
1509             return 0;
1510          }
1511          bDetached = true;
1512       }
1513 
1514       /* Change the file mode mask */
1515       umask(0077);
1516 
1517       if (!debug)
1518       {
1519          /* Open any logs here */
1520          openlog("tf_daemon", 0, LOG_DAEMON);
1521 
1522          /* Detach from the console */
1523          sid = setsid();
1524          if (sid < 0)
1525          {
1526             /* Log the failure */
1527             LogError("daemon group creation failed");
1528             return 1;
1529          }
1530          /* Close out the standard file descriptors */
1531          close(STDIN_FILENO);
1532          close(STDOUT_FILENO);
1533          close(STDERR_FILENO);
1534       }
1535    }
1536    /* Change priority so that tf_driver.ko with no polling thread is faster */
1537    if (setpriority(PRIO_PROCESS, 0, 19)!=0)
1538    {
1539       LogError("Daemon cannot change priority");
1540       return 1;
1541    }
1542 
1543 #endif
1544 
1545    TRACE_INFO("Sector size is %d", g_nSectorSize);
1546 
1547    LogInfo("tf_daemon - started");
1548 
1549    nError = TEEC_InitializeContext(NULL,  /* const char * name */
1550                                    &sContext);   /* TEEC_Context* context */
1551    if (nError != TEEC_SUCCESS)
1552    {
1553       LogError("TEEC_InitializeContext error: 0x%08X", nError);
1554       LogError("Now exiting...");
1555       exit(2);
1556    }
1557 
1558    /* Open a session */
1559    if(createSession(&sContext, &sSession, &sOperation) == 0)
1560    {
1561       /* Run the session. This should never return */
1562       runSession(&sContext, &sSession, &sOperation);
1563    }
1564    TEEC_FinalizeContext(&sContext);
1565 
1566    return 3;
1567 }
1568