• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 "sandbox_utils.h"
17 
18 #include <fcntl.h>
19 #include <unistd.h>
20 
21 #include <sys/mount.h>
22 #include <sys/stat.h>
23 #include <sys/syscall.h>
24 #include <sys/types.h>
25 #include <cerrno>
26 
27 #include "json_utils.h"
28 #include "securec.h"
29 #include "appspawn_server.h"
30 
31 using namespace std;
32 using namespace OHOS;
33 
34 namespace OHOS {
35 namespace AppSpawn {
36 namespace {
37     constexpr int32_t UID_BASE = 200000;
38     constexpr int32_t FUSE_OPTIONS_MAX_LEN = 128;
39     constexpr int32_t DLP_FUSE_FD = 1000;
40     constexpr int32_t DATABASE_DIR_GID = 3012;
41     constexpr int32_t DFS_GID = 1009;
42     constexpr static mode_t FILE_MODE = 0711;
43     constexpr static mode_t BASE_FOLDER_FILE_MODE = 0700;
44     constexpr static mode_t DATABASE_FOLDER_FILE_MODE = S_IRWXU | S_IRWXG;
45     constexpr static mode_t BASIC_MOUNT_FLAGS = MS_REC | MS_BIND;
46     constexpr std::string_view APL_SYSTEM_CORE("system_core");
47     constexpr std::string_view APL_SYSTEM_BASIC("system_basic");
48     const std::string g_packageItems[] = {{"cache"}, {"files"}, {"temp"}, {"preferences"}, {"haps"}};
49     const std::string g_physicalAppInstallPath = "/data/app/el1/bundle/public/";
50     const std::string g_sandBoxAppInstallPath = "/data/accounts/account_0/applications/";
51     const std::string g_dataBundles = "/data/bundles/";
52     const std::string g_userId = "<currentUserId>";
53     const std::string g_packageName = "<PackageName>";
54     const std::string g_packageNameIndex = "<PackageName_index>";
55     const std::string g_sandBoxDir = "/mnt/sandbox/";
56     const std::string g_statusCheck = "true";
57     const std::string g_sbxSwitchCheck = "ON";
58     const std::string g_dlpBundleName = "com.ohos.dlpmanager";
59     const std::string g_internal = "__internal__";
60     const char *g_actionStatuc = "check-action-status";
61     const char *g_accountPrefix = "/account/data/";
62     const char *g_accountNonPrefix = "/non_account/data/";
63     const char *g_appBase = "app-base";
64     const char *g_appResources = "app-resources";
65     const char *g_appAplName = "app-apl-name";
66     const char *g_basePrefix = "/base";
67     const char *g_commonPrefix = "common";
68     const char *g_databasePrefix = "/database";
69     const char *g_destMode = "dest-mode";
70     const char *g_el2Prefix = "/data/app/el2";
71     const char *g_fsType = "fs-type";
72     const char *g_linkName = "link-name";
73     const char *g_mountPrefix = "mount-paths";
74     const char *g_privatePrefix = "individual";
75     const char *g_srcPath = "src-path";
76     const char *g_sandBoxPath = "sandbox-path";
77     const char *g_sandBoxFlags = "sandbox-flags";
78     const char *g_sandBoxSwitchPrefix = "sandbox-switch";
79     const char *g_serviceEl2Prefix = "/data/serivce/el2";
80     const char *g_symlinkPrefix = "symbol-links";
81     const char *g_sandboxRootPrefix = "sandbox-root";
82     const char *g_topSandBoxSwitchPrefix = "top-sandbox-switch";
83     const char *g_targetName = "target-name";
84     const char *g_flagePoint = "flags-point";
85     const char *g_flags = "flags";
86     const char *g_sandBoxNameSpace = "sandbox-namespace";
87     const char *g_sandBoxCloneFlags = "clone-flags";
88 #ifndef NWEB_SPAWN
89     const std::string g_sandBoxRootDir = "/mnt/sandbox/";
90 #else
91     const std::string g_ohosRender = "__internal__.com.ohos.render";
92     const std::string g_sandBoxRootDir = "/mnt/sandbox/com.ohos.render/";
93 #endif
94 }
95 
96 nlohmann::json SandboxUtils::appNamespaceConfig_;
97 nlohmann::json SandboxUtils::appSandboxConfig_;
98 nlohmann::json SandboxUtils::productSandboxConfig_;
99 
StoreNamespaceJsonConfig(nlohmann::json & appNamespaceConfig)100 void SandboxUtils::StoreNamespaceJsonConfig(nlohmann::json &appNamespaceConfig)
101 {
102     SandboxUtils::appNamespaceConfig_ = appNamespaceConfig;
103 }
104 
GetNamespaceJsonConfig(void)105 nlohmann::json SandboxUtils::GetNamespaceJsonConfig(void)
106 {
107     return SandboxUtils::appNamespaceConfig_;
108 }
109 
StoreJsonConfig(nlohmann::json & appSandboxConfig)110 void SandboxUtils::StoreJsonConfig(nlohmann::json &appSandboxConfig)
111 {
112     SandboxUtils::appSandboxConfig_ = appSandboxConfig;
113 }
114 
GetJsonConfig()115 nlohmann::json SandboxUtils::GetJsonConfig()
116 {
117     return SandboxUtils::appSandboxConfig_;
118 }
119 
StoreProductJsonConfig(nlohmann::json & productSandboxConfig)120 void SandboxUtils::StoreProductJsonConfig(nlohmann::json &productSandboxConfig)
121 {
122     SandboxUtils::productSandboxConfig_ = productSandboxConfig;
123 }
124 
GetProductJsonConfig()125 nlohmann::json SandboxUtils::GetProductJsonConfig()
126 {
127     return SandboxUtils::productSandboxConfig_;
128 }
129 
NamespaceFlagsFromConfig(const std::vector<std::string> & vec)130 static uint32_t NamespaceFlagsFromConfig(const std::vector<std::string> &vec)
131 {
132     const std::map<std::string, uint32_t> NamespaceFlagsMap = { {"mnt", CLONE_NEWNS}, {"pid", CLONE_NEWPID} };
133     uint32_t cloneFlags = 0;
134 
135     for (unsigned int j = 0; j < vec.size(); j++) {
136         if (NamespaceFlagsMap.count(vec[j])) {
137             cloneFlags |= NamespaceFlagsMap.at(vec[j]);
138         }
139     }
140     return cloneFlags;
141 }
142 
GetNamespaceFlagsFromConfig(const char * bundleName)143 uint32_t SandboxUtils::GetNamespaceFlagsFromConfig(const char *bundleName)
144 {
145     nlohmann::json config = SandboxUtils::GetNamespaceJsonConfig();
146     uint32_t cloneFlags = CLONE_NEWNS;
147 
148     if (config.find(g_sandBoxNameSpace) == config.end()) {
149         APPSPAWN_LOGE("namespace config is not found");
150         return 0;
151     }
152 
153     nlohmann::json namespaceApp = config[g_sandBoxNameSpace][0];
154     if (namespaceApp.find(bundleName) == namespaceApp.end()) {
155         return cloneFlags;
156     }
157 
158     nlohmann::json app = namespaceApp[bundleName][0];
159     cloneFlags |= NamespaceFlagsFromConfig(app[g_sandBoxCloneFlags].get<std::vector<std::string>>());
160     return cloneFlags;
161 }
162 
MkdirAndChown(const std::string & srcPath,mode_t filemode,uint32_t uid,uint32_t gid)163 static void MkdirAndChown(const std::string &srcPath, mode_t filemode, uint32_t uid, uint32_t gid)
164 {
165     mkdir(srcPath.c_str(), filemode);
166     chown(srcPath.c_str(), uid, gid);
167 }
168 
MakeDirRecursive(const std::string & path,mode_t mode)169 static void MakeDirRecursive(const std::string &path, mode_t mode)
170 {
171     size_t size = path.size();
172     if (size == 0) {
173         return;
174     }
175 
176     size_t index = 0;
177     do {
178         size_t pathIndex = path.find_first_of('/', index);
179         index = pathIndex == std::string::npos ? size : pathIndex + 1;
180         std::string dir = path.substr(0, index);
181         APPSPAWN_CHECK(!(access(dir.c_str(), F_OK) < 0 && mkdir(dir.c_str(), mode) < 0),
182             return, "mkdir %s failed, error is %d", dir.c_str(), errno);
183     } while (index < size);
184 }
185 
DoAppSandboxMountOnce(const char * originPath,const char * destinationPath,const char * fsType,unsigned long mountFlags,const char * options)186 int32_t SandboxUtils::DoAppSandboxMountOnce(const char *originPath, const char *destinationPath,
187                                             const char *fsType, unsigned long mountFlags,
188                                             const char *options)
189 {
190     // To make sure destinationPath exist
191     MakeDirRecursive(destinationPath, FILE_MODE);
192 #ifndef APPSPAWN_TEST
193     int ret = 0;
194     // to mount fs and bind mount files or directory
195     ret = mount(originPath, destinationPath, fsType, mountFlags, options);
196     APPSPAWN_CHECK(ret == 0, return ret,  "bind mount %s to %s failed %d, just DEBUG MESSAGE here",
197                    originPath, destinationPath, errno);
198     ret = mount(NULL, destinationPath, NULL, MS_SLAVE, NULL);
199     APPSPAWN_CHECK(ret == 0, return ret, "private mount to %s failed %d", destinationPath, errno);
200 #endif
201     return 0;
202 }
203 
replace_all(std::string & str,const std::string & old_value,const std::string & new_value)204 static std::string& replace_all(std::string& str, const std::string& old_value, const std::string& new_value)
205 {
206     while (true) {
207         std::string::size_type pos(0);
208         if ((pos = str.find(old_value)) != std::string::npos) {
209             str.replace(pos, old_value.length(), new_value);
210         } else {
211             break;
212         }
213     }
214     return str;
215 }
216 
split(std::string & str,const std::string & pattern)217 static std::vector<std::string> split(std::string &str, const std::string &pattern)
218 {
219     std::string::size_type pos;
220     std::vector<std::string> result;
221     str += pattern;
222     size_t size = str.size();
223 
224     for (unsigned int i = 0; i < size; i++) {
225         pos = str.find(pattern, i);
226         if (pos < size) {
227             std::string s = str.substr(i, pos - i);
228             result.push_back(s);
229             i = pos + pattern.size() - 1;
230         }
231     }
232 
233     return result;
234 }
235 
DoSandboxChmod(nlohmann::json jsonConfig,std::string & sandboxRoot)236 void SandboxUtils::DoSandboxChmod(nlohmann::json jsonConfig, std::string &sandboxRoot)
237 {
238     const std::map<std::string, mode_t> modeMap = {{"S_IRUSR", S_IRUSR}, {"S_IWUSR", S_IWUSR}, {"S_IXUSR", S_IXUSR},
239                                                    {"S_IRGRP", S_IRGRP}, {"S_IWGRP", S_IWGRP}, {"S_IXGRP", S_IXGRP},
240                                                    {"S_IROTH", S_IROTH}, {"S_IWOTH", S_IWOTH}, {"S_IXOTH", S_IXOTH},
241                                                    {"S_IRWXU", S_IRWXU}, {"S_IRWXG", S_IRWXG}, {"S_IRWXO", S_IRWXO}};
242     std::string fileModeStr;
243     mode_t mode = 0;
244 
245     bool rc = JsonUtils::GetStringFromJson(jsonConfig, g_destMode, fileModeStr);
246     if (rc == false) {
247         return;
248     }
249 
250     std::vector<std::string> modeVec = split(fileModeStr, "|");
251     for (unsigned int i = 0; i < modeVec.size(); i++) {
252         if (modeMap.count(modeVec[i])) {
253             mode |= modeMap.at(modeVec[i]);
254         }
255     }
256 
257     chmod(sandboxRoot.c_str(), mode);
258 }
259 
GetMountFlagsFromConfig(const std::vector<std::string> & vec)260 unsigned long SandboxUtils::GetMountFlagsFromConfig(const std::vector<std::string> &vec)
261 {
262     const std::map<std::string, mode_t> MountFlagsMap = { {"rec", MS_REC}, {"MS_REC", MS_REC},
263                                                           {"bind", MS_BIND}, {"MS_BIND", MS_BIND},
264                                                           {"move", MS_MOVE}, {"MS_MOVE", MS_MOVE},
265                                                           {"slave", MS_SLAVE}, {"MS_SLAVE", MS_SLAVE},
266                                                           {"rdonly", MS_RDONLY}, {"MS_RDONLY", MS_RDONLY},
267                                                           {"shared", MS_SHARED}, {"MS_SHARED", MS_SHARED},
268                                                           {"unbindable", MS_UNBINDABLE},
269                                                           {"MS_UNBINDABLE", MS_UNBINDABLE},
270                                                           {"remount", MS_REMOUNT}, {"MS_REMOUNT", MS_REMOUNT},
271                                                           {"nosuid", MS_NOSUID}, {"MS_NOSUID", MS_NOSUID},
272                                                           {"nodev", MS_NODEV}, {"MS_NODEV", MS_NODEV},
273                                                           {"noexec", MS_NOEXEC}, {"MS_NOEXEC", MS_NOEXEC},
274                                                           {"noatime", MS_NOATIME}, {"MS_NOATIME", MS_NOATIME},
275                                                           {"lazytime", MS_LAZYTIME}, {"MS_LAZYTIME", MS_LAZYTIME}};
276     unsigned long mountFlags = 0;
277 
278     for (unsigned int i = 0; i < vec.size(); i++) {
279         if (MountFlagsMap.count(vec[i])) {
280             mountFlags |= MountFlagsMap.at(vec[i]);
281         }
282     }
283 
284     return mountFlags;
285 }
286 
ConvertToRealPath(const ClientSocket::AppProperty * appProperty,std::string path)287 string SandboxUtils::ConvertToRealPath(const ClientSocket::AppProperty *appProperty, std::string path)
288 {
289     if (path.find(g_packageNameIndex) != std::string::npos) {
290         std::string bundleNameIndex = appProperty->bundleName;
291         bundleNameIndex = bundleNameIndex + "_" + std::to_string(appProperty->bundleIndex);
292         path = replace_all(path, g_packageNameIndex, bundleNameIndex);
293     }
294 
295     if (path.find(g_packageName) != std::string::npos) {
296         path = replace_all(path, g_packageName, appProperty->bundleName);
297     }
298 
299     if (path.find(g_userId) != std::string::npos) {
300         path = replace_all(path, g_userId, std::to_string(appProperty->uid / UID_BASE));
301     }
302 
303     return path;
304 }
305 
GetSbxPathByConfig(const ClientSocket::AppProperty * appProperty,nlohmann::json & config)306 std::string SandboxUtils::GetSbxPathByConfig(const ClientSocket::AppProperty *appProperty, nlohmann::json &config)
307 {
308     std::string sandboxRoot = "";
309     if (config.find(g_sandboxRootPrefix) != config.end()) {
310         sandboxRoot = config[g_sandboxRootPrefix].get<std::string>();
311         sandboxRoot = ConvertToRealPath(appProperty, sandboxRoot);
312     } else {
313         sandboxRoot = g_sandBoxDir + appProperty->bundleName;
314         APPSPAWN_LOGE("read sandbox-root config failed, set sandbox-root to default root"
315             "app name is %s", appProperty->bundleName);
316     }
317 
318     return sandboxRoot;
319 }
320 
GetSbxSwitchStatusByConfig(nlohmann::json & config)321 bool SandboxUtils::GetSbxSwitchStatusByConfig(nlohmann::json &config)
322 {
323     if (config.find(g_sandBoxSwitchPrefix) != config.end()) {
324         std::string switchStatus = config[g_sandBoxSwitchPrefix].get<std::string>();
325         if (switchStatus == g_sbxSwitchCheck) {
326             return true;
327         } else {
328             return false;
329         }
330     }
331 
332     // if not find sandbox-switch node, default switch status is true
333     return true;
334 }
335 
CheckMountConfig(nlohmann::json & mntPoint,const ClientSocket::AppProperty * appProperty,bool checkFlag)336 static bool CheckMountConfig(nlohmann::json &mntPoint, const ClientSocket::AppProperty *appProperty,
337                              bool checkFlag)
338 {
339     bool istrue = mntPoint.find(g_srcPath) == mntPoint.end() || mntPoint.find(g_sandBoxPath) == mntPoint.end()
340             || mntPoint.find(g_sandBoxFlags) == mntPoint.end();
341     APPSPAWN_CHECK(!istrue, return false, "read mount config failed, app name is %s", appProperty->bundleName);
342 
343     if (mntPoint[g_appAplName] != nullptr) {
344         std::string app_apl_name = mntPoint[g_appAplName].get<std::string>();
345         const char *p_app_apl = nullptr;
346         p_app_apl = app_apl_name.c_str();
347         if (!strcmp(p_app_apl, appProperty->apl)) {
348             return false;
349         }
350     }
351 
352     const std::string configSrcPath = mntPoint[g_srcPath].get<std::string>();
353     // special handle wps and don't use /data/app/xxx/<Package> config
354     if (checkFlag && (configSrcPath.find("/data/app") != std::string::npos &&
355         (configSrcPath.find("/base") != std::string::npos ||
356          configSrcPath.find("/database") != std::string::npos
357         ) && configSrcPath.find(g_packageName) != std::string::npos)) {
358         return false;
359     }
360 
361     return true;
362 }
363 
DoDlpAppMountStrategy(const ClientSocket::AppProperty * appProperty,const std::string & srcPath,const std::string & sandboxPath,const std::string & fsType,unsigned long mountFlags)364 static int32_t DoDlpAppMountStrategy(const ClientSocket::AppProperty *appProperty,
365                                      const std::string &srcPath, const std::string &sandboxPath,
366                                      const std::string &fsType, unsigned long mountFlags)
367 {
368     int fd = open("/dev/fuse", O_RDWR);
369     APPSPAWN_CHECK(fd != -1, return -EINVAL, "open /dev/fuse failed, errno is %d", errno);
370 
371     char options[FUSE_OPTIONS_MAX_LEN];
372     (void)sprintf_s(options, sizeof(options), "fd=%d,rootmode=40000,user_id=%d,group_id=%d,allow_other", fd,
373                     appProperty->uid, appProperty->gid);
374 
375     // To make sure destinationPath exist
376     MakeDirRecursive(sandboxPath, FILE_MODE);
377 
378     int ret = 0;
379 #ifndef APPSPAWN_TEST
380     ret = mount(srcPath.c_str(), sandboxPath.c_str(), fsType.c_str(), mountFlags, options);
381     APPSPAWN_CHECK(ret == 0, return ret, "DoDlpAppMountStrategy failed, bind mount %s to %s"
382         "failed %d", srcPath.c_str(), sandboxPath.c_str(), errno);
383 
384     ret = mount(NULL, sandboxPath.c_str(), NULL, MS_PRIVATE, NULL);
385     APPSPAWN_CHECK(ret == 0, return ret, "private mount to %s failed %d", sandboxPath.c_str(), errno);
386 #endif
387     /* close DLP_FUSE_FD and dup FD to it */
388     close(DLP_FUSE_FD);
389     ret = dup2(fd, DLP_FUSE_FD);
390     APPSPAWN_CHECK_ONLY_LOG(ret != -1, "dup fuse fd %d failed, errno is %d", fd, errno);
391     return ret;
392 }
393 
HandleSpecialAppMount(const ClientSocket::AppProperty * appProperty,const std::string & srcPath,const std::string & sandboxPath,const std::string & fsType,unsigned long mountFlags)394 static int32_t HandleSpecialAppMount(const ClientSocket::AppProperty *appProperty,
395                                      const std::string &srcPath, const std::string &sandboxPath,
396                                      const std::string &fsType, unsigned long mountFlags)
397 {
398     std::string bundleName = appProperty->bundleName;
399 
400     /* dlp application mount strategy */
401     /* dlp is an example, we should change to real bundle name later */
402     if (bundleName.find(g_dlpBundleName) != std::string::npos) {
403         if (fsType.empty()) {
404             return -1;
405         } else {
406             return DoDlpAppMountStrategy(appProperty, srcPath, sandboxPath, fsType, mountFlags);
407         }
408     }
409 
410     return -1;
411 }
412 
ConvertFlagStr(const std::string & flagStr)413 static uint32_t ConvertFlagStr(const std::string &flagStr)
414 {
415     const std::map<std::string, int> flagsMap = {{"0", 0}, {"START_FLAGS_BACKUP", 1},
416                                                  {"DLP_MANAGER", 2}};
417 
418     if (flagsMap.count(flagStr)) {
419         return 1 << flagsMap.at(flagStr);
420     }
421 
422     return 0;
423 }
424 
425 /* Check and Create physical /data/app/el2 path when BMS failed to create related package folder */
CheckAndPrepareSrcPath(const ClientSocket::AppProperty * appProperty,const std::string & srcPath)426 void SandboxUtils::CheckAndPrepareSrcPath(const ClientSocket::AppProperty *appProperty, const std::string &srcPath)
427 {
428     if (access(srcPath.c_str(), F_OK) == 0) {
429         return;
430     }
431 
432     if (srcPath.find(g_el2Prefix) != std::string::npos) {
433         if (srcPath.find(g_basePrefix) != std::string::npos) {
434             MakeDirRecursive(srcPath.c_str(), BASE_FOLDER_FILE_MODE);
435             chown(srcPath.c_str(), appProperty->uid, appProperty->gid);
436 
437             for (const std::string &packageItem : g_packageItems) {
438                 const std::string newPath = srcPath + "/" + packageItem;
439                 MkdirAndChown(newPath, BASE_FOLDER_FILE_MODE, appProperty->uid, appProperty->gid);
440             }
441         } else if (srcPath.find(g_databasePrefix) != std::string::npos) {
442             MakeDirRecursive(srcPath.c_str(), DATABASE_FOLDER_FILE_MODE);
443             /* Add S_ISGID mode and change group owner to DATABASE */
444             chmod(srcPath.c_str(), DATABASE_FOLDER_FILE_MODE | S_ISGID);
445             chown(srcPath.c_str(), appProperty->uid, DATABASE_DIR_GID);
446         } else {
447             APPSPAWN_LOGI("failed to access path: %s", srcPath.c_str());
448         }
449     }
450 
451     if (srcPath.find(g_serviceEl2Prefix) != std::string::npos) {
452         if (srcPath.find(g_accountPrefix) != std::string::npos) {
453             MakeDirRecursive(srcPath.c_str(), DATABASE_FOLDER_FILE_MODE);
454             chmod(srcPath.c_str(), DATABASE_FOLDER_FILE_MODE | S_ISGID);
455             chown(srcPath.c_str(), appProperty->uid, appProperty->gid);
456         } else if (srcPath.find(g_accountNonPrefix) != std::string::npos) {
457             MakeDirRecursive(srcPath.c_str(), DATABASE_FOLDER_FILE_MODE);
458             /* Add S_ISGID mode and change group owner to DFS */
459             chmod(srcPath.c_str(), DATABASE_FOLDER_FILE_MODE | S_ISGID);
460             chown(srcPath.c_str(), appProperty->uid, DFS_GID);
461         } else {
462             APPSPAWN_LOGI("failed to access path: %s", srcPath.c_str());
463         }
464     }
465 }
466 
DoAllMntPointsMount(const ClientSocket::AppProperty * appProperty,nlohmann::json & appConfig)467 int SandboxUtils::DoAllMntPointsMount(const ClientSocket::AppProperty *appProperty, nlohmann::json &appConfig)
468 {
469     std::string bundleName = appProperty->bundleName;
470     if (appConfig.find(g_mountPrefix) == appConfig.end()) {
471         APPSPAWN_LOGV("mount config is not found, app name is %s", bundleName.c_str());
472         return 0;
473     }
474 
475     bool checkFlag = false;
476     if (appConfig.find(g_flags) != appConfig.end()) {
477         if (((ConvertFlagStr(appConfig[g_flags].get<std::string>()) & appProperty->flags) != 0) &&
478             bundleName.find("wps") != std::string::npos) {
479             checkFlag = true;
480         }
481     }
482 
483     nlohmann::json mountPoints = appConfig[g_mountPrefix];
484     std::string sandboxRoot = GetSbxPathByConfig(appProperty, appConfig);
485     unsigned int mountPointSize = mountPoints.size();
486 
487     for (unsigned int i = 0; i < mountPointSize; i++) {
488         nlohmann::json mntPoint = mountPoints[i];
489 
490         if (CheckMountConfig(mntPoint, appProperty, checkFlag) == false) {
491             continue;
492         }
493 
494         std::string srcPath = ConvertToRealPath(appProperty, mntPoint[g_srcPath].get<std::string>());
495         std::string sandboxPath = sandboxRoot + ConvertToRealPath(appProperty,
496                                                                   mntPoint[g_sandBoxPath].get<std::string>());
497         unsigned long mountFlags = GetMountFlagsFromConfig(mntPoint[g_sandBoxFlags].get<std::vector<std::string>>());
498         std::string fsType = "";
499         if (mntPoint.find(g_fsType) != mntPoint.end()) {
500             fsType = mntPoint[g_fsType].get<std::string>();
501         }
502 
503         int ret = 0;
504         /* check and prepare /data/app/el2 base and database package path to avoid BMS failed to create this folder */
505         CheckAndPrepareSrcPath(appProperty, srcPath);
506         /* if app mount failed for special strategy, we need deal with common mount config */
507         ret = HandleSpecialAppMount(appProperty, srcPath, sandboxPath, fsType, mountFlags);
508         if (ret < 0) {
509             if (fsType.empty()) {
510                 ret = DoAppSandboxMountOnce(srcPath.c_str(), sandboxPath.c_str(), nullptr, mountFlags, nullptr);
511             } else {
512                 ret = DoAppSandboxMountOnce(srcPath.c_str(), sandboxPath.c_str(), fsType.c_str(), mountFlags, nullptr);
513             }
514         }
515         if (ret) {
516             std::string actionStatus = g_statusCheck;
517             (void)JsonUtils::GetStringFromJson(mntPoint, g_actionStatuc, actionStatus);
518             if (actionStatus == g_statusCheck) {
519                 APPSPAWN_LOGE("DoAppSandboxMountOnce failed, %s", sandboxPath.c_str());
520                 return ret;
521             }
522         }
523 
524         DoSandboxChmod(mntPoint, sandboxRoot);
525     }
526 
527     return 0;
528 }
529 
DoAllSymlinkPointslink(const ClientSocket::AppProperty * appProperty,nlohmann::json & appConfig)530 int SandboxUtils::DoAllSymlinkPointslink(const ClientSocket::AppProperty *appProperty, nlohmann::json &appConfig)
531 {
532     APPSPAWN_CHECK(appConfig.find(g_symlinkPrefix) != appConfig.end(), return 0, "symlink config is not found,"
533         "maybe reuslt sandbox launch failed app name is %s", appProperty->bundleName);
534 
535     nlohmann::json symlinkPoints = appConfig[g_symlinkPrefix];
536     std::string sandboxRoot = GetSbxPathByConfig(appProperty, appConfig);
537     unsigned int symlinkPointSize = symlinkPoints.size();
538 
539     for (unsigned int i = 0; i < symlinkPointSize; i++) {
540         nlohmann::json symPoint = symlinkPoints[i];
541 
542         // Check the validity of the symlink configuration
543         if (symPoint.find(g_targetName) == symPoint.end() || symPoint.find(g_linkName) == symPoint.end()) {
544             APPSPAWN_LOGE("read symlink config failed, app name is %s", appProperty->bundleName);
545             continue;
546         }
547 
548         std::string targetName = ConvertToRealPath(appProperty, symPoint[g_targetName].get<std::string>());
549         std::string linkName = sandboxRoot + ConvertToRealPath(appProperty, symPoint[g_linkName].get<std::string>());
550         APPSPAWN_LOGV("symlink, from %s to %s", targetName.c_str(), linkName.c_str());
551 
552         int ret = symlink(targetName.c_str(), linkName.c_str());
553         if (ret && errno != EEXIST) {
554             APPSPAWN_LOGE("symlink failed, %s, errno is %d", linkName.c_str(), errno);
555 
556             std::string actionStatus = g_statusCheck;
557             (void)JsonUtils::GetStringFromJson(symPoint, g_actionStatuc, actionStatus);
558             if (actionStatus == g_statusCheck) {
559                 return ret;
560             }
561         }
562 
563         DoSandboxChmod(symPoint, sandboxRoot);
564     }
565 
566     return 0;
567 }
568 
DoSandboxFilePrivateBind(const ClientSocket::AppProperty * appProperty,nlohmann::json & wholeConfig)569 int32_t SandboxUtils::DoSandboxFilePrivateBind(const ClientSocket::AppProperty *appProperty,
570                                                nlohmann::json &wholeConfig)
571 {
572     nlohmann::json privateAppConfig = wholeConfig[g_privatePrefix][0];
573     if (privateAppConfig.find(appProperty->bundleName) != privateAppConfig.end()) {
574         return DoAllMntPointsMount(appProperty, privateAppConfig[appProperty->bundleName][0]);
575     }
576 
577     return 0;
578 }
579 
DoSandboxFilePrivateSymlink(const ClientSocket::AppProperty * appProperty,nlohmann::json & wholeConfig)580 int32_t SandboxUtils::DoSandboxFilePrivateSymlink(const ClientSocket::AppProperty *appProperty,
581                                                   nlohmann::json &wholeConfig)
582 {
583     nlohmann::json privateAppConfig = wholeConfig[g_privatePrefix][0];
584     if (privateAppConfig.find(appProperty->bundleName) != privateAppConfig.end()) {
585         return DoAllSymlinkPointslink(appProperty, privateAppConfig[appProperty->bundleName][0]);
586     }
587 
588     return 0;
589 }
590 
HandleFlagsPoint(const ClientSocket::AppProperty * appProperty,nlohmann::json & appConfig)591 int32_t SandboxUtils::HandleFlagsPoint(const ClientSocket::AppProperty *appProperty,
592                                        nlohmann::json &appConfig)
593 {
594     if (appConfig.find(g_flagePoint) == appConfig.end()) {
595         return 0;
596     }
597 
598     nlohmann::json flagsPoints = appConfig[g_flagePoint];
599     unsigned int flagsPointSize = flagsPoints.size();
600 
601     for (unsigned int i = 0; i < flagsPointSize; i++) {
602         nlohmann::json flagPoint = flagsPoints[i];
603 
604         if (flagPoint.find(g_flags) != flagPoint.end()) {
605             std::string flagsStr = flagPoint[g_flags].get<std::string>();
606             uint32_t flag = ConvertFlagStr(flagsStr);
607             if ((appProperty->flags & flag) != 0) {
608                 return DoAllMntPointsMount(appProperty, flagPoint);
609             }
610         } else {
611             APPSPAWN_LOGE("read flags config failed, app name is %s", appProperty->bundleName);
612         }
613     }
614 
615     return 0;
616 }
617 
DoSandboxFilePrivateFlagsPointHandle(const ClientSocket::AppProperty * appProperty,nlohmann::json & wholeConfig)618 int32_t SandboxUtils::DoSandboxFilePrivateFlagsPointHandle(const ClientSocket::AppProperty *appProperty,
619                                                            nlohmann::json &wholeConfig)
620 {
621     nlohmann::json privateAppConfig = wholeConfig[g_privatePrefix][0];
622     if (privateAppConfig.find(appProperty->bundleName) != privateAppConfig.end()) {
623         return HandleFlagsPoint(appProperty, privateAppConfig[appProperty->bundleName][0]);
624     }
625 
626     return 0;
627 }
628 
DoSandboxFileCommonFlagsPointHandle(const ClientSocket::AppProperty * appProperty,nlohmann::json & wholeConfig)629 int32_t SandboxUtils::DoSandboxFileCommonFlagsPointHandle(const ClientSocket::AppProperty *appProperty,
630                                                           nlohmann::json &wholeConfig)
631 {
632     nlohmann::json commonConfig = wholeConfig[g_commonPrefix][0];
633     if (commonConfig.find(g_appResources) != commonConfig.end()) {
634         return HandleFlagsPoint(appProperty, commonConfig[g_appResources][0]);
635     }
636 
637     return 0;
638 }
639 
DoSandboxFileCommonBind(const ClientSocket::AppProperty * appProperty,nlohmann::json & wholeConfig)640 int32_t SandboxUtils::DoSandboxFileCommonBind(const ClientSocket::AppProperty *appProperty, nlohmann::json &wholeConfig)
641 {
642     nlohmann::json commonConfig = wholeConfig[g_commonPrefix][0];
643     int ret = 0;
644 
645     if (commonConfig.find(g_appBase) != commonConfig.end()) {
646         ret = DoAllMntPointsMount(appProperty, commonConfig[g_appBase][0]);
647         if (ret) {
648             return ret;
649         }
650     }
651 
652     if (commonConfig.find(g_appResources) != commonConfig.end()) {
653         ret = DoAllMntPointsMount(appProperty, commonConfig[g_appResources][0]);
654     }
655 
656     return ret;
657 }
658 
DoSandboxFileCommonSymlink(const ClientSocket::AppProperty * appProperty,nlohmann::json & wholeConfig)659 int32_t SandboxUtils::DoSandboxFileCommonSymlink(const ClientSocket::AppProperty *appProperty,
660                                                  nlohmann::json &wholeConfig)
661 {
662     nlohmann::json commonConfig = wholeConfig[g_commonPrefix][0];
663     int ret = 0;
664 
665     if (commonConfig.find(g_appBase) != commonConfig.end()) {
666         ret = DoAllSymlinkPointslink(appProperty, commonConfig[g_appBase][0]);
667         if (ret) {
668             return ret;
669         }
670     }
671 
672     if (commonConfig.find(g_appResources) != commonConfig.end()) {
673         ret = DoAllSymlinkPointslink(appProperty, commonConfig[g_appResources][0]);
674     }
675 
676     return ret;
677 }
678 
SetPrivateAppSandboxProperty_(const ClientSocket::AppProperty * appProperty,nlohmann::json & config)679 int32_t SandboxUtils::SetPrivateAppSandboxProperty_(const ClientSocket::AppProperty *appProperty,
680                                                     nlohmann::json &config)
681 {
682     int ret = 0;
683 
684     ret = DoSandboxFilePrivateBind(appProperty, config);
685     APPSPAWN_CHECK(ret == 0, return ret, "DoSandboxFilePrivateBind failed");
686 
687     ret = DoSandboxFilePrivateSymlink(appProperty, config);
688     APPSPAWN_CHECK_ONLY_LOG(ret == 0, "DoSandboxFilePrivateSymlink failed");
689 
690     ret = DoSandboxFilePrivateFlagsPointHandle(appProperty, config);
691     APPSPAWN_CHECK_ONLY_LOG(ret == 0, "DoSandboxFilePrivateFlagsPointHandle failed");
692 
693     return ret;
694 }
695 
SetRenderSandboxProperty(const ClientSocket::AppProperty * appProperty,std::string & sandboxPackagePath)696 int32_t SandboxUtils::SetRenderSandboxProperty(const ClientSocket::AppProperty *appProperty,
697                                                std::string &sandboxPackagePath)
698 {
699 #ifdef NWEB_SPAWN
700     nlohmann::json config = SandboxUtils::GetJsonConfig();
701     nlohmann::json privateAppConfig = config[g_privatePrefix][0];
702 
703     if (privateAppConfig.find(g_ohosRender) != privateAppConfig.end()) {
704         int ret = DoAllMntPointsMount(appProperty, privateAppConfig[g_ohosRender][0]);
705         APPSPAWN_CHECK(ret == 0, return ret, "DoAllMntPointsMount failed, %s",
706             appProperty->bundleName);
707         ret = DoAllSymlinkPointslink(appProperty, privateAppConfig[g_ohosRender][0]);
708         APPSPAWN_CHECK(ret == 0, return ret, "DoAllSymlinkPointslink  failed, %s",
709             appProperty->bundleName);
710     }
711 #endif
712     return 0;
713 }
714 
SetPrivateAppSandboxProperty(const ClientSocket::AppProperty * appProperty)715 int32_t SandboxUtils::SetPrivateAppSandboxProperty(const ClientSocket::AppProperty *appProperty)
716 {
717     nlohmann::json productConfig = SandboxUtils::GetProductJsonConfig();
718     nlohmann::json config = SandboxUtils::GetJsonConfig();
719     int ret = 0;
720 
721     ret = SetPrivateAppSandboxProperty_(appProperty, config);
722     APPSPAWN_CHECK(ret == 0, return ret, "parse adddata-sandbox config failed");
723     ret = SetPrivateAppSandboxProperty_(appProperty, productConfig);
724     APPSPAWN_CHECK_ONLY_LOG(ret == 0, "parse product-sandbox config failed");
725 
726     return ret;
727 }
728 
SetCommonAppSandboxProperty_(const ClientSocket::AppProperty * appProperty,nlohmann::json & config)729 int32_t SandboxUtils::SetCommonAppSandboxProperty_(const ClientSocket::AppProperty *appProperty,
730                                                    nlohmann::json &config)
731 {
732     int rc = 0;
733 
734     rc = DoSandboxFileCommonBind(appProperty, config);
735     APPSPAWN_CHECK(rc == 0, return rc, "DoSandboxFileCommonBind failed, %s", appProperty->bundleName);
736 
737     // if sandbox switch is off, don't do symlink work again
738     if (CheckAppSandboxSwitchStatus(appProperty) == true && (CheckTotalSandboxSwitchStatus(appProperty) == true)) {
739         rc = DoSandboxFileCommonSymlink(appProperty, config);
740         APPSPAWN_CHECK(rc == 0, return rc, "DoSandboxFileCommonSymlink failed, %s", appProperty->bundleName);
741     }
742 
743     rc = DoSandboxFileCommonFlagsPointHandle(appProperty, config);
744     APPSPAWN_CHECK_ONLY_LOG(rc == 0, "DoSandboxFilePrivateFlagsPointHandle failed");
745 
746     return rc;
747 }
748 
SetCommonAppSandboxProperty(const ClientSocket::AppProperty * appProperty,std::string & sandboxPackagePath)749 int32_t SandboxUtils::SetCommonAppSandboxProperty(const ClientSocket::AppProperty *appProperty,
750                                                   std::string &sandboxPackagePath)
751 {
752     nlohmann::json jsonConfig = SandboxUtils::GetJsonConfig();
753     nlohmann::json productConfig = SandboxUtils::GetProductJsonConfig();
754     int ret = 0;
755 
756     ret = SetCommonAppSandboxProperty_(appProperty, jsonConfig);
757     APPSPAWN_CHECK(ret == 0, return ret, "parse appdata config for common failed, %s", sandboxPackagePath.c_str());
758 
759     ret = SetCommonAppSandboxProperty_(appProperty, productConfig);
760     APPSPAWN_CHECK(ret == 0, return ret, "parse product config for common failed, %s", sandboxPackagePath.c_str());
761 
762     if (strcmp(appProperty->apl, APL_SYSTEM_BASIC.data()) == 0 ||
763         strcmp(appProperty->apl, APL_SYSTEM_CORE.data()) == 0 ||
764         (appProperty->flags & APP_ACCESS_BUNDLE_DIR) != 0) {
765         // need permission check for system app here
766         std::string destbundlesPath = sandboxPackagePath + g_dataBundles;
767         DoAppSandboxMountOnce(g_physicalAppInstallPath.c_str(), destbundlesPath.c_str(), "", BASIC_MOUNT_FLAGS,
768                               nullptr);
769     }
770 
771     return 0;
772 }
773 
DoSandboxRootFolderCreateAdapt(std::string & sandboxPackagePath)774 int32_t SandboxUtils::DoSandboxRootFolderCreateAdapt(std::string &sandboxPackagePath)
775 {
776 #ifndef APPSPAWN_TEST
777     int rc = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL);
778     APPSPAWN_CHECK(rc == 0, return rc, "set propagation slave failed");
779 #endif
780     MakeDirRecursive(sandboxPackagePath, FILE_MODE);
781 
782     // bind mount "/" to /mnt/sandbox/<packageName> path
783     // rootfs: to do more resources bind mount here to get more strict resources constraints
784 #ifndef APPSPAWN_TEST
785     rc = mount("/", sandboxPackagePath.c_str(), NULL, BASIC_MOUNT_FLAGS, NULL);
786     APPSPAWN_CHECK(rc == 0, return rc, "mount bind / failed, %d", errno);
787 #endif
788     return 0;
789 }
790 
DoSandboxRootFolderCreate(const ClientSocket::AppProperty * appProperty,std::string & sandboxPackagePath)791 int32_t SandboxUtils::DoSandboxRootFolderCreate(const ClientSocket::AppProperty *appProperty,
792                                                 std::string &sandboxPackagePath)
793 {
794 #ifndef APPSPAWN_TEST
795     int rc = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL);
796     if (rc) {
797         return rc;
798     }
799 #endif
800     DoAppSandboxMountOnce(sandboxPackagePath.c_str(), sandboxPackagePath.c_str(), "",
801                           BASIC_MOUNT_FLAGS, nullptr);
802 
803     return 0;
804 }
805 
CheckBundleNameForPrivate(const std::string & bundleName)806 bool SandboxUtils::CheckBundleNameForPrivate(const std::string &bundleName)
807 {
808     if (bundleName.find(g_internal) != std::string::npos) {
809         return false;
810     }
811     return true;
812 }
813 
CheckTotalSandboxSwitchStatus(const ClientSocket::AppProperty * appProperty)814 bool SandboxUtils::CheckTotalSandboxSwitchStatus(const ClientSocket::AppProperty *appProperty)
815 {
816     nlohmann::json wholeConfig = SandboxUtils::GetJsonConfig();
817 
818     nlohmann::json commonAppConfig = wholeConfig[g_commonPrefix][0];
819     if (commonAppConfig.find(g_topSandBoxSwitchPrefix) != commonAppConfig.end()) {
820         std::string switchStatus = commonAppConfig[g_topSandBoxSwitchPrefix].get<std::string>();
821         if (switchStatus == g_sbxSwitchCheck) {
822             return true;
823         } else {
824             return false;
825         }
826     }
827 
828     // default sandbox switch is on
829     return true;
830 }
831 
CheckAppSandboxSwitchStatus(const ClientSocket::AppProperty * appProperty)832 bool SandboxUtils::CheckAppSandboxSwitchStatus(const ClientSocket::AppProperty *appProperty)
833 {
834     nlohmann::json wholeConfig = SandboxUtils::GetJsonConfig();
835     bool rc = true;
836 
837     nlohmann::json privateAppConfig = wholeConfig[g_privatePrefix][0];
838     if (privateAppConfig.find(appProperty->bundleName) != privateAppConfig.end()) {
839         nlohmann::json appConfig = privateAppConfig[appProperty->bundleName][0];
840         rc = GetSbxSwitchStatusByConfig(appConfig);
841         APPSPAWN_LOGE("CheckAppSandboxSwitchStatus middle, %d", rc);
842     }
843 
844     // default sandbox switch is on
845     return rc;
846 }
847 
CheckBundleName(const std::string & bundleName)848 static int CheckBundleName(const std::string &bundleName)
849 {
850     if (bundleName.empty() || bundleName.size() > APP_LEN_BUNDLE_NAME) {
851         return -1;
852     }
853     if (bundleName.find('\\') != std::string::npos || bundleName.find('/') != std::string::npos) {
854         return -1;
855     }
856     return 0;
857 }
858 
SetAppSandboxProperty(const ClientSocket::AppProperty * appProperty)859 int32_t SandboxUtils::SetAppSandboxProperty(const ClientSocket::AppProperty *appProperty)
860 {
861     if (appProperty == nullptr || CheckBundleName(appProperty->bundleName) != 0) {
862         return -1;
863     }
864     std::string sandboxPackagePath = g_sandBoxRootDir;
865     const std::string bundleName = appProperty->bundleName;
866     sandboxPackagePath += bundleName;
867     MakeDirRecursive(sandboxPackagePath.c_str(), FILE_MODE);
868     int rc = 0;
869     // when CLONE_NEWPID is enabled, CLONE_NEWNS must be enabled.
870     if (!(appProperty->cloneFlags & CLONE_NEWPID)) {
871         // add pid to a new mnt namespace
872         rc = unshare(CLONE_NEWNS);
873         APPSPAWN_CHECK(rc == 0, return rc, "unshare failed, packagename is %s", bundleName.c_str());
874     }
875 
876     // check app sandbox switch
877     if ((CheckTotalSandboxSwitchStatus(appProperty) == false) ||
878         (CheckAppSandboxSwitchStatus(appProperty) == false)) {
879         rc = DoSandboxRootFolderCreateAdapt(sandboxPackagePath);
880     } else {
881         rc = DoSandboxRootFolderCreate(appProperty, sandboxPackagePath);
882     }
883     APPSPAWN_CHECK(rc == 0, return rc, "DoSandboxRootFolderCreate failed, %s", bundleName.c_str());
884 #ifndef NWEB_SPAWN
885     rc = SetCommonAppSandboxProperty(appProperty, sandboxPackagePath);
886     APPSPAWN_CHECK(rc == 0, return rc, "SetCommonAppSandboxProperty failed, packagename is %s",
887         bundleName.c_str());
888     if (CheckBundleNameForPrivate(bundleName)) {
889         rc = SetPrivateAppSandboxProperty(appProperty);
890         APPSPAWN_CHECK(rc == 0, return rc, "SetPrivateAppSandboxProperty failed, packagename is %s",
891             bundleName.c_str());
892     }
893 #else
894     // rendering process can be created by different apps,
895     // and the bundle names of these apps are different,
896     // so we can't use the method SetPrivateAppSandboxProperty
897     // which mount dirs by using bundle name.
898     rc = SetRenderSandboxProperty(appProperty, sandboxPackagePath);
899     APPSPAWN_CHECK(rc == 0, return rc, "SetRenderSandboxProperty failed, packagename is %s",
900         sandboxPackagePath.c_str());
901 #endif
902     rc = chdir(sandboxPackagePath.c_str());
903     APPSPAWN_CHECK(rc == 0, return rc, "chdir failed, packagename is %s, path is %s",
904         bundleName.c_str(), sandboxPackagePath.c_str());
905 
906 #ifndef APPSPAWN_TEST
907     rc = syscall(SYS_pivot_root, sandboxPackagePath.c_str(), sandboxPackagePath.c_str());
908     APPSPAWN_CHECK(rc == 0, return rc, "pivot root failed, packagename is %s, errno is %d",
909         bundleName.c_str(), errno);
910 #endif
911 
912     rc = umount2(".", MNT_DETACH);
913     APPSPAWN_CHECK(rc == 0, return rc, "MNT_DETACH failed, packagename is %s", bundleName.c_str());
914     return 0;
915 }
916 } // namespace AppSpawn
917 } // namespace OHOS
918