Home | History | Annotate | Download | only in tf_daemon
      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 
    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 
    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 }
    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 
    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 
    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 
    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
    306 static MD_INLINE void LogError(const char* format, ...)
    307 {
    308    MD_VAR_NOT_USED(format);
    309 }
    310 static MD_INLINE void LogWarning(const char* format, ...)
    311 {
    312    MD_VAR_NOT_USED(format);
    313 }
    314 static MD_INLINE void LogInfo(const char* format, ...)
    315 {
    316    MD_VAR_NOT_USED(format);
    317 }
    318 
    319 static MD_INLINE void TRACE_ERROR(const char* format, ...)
    320 {
    321    MD_VAR_NOT_USED(format);
    322 }
    323 
    324 static MD_INLINE void TRACE_WARNING(const char* format, ...)
    325 {
    326    MD_VAR_NOT_USED(format);
    327 }
    328 
    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 
    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 }
    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 }
    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 
    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 
    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 
    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  *----------------------------------------------------------------------------*/
    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 
    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  */
    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  **/
    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  **/
    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  **/
    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  **/
    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  **/
    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
    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  **/
    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
    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  **/
    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  **/
    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  **/
    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  */
    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  **/
   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
   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