1e656c62eSopenharmony_ci/*
2e656c62eSopenharmony_ci * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3e656c62eSopenharmony_ci * Licensed under the Mulan PSL v2.
4e656c62eSopenharmony_ci * You can use this software according to the terms and conditions of the Mulan PSL v2.
5e656c62eSopenharmony_ci * You may obtain a copy of Mulan PSL v2 at:
6e656c62eSopenharmony_ci *     http://license.coscl.org.cn/MulanPSL2
7e656c62eSopenharmony_ci * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8e656c62eSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9e656c62eSopenharmony_ci * PURPOSE.
10e656c62eSopenharmony_ci * See the Mulan PSL v2 for more details.
11e656c62eSopenharmony_ci */
12e656c62eSopenharmony_ci
13e656c62eSopenharmony_ci#include "secfile_load_agent.h"
14e656c62eSopenharmony_ci#include <limits.h>
15e656c62eSopenharmony_ci#include <securec.h>
16e656c62eSopenharmony_ci#include <sys/prctl.h>
17e656c62eSopenharmony_ci#include "tc_ns_client.h"
18e656c62eSopenharmony_ci#include "tee_log.h"
19e656c62eSopenharmony_ci
20e656c62eSopenharmony_ci#define MAX_PATH_LEN 256
21e656c62eSopenharmony_ci#ifdef LOG_TAG
22e656c62eSopenharmony_ci#undef LOG_TAG
23e656c62eSopenharmony_ci#endif
24e656c62eSopenharmony_ci#define LOG_TAG "teecd_agent"
25e656c62eSopenharmony_ci#define MAX_BUFFER_LEN (8 * 1024 * 1024)
26e656c62eSopenharmony_ci#define H_OFFSET                  32
27e656c62eSopenharmony_ciint g_secLoadAgentFd = -1;
28e656c62eSopenharmony_ci
29e656c62eSopenharmony_ciint GetSecLoadAgentFd(void)
30e656c62eSopenharmony_ci{
31e656c62eSopenharmony_ci    return g_secLoadAgentFd;
32e656c62eSopenharmony_ci}
33e656c62eSopenharmony_ci
34e656c62eSopenharmony_civoid SetSecLoadAgentFd(int secLoadAgentFd)
35e656c62eSopenharmony_ci{
36e656c62eSopenharmony_ci    g_secLoadAgentFd = secLoadAgentFd;
37e656c62eSopenharmony_ci}
38e656c62eSopenharmony_ci
39e656c62eSopenharmony_cistatic int GetImgLen(FILE *fp, long *totalLlen)
40e656c62eSopenharmony_ci{
41e656c62eSopenharmony_ci    int ret;
42e656c62eSopenharmony_ci
43e656c62eSopenharmony_ci    ret = fseek(fp, 0, SEEK_END);
44e656c62eSopenharmony_ci    if (ret != 0) {
45e656c62eSopenharmony_ci        tloge("fseek error\n");
46e656c62eSopenharmony_ci        return -1;
47e656c62eSopenharmony_ci    }
48e656c62eSopenharmony_ci    *totalLlen = ftell(fp);
49e656c62eSopenharmony_ci    if (*totalLlen <= 0 || *totalLlen > MAX_BUFFER_LEN) {
50e656c62eSopenharmony_ci        tloge("file is not exist or size is too large, filesize = %ld\n", *totalLlen);
51e656c62eSopenharmony_ci        return -1;
52e656c62eSopenharmony_ci    }
53e656c62eSopenharmony_ci    ret = fseek(fp, 0, SEEK_SET);
54e656c62eSopenharmony_ci    if (ret != 0) {
55e656c62eSopenharmony_ci        tloge("fseek error\n");
56e656c62eSopenharmony_ci        return -1;
57e656c62eSopenharmony_ci    }
58e656c62eSopenharmony_ci    return ret;
59e656c62eSopenharmony_ci}
60e656c62eSopenharmony_ci
61e656c62eSopenharmony_cistatic int32_t SecFileLoadWork(int tzFd, const char *filePath, enum SecFileType fileType, const TEEC_UUID *uuid)
62e656c62eSopenharmony_ci{
63e656c62eSopenharmony_ci    char realPath[PATH_MAX + 1] = { 0 };
64e656c62eSopenharmony_ci    FILE *fp                    = NULL;
65e656c62eSopenharmony_ci    int ret;
66e656c62eSopenharmony_ci
67e656c62eSopenharmony_ci    if (tzFd < 0) {
68e656c62eSopenharmony_ci        tloge("fd of tzdriver is valid!\n");
69e656c62eSopenharmony_ci        return -1;
70e656c62eSopenharmony_ci    }
71e656c62eSopenharmony_ci    if (realpath(filePath, realPath) == NULL) {
72e656c62eSopenharmony_ci        tloge("realpath open file err=%d, filePath=%s\n", errno, filePath);
73e656c62eSopenharmony_ci        return -1;
74e656c62eSopenharmony_ci    }
75e656c62eSopenharmony_ci    if (strncmp(realPath, TEE_DEFAULT_PATH, strlen(TEE_DEFAULT_PATH)) != 0) {
76e656c62eSopenharmony_ci        tloge("realpath -%s- is invalid\n", realPath);
77e656c62eSopenharmony_ci        return -1;
78e656c62eSopenharmony_ci    }
79e656c62eSopenharmony_ci    fp = fopen(realPath, "r");
80e656c62eSopenharmony_ci    if (fp == NULL) {
81e656c62eSopenharmony_ci        tloge("open file err=%d, path=%s\n", errno, filePath);
82e656c62eSopenharmony_ci        return -1;
83e656c62eSopenharmony_ci    }
84e656c62eSopenharmony_ci    ret = LoadSecFile(tzFd, fp, fileType, uuid);
85e656c62eSopenharmony_ci    if (fp != NULL) {
86e656c62eSopenharmony_ci        fclose(fp);
87e656c62eSopenharmony_ci    }
88e656c62eSopenharmony_ci    return ret;
89e656c62eSopenharmony_ci}
90e656c62eSopenharmony_ci
91e656c62eSopenharmony_ci// input param uuid may be NULL, so don need to check if uuid is NULL
92e656c62eSopenharmony_ciint32_t LoadSecFile(int tzFd, FILE *fp, enum SecFileType fileType, const TEEC_UUID *uuid)
93e656c62eSopenharmony_ci{
94e656c62eSopenharmony_ci    int32_t ret;
95e656c62eSopenharmony_ci    char *fileBuffer                   = NULL;
96e656c62eSopenharmony_ci    struct SecLoadIoctlStruct ioctlArg = {{ 0 }, { 0 }, { NULL } };
97e656c62eSopenharmony_ci
98e656c62eSopenharmony_ci    if (tzFd < 0 || fp == NULL) {
99e656c62eSopenharmony_ci        tloge("param erro!\n");
100e656c62eSopenharmony_ci        return -1;
101e656c62eSopenharmony_ci    }
102e656c62eSopenharmony_ci
103e656c62eSopenharmony_ci    do {
104e656c62eSopenharmony_ci        long totalLen = 0;
105e656c62eSopenharmony_ci        ret           = GetImgLen(fp, &totalLen);
106e656c62eSopenharmony_ci        if (ret != 0) {
107e656c62eSopenharmony_ci            break;
108e656c62eSopenharmony_ci        }
109e656c62eSopenharmony_ci
110e656c62eSopenharmony_ci        if (totalLen <= 0 || totalLen > MAX_BUFFER_LEN) {
111e656c62eSopenharmony_ci            ret = -1;
112e656c62eSopenharmony_ci            tloge("totalLen is invalid\n");
113e656c62eSopenharmony_ci            break;
114e656c62eSopenharmony_ci        }
115e656c62eSopenharmony_ci
116e656c62eSopenharmony_ci        /* alloc a less than 8M heap memory, it needn't slice. */
117e656c62eSopenharmony_ci        fileBuffer = malloc((size_t)totalLen);
118e656c62eSopenharmony_ci        if (fileBuffer == NULL) {
119e656c62eSopenharmony_ci            tloge("alloc TA file buffer(size=%ld) failed\n", totalLen);
120e656c62eSopenharmony_ci            ret = -1;
121e656c62eSopenharmony_ci            break;
122e656c62eSopenharmony_ci        }
123e656c62eSopenharmony_ci
124e656c62eSopenharmony_ci        /* read total ta file to file buffer */
125e656c62eSopenharmony_ci        long fileSize = (long)fread(fileBuffer, 1, totalLen, fp);
126e656c62eSopenharmony_ci        if (fileSize != totalLen) {
127e656c62eSopenharmony_ci            tloge("read ta file failed, read size/total size=%ld/%ld\n", fileSize, totalLen);
128e656c62eSopenharmony_ci            ret = -1;
129e656c62eSopenharmony_ci            break;
130e656c62eSopenharmony_ci        }
131e656c62eSopenharmony_ci
132e656c62eSopenharmony_ci        ioctlArg.secFileInfo.fileType = fileType;
133e656c62eSopenharmony_ci        ioctlArg.secFileInfo.fileSize = (uint32_t)totalLen;
134e656c62eSopenharmony_ci        ioctlArg.memref.file_addr = (uint32_t)(uintptr_t)fileBuffer;
135e656c62eSopenharmony_ci        ioctlArg.memref.file_h_addr = (uint32_t)(((uint64_t)(uintptr_t)fileBuffer) >> H_OFFSET);
136e656c62eSopenharmony_ci        if (uuid != NULL && memcpy_s((void *)(&ioctlArg.uuid), sizeof(ioctlArg.uuid), uuid, sizeof(*uuid)) != EOK) {
137e656c62eSopenharmony_ci            tloge("memcpy uuid fail\n");
138e656c62eSopenharmony_ci            break;
139e656c62eSopenharmony_ci        }
140e656c62eSopenharmony_ci
141e656c62eSopenharmony_ci        ret = ioctl(tzFd, (int)TC_NS_CLIENT_IOCTL_LOAD_APP_REQ, &ioctlArg);
142e656c62eSopenharmony_ci        if (ret != 0) {
143e656c62eSopenharmony_ci            tloge("ioctl to load sec file failed, ret = 0x%x\n", ret);
144e656c62eSopenharmony_ci        }
145e656c62eSopenharmony_ci    } while (false);
146e656c62eSopenharmony_ci
147e656c62eSopenharmony_ci    if (fileBuffer != NULL) {
148e656c62eSopenharmony_ci        free(fileBuffer);
149e656c62eSopenharmony_ci    }
150e656c62eSopenharmony_ci    return ret;
151e656c62eSopenharmony_ci}
152e656c62eSopenharmony_ci
153e656c62eSopenharmony_cistatic bool IsTaLib(const TEEC_UUID *uuid)
154e656c62eSopenharmony_ci{
155e656c62eSopenharmony_ci    char *chr = (char *)uuid;
156e656c62eSopenharmony_ci    uint32_t i;
157e656c62eSopenharmony_ci
158e656c62eSopenharmony_ci    for (i = 0; i < sizeof(*uuid); i++) {
159e656c62eSopenharmony_ci        if (chr[i] != 0) {
160e656c62eSopenharmony_ci            return true;
161e656c62eSopenharmony_ci        }
162e656c62eSopenharmony_ci    }
163e656c62eSopenharmony_ci    return false;
164e656c62eSopenharmony_ci}
165e656c62eSopenharmony_ci
166e656c62eSopenharmony_cistatic void LoadLib(struct SecAgentControlType *secAgentControl)
167e656c62eSopenharmony_ci{
168e656c62eSopenharmony_ci    int32_t ret;
169e656c62eSopenharmony_ci    char fname[MAX_PATH_LEN] = { 0 };
170e656c62eSopenharmony_ci
171e656c62eSopenharmony_ci    if (secAgentControl == NULL) {
172e656c62eSopenharmony_ci        tloge("secAgentControl is null\n");
173e656c62eSopenharmony_ci        return;
174e656c62eSopenharmony_ci    }
175e656c62eSopenharmony_ci    if (strnlen(secAgentControl->LibSec.libName, MAX_SEC_FILE_NAME_LEN) >= MAX_SEC_FILE_NAME_LEN) {
176e656c62eSopenharmony_ci        tloge("libName is too long!\n");
177e656c62eSopenharmony_ci        secAgentControl->ret = -1;
178e656c62eSopenharmony_ci        return;
179e656c62eSopenharmony_ci    }
180e656c62eSopenharmony_ci
181e656c62eSopenharmony_ci    if (IsTaLib(&(secAgentControl->LibSec.uuid))) {
182e656c62eSopenharmony_ci        ret =
183e656c62eSopenharmony_ci            snprintf_s(fname, sizeof(fname), MAX_PATH_LEN - 1,
184e656c62eSopenharmony_ci                "%s/%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x%s.sec",
185e656c62eSopenharmony_ci                TEE_DEFAULT_PATH, secAgentControl->LibSec.uuid.timeLow, secAgentControl->LibSec.uuid.timeMid,
186e656c62eSopenharmony_ci                secAgentControl->LibSec.uuid.timeHiAndVersion, secAgentControl->LibSec.uuid.clockSeqAndNode[0],
187e656c62eSopenharmony_ci                secAgentControl->LibSec.uuid.clockSeqAndNode[1], secAgentControl->LibSec.uuid.clockSeqAndNode[2],
188e656c62eSopenharmony_ci                secAgentControl->LibSec.uuid.clockSeqAndNode[3], secAgentControl->LibSec.uuid.clockSeqAndNode[4],
189e656c62eSopenharmony_ci                secAgentControl->LibSec.uuid.clockSeqAndNode[5], secAgentControl->LibSec.uuid.clockSeqAndNode[6],
190e656c62eSopenharmony_ci                secAgentControl->LibSec.uuid.clockSeqAndNode[7], secAgentControl->LibSec.libName);
191e656c62eSopenharmony_ci    } else {
192e656c62eSopenharmony_ci        ret = snprintf_s(fname, sizeof(fname), MAX_PATH_LEN - 1,
193e656c62eSopenharmony_ci            "%s/%s.sec", TEE_DEFAULT_PATH, secAgentControl->LibSec.libName);
194e656c62eSopenharmony_ci    }
195e656c62eSopenharmony_ci    if (ret < 0) {
196e656c62eSopenharmony_ci        tloge("pack fname err\n");
197e656c62eSopenharmony_ci        secAgentControl->ret = -1;
198e656c62eSopenharmony_ci        return;
199e656c62eSopenharmony_ci    }
200e656c62eSopenharmony_ci    ret = SecFileLoadWork(g_secLoadAgentFd, (const char *)fname, LOAD_LIB, NULL);
201e656c62eSopenharmony_ci    if (ret != 0) {
202e656c62eSopenharmony_ci        tloge("teec load app failed\n");
203e656c62eSopenharmony_ci        secAgentControl->ret   = -1;
204e656c62eSopenharmony_ci        secAgentControl->error = errno;
205e656c62eSopenharmony_ci        return;
206e656c62eSopenharmony_ci    }
207e656c62eSopenharmony_ci    secAgentControl->ret = 0;
208e656c62eSopenharmony_ci    return;
209e656c62eSopenharmony_ci}
210e656c62eSopenharmony_ci
211e656c62eSopenharmony_cistatic void LoadTa(struct SecAgentControlType *secAgentControl)
212e656c62eSopenharmony_ci{
213e656c62eSopenharmony_ci    int32_t ret;
214e656c62eSopenharmony_ci    char fname[MAX_PATH_LEN] = { 0 };
215e656c62eSopenharmony_ci
216e656c62eSopenharmony_ci    if (secAgentControl == NULL) {
217e656c62eSopenharmony_ci        tloge("secAgentControl is null\n");
218e656c62eSopenharmony_ci        return;
219e656c62eSopenharmony_ci    }
220e656c62eSopenharmony_ci
221e656c62eSopenharmony_ci    ret = snprintf_s(fname, sizeof(fname), MAX_PATH_LEN - 1, "%s/%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x.sec",
222e656c62eSopenharmony_ci                     TEE_DEFAULT_PATH, secAgentControl->TaSec.uuid.timeLow, secAgentControl->TaSec.uuid.timeMid,
223e656c62eSopenharmony_ci                     secAgentControl->TaSec.uuid.timeHiAndVersion, secAgentControl->TaSec.uuid.clockSeqAndNode[0],
224e656c62eSopenharmony_ci                     secAgentControl->TaSec.uuid.clockSeqAndNode[1], secAgentControl->TaSec.uuid.clockSeqAndNode[2],
225e656c62eSopenharmony_ci                     secAgentControl->TaSec.uuid.clockSeqAndNode[3], secAgentControl->TaSec.uuid.clockSeqAndNode[4],
226e656c62eSopenharmony_ci                     secAgentControl->TaSec.uuid.clockSeqAndNode[5], secAgentControl->TaSec.uuid.clockSeqAndNode[6],
227e656c62eSopenharmony_ci                     secAgentControl->TaSec.uuid.clockSeqAndNode[7]);
228e656c62eSopenharmony_ci    if (ret < 0) {
229e656c62eSopenharmony_ci        tloge("pack fname err\n");
230e656c62eSopenharmony_ci        secAgentControl->ret = -1;
231e656c62eSopenharmony_ci        return;
232e656c62eSopenharmony_ci    }
233e656c62eSopenharmony_ci    secAgentControl->ret = 0;
234e656c62eSopenharmony_ci    ret = SecFileLoadWork(g_secLoadAgentFd, (const char *)fname, LOAD_TA, &(secAgentControl->TaSec.uuid));
235e656c62eSopenharmony_ci    if (ret != 0) {
236e656c62eSopenharmony_ci        tloge("teec load TA app failed\n");
237e656c62eSopenharmony_ci        secAgentControl->ret   = ret;
238e656c62eSopenharmony_ci        secAgentControl->error = errno;
239e656c62eSopenharmony_ci        return;
240e656c62eSopenharmony_ci    }
241e656c62eSopenharmony_ci    return;
242e656c62eSopenharmony_ci}
243e656c62eSopenharmony_ci
244e656c62eSopenharmony_cistatic void SecLoadAgentWork(struct SecAgentControlType *secAgentControl)
245e656c62eSopenharmony_ci{
246e656c62eSopenharmony_ci    if (secAgentControl == NULL) {
247e656c62eSopenharmony_ci        tloge("secAgentControl is null\n");
248e656c62eSopenharmony_ci        return;
249e656c62eSopenharmony_ci    }
250e656c62eSopenharmony_ci    switch (secAgentControl->cmd) {
251e656c62eSopenharmony_ci        case LOAD_LIB_SEC:
252e656c62eSopenharmony_ci            LoadLib(secAgentControl);
253e656c62eSopenharmony_ci            break;
254e656c62eSopenharmony_ci        case LOAD_TA_SEC:
255e656c62eSopenharmony_ci            LoadTa(secAgentControl);
256e656c62eSopenharmony_ci            break;
257e656c62eSopenharmony_ci        case LOAD_SERVICE_SEC:
258e656c62eSopenharmony_ci        default:
259e656c62eSopenharmony_ci            tloge("gtask agent error cmd:%d\n", secAgentControl->cmd);
260e656c62eSopenharmony_ci            secAgentControl->ret = -1;
261e656c62eSopenharmony_ci            break;
262e656c62eSopenharmony_ci    }
263e656c62eSopenharmony_ci}
264e656c62eSopenharmony_ci
265e656c62eSopenharmony_civoid *SecfileLoadAgentThread(void *control)
266e656c62eSopenharmony_ci{
267e656c62eSopenharmony_ci    (void)prctl(PR_SET_NAME, "teecd_sec_load_agent", 0, 0, 0);
268e656c62eSopenharmony_ci    struct SecAgentControlType *secAgentControl = NULL;
269e656c62eSopenharmony_ci    if (control == NULL) {
270e656c62eSopenharmony_ci        tloge("control is NULL\n");
271e656c62eSopenharmony_ci        return NULL;
272e656c62eSopenharmony_ci    }
273e656c62eSopenharmony_ci    secAgentControl = (struct SecAgentControlType *)control;
274e656c62eSopenharmony_ci    if (g_secLoadAgentFd < 0) {
275e656c62eSopenharmony_ci        tloge("m_gtask_agent_fd is -1\n");
276e656c62eSopenharmony_ci        return NULL;
277e656c62eSopenharmony_ci    }
278e656c62eSopenharmony_ci    secAgentControl->magic = SECFILE_LOAD_AGENT_ID;
279e656c62eSopenharmony_ci    while (true) {
280e656c62eSopenharmony_ci        int ret = ioctl(g_secLoadAgentFd, (int)TC_NS_CLIENT_IOCTL_WAIT_EVENT, SECFILE_LOAD_AGENT_ID);
281e656c62eSopenharmony_ci        if (ret) {
282e656c62eSopenharmony_ci            tloge("gtask agent wait event failed, errno = %d\n", errno);
283e656c62eSopenharmony_ci            break;
284e656c62eSopenharmony_ci        }
285e656c62eSopenharmony_ci        SecLoadAgentWork(secAgentControl);
286e656c62eSopenharmony_ci
287e656c62eSopenharmony_ci        __asm__ volatile("isb");
288e656c62eSopenharmony_ci        __asm__ volatile("dsb sy");
289e656c62eSopenharmony_ci
290e656c62eSopenharmony_ci        secAgentControl->magic = SECFILE_LOAD_AGENT_ID;
291e656c62eSopenharmony_ci
292e656c62eSopenharmony_ci        __asm__ volatile("isb");
293e656c62eSopenharmony_ci        __asm__ volatile("dsb sy");
294e656c62eSopenharmony_ci        ret = ioctl(g_secLoadAgentFd, (int)TC_NS_CLIENT_IOCTL_SEND_EVENT_RESPONSE, SECFILE_LOAD_AGENT_ID);
295e656c62eSopenharmony_ci        if (ret) {
296e656c62eSopenharmony_ci            tloge("gtask agent send reponse failed\n");
297e656c62eSopenharmony_ci            break;
298e656c62eSopenharmony_ci        }
299e656c62eSopenharmony_ci    }
300e656c62eSopenharmony_ci    return NULL;
301e656c62eSopenharmony_ci}
302