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