1/*
2 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 *     http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12
13#include "tee_client.h"
14#include <fcntl.h>
15#include <securec.h>
16#include <sys/mman.h>
17#include <unistd.h>
18#include "ashmem.h"
19#include "if_system_ability_manager.h"
20#include "ipc_skeleton.h"
21#include "ipc_types.h"
22#include "iremote_proxy.h"
23#include "iremote_stub.h"
24#include "iservice_registry.h"
25#include "system_ability_definition.h"
26#include "tee_client_api.h"
27#include "tee_client_ext_api.h"
28#include "tee_client_inner.h"
29#include "tee_log.h"
30
31using namespace std;
32namespace OHOS {
33bool TeeClient::mServiceValid = false;
34
35bool TeeClient::SetCallBack()
36{
37    MessageParcel data;
38    MessageParcel reply;
39    MessageOption option;
40
41    if (mNotify == nullptr || mTeecService == nullptr) {
42        tloge("get call back handle failed\n");
43        return false;
44    }
45
46    bool result = data.WriteInterfaceToken(INTERFACE_TOKEN);
47    if (!result) {
48        tloge("write token failed\n");
49        return false;
50    }
51
52    result = data.WriteRemoteObject(mNotify);
53    if (!result) {
54        tloge("write notify failed\n");
55        return false;
56    }
57
58    int ret = mTeecService->SendRequest(SET_CALL_BACK, data, reply, option);
59    if (ret != ERR_NONE) {
60        tloge("send notify failed\n");
61        return false;
62    }
63
64    return true;
65}
66
67void TeeClient::InitTeecService()
68{
69    lock_guard<mutex> autoLock(mServiceLock);
70
71    if (mServiceValid) {
72        return;
73    }
74
75    if (mNotify == nullptr) {
76        mNotify = new IPCObjectStub(u"TeecClientDeathRecipient");
77        if (mNotify == nullptr) {
78            tloge("new mNotify failed\n");
79            return;
80        }
81    }
82
83    sptr<ISystemAbilityManager> sm = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
84    if (sm == nullptr) {
85        tloge("get system ability failed\n");
86        return;
87    }
88
89    mTeecService = sm->GetSystemAbility(CA_DAEMON_ID);
90    if (mTeecService == nullptr) {
91        tloge("get teec service failed\n");
92        return;
93    }
94
95    mDeathNotifier = new DeathNotifier(mTeecService);
96    if (mDeathNotifier == nullptr) {
97        tloge("new death notify failed\n");
98        mTeecService = nullptr;
99        return;
100    }
101
102    /* death notify, TeecService-->CA */
103    bool result = mTeecService->AddDeathRecipient(mDeathNotifier);
104    if (!result) {
105        tloge("set service to ca failed\n");
106        mTeecService = nullptr;
107        return;
108    }
109
110    /* death notify, CA-->TeecService */
111    result = SetCallBack();
112    if (!result) {
113        tloge("set ca to service failed\n");
114        mTeecService = nullptr;
115        return;
116    }
117
118    mServiceValid = true;
119}
120
121static TEEC_Result TEEC_CheckTmpRef(TEEC_TempMemoryReference tmpref)
122{
123    if ((tmpref.buffer == nullptr) || (tmpref.size == 0)) {
124        tloge("tmpref buffer is null, or size is zero\n");
125        return TEEC_ERROR_BAD_PARAMETERS;
126    }
127    return TEEC_SUCCESS;
128}
129
130static TEEC_Result TEEC_CheckMemRef(TEEC_RegisteredMemoryReference memref, uint32_t paramType)
131{
132    if ((memref.parent == nullptr) || (memref.parent->buffer == nullptr)) {
133        tloge("parent of memref is null, or the buffer is zero\n");
134        return TEEC_ERROR_BAD_PARAMETERS;
135    }
136
137    if (paramType == TEEC_MEMREF_PARTIAL_INPUT) {
138        if (!(memref.parent->flags & TEEC_MEM_INPUT)) {
139            goto PARAM_ERROR;
140        }
141    } else if (paramType == TEEC_MEMREF_PARTIAL_OUTPUT) {
142        if (!(memref.parent->flags & TEEC_MEM_OUTPUT)) {
143            goto PARAM_ERROR;
144        }
145    } else if (paramType == TEEC_MEMREF_PARTIAL_INOUT) {
146        if (!(memref.parent->flags & TEEC_MEM_INPUT)) {
147            goto PARAM_ERROR;
148        }
149        if (!(memref.parent->flags & TEEC_MEM_OUTPUT)) {
150            goto PARAM_ERROR;
151        }
152    } else {
153        /*  if type is TEEC_MEMREF_WHOLE, ignore it */
154    }
155
156    if ((paramType == TEEC_MEMREF_PARTIAL_INPUT) ||
157        (paramType == TEEC_MEMREF_PARTIAL_OUTPUT) ||
158        (paramType == TEEC_MEMREF_PARTIAL_INOUT)) {
159        if (((memref.offset + memref.size) < memref.offset) ||
160            ((memref.offset + memref.size) > memref.parent->size)) {
161            tloge("partial mem check failed, offset %{public}u size %{public}u\n", memref.offset, memref.size);
162            return TEEC_ERROR_BAD_PARAMETERS;
163        }
164    }
165
166    return TEEC_SUCCESS;
167PARAM_ERROR:
168    tloge("type of memref not belong to the parent flags\n");
169    return TEEC_ERROR_BAD_PARAMETERS;
170}
171
172TEEC_Result TeeClient::TEEC_CheckOperation(const TEEC_Operation *operation)
173{
174    TEEC_Result ret = TEEC_SUCCESS;
175
176    if (operation == nullptr) {
177        return ret;
178    }
179    if (!operation->started) {
180        tloge("sorry, cancellation not support\n");
181        return TEEC_ERROR_NOT_IMPLEMENTED;
182    }
183
184    for (uint32_t i = 0; i < TEEC_PARAM_NUM; i++) {
185        uint32_t paramType = TEEC_PARAM_TYPE_GET(operation->paramTypes, i);
186        if (IS_TEMP_MEM(paramType)) {
187            ret = TEEC_CheckTmpRef(operation->params[i].tmpref);
188        } else if (IS_PARTIAL_MEM(paramType)) {
189            ret = TEEC_CheckMemRef(operation->params[i].memref, paramType);
190        } else if (IS_VALUE_MEM(paramType)) {
191            /*  if type is value, ignore it */
192        } else if (paramType == TEEC_NONE) {
193            /*  if type is none, ignore it */
194        } else {
195            tloge("param %{public}u has invalid type %{public}u\n", i, paramType);
196            ret = TEEC_ERROR_BAD_PARAMETERS;
197            break;
198        }
199
200        if (ret != TEEC_SUCCESS) {
201            tloge("param %{public}u check failed\n", i);
202            break;
203        }
204    }
205    return ret;
206}
207
208static inline bool IsOverFlow(uint32_t num1, uint32_t num2)
209{
210    if (num1 + num2 < num1) {
211        return true;
212    }
213    return false;
214}
215
216static bool WriteChar(const char *srcStr, MessageParcel &data)
217{
218    bool writeRet = false;
219    if (srcStr == nullptr) {
220        writeRet = data.WriteUint32(0);
221        CHECK_ERR_RETURN(writeRet, true, writeRet);
222    } else {
223        if (strnlen(srcStr, PATH_MAX) == PATH_MAX) {
224            tloge("param srcStr is too long\n");
225            return false;
226        }
227        string tempStr = srcStr;
228        writeRet = data.WriteUint32(strlen(srcStr));
229        CHECK_ERR_RETURN(writeRet, true, writeRet);
230        writeRet = data.WriteString(tempStr);
231        CHECK_ERR_RETURN(writeRet, true, writeRet);
232    }
233    return true;
234}
235
236static bool WriteContext(MessageParcel &data, TEEC_Context *context)
237{
238    return data.WriteBuffer(context, sizeof(*context));
239}
240
241static bool WriteSession(MessageParcel &data, TEEC_Session *session)
242{
243    return data.WriteBuffer(session, sizeof(*session));
244}
245
246static bool WriteSharedMem(MessageParcel &data, TEEC_SharedMemory *shm)
247{
248    return data.WriteBuffer(shm, sizeof(*shm));
249}
250
251static bool CheckSharedMemoryFLag(uint32_t flag)
252{
253    return (flag == TEEC_MEM_INPUT || flag == TEEC_MEM_OUTPUT || flag == TEEC_MEM_INOUT);
254}
255
256uint32_t TeeClient::FindShareMemOffset(const void *buffer)
257{
258    lock_guard<mutex> autoLock(mSharMemLock);
259    size_t count = mShareMem.size();
260    for (size_t index = 0; index < count; index++) {
261        if (mShareMem[index].buffer == buffer) {
262            return mShareMem[index].offset;
263        }
264    }
265
266    return UINT32_MAX;
267}
268
269void TeeClient::FreeAllShareMem()
270{
271    size_t index;
272
273    lock_guard<mutex> autoLock(mSharMemLock);
274    size_t count = mShareMem.size();
275    for (index = 0; index < count; index++) {
276        if ((mShareMem[index].buffer != nullptr) && (mShareMem[index].buffer != ZERO_SIZE_PTR) &&
277            (mShareMem[index].size != 0)) {
278            int32_t ret = munmap(mShareMem[index].buffer, mShareMem[index].size);
279            if (ret != 0) {
280                tloge("munmap share mem failed, ret=0x%x\n", ret);
281            }
282        }
283    }
284    mShareMem.clear();
285    return;
286}
287
288void TeeClient::FreeAllShareMemoryInContext(const TEEC_Context *context)
289{
290    std::vector<TC_NS_ShareMem>::iterator vec;
291
292    lock_guard<mutex> autoLock(mSharMemLock);
293    for (vec = mShareMem.begin(); vec != mShareMem.end();) {
294        if ((vec->fd == context->fd) && (vec->buffer != nullptr) && (vec->buffer != ZERO_SIZE_PTR) &&
295            (vec->size != 0)) {
296            int32_t ret = munmap(vec->buffer, vec->size);
297            if (ret != 0) {
298                tloge("munmap share mem failed, ret=0x%x\n", ret);
299            }
300            vec = mShareMem.erase(vec);
301        } else {
302            ++vec;
303        }
304    }
305    return;
306}
307
308static void SleepNs(long num)
309{
310    struct timespec ts;
311    ts.tv_sec  = 0;
312    ts.tv_nsec = num;
313
314    if (nanosleep(&ts, NULL) != 0) {
315        tlogd("nanosleep ms error\n");
316    }
317}
318
319#define SLEEP_TIME (200*1000*1000)
320#define CONNECT_MAX_NUM 50
321
322TEEC_Result TeeClient::InitializeContextSendCmd(const char *name, MessageParcel &reply)
323{
324    MessageParcel data;
325    MessageOption option;
326    uint32_t connectTime = 0;
327    /* add retry to avoid app start before daemon */
328    while (connectTime++ < CONNECT_MAX_NUM) {
329        InitTeecService();
330        if (mServiceValid) {
331            break;
332        }
333        tlogd("get cadaemon handle retry\n");
334        SleepNs(SLEEP_TIME);
335    }
336    if (connectTime > CONNECT_MAX_NUM) {
337        tloge("get cadaemon handle failed\n");
338        return TEEC_FAIL;
339    }
340
341    bool writeRet = data.WriteInterfaceToken(INTERFACE_TOKEN);
342    CHECK_ERR_RETURN(writeRet, true, TEEC_FAIL);
343
344    writeRet = WriteChar(name, data);
345    CHECK_ERR_RETURN(writeRet, true, TEEC_FAIL);
346
347    int32_t ret = mTeecService->SendRequest(INIT_CONTEXT, data, reply, option);
348    CHECK_ERR_RETURN(ret, ERR_NONE, TEEC_FAIL);
349
350    return TEEC_SUCCESS;
351}
352
353TEEC_Result TeeClient::InitializeContext(const char *name, TEEC_Context *context)
354{
355    if (context == nullptr) {
356        tloge("context is nullptr\n");
357        return TEEC_ERROR_BAD_PARAMETERS;
358    }
359
360    MessageParcel reply;
361    int32_t ret = InitializeContextSendCmd(name, reply);
362    if ((TEEC_Result)ret != TEEC_SUCCESS) {
363        tloge("initialize context send cmd failed\n");
364        return TEEC_FAIL;
365    }
366
367    bool readRet = reply.ReadInt32(ret);
368    CHECK_ERR_RETURN(readRet, true, TEEC_FAIL);
369
370    if ((TEEC_Result)ret != TEEC_SUCCESS) {
371        tloge("init context failed:0x%x\n", ret);
372        return (TEEC_Result)ret;
373    }
374
375    context->ta_path = nullptr;
376    readRet = reply.ReadInt32(context->fd);
377    CHECK_ERR_RETURN(readRet, true, TEEC_FAIL);
378    if (context->fd < 0) {
379        return TEEC_FAIL;
380    }
381    return TEEC_SUCCESS;
382}
383
384void TeeClient::FinalizeContext(TEEC_Context *context)
385{
386    MessageParcel data;
387    MessageOption option;
388    MessageParcel reply;
389    bool parRet = false;
390
391    if (context == nullptr) {
392        tloge("invalid context\n");
393        return;
394    }
395
396    InitTeecService();
397    if (!mServiceValid) {
398        return;
399    }
400
401    parRet = data.WriteInterfaceToken(INTERFACE_TOKEN);
402    if (!parRet) {
403        return;
404    }
405
406    parRet = WriteContext(data, context);
407    if (!parRet) {
408        return;
409    }
410
411    int32_t ret = mTeecService->SendRequest(FINAL_CONTEXT, data, reply, option);
412    if (ret != ERR_NONE) {
413        tloge("close session failed\n");
414    }
415
416    FreeAllShareMemoryInContext(context);
417    context->fd = -1;
418}
419
420TEEC_Result TeeClient::OpenSession(TEEC_Context *context, TEEC_Session *session, const TEEC_UUID *destination,
421    uint32_t connectionMethod, const void *connectionData, TEEC_Operation *operation,
422    uint32_t *returnOrigin)
423{
424    uint32_t retOrigin  = TEEC_ORIGIN_API;
425    TEEC_Result teecRet = TEEC_ERROR_BAD_PARAMETERS;
426    int fd              = -1;
427
428    bool condition = (context == nullptr) || (session == nullptr) || (destination == nullptr);
429    if (condition) {
430        tloge("open Session: OpenSession in params error!\n");
431        goto END;
432    }
433
434    /*
435     * ca may call closesession even if opensession failed,
436     * we set session->context here to avoid receive a illegal ptr
437     */
438    session->context = context;
439
440    teecRet = TEEC_CheckOperation(operation);
441    if (teecRet != TEEC_SUCCESS) {
442        tloge("invoke command:check operation failed!\n");
443        goto END;
444    }
445
446    condition = (connectionMethod != TEEC_LOGIN_IDENTIFY) || (connectionData != nullptr);
447    if (condition) {
448        tloge("Login method is not supported or connection data is not nullptr\n");
449        teecRet = TEEC_ERROR_BAD_PARAMETERS;
450        goto END;
451    }
452
453    if (operation != nullptr) {
454        /* Params 2 and 3 are used for ident by teecd hence ->TEEC_NONE */
455        operation->paramTypes = TEEC_PARAM_TYPES(TEEC_PARAM_TYPE_GET(operation->paramTypes, 0),
456            TEEC_PARAM_TYPE_GET(operation->paramTypes, 1), TEEC_NONE, TEEC_NONE);
457    }
458
459    fd = GetFileFd((const char *)context->ta_path);
460    teecRet = OpenSessionSendCmd(context, session, destination, connectionMethod, fd, operation, &retOrigin);
461
462    if (fd >= 0) {
463        close(fd);
464    }
465
466END:
467    if (returnOrigin != nullptr) {
468        *returnOrigin = retOrigin;
469    }
470    return teecRet;
471}
472
473static bool WriteOpenData(MessageParcel &data, TEEC_Context *context, int32_t fd,
474    const TEEC_UUID *destination, uint32_t connectionMethod)
475{
476    bool retTmp = data.WriteInterfaceToken(INTERFACE_TOKEN);
477    CHECK_ERR_RETURN(retTmp, true, TEEC_FAIL);
478
479    retTmp = WriteContext(data, context);
480    CHECK_ERR_RETURN(retTmp, true, TEEC_FAIL);
481
482    retTmp = WriteChar((const char *)context->ta_path, data);
483    CHECK_ERR_RETURN(retTmp, true, retTmp);
484
485    if (fd < 0) {
486        retTmp = data.WriteBool(false);
487        CHECK_ERR_RETURN(retTmp, true, retTmp);
488    } else {
489        retTmp = data.WriteBool(true);
490        CHECK_ERR_RETURN(retTmp, true, retTmp);
491        retTmp = data.WriteFileDescriptor(fd);
492        CHECK_ERR_RETURN(retTmp, true, retTmp);
493    }
494
495    retTmp = data.WriteBuffer(destination, sizeof(*destination));
496    CHECK_ERR_RETURN(retTmp, true, retTmp);
497    retTmp = data.WriteUint32(connectionMethod);
498    CHECK_ERR_RETURN(retTmp, true, retTmp);
499
500    return retTmp;
501}
502
503static bool WriteOperation(MessageParcel &data, TEEC_Operation *operation)
504{
505    if (operation == nullptr) {
506        return data.WriteBool(false);
507    }
508
509    bool parRet = data.WriteBool(true);
510    CHECK_ERR_RETURN(parRet, true, false);
511    tloge("write operation->paramTypes = %{public}d\n", operation->paramTypes);
512    return data.WriteBuffer(operation, sizeof(*operation));
513}
514
515bool TeeClient::FormatSession(TEEC_Session *session, MessageParcel &reply)
516{
517    bool sessFlag = false;
518    bool retTmp = reply.ReadBool(sessFlag);
519    CHECK_ERR_RETURN(retTmp, true, retTmp);
520    if (!sessFlag) {
521        tloge("session is nullptr\n");
522        return false;
523    }
524
525    TEEC_Session *sessRet = nullptr;
526    size_t len = sizeof(*sessRet);
527    sessRet = (TEEC_Session *)(reply.ReadBuffer(len));
528    if (sessRet == nullptr) {
529        tloge("read session failed\n");
530        return false;
531    }
532    tloge("reieve sessRet_id = %{public}d\n", sessRet->session_id);
533
534    session->session_id = sessRet->session_id;
535    session->service_id = sessRet->service_id;
536    session->ops_cnt    = sessRet->ops_cnt;
537    ListInit(&session->head);
538    return true;
539}
540
541TEEC_Result TeeClient::GetTeecOptMem(TEEC_Operation *operation,
542    size_t optMemSize, sptr<Ashmem> &optMem, MessageParcel &reply)
543{
544    if (operation == nullptr) {
545        return TEEC_SUCCESS;
546    }
547
548    bool opFlag = false;
549    bool retTmp = reply.ReadBool(opFlag);
550    CHECK_ERR_RETURN(retTmp, true, TEEC_FAIL);
551
552    if (!opFlag) {
553        tloge("operation is nullptr\n");
554        return TEEC_FAIL;
555    }
556
557    TEEC_Operation *optRet = nullptr;
558    size_t len = sizeof(*optRet);
559    optRet = (TEEC_Operation *)(reply.ReadBuffer(len));
560    if (optRet == nullptr) {
561        tloge("the buffer is NULL\n");
562        return TEEC_FAIL;
563    }
564
565    const void *data = nullptr;
566    if (optMemSize != 0) {
567        data = optMem->ReadFromAshmem(optMemSize, 0);
568    }
569    return TeecOptDecode(operation, optRet, reinterpret_cast<const uint8_t *>(data), optMemSize);
570}
571
572TEEC_Result TeeClient::TeecOptDecodePartialMem(TEEC_Parameter *param,
573    uint32_t paramType, TEEC_Parameter *inParam, const uint8_t **data, size_t *dataSize)
574{
575    TEEC_SharedMemory *shm = param->memref.parent;
576    /* we put 4 uint32 and 1 bool in sharemem */
577    uint32_t shmSize       = 4 * (sizeof(uint32_t)) + 1 * (sizeof(bool));
578    uint32_t cSize         = param->memref.size;
579    uint32_t tSize         = inParam->memref.size; /* size return from ta */
580    uint8_t *p = nullptr;
581
582    if (paramType == TEEC_MEMREF_WHOLE) {
583        cSize = shm->size;
584        /*
585         * Actually, we should usr tSize return from ta,
586         * but our process is temporarily not supported,
587         * so we usr cSize instead. There will be a problem,
588         * if ta write a larger buff size, we can not transfer it to ca
589         */
590        tSize = cSize;
591    }
592
593    if (IsOverFlow(cSize, shmSize) || (*dataSize < (cSize + shmSize))) {
594        tloge("cSize:%{public}u, shmSize:%{public}u, dataSize:%{public}zu\n", cSize, shmSize, *dataSize);
595        return TEEC_FAIL;
596    }
597
598    *data += shmSize;
599    *dataSize -= shmSize;
600    if (paramType == TEEC_MEMREF_PARTIAL_INPUT) {
601        goto END;
602    }
603
604    p = reinterpret_cast<uint8_t *>(param->memref.parent->buffer);
605    if (p == nullptr) {
606        goto COPY_TA_SIZE_TO_CA;
607    }
608    p += param->memref.offset;
609
610    if (cSize == 0 && tSize == 0) {
611        tlogd("cSize=0 && inOpt->memref.size=0\n");
612        goto COPY_TA_SIZE_TO_CA;
613    }
614    if (!shm->is_allocated) {
615        /* if ta buff size > ca buff size, copy ta size to ca */
616        if (cSize < tSize) {
617            tloge("size from ca is:%{public}u, size from ta is:%{public}u\n", cSize, tSize);
618            goto COPY_TA_SIZE_TO_CA;
619        }
620
621        if (memcpy_s(p, cSize, *data, tSize) != EOK) {
622            tloge("operation memcpy failed\n");
623            return TEEC_FAIL;
624        }
625    }
626
627COPY_TA_SIZE_TO_CA:
628    param->memref.size = inParam->memref.size;
629
630END:
631    *data += cSize;
632    *dataSize -= cSize;
633    return TEEC_SUCCESS;
634}
635
636TEEC_Result TeeClient::TeecOptDecode(TEEC_Operation *operation,
637    TEEC_Operation *inOpt, const uint8_t *data, size_t dataSize)
638{
639    uint32_t paramType[TEEC_PARAM_NUM] = { 0 };
640    uint32_t paramCnt;
641    const uint8_t *ptr = data;
642    size_t sizeLeft = dataSize;
643    TEEC_Result teeRet = TEEC_SUCCESS;
644
645    for (paramCnt = 0; paramCnt < TEEC_PARAM_NUM; paramCnt++) {
646        paramType[paramCnt] = TEEC_PARAM_TYPE_GET(operation->paramTypes, paramCnt);
647        if (IS_TEMP_MEM(paramType[paramCnt])) {
648            if (ptr == nullptr) {
649                return TEEC_ERROR_BAD_PARAMETERS;
650            }
651            teeRet = TeecOptDecodeTempMem(&(operation->params[paramCnt]), paramType[paramCnt],
652                &(inOpt->params[paramCnt]), &ptr, &sizeLeft);
653        } else if (IS_PARTIAL_MEM(paramType[paramCnt])) {
654            if (ptr == nullptr) {
655                return TEEC_ERROR_BAD_PARAMETERS;
656            }
657            teeRet = TeecOptDecodePartialMem(&(operation->params[paramCnt]), paramType[paramCnt],
658                &(inOpt->params[paramCnt]), &ptr, &sizeLeft);
659        } else if (IS_VALUE_MEM(paramType[paramCnt])) {
660            operation->params[paramCnt].value.a = inOpt->params[paramCnt].value.a;
661            operation->params[paramCnt].value.b = inOpt->params[paramCnt].value.b;
662        }
663        if (teeRet != TEEC_SUCCESS) {
664            tloge("opt decode param fail. paramCnt: %{public}u, ret: 0x%x\n", paramCnt, teeRet);
665            return teeRet;
666        }
667    }
668    return TEEC_SUCCESS;
669}
670
671TEEC_Result TeeClient::TeecOptDecodeTempMem(TEEC_Parameter *param, uint32_t paramType,
672    const TEEC_Parameter *inParam, const uint8_t **data, size_t *dataSize)
673{
674    size_t sizeLeft = *dataSize;
675    const uint8_t *ptr    = *data;
676    uint8_t *p = nullptr;
677    if (sizeLeft < param->tmpref.size) {
678        tloge("size is error:%zu:%{public}u\n", sizeLeft, param->tmpref.size);
679        return TEEC_FAIL;
680    }
681
682    if (paramType == TEEC_MEMREF_TEMP_INPUT) {
683        ptr += param->tmpref.size;
684        sizeLeft -= param->tmpref.size;
685        goto END;
686    }
687
688    p = reinterpret_cast<uint8_t *>(param->tmpref.buffer);
689    if (p != nullptr) {
690        /* if ta buff size > ca buff size, copy ta size to ca */
691        if (param->tmpref.size < inParam->tmpref.size) {
692            tlogw("size from ca is:%{public}u, size from ta is:%{public}u\n", param->tmpref.size, inParam->tmpref.size);
693            goto COPY_TA_SIZE_TO_CA;
694        }
695        if (sizeLeft < inParam->tmpref.size) {
696            tloge("size is not enough:%zu:%{public}u\n", sizeLeft, inParam->tmpref.size);
697            return TEEC_FAIL;
698        }
699
700        if (memcpy_s(p, param->tmpref.size, ptr, inParam->tmpref.size) != EOK) {
701            tloge("peration decode memcpy_s failed\n");
702            return TEEC_FAIL;
703        }
704    }
705
706COPY_TA_SIZE_TO_CA:
707    ptr += param->tmpref.size;
708    sizeLeft -= param->tmpref.size;
709    param->tmpref.size = inParam->tmpref.size;
710
711END:
712    *data     = ptr;
713    *dataSize = sizeLeft;
714    return TEEC_SUCCESS;
715}
716
717static inline void ClearAsmMem(sptr<Ashmem> &optMem)
718{
719    if (optMem != nullptr) {
720        optMem->UnmapAshmem();
721        optMem->CloseAshmem();
722    }
723}
724
725TEEC_Result TeeClient::OpenSessionSendCmd(TEEC_Context *context, TEEC_Session *session, const TEEC_UUID *destination,
726    uint32_t connectionMethod, int32_t fd, TEEC_Operation *operation, uint32_t *retOrigin)
727{
728    MessageParcel data;
729    MessageOption option;
730    MessageParcel reply;
731    int32_t ret = (int32_t)TEEC_FAIL;
732
733    InitTeecService();
734    CHECK_ERR_RETURN(mServiceValid, true, TEEC_FAIL);
735
736    size_t optMemSize;
737    sptr<Ashmem> optMem;
738    TEEC_Result nRet = GetOptMemSize(operation, &optMemSize);
739    CHECK_ERR_RETURN(nRet, TEEC_SUCCESS, TEEC_ERROR_BAD_PARAMETERS);
740
741    nRet = CopyTeecOptMem(operation, optMemSize, optMem);
742    if (nRet != TEEC_SUCCESS) {
743        tloge("copy teec opt mem failed\n");
744        return nRet;
745    }
746
747    bool parRet = WriteOpenData(data, context, fd, destination, connectionMethod);
748    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
749
750    parRet = WriteOperation(data, operation);
751    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
752
753    parRet = data.WriteUint32(optMemSize);
754    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
755    if (optMemSize > 0) {
756        parRet = data.WriteAshmem(optMem);
757        CHECK_ERR_GOTO(parRet, true, ERROR);
758    }
759
760    ret = mTeecService->SendRequest(OPEN_SESSION, data, reply, option);
761    CHECK_ERR_GOTO(ret, ERR_NONE, ERROR);
762
763    parRet = reply.ReadUint32(*retOrigin);
764    CHECK_ERR_GOTO(parRet, true, ERROR);
765
766    parRet = reply.ReadInt32(ret);
767    CHECK_ERR_GOTO(parRet, true, ERROR);
768
769    parRet = FormatSession(session, reply);
770    if (!parRet) {
771        ret = (ret == (int32_t)TEEC_SUCCESS) ? (int32_t)TEEC_FAIL : ret;
772        goto END;
773    }
774
775    nRet = GetTeecOptMem(operation, optMemSize, optMem, reply);
776    if (nRet != TEEC_SUCCESS && ret == (int32_t)TEEC_SUCCESS) {
777        ret = (int32_t)nRet;
778    }
779
780END:
781    ClearAsmMem(optMem);
782    return (TEEC_Result)ret;
783
784ERROR:
785    ClearAsmMem(optMem);
786    return TEEC_FAIL;
787}
788
789TEEC_Result TeeClient::TeecOptEncodeTempMem(const TEEC_Parameter *param, sptr<Ashmem> &optMem, size_t *dataSize)
790{
791    if (*dataSize < param->tmpref.size) {
792        tloge("size is error:%zu:%{public}u\n", *dataSize, param->tmpref.size);
793        return TEEC_FAIL;
794    }
795
796    uint8_t *p = reinterpret_cast<uint8_t *>(param->tmpref.buffer);
797    if (p == nullptr) {
798        tloge("operation encode param tmpref buffer is nullptr\n");
799        return TEEC_ERROR_BAD_PARAMETERS;
800    }
801
802    bool nRet = optMem->WriteToAshmem(p, (int32_t)(param->tmpref.size),
803        optMem->GetAshmemSize() - (int32_t)(*dataSize));
804    if (!nRet) {
805        tloge("temp mem to hal memcpy failed : %{public}d\n", nRet);
806        return TEEC_FAIL;
807    }
808
809    *dataSize -= param->tmpref.size;
810
811    return TEEC_SUCCESS;
812}
813
814bool TeeClient::CovertEncodePtr(sptr<Ashmem> &optMem, size_t *sizeLeft, TEEC_SharedMemory *shm)
815{
816    bool nRet = optMem->WriteToAshmem(&(shm->is_allocated), (int32_t)(sizeof(bool)),
817        optMem->GetAshmemSize() - (int32_t)(*sizeLeft));
818    CHECK_ERR_RETURN(nRet, true, false);
819
820    *sizeLeft -= sizeof(bool);
821
822    nRet = optMem->WriteToAshmem(&(shm->flags), (int32_t)(sizeof(uint32_t)),
823        optMem->GetAshmemSize() - (int32_t)(*sizeLeft));
824    CHECK_ERR_RETURN(nRet, true, false);
825
826    *sizeLeft -= sizeof(uint32_t);
827
828    nRet = optMem->WriteToAshmem(&(shm->ops_cnt), (int32_t)(sizeof(uint32_t)),
829        optMem->GetAshmemSize() - (int32_t)(*sizeLeft));
830    CHECK_ERR_RETURN(nRet, true, false);
831
832    *sizeLeft -= sizeof(uint32_t);
833
834    uint32_t shmOffset = FindShareMemOffset(shm->buffer);
835    nRet = optMem->WriteToAshmem(&shmOffset, (int32_t)(sizeof(uint32_t)),
836        optMem->GetAshmemSize() - (int32_t)(*sizeLeft));
837    CHECK_ERR_RETURN(nRet, true, false);
838
839    *sizeLeft -= sizeof(uint32_t);
840
841    nRet = optMem->WriteToAshmem(&(shm->size), (int32_t)(sizeof(uint32_t)),
842        optMem->GetAshmemSize() - (int32_t)(*sizeLeft));
843    CHECK_ERR_RETURN(nRet, true, false);
844
845    *sizeLeft -= sizeof(uint32_t);
846
847    return nRet;
848}
849
850TEEC_Result TeeClient::TeecOptEncodePartialMem(const TEEC_Parameter *param,
851    uint32_t paramType, sptr<Ashmem> &optMem, size_t *dataSize)
852{
853    size_t sizeLeft = *dataSize;
854
855    TEEC_SharedMemory *shm = param->memref.parent;
856
857    if ((shm == nullptr) || (shm->buffer == nullptr)) {
858        tloge("parent of memref is nullptr, or the buffer is zero\n");
859        return (TEEC_Result)TEEC_ERROR_BAD_PARAMETERS;
860    }
861    /* we put 4 uint32 and 1 bool in sharemem */
862    uint32_t shmSize = 4 * (sizeof(uint32_t)) + 1 * (sizeof(bool));
863    if (sizeLeft < shmSize) {
864        tloge("size is error:%zu:%{public}u\n", sizeLeft, shmSize);
865        return TEEC_FAIL;
866    }
867
868    bool nRet = CovertEncodePtr(optMem, &sizeLeft, shm);
869    CHECK_ERR_RETURN(nRet, true, TEEC_FAIL);
870
871    uint32_t cSize = param->memref.size;
872    if (paramType == TEEC_MEMREF_WHOLE) {
873        cSize = shm->size;
874    }
875    if (sizeLeft < cSize) {
876        tloge("size is error:%zu:%{public}u\n", sizeLeft, cSize);
877        return TEEC_FAIL;
878    }
879
880    if (!shm->is_allocated) {
881        uint8_t *p = reinterpret_cast<uint8_t *>(param->memref.parent->buffer);
882        if (p != nullptr) {
883            if (paramType != TEEC_MEMREF_WHOLE) {
884                p += param->memref.offset;
885            }
886            if ((sizeLeft == 0) || (cSize == 0)) {
887                tlogd("size left=%zu, ca size=%{public}u\n", sizeLeft, cSize);
888            } else {
889                nRet = optMem->WriteToAshmem(p, (int32_t)cSize, optMem->GetAshmemSize() - (int32_t)sizeLeft);
890                CHECK_ERR_RETURN(nRet, true, TEEC_FAIL);
891            }
892        }
893    }
894
895    sizeLeft -= cSize;
896    *dataSize = sizeLeft;
897    return TEEC_SUCCESS;
898}
899
900TEEC_Result TeeClient::TeecOptEncode(TEEC_Operation *operation, sptr<Ashmem> &optMem, size_t dataSize)
901{
902    uint32_t paramType[TEEC_PARAM_NUM] = { 0 };
903    uint32_t paramCnt;
904    size_t sizeLeft    = dataSize;
905    TEEC_Result teeRet = TEEC_SUCCESS;
906    for (paramCnt = 0; paramCnt < TEEC_PARAM_NUM; paramCnt++) {
907        paramType[paramCnt] = TEEC_PARAM_TYPE_GET(operation->paramTypes, paramCnt);
908        if (IS_TEMP_MEM(paramType[paramCnt])) {
909            teeRet = TeecOptEncodeTempMem(&(operation->params[paramCnt]), optMem, &sizeLeft);
910        } else if (IS_PARTIAL_MEM(paramType[paramCnt])) {
911            teeRet = TeecOptEncodePartialMem(&(operation->params[paramCnt]), paramType[paramCnt], optMem, &sizeLeft);
912        }
913        if (teeRet != TEEC_SUCCESS) {
914            tloge("opt encode param fail. paramCnt: %{public}u, ret: 0x%x\n", paramCnt, teeRet);
915            return teeRet;
916        }
917    }
918    return TEEC_SUCCESS;
919}
920
921TEEC_Result TeeClient::CopyTeecOptMem(TEEC_Operation *operation, size_t optMemSize, sptr<Ashmem> &optMem)
922{
923    TEEC_Result ret;
924    bool mapRet = false;
925    if (optMemSize == 0 || operation == nullptr) {
926        return TEEC_SUCCESS;
927    }
928
929    optMem = Ashmem::CreateAshmem("TeeClient", static_cast<int32_t>(optMemSize));
930    if (optMem == nullptr) {
931        tloge("not enough memory for opt size=%{public}u", static_cast<uint32_t>(optMemSize));
932        goto ERROR;
933    }
934
935    mapRet = optMem->MapReadAndWriteAshmem();
936    if (!mapRet) {
937        tloge("map ashmem failed\n");
938        goto ERROR;
939    }
940
941    ret = TeecOptEncode(operation, optMem, optMemSize);
942    if (ret != TEEC_SUCCESS) {
943        tloge("copy ashmem failed\n");
944        goto ERROR;
945    }
946
947    return TEEC_SUCCESS;
948
949ERROR:
950    ClearAsmMem(optMem);
951    return TEEC_FAIL;
952}
953
954
955TEEC_Result TeeClient::GetPartialMemSize(TEEC_Operation *operation, size_t optMemSize,
956                                         uint32_t paramCnt, uint32_t *cSize)
957{
958    uint32_t shmSize;
959    uint32_t paramType[TEEC_PARAM_NUM] = { 0 };
960    TEEC_Parameter *param = &(operation->params[paramCnt]);
961    if (param->memref.parent == nullptr) {
962        tlogd("params[%{public}u] shm = nullptr\n", paramCnt);
963        return TEEC_ERROR_GENERIC;
964    }
965
966    paramType[paramCnt] = TEEC_PARAM_TYPE_GET(operation->paramTypes, paramCnt);
967    if ((paramType[paramCnt] != TEEC_MEMREF_WHOLE) &&
968        ((param->memref.offset + param->memref.size) > param->memref.parent->size)) {
969        tloge("share mem offset + size exceed the parent size\n");
970        return TEEC_ERROR_BAD_PARAMETERS;
971    }
972    /* we put 4 uint32 and 1 bool in sharemem */
973    shmSize = 4 * (sizeof(uint32_t)) + 1 * (sizeof(bool));
974    *cSize            = param->memref.size;
975    if (paramType[paramCnt] == TEEC_MEMREF_WHOLE) {
976        *cSize = param->memref.parent->size;
977    }
978    if (IsOverFlow(*cSize, shmSize)) {
979        tloge("cSize:%{public}u, shmSize:%{public}u\n", *cSize, shmSize);
980        return TEEC_ERROR_BAD_PARAMETERS;
981    }
982    *cSize += shmSize;
983    if (IsOverFlow(optMemSize, *cSize)) {
984        tloge("cSize:%{public}u, optMemSize:%zu\n", *cSize, optMemSize);
985        return TEEC_ERROR_BAD_PARAMETERS;
986    }
987    return TEEC_SUCCESS;
988}
989
990TEEC_Result TeeClient::GetOptMemSize(TEEC_Operation *operation, size_t *memSize)
991{
992    uint32_t paramType[TEEC_PARAM_NUM] = { 0 };
993    uint32_t paramCnt;
994    size_t optMemSize = 0;
995    uint32_t cSize;
996    TEEC_Result ret;
997
998    if (operation == nullptr) {
999        *memSize = optMemSize;
1000        return TEEC_SUCCESS;
1001    }
1002
1003    for (paramCnt = 0; paramCnt < TEEC_PARAM_NUM; paramCnt++) {
1004        paramType[paramCnt] = TEEC_PARAM_TYPE_GET(operation->paramTypes, paramCnt);
1005        if (IS_TEMP_MEM(paramType[paramCnt])) {
1006            cSize = operation->params[paramCnt].tmpref.size;
1007            if (IsOverFlow(optMemSize, cSize)) {
1008                tloge("cSize:%{public}u, optMemSize:%{public}zu\n", cSize, optMemSize);
1009                return TEEC_ERROR_BAD_PARAMETERS;
1010            }
1011            optMemSize += cSize;
1012        } else if (IS_PARTIAL_MEM(paramType[paramCnt])) {
1013            ret = GetPartialMemSize(operation, optMemSize, paramCnt, &cSize);
1014            if (ret == TEEC_ERROR_GENERIC) {
1015                continue;
1016            }
1017            if (ret == TEEC_ERROR_BAD_PARAMETERS) {
1018                return TEEC_ERROR_BAD_PARAMETERS;
1019            }
1020            optMemSize += cSize;
1021        }
1022    }
1023
1024    if (optMemSize > PARAM_SIZE_LIMIT) {
1025        tloge("opt mem size over limit:%zu\n", optMemSize);
1026        return TEEC_ERROR_BAD_PARAMETERS;
1027    }
1028    *memSize = optMemSize;
1029    return TEEC_SUCCESS;
1030}
1031
1032TEEC_Result TeeClient::InvokeCommand(TEEC_Session *session, uint32_t commandID,
1033    TEEC_Operation *operation, uint32_t *returnOrigin)
1034{
1035    uint32_t retOrigin  = TEEC_ORIGIN_API;
1036    TEEC_Result ret = TEEC_ERROR_BAD_PARAMETERS;
1037
1038    if (session == nullptr || session->context == nullptr) {
1039        tloge("InvokeCommand in params error!\n");
1040        goto END;
1041    }
1042
1043    ret = TEEC_CheckOperation(operation);
1044    if (ret != TEEC_SUCCESS) {
1045        tloge("invoke command:check operation failed!\n");
1046        goto END;
1047    }
1048
1049    ret = InvokeCommandSendCmd(session->context, session, commandID, operation, &retOrigin);
1050    if (ret != TEEC_SUCCESS) {
1051        tloge("invokeCommand: send cmd failed, ret=0x%x\n", ret);
1052    }
1053
1054END:
1055        if (returnOrigin != nullptr) {
1056            *returnOrigin = retOrigin;
1057        }
1058        return ret;
1059}
1060
1061static bool WriteInvokeData(MessageParcel &data, TEEC_Context *context,
1062    TEEC_Session *session, uint32_t commandID, TEEC_Operation *operation)
1063{
1064    bool parRet = data.WriteInterfaceToken(INTERFACE_TOKEN);
1065    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1066
1067    parRet = WriteContext(data, context);
1068    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1069
1070    parRet = WriteSession(data, session);
1071    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1072
1073    parRet = data.WriteUint32(commandID);
1074    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1075
1076    parRet = WriteOperation(data, operation);
1077    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1078
1079    return true;
1080}
1081
1082static inline bool RecReply(MessageParcel &reply, int32_t &ret, uint32_t *returnOrigin)
1083{
1084    bool parRet = reply.ReadUint32(*returnOrigin);
1085    CHECK_ERR_RETURN(parRet, true, parRet);
1086
1087    parRet = reply.ReadInt32(ret);
1088    CHECK_ERR_RETURN(parRet, true, parRet);
1089
1090    return true;
1091}
1092
1093TEEC_Result TeeClient::InvokeCommandSendCmd(TEEC_Context *context, TEEC_Session *session,
1094    uint32_t commandID, TEEC_Operation *operation, uint32_t *returnOrigin)
1095{
1096    MessageParcel data;
1097    MessageOption option;
1098    MessageParcel reply;
1099    int32_t ret = (int32_t)TEEC_FAIL;
1100
1101    InitTeecService();
1102    CHECK_ERR_RETURN(mServiceValid, true, TEEC_FAIL);
1103
1104    size_t optMemSize;
1105    sptr<Ashmem> optMem;
1106    TEEC_Result nRet = GetOptMemSize(operation, &optMemSize);
1107    CHECK_ERR_RETURN(nRet, TEEC_SUCCESS, TEEC_ERROR_BAD_PARAMETERS);
1108
1109    bool parRet = WriteInvokeData(data, context, session, commandID, operation);
1110    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1111
1112    parRet = data.WriteUint32(optMemSize);
1113    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1114
1115    nRet = CopyTeecOptMem(operation, optMemSize, optMem);
1116    if (nRet != TEEC_SUCCESS) {
1117        tloge("copy teec opt mem failed\n");
1118        return nRet;
1119    }
1120
1121    if (optMemSize > 0) {
1122        parRet = data.WriteAshmem(optMem);
1123        if (!parRet) {
1124            tloge("write ash mem to parcel failed\n");
1125            goto CLEAR_MEM;
1126        }
1127    }
1128
1129    ret = mTeecService->SendRequest(INVOKE_COMMND, data, reply, option);
1130    if (ret != ERR_NONE) {
1131        tloge("invoke command failed\n");
1132        ret = TEEC_FAIL;
1133        goto CLEAR_MEM;
1134    }
1135
1136    parRet = RecReply(reply, ret, returnOrigin);
1137    if (!parRet) {
1138        ret = TEEC_FAIL;
1139        goto CLEAR_MEM;
1140    }
1141
1142    nRet = GetTeecOptMem(operation, optMemSize, optMem, reply);
1143    if (nRet != TEEC_SUCCESS && ret == TEEC_SUCCESS) {
1144        ret = nRet;
1145    }
1146
1147CLEAR_MEM:
1148    ClearAsmMem(optMem);
1149    return (TEEC_Result)ret;
1150}
1151
1152void TeeClient::CloseSession(TEEC_Session *session)
1153{
1154    MessageParcel data;
1155    MessageOption option;
1156    MessageParcel reply;
1157    bool parRet = false;
1158
1159    if ((session == nullptr) || (session->context == nullptr)) {
1160        tloge("closeSession: invalid params\n");
1161        return;
1162    }
1163
1164    InitTeecService();
1165    if (!mServiceValid) {
1166        return;
1167    }
1168
1169    parRet = data.WriteInterfaceToken(INTERFACE_TOKEN);
1170    if (!parRet) {
1171        return;
1172    }
1173
1174    parRet = WriteContext(data, session->context);
1175    if (!parRet) {
1176        return;
1177    }
1178
1179    parRet = WriteSession(data, session);
1180    if (!parRet) {
1181        return;
1182    }
1183
1184    int32_t ret = mTeecService->SendRequest(CLOSE_SESSION, data, reply, option);
1185    if (ret != ERR_NONE) {
1186        tloge("close session failed\n");
1187    }
1188
1189    session->session_id = 0;
1190    session->ops_cnt    = 0;
1191    session->context    = nullptr;
1192}
1193
1194int32_t TeeClient::GetFileFd(const char *filePath)
1195{
1196    if (filePath == nullptr) {
1197        return -1;
1198    }
1199
1200    if (!((strlen(filePath) < MAX_TA_PATH_LEN) && strstr(filePath, ".sec"))) {
1201        tloge("ta_path format is wrong\n");
1202        return -1;
1203    }
1204
1205    char realLoadFile[PATH_MAX + 1] = { 0 };
1206    if (realpath(filePath, realLoadFile) == nullptr) {
1207        tloge("real path failed err=%{public}d\n", errno);
1208        return -1;
1209    }
1210
1211    if (strncmp(realLoadFile, "/data/", sizeof("/data/") - 1) == 0) {
1212        int fd = open(realLoadFile, O_RDONLY);
1213        if (fd == -1) {
1214            tloge("open ta failed\n");
1215        }
1216        return fd;
1217    }
1218    return -1;
1219}
1220
1221TEEC_Result TeeClient::FormatSharedMemory(MessageParcel &reply, TEEC_SharedMemory *sharedMem, uint32_t *offset)
1222{
1223    TEEC_SharedMemory *shmRet = nullptr;
1224    size_t len = sizeof(*shmRet);
1225    shmRet = (TEEC_SharedMemory *)(reply.ReadBuffer(len));
1226    if (shmRet == nullptr) {
1227        tloge("read session failed\n");
1228        return TEEC_FAIL;
1229    }
1230    tloge("reieve shmRet_is_allocated = %{public}d\n", shmRet->is_allocated);
1231
1232    sharedMem->ops_cnt      = shmRet->ops_cnt;
1233    sharedMem->is_allocated = shmRet->is_allocated;
1234    ListInit(&sharedMem->head);
1235
1236    if (offset != nullptr) {
1237        bool ret = reply.ReadUint32(*offset);
1238        CHECK_ERR_RETURN(ret, true, TEEC_FAIL);
1239    }
1240    return TEEC_SUCCESS;
1241}
1242
1243TEEC_Result TeeClient::RegisterSharedMemory(TEEC_Context *context, TEEC_SharedMemory *sharedMem)
1244{
1245    MessageParcel data;
1246    MessageParcel reply;
1247    MessageOption option;
1248
1249    if ((context == nullptr) || (sharedMem == nullptr)) {
1250        tloge("context or sharedMem is nullptr\n");
1251        return TEEC_ERROR_BAD_PARAMETERS;
1252    }
1253
1254    /*
1255     * ca may call ReleaseShareMemory even if RegisterShareMem failed,
1256     * we set sharedMem->context here to avoid receive a illegal ptr
1257     */
1258    sharedMem->context = context;
1259
1260    if (sharedMem->buffer == nullptr || !CheckSharedMemoryFLag(sharedMem->flags)) {
1261        tloge("register shr mem failed: flag %{public}d is invalid\n", sharedMem->flags);
1262        return TEEC_ERROR_BAD_PARAMETERS;
1263    }
1264
1265    InitTeecService();
1266    if (!mServiceValid) {
1267        tloge("teec service not valid\n");
1268        return TEEC_FAIL;
1269    }
1270
1271    bool parRet = data.WriteInterfaceToken(INTERFACE_TOKEN);
1272    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1273
1274    parRet = WriteContext(data, context);
1275    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1276
1277    parRet = WriteSharedMem(data, sharedMem);
1278    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1279
1280    int32_t ret = mTeecService->SendRequest(REGISTER_MEM, data, reply, option);
1281    CHECK_ERR_RETURN(ret, ERR_NONE, TEEC_FAIL);
1282
1283    parRet = reply.ReadInt32(ret);
1284    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1285
1286    if ((TEEC_Result)ret != TEEC_SUCCESS) {
1287        tloge("return failed from tee\n");
1288        return (TEEC_Result)ret;
1289    }
1290    return FormatSharedMemory(reply, sharedMem, nullptr);
1291}
1292
1293TEEC_Result TeeClient::MapSharedMemory(int fd, uint32_t offset, TEEC_SharedMemory *sharedMem)
1294{
1295    if (sharedMem->size != 0) {
1296        sharedMem->buffer = mmap(0, sharedMem->size,
1297            (PROT_READ | PROT_WRITE), MAP_SHARED, fd, (off_t)(offset * PAGE_SIZE));
1298    } else {
1299        sharedMem->buffer = ZERO_SIZE_PTR;
1300    }
1301
1302    if (sharedMem->buffer == MAP_FAILED) {
1303        tloge("mmap failed\n");
1304        sharedMem->buffer = nullptr;
1305        return TEEC_ERROR_OUT_OF_MEMORY;
1306    }
1307
1308    return TEEC_SUCCESS;
1309}
1310
1311void TeeClient::AddShareMem(void *buffer, uint32_t offset, uint32_t size, int32_t fd)
1312{
1313    TC_NS_ShareMem shareMem;
1314
1315    shareMem.offset = offset;
1316    shareMem.buffer = buffer;
1317    shareMem.size   = size;
1318    shareMem.fd     = fd;
1319    lock_guard<mutex> autoLock(mSharMemLock);
1320    mShareMem.push_back(shareMem);
1321    return;
1322}
1323
1324TEEC_Result TeeClient::ProcAllocateSharedMemory(MessageParcel &reply, TEEC_SharedMemory *sharedMem)
1325{
1326    int32_t ret;
1327
1328    bool retStatus = reply.ReadInt32(ret);
1329    CHECK_ERR_RETURN(retStatus, true, TEEC_FAIL);
1330
1331    if ((TEEC_Result)ret != TEEC_SUCCESS) {
1332        tloge("alloca share mem return failed\n");
1333        return (TEEC_Result)ret;
1334    }
1335
1336    uint32_t offset;
1337    TEEC_Result rRet = FormatSharedMemory(reply, sharedMem, &offset);
1338    CHECK_ERR_RETURN(rRet, TEEC_SUCCESS, rRet);
1339
1340    int fd = reply.ReadFileDescriptor();
1341    if (fd < 0) {
1342        tloge("alloca share mem read fd failed\n");
1343        return TEEC_FAIL;
1344    }
1345
1346    rRet = MapSharedMemory(fd, offset, sharedMem);
1347    if (rRet != TEEC_SUCCESS) {
1348        tloge("map shared mem failed\n");
1349        goto END;
1350    }
1351
1352    AddShareMem(sharedMem->buffer, offset, sharedMem->size, sharedMem->context->fd);
1353
1354END:
1355    if (fd >= 0) {
1356        close(fd);
1357    }
1358    return TEEC_SUCCESS;
1359}
1360
1361TEEC_Result TeeClient::AllocateSharedMemory(TEEC_Context *context, TEEC_SharedMemory *sharedMem)
1362{
1363    MessageParcel data;
1364    MessageParcel reply;
1365    MessageOption option;
1366
1367    if ((context == nullptr) || (sharedMem == nullptr)) {
1368        tloge("alloca share mem: context or sharedMem is nullptr\n");
1369        return TEEC_ERROR_BAD_PARAMETERS;
1370    }
1371
1372    /*
1373     * ca may call ReleaseShareMemory even if AllocateSharedMemory failed,
1374     * we set sharedMem->context here to avoid receive a illegal ptr
1375     */
1376    sharedMem->context = context;
1377
1378    if (!CheckSharedMemoryFLag(sharedMem->flags)) {
1379        tloge("alloc shr mem: failed: flag %{public}d is invalid\n", sharedMem->flags);
1380        return TEEC_ERROR_BAD_PARAMETERS;
1381    }
1382
1383    InitTeecService();
1384    if (!mServiceValid) {
1385        tloge("alloca share mem: teec service not valid\n");
1386        return TEEC_FAIL;
1387    }
1388
1389    bool parRet = data.WriteInterfaceToken(INTERFACE_TOKEN);
1390    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1391
1392    parRet = WriteContext(data, context);
1393    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1394
1395    parRet = WriteSharedMem(data, sharedMem);
1396    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1397
1398    int32_t ret = mTeecService->SendRequest(ALLOC_MEM, data, reply, option);
1399    CHECK_ERR_RETURN(ret, ERR_NONE, TEEC_FAIL);
1400
1401    return ProcAllocateSharedMemory(reply, sharedMem);
1402}
1403
1404TEEC_Result TeeClient::FreeShareMem(TEEC_SharedMemory *sharedMem)
1405{
1406    size_t index;
1407    bool findFlag = false;
1408
1409    lock_guard<mutex> autoLock(mSharMemLock);
1410    size_t count = mShareMem.size();
1411    for (index = 0; index < count; index++) {
1412        if (mShareMem[index].buffer == sharedMem->buffer) {
1413            findFlag = true;
1414            break;
1415        }
1416    }
1417
1418    if (findFlag) {
1419        if ((sharedMem->buffer != nullptr) && (sharedMem->buffer != ZERO_SIZE_PTR) && (sharedMem->size != 0)) {
1420            int32_t ret = munmap(sharedMem->buffer, sharedMem->size);
1421            if (ret != 0) {
1422                tloge("munmap share mem failed, ret=0x%x\n", ret);
1423            }
1424            sharedMem->buffer = nullptr;
1425            sharedMem->size   = 0;
1426        }
1427        mShareMem.erase(mShareMem.begin() + index);
1428    } else {
1429        tloge("failed to find share mem in vector\n");
1430        return TEEC_FAIL;
1431    }
1432
1433    return TEEC_SUCCESS;
1434}
1435
1436void TeeClient::ReleaseSharedMemory(TEEC_SharedMemory *sharedMem)
1437{
1438    MessageParcel data;
1439    MessageParcel reply;
1440    MessageOption option;
1441
1442    if (sharedMem == nullptr || sharedMem->context == nullptr) {
1443        tloge("releaseSharemem: wrong params");
1444        return;
1445    }
1446
1447    uint32_t shmOffset = UINT32_MAX;
1448    if (sharedMem->buffer != nullptr) {
1449        shmOffset = FindShareMemOffset(sharedMem->buffer);
1450        if (sharedMem->is_allocated) {
1451            if (FreeShareMem(sharedMem)) {
1452                tloge("releaseSharemem: free share mem failed\n");
1453            }
1454        }
1455    }
1456
1457    InitTeecService();
1458    CHECK_ERR_NO_RETURN(mServiceValid, true);
1459
1460    bool parRet = data.WriteInterfaceToken(INTERFACE_TOKEN);
1461    CHECK_ERR_NO_RETURN(parRet, true);
1462
1463    parRet = WriteContext(data, sharedMem->context);
1464    CHECK_ERR_NO_RETURN(parRet, true);
1465
1466    parRet = WriteSharedMem(data, sharedMem);
1467    CHECK_ERR_NO_RETURN(parRet, true);
1468
1469    parRet = data.WriteUint32(shmOffset);
1470    CHECK_ERR_NO_RETURN(parRet, true);
1471
1472    int32_t ret = mTeecService->SendRequest(RELEASE_MEM, data, reply, option);
1473    if (ret != ERR_NONE) {
1474        tloge("releaseSharemem: send request failed\n");
1475        return;
1476    }
1477
1478    sharedMem->buffer  = nullptr;
1479    sharedMem->size    = 0;
1480    sharedMem->flags   = 0;
1481    sharedMem->ops_cnt = 0;
1482    sharedMem->context = nullptr;
1483}
1484
1485void TeeClient::RequestCancellation(const TEEC_Operation *operation)
1486{
1487    tloge("requestCancellation not support!\n");
1488    (void)operation;
1489    return;
1490}
1491
1492TEEC_Result TeeClient::SendSecfile(const char *path, TEEC_Session *session)
1493{
1494    MessageParcel data;
1495    MessageParcel reply;
1496    MessageOption option;
1497    uint32_t result;
1498    if (path == NULL || session == NULL || session->context == NULL) {
1499        tloge("the params is error\n");
1500        return TEEC_ERROR_BAD_PARAMETERS;
1501    }
1502
1503    InitTeecService();
1504    if (!mServiceValid) {
1505        return TEEC_FAIL;
1506    }
1507
1508    bool parRet = data.WriteInterfaceToken(INTERFACE_TOKEN);
1509    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1510
1511    int fd = GetFileFd(path);
1512    if (fd < 0) {
1513        tloge("open the path error\n");
1514        return TEEC_FAIL;
1515    }
1516
1517    parRet = WriteChar(path, data);
1518    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1519
1520    parRet = data.WriteBool(true);
1521    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1522    parRet = data.WriteFileDescriptor(fd);
1523    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1524
1525    parRet = WriteContext(data, session->context);
1526    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1527
1528    parRet = WriteSession(data, session);
1529    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1530
1531    int ret = mTeecService->SendRequest(SEND_SECFILE, data, reply, option);
1532    CHECK_ERR_RETURN(ret, ERR_NONE, TEEC_FAIL);
1533
1534    parRet = reply.ReadUint32(result);
1535    CHECK_ERR_RETURN(parRet, true, TEEC_FAIL);
1536
1537    return (TEEC_Result)result;
1538}
1539
1540TEEC_Result TeeClient::GetTeeVersion(uint32_t &teeVersion)
1541{
1542    MessageParcel data;
1543    MessageParcel reply;
1544    MessageOption option;
1545
1546    InitTeecService();
1547    if (!mServiceValid) {
1548        return TEEC_FAIL;
1549    }
1550
1551    int ret = mTeecService->SendRequest(GET_TEE_VERSION, data, reply, option);
1552    CHECK_ERR_RETURN(ret, ERR_NONE, TEEC_FAIL);
1553    bool result = reply.ReadUint32(teeVersion);
1554    CHECK_ERR_RETURN(result, true, TEEC_FAIL);
1555    return TEEC_SUCCESS;
1556}
1557
1558} // namespace OHOS
1559
1560
1561TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context)
1562{
1563    return OHOS::TeeClient::GetInstance().InitializeContext(name, context);
1564}
1565
1566void TEEC_FinalizeContext(TEEC_Context *context)
1567{
1568    OHOS::TeeClient::GetInstance().FinalizeContext(context);
1569}
1570
1571TEEC_Result TEEC_OpenSession(TEEC_Context *context, TEEC_Session *session, const TEEC_UUID *destination,
1572    uint32_t connectionMethod, const void *connectionData, TEEC_Operation *operation,
1573    uint32_t *returnOrigin)
1574{
1575    return OHOS::TeeClient::GetInstance().OpenSession(context, session, destination,
1576        connectionMethod, connectionData, operation, returnOrigin);
1577}
1578
1579void TEEC_CloseSession(TEEC_Session *session)
1580{
1581    OHOS::TeeClient::GetInstance().CloseSession(session);
1582}
1583
1584TEEC_Result TEEC_InvokeCommand(TEEC_Session *session, uint32_t commandID, TEEC_Operation *operation,
1585    uint32_t *returnOrigin)
1586{
1587    return OHOS::TeeClient::GetInstance().InvokeCommand(session, commandID, operation, returnOrigin);
1588}
1589
1590TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context, TEEC_SharedMemory *sharedMem)
1591{
1592    return OHOS::TeeClient::GetInstance().RegisterSharedMemory(context, sharedMem);
1593}
1594
1595TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context, TEEC_SharedMemory *sharedMem)
1596{
1597    return OHOS::TeeClient::GetInstance().AllocateSharedMemory(context, sharedMem);
1598}
1599
1600void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMem)
1601{
1602    return OHOS::TeeClient::GetInstance().ReleaseSharedMemory(sharedMem);
1603}
1604
1605void TEEC_RequestCancellation(TEEC_Operation *operation)
1606{
1607    OHOS::TeeClient::GetInstance().RequestCancellation(operation);
1608}
1609
1610TEEC_Result TEEC_SendSecfile(const char *path, TEEC_Session *session)
1611{
1612    return OHOS::TeeClient::GetInstance().SendSecfile(path, session);
1613}
1614
1615uint32_t TEEC_GetTEEVersion(void)
1616{
1617    uint32_t teeVersion = 0;
1618    TEEC_Result result = OHOS::TeeClient::GetInstance().GetTeeVersion(teeVersion);
1619    if (result != TEEC_SUCCESS || teeVersion == 0) {
1620        tloge("get the tee version failed, result:0x%x, the version:0x%x", result, teeVersion);
1621    }
1622    return teeVersion;
1623}
1624