1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "appspawn_manager.h"
17#include "appspawn_sandbox.h"
18#include "appspawn_utils.h"
19#include "modulemgr.h"
20#include "parameter.h"
21#include "securec.h"
22
23struct ListNode g_sandboxVarList = {&g_sandboxVarList, &g_sandboxVarList};
24
25static int VarPackageNameIndexReplace(const SandboxContext *context,
26    const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
27{
28    AppSpawnMsgBundleInfo *bundleInfo = (
29        AppSpawnMsgBundleInfo *)GetSpawningMsgInfo(context, TLV_BUNDLE_INFO);
30    APPSPAWN_CHECK(bundleInfo != NULL, return APPSPAWN_TLV_NONE,
31        "No bundle info in msg %{public}s", context->bundleName);
32    int len = 0;
33    if (bundleInfo->bundleIndex > 0) {
34        len = sprintf_s((char *)buffer, bufferLen, "%s_%d", bundleInfo->bundleName, bundleInfo->bundleIndex);
35    } else {
36        len = sprintf_s((char *)buffer, bufferLen, "%s", bundleInfo->bundleName);
37    }
38    APPSPAWN_CHECK(len > 0 && ((uint32_t)len < bufferLen),
39        return -1, "Failed to format path app: %{public}s", context->bundleName);
40    *realLen = (uint32_t)len;
41    return 0;
42}
43
44APPSPAWN_STATIC int VarPackageNameReplace(const SandboxContext *context,
45    const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
46{
47    int len = sprintf_s((char *)buffer, bufferLen, "%s", context->bundleName);
48    APPSPAWN_CHECK(len > 0 && ((uint32_t)len < bufferLen),
49        return -1, "Failed to format path app: %{public}s", context->bundleName);
50    *realLen = (uint32_t)len;
51    return 0;
52}
53
54static int VarCurrentUseIdReplace(const SandboxContext *context,
55    const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
56{
57    AppSpawnMsgDacInfo *info = (AppSpawnMsgDacInfo *)GetSpawningMsgInfo(context, TLV_DAC_INFO);
58    APPSPAWN_CHECK(info != NULL, return APPSPAWN_TLV_NONE,
59        "No tlv %{public}d in msg %{public}s", TLV_DAC_INFO, context->bundleName);
60    int len = 0;
61    if (extraData == NULL || !CHECK_FLAGS_BY_INDEX(extraData->operation, SANDBOX_TAG_PERMISSION)) {
62        len = sprintf_s((char *)buffer, bufferLen, "%u", info->uid / UID_BASE);
63    } else {
64        len = sprintf_s((char *)buffer, bufferLen, "%s", "currentUser");
65    }
66    APPSPAWN_CHECK(len > 0 && ((uint32_t)len < bufferLen),
67        return -1, "Failed to format path app: %{public}s", context->bundleName);
68    *realLen = (uint32_t)len;
69    return 0;
70}
71
72static int VarArkWebPackageNameReplace(const SandboxContext *context,
73    const char *buffer, uint32_t bufferLen, uint32_t *realLen,
74    const VarExtraData *extraData)
75{
76    static char arkWebPackageName[PARAM_BUFFER_SIZE] = {0};
77    if (strlen(arkWebPackageName) == 0) {
78        int len = GetParameter(ARK_WEB_PERSIST_PACKAGE_NAME, "",
79                               arkWebPackageName, sizeof(arkWebPackageName));
80        APPSPAWN_CHECK(len > 0, return -1,
81                "Failed to get param for var %{public}s",
82                ARK_WEB_PERSIST_PACKAGE_NAME);
83    }
84    APPSPAWN_LOGV("ArkWebPackageNameReplace '%{public}s'", arkWebPackageName);
85
86    int len = sprintf_s((char*) buffer, bufferLen, "%s", arkWebPackageName);
87    APPSPAWN_CHECK(len > 0 && ((uint32_t)len < bufferLen), return -1,
88            "Failed to format path app: %{public}s", arkWebPackageName);
89    *realLen = (uint32_t) len;
90    return 0;
91}
92
93static int VariableNodeCompareName(ListNode *node, void *data)
94{
95    AppSandboxVarNode *varNode = (AppSandboxVarNode *)ListEntry(node, AppSandboxVarNode, node);
96    return strcmp((char *)data, varNode->name);
97}
98
99static AppSandboxVarNode *GetAppSandboxVarNode(const char *name)
100{
101    ListNode *node = OH_ListFind(&g_sandboxVarList, (void *)name, VariableNodeCompareName);
102    if (node == NULL) {
103        return NULL;
104    }
105    return (AppSandboxVarNode *)ListEntry(node, AppSandboxVarNode, node);
106}
107
108static int ReplaceVariableByParameter(const char *varData, SandboxBuffer *sandboxBuffer)
109{
110    // "<param:persist.nweb.sandbox.src_path>"
111    int len = GetParameter(varData + sizeof("<param:") - 1,
112        DEFAULT_NWEB_SANDBOX_SEC_PATH, sandboxBuffer->buffer + sandboxBuffer->current,
113        sandboxBuffer->bufferLen - sandboxBuffer->current - 1);
114    APPSPAWN_CHECK(len > 0, return -1, "Failed to get param for var %{public}s", varData);
115    sandboxBuffer->current += len;
116    return 0;
117}
118
119APPSPAWN_STATIC int ReplaceVariableForDepSandboxPath(const SandboxContext *context,
120    const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
121{
122    APPSPAWN_CHECK(extraData != NULL && extraData->data.depNode != NULL, return -1, "Invalid extra data ");
123    uint32_t len = strlen(extraData->data.depNode->target);
124    int ret = memcpy_s((char *)buffer, bufferLen, extraData->data.depNode->target, len);
125    APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
126    *realLen = len;
127    return 0;
128}
129
130APPSPAWN_STATIC int ReplaceVariableForDepSrcPath(const SandboxContext *context,
131    const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
132{
133    APPSPAWN_CHECK(extraData != NULL && extraData->data.depNode != NULL, return -1, "Invalid extra data ");
134    uint32_t len = strlen(extraData->data.depNode->source);
135    int ret = memcpy_s((char *)buffer, bufferLen, extraData->data.depNode->source, len);
136    APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
137    *realLen = len;
138    return 0;
139}
140
141APPSPAWN_STATIC int ReplaceVariableForDepPath(const SandboxContext *context,
142    const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
143{
144    APPSPAWN_CHECK(extraData != NULL && extraData->data.depNode != NULL, return -1, "Invalid extra data ");
145    char *path = extraData->data.depNode->source;
146    if (CHECK_FLAGS_BY_INDEX(extraData->operation, MOUNT_PATH_OP_REPLACE_BY_SANDBOX)) {
147        path = extraData->data.depNode->target;
148    } else if (CHECK_FLAGS_BY_INDEX(extraData->operation, MOUNT_PATH_OP_REPLACE_BY_SRC) && IsPathEmpty(path)) {
149        path = extraData->data.depNode->target;
150    }
151    APPSPAWN_CHECK(path != NULL, return -1, "Invalid path %{public}x ", extraData->operation);
152    uint32_t len = strlen(path);
153    int ret = memcpy_s((char *)buffer, bufferLen, path, len);
154    APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
155    *realLen = len;
156    return 0;
157}
158
159static int ReplaceVariableForpackageName(const SandboxContext *context,
160    const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
161{
162    APPSPAWN_CHECK(context != NULL, return -1, "Invalid context");
163    AppSpawnMsgBundleInfo *bundleInfo = (AppSpawnMsgBundleInfo *)GetSpawningMsgInfo(context, TLV_BUNDLE_INFO);
164    APPSPAWN_CHECK(bundleInfo != NULL, return APPSPAWN_TLV_NONE,
165        "No bundle info in msg %{public}s", context->bundleName);
166
167    uint32_t flags = 0;
168    char *extension = NULL;
169    if (CheckAppSpawnMsgFlag(context->message, TLV_MSG_FLAGS, APP_FLAGS_ATOMIC_SERVICE)) {
170        flags |= SANDBOX_PACKAGENAME_ATOMIC_SERVICE;
171    } else {
172        flags |= (CheckAppSpawnMsgFlag(context->message, TLV_MSG_FLAGS, APP_FLAGS_CLONE_ENABLE) &&
173            bundleInfo->bundleIndex > 0) ? SANDBOX_PACKAGENAME_CLONE : 0;
174        flags |= CheckAppSpawnMsgFlag(context->message, TLV_MSG_FLAGS, APP_FLAGS_EXTENSION_SANDBOX)
175            ? SANDBOX_PACKAGENAME_EXTENSION : 0;
176        extension = (char *)GetAppSpawnMsgExtInfo(context->message, MSG_EXT_NAME_APP_EXTENSION, NULL);
177    }
178
179    int32_t len = 0;
180    switch (flags) {
181        case SANDBOX_PACKAGENAME_DEFAULT:               // 0 packageName
182            len = sprintf_s((char *)buffer, bufferLen, "%s", bundleInfo->bundleName);
183            break;
184        case SANDBOX_PACKAGENAME_CLONE:                 // 1 +clone-bundleIndex+packageName
185            len = sprintf_s((char *)buffer, bufferLen, "+clone-%u+%s", bundleInfo->bundleIndex, bundleInfo->bundleName);
186            break;
187        case SANDBOX_PACKAGENAME_EXTENSION: {           // 2 +extension-<extensionType>+packageName
188            APPSPAWN_CHECK(extension != NULL, return -1, "Invalid extension data");
189            len = sprintf_s((char *)buffer, bufferLen, "+extension-%s+%s", extension, bundleInfo->bundleName);
190            break;
191        }
192        case SANDBOX_PACKAGENAME_CLONE_AND_EXTENSION: { // 3 +clone-bundleIndex+extension-<extensionType>+packageName
193            APPSPAWN_CHECK(extension != NULL, return -1, "Invalid extension data");
194            len = sprintf_s((char *)buffer, bufferLen, "+clone-%u+extension-%s+%s",
195                bundleInfo->bundleIndex, extension, bundleInfo->bundleName);
196            break;
197        }
198        case SANDBOX_PACKAGENAME_ATOMIC_SERVICE: {      // 4 +auid-<accountId>+packageName
199            char *accountId = (char *)GetAppSpawnMsgExtInfo(context->message, MSG_EXT_NAME_ACCOUNT_ID, NULL);
200            APPSPAWN_CHECK(accountId != NULL, return -1, "Invalid accountId data");
201            len = sprintf_s((char *)buffer, bufferLen, "+auid-%s+%s", accountId, bundleInfo->bundleName);
202            break;
203        }
204        default:
205            break;
206    }
207    APPSPAWN_CHECK(len > 0 && ((uint32_t)len < bufferLen),
208        return -1, "Failed to format path app: %{public}s flags %{public}u", context->bundleName, flags);
209    *realLen = (uint32_t)len;
210    return 0;
211}
212
213static int GetVariableName(char *varData, uint32_t len, const char *varStart, uint32_t *varLen)
214{
215    uint32_t i = 0;
216    uint32_t sourceLen = strlen(varStart);
217    for (; i < sourceLen; i++) {
218        if (i > len) {
219            return -1;
220        }
221        varData[i] = *(varStart + i);
222        if (varData[i] == '>') {
223            break;
224        }
225    }
226    varData[i + 1] = '\0';
227    *varLen = i + 1;
228    return 0;
229}
230
231static int ReplaceVariable(const SandboxContext *context,
232    const char *varStart, SandboxBuffer *sandboxBuffer, uint32_t *varLen, const VarExtraData *extraData)
233{
234    char varName[128] = {0};  // 128 max len for var
235    int ret = GetVariableName(varName, sizeof(varName), varStart, varLen);
236    APPSPAWN_CHECK(ret == 0, return -1, "Failed to get variable name");
237
238    uint32_t valueLen = 0;
239    AppSandboxVarNode *node = GetAppSandboxVarNode(varName);
240    if (node != NULL) {
241        ret = node->replaceVar(context, sandboxBuffer->buffer + sandboxBuffer->current,
242            sandboxBuffer->bufferLen - sandboxBuffer->current - 1, &valueLen, extraData);
243        APPSPAWN_CHECK(ret == 0 && valueLen < (sandboxBuffer->bufferLen - sandboxBuffer->current),
244            return -1, "Failed to fill real data");
245        sandboxBuffer->current += valueLen;
246        return 0;
247    }
248    // "<param:persist.nweb.sandbox.src_path>"
249    if (strncmp(varName, "<param:", sizeof("<param:") - 1) == 0) {  // retry param:
250        varName[*varLen - 1] = '\0';                                // erase last >
251        return ReplaceVariableByParameter(varName, sandboxBuffer);
252    }
253    if (strncmp(varName, "<lib>", sizeof("<lib>") - 1) == 0) {  // retry lib
254        ret = memcpy_s(sandboxBuffer->buffer + sandboxBuffer->current,
255            sandboxBuffer->bufferLen - sandboxBuffer->current, APPSPAWN_LIB_NAME, strlen(APPSPAWN_LIB_NAME));
256        APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
257        sandboxBuffer->current += strlen(APPSPAWN_LIB_NAME);
258        return 0;
259    }
260    // no match revered origin data
261    APPSPAWN_LOGE("ReplaceVariable var '%{public}s' no match variable", varName);
262    ret = memcpy_s(sandboxBuffer->buffer + sandboxBuffer->current,
263        sandboxBuffer->bufferLen - sandboxBuffer->current, varName, *varLen);
264    APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
265    sandboxBuffer->current += *varLen;
266    return 0;
267}
268
269static int HandleVariableReplace(const SandboxContext *context,
270    SandboxBuffer *sandboxBuffer, const char *source, const VarExtraData *extraData)
271{
272    size_t sourceLen = strlen(source);
273    for (size_t i = 0; i < sourceLen; i++) {
274        if ((sandboxBuffer->current + 1) >= sandboxBuffer->bufferLen) {
275            return -1;
276        }
277        if (*(source + i) != '<') {  // copy source
278            *(sandboxBuffer->buffer + sandboxBuffer->current) = *(source + i);
279            sandboxBuffer->current++;
280            continue;
281        }
282        uint32_t varLen = 0;
283        int ret = ReplaceVariable(context, source + i, sandboxBuffer, &varLen, extraData);
284        APPSPAWN_CHECK(ret == 0, return ret, "Failed to fill real data");
285        i += (varLen - 1);
286    }
287    return 0;
288}
289
290const char *GetSandboxRealVar(const SandboxContext *context,
291    uint32_t bufferType, const char *source, const char *prefix, const VarExtraData *extraData)
292{
293    APPSPAWN_CHECK_ONLY_EXPER(context != NULL, return NULL);
294    APPSPAWN_CHECK(bufferType < ARRAY_LENGTH(context->buffer), return NULL, "Invalid index for buffer");
295    SandboxBuffer *sandboxBuffer = &((SandboxContext *)context)->buffer[bufferType];
296    APPSPAWN_CHECK_ONLY_EXPER(sandboxBuffer != NULL && sandboxBuffer->buffer != NULL, return NULL);
297    const char *tmp = source;
298    int ret = 0;
299    if (!IsPathEmpty(prefix)) {  // copy prefix data
300        ret = HandleVariableReplace(context, sandboxBuffer, prefix, extraData);
301        APPSPAWN_CHECK(ret == 0, return NULL, "Failed to replace source %{public}s ", prefix);
302
303        if (tmp != NULL && sandboxBuffer->buffer[sandboxBuffer->current - 1] == '/' && *tmp == '/') {
304            tmp = source + 1;
305        }
306    }
307    if (!IsPathEmpty(tmp)) {  // copy source data
308        ret = HandleVariableReplace(context, sandboxBuffer, tmp, extraData);
309        APPSPAWN_CHECK(ret == 0, return NULL, "Failed to replace source %{public}s ", source);
310    }
311    sandboxBuffer->buffer[sandboxBuffer->current] = '\0';
312    // restore buffer
313    sandboxBuffer->current = 0;
314
315    // For the depNode scenario, if there are variables in the deps path, a secondary replacement is required
316    if (extraData != NULL && extraData->sandboxTag == SANDBOX_TAG_NAME_GROUP && extraData->data.depNode != NULL) {
317        if (strstr(sandboxBuffer->buffer, "<") != NULL) {
318            SandboxBuffer *tmpBuffer = &((SandboxContext *)context)->buffer[BUFFER_FOR_TMP];
319            ret = HandleVariableReplace(context, tmpBuffer, sandboxBuffer->buffer, extraData);
320            APPSPAWN_CHECK(ret == 0, return NULL, "Failed to replace source %{public}s ", sandboxBuffer->buffer);
321            tmpBuffer->buffer[tmpBuffer->current] = '\0';
322            ret = strcpy_s(sandboxBuffer->buffer, sandboxBuffer->bufferLen, tmpBuffer->buffer);
323            APPSPAWN_CHECK(ret == 0, return NULL, "Failed to copy source %{public}s ", sandboxBuffer->buffer);
324        }
325    }
326    return sandboxBuffer->buffer;
327}
328
329int AddVariableReplaceHandler(const char *name, ReplaceVarHandler handler)
330{
331    APPSPAWN_CHECK(name != NULL && handler != NULL, return APPSPAWN_ARG_INVALID, "Invalid arg ");
332    if (GetAppSandboxVarNode(name) != NULL) {
333        return APPSPAWN_NODE_EXIST;
334    }
335
336    size_t len = APPSPAWN_ALIGN(strlen(name) + 1);
337    AppSandboxVarNode *node = (AppSandboxVarNode *)malloc(sizeof(AppSandboxVarNode) + len);
338    APPSPAWN_CHECK(node != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to create sandbox");
339    OH_ListInit(&node->node);
340    node->replaceVar = handler;
341    int ret = strcpy_s(node->name, len, name);
342    APPSPAWN_CHECK(ret == 0, free(node);
343        return -1, "Failed to copy name %{public}s", name);
344    OH_ListAddTail(&g_sandboxVarList, &node->node);
345    return 0;
346}
347
348void AddDefaultVariable(void)
349{
350    AddVariableReplaceHandler(PARAMETER_PACKAGE_NAME, VarPackageNameReplace);
351    AddVariableReplaceHandler(PARAMETER_USER_ID, VarCurrentUseIdReplace);
352    AddVariableReplaceHandler(PARAMETER_PACKAGE_INDEX, VarPackageNameIndexReplace);
353    AddVariableReplaceHandler(PARAMETER_ARK_WEB_PACKAGE_INDEX, VarArkWebPackageNameReplace);
354    /*
355        deps-path路径变量的含义:
356        1)首次挂载时,表示mount-paths-deps->sandbox-path  【STAGE_GLOBAL或者应用孵化时的挂载】
357        使用 MOUNT_PATH_OP_REPLACE_BY_SANDBOX 标记
358        2)二次挂载时,表示mount-paths-deps->src-path;
359            如果mount-paths-deps->src-path为空,则使用mount-paths-deps->sandbox-path
360        使用 MOUNT_PATH_OP_ONLY_SANDBOX + MOUNT_PATH_OP_REPLACE_BY_SRC,只使用源目录,不添加root-dir
361        【RemountByName时,如el2解锁或nweb更新时】
362    */
363    AddVariableReplaceHandler("<deps-sandbox-path>", ReplaceVariableForDepSandboxPath);
364    AddVariableReplaceHandler("<deps-src-path>", ReplaceVariableForDepSrcPath);
365    AddVariableReplaceHandler("<deps-path>", ReplaceVariableForDepPath);
366    AddVariableReplaceHandler("<variablePackageName>", ReplaceVariableForpackageName);
367}
368
369void ClearVariable(void)
370{
371    OH_ListRemoveAll(&g_sandboxVarList, NULL);
372}
373