已开启
提供跨应用通信功能 #2950
提供跨应用通信功能 #2950
已开启
创建于 8 天前
5 个文件变更+801-37
@@ -322,6 +322,7 @@ int AppSpawnClientAddPermission(AppSpawnClientHandle handle, AppSpawnReqMsgHandl
322#define MSG_EXT_NAME_APP_SIGN_TYPE "AppSignType"322#define MSG_EXT_NAME_APP_SIGN_TYPE "AppSignType"
323#define MSG_EXT_NAME_APP_DISTRIBUTION_TYPE "AppDistributionType"323#define MSG_EXT_NAME_APP_DISTRIBUTION_TYPE "AppDistributionType"
324#define MSG_EXT_NAME_XPM_ID_TYPE "XpmIdType"324#define MSG_EXT_NAME_XPM_ID_TYPE "XpmIdType"
325+#define MSG_EXT_NAME_IPC_GROUP "IPCGroup"
325 326 
326int AppSpawnReqMsgAddExtInfo(AppSpawnReqMsgHandle reqHandle, const char *name, const uint8_t *value, uint32_t valueLen);327int AppSpawnReqMsgAddExtInfo(AppSpawnReqMsgHandle reqHandle, const char *name, const uint8_t *value, uint32_t valueLen);
327 328 
@@ -484,6 +484,36 @@ static inline cJSON *GetJsonObjFromProperty(const AppSpawningCtx *appProperty, c
484 return root;484 return root;
485}485}
486 486 
487+static int EnsureDirWithMode(const std::string &path, uid_t uid, gid_t gid, mode_t mode, bool restorecon = false)
488+{
489+ struct stat statBuff;
490+ if (stat(path.c_str(), &statBuff) == 0 &&
491+ statBuff.st_uid == uid && statBuff.st_gid == gid &&
492+ (statBuff.st_mode & SandboxCommonDef::ALL_FILE_MODE_BITS) == mode) {
493+ return 0;
494+ }
495+ int ret = SandboxCommon::CreateDirRecursive(path, SandboxCommonDef::FILE_MODE);
496+ if (ret != 0) {
497+ APPSPAWN_LOGE("mkdir %{public}s failed, errno %{public}d", path.c_str(), errno);
498+ return -1;
499+ }
500+ if (restorecon && RestoreconRecurse(path.c_str()) != 0) {
501+ APPSPAWN_LOGW("restorecon failed for %{public}s", path.c_str());
502+ }
503+ if (chmod(path.c_str(), mode) < 0 || chown(path.c_str(), uid, gid) < 0) {
504+ APPSPAWN_LOGE("chmod or chown failed for %{public}s, errno %{public}d", path.c_str(), errno);
505+ if (stat(path.c_str(), &statBuff) < 0) {
506+ APPSPAWN_LOGE("stat %{public}s failed", path.c_str());
507+ } else if (statBuff.st_uid != uid || statBuff.st_gid != gid ||
soulrequiem
soulrequiemsoulrequiem3 天前

medium modules/sandbox/normal/sandbox_core.cpp:507

问题:EnsureDirWithMode 中 chmod/chown 失败仅打日志后 return 0。IPCGroup 目录权限为 01771(sticky+setgid),属主/属组错误意味着共享内存的组内互访边界被破坏,但挂载照常完成,应用无感知。

证据:失败分支只 LOGE 后落到 return 0,调用方 EnsureDirWithMode(...) != 0 的检查在该路径永远不触发。

建议:IPCGroup 场景下 chmod/chown 失败应返回错误并跳过该项挂载,或至少提供可观测的上报手段。

likedislike
508+ (statBuff.st_mode & SandboxCommonDef::ALL_FILE_MODE_BITS) != mode) {
509+ APPSPAWN_LOGE("chmod or chown mismatch for %{public}s, expected uid=%{public}d, "
510+ "gid=%{public}d, mode=%{public}d; actual uid=%{public}d, gid=%{public}d, mode=%{public}d",
511+ path.c_str(), uid, gid, mode, statBuff.st_uid, statBuff.st_gid, statBuff.st_mode);
512+ }
513+ }
514+ return 0;
515+}
516+ 
487int32_t SandboxCore::MountAllHsp(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath, cJSON *hspRoot)517int32_t SandboxCore::MountAllHsp(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath, cJSON *hspRoot)
488{518{
489 if (appProperty == nullptr || sandboxPackagePath == "") {519 if (appProperty == nullptr || sandboxPackagePath == "") {
@@ -756,6 +786,65 @@ int32_t SandboxCore::DoAllMntPointsMountNocheck(const AppSpawningCtx *appPropert
756 return SandboxCommon::HandleArrayForeach(mountPoints, processor);786 return SandboxCommon::HandleArrayForeach(mountPoints, processor);
757}787}
758 788 
789+static int32_t ProcessIPCGroupItem(cJSON *groupItem, const AppSpawningCtx *appProperty,
790+ const std::string &sandboxPackagePath, const std::string &userId)
791+{
792+ cJSON *groupIdItem = cJSON_GetObjectItemCaseSensitive(
793+ groupItem, SandboxCommonDef::g_ipcGroupList_key_groupId.c_str());
794+ if (groupIdItem == nullptr || !cJSON_IsString(groupIdItem) || strlen(groupIdItem->valuestring) == 0) {
795+ APPSPAWN_LOGI("IPCGroup item missing or empty groupId");
796+ return -1;
797+ }
798+ std::string groupId(groupIdItem->valuestring);
799+ if (groupId.find_first_not_of("0123456789") != std::string::npos) {
800+ APPSPAWN_LOGI("IPCGroup item invalid groupId");
801+ return -1;
802+ }
803+ cJSON *groupGidItem = cJSON_GetObjectItemCaseSensitive(
804+ groupItem, SandboxCommonDef::g_ipcGroupList_key_groupGid.c_str());
805+ if (groupGidItem == nullptr || !cJSON_IsString(groupGidItem)) {
806+ APPSPAWN_LOGI("IPCGroup item missing or invalid groupGid");
807+ return -1;
808+ }
809+ gid_t groupGid = static_cast<gid_t>(atoi(groupGidItem->valuestring));
810+ if (groupGid == 0) {
811+ APPSPAWN_LOGI("IPCGroup item invalid groupGid value");
812+ return -1;
813+ }
814+ std::string srcPath = SandboxCommonDef::g_ipcGroupSrcPathPrefix + userId + "/group/" + groupId;
815+ if (EnsureDirWithMode(srcPath, 0, groupGid, SandboxCommonDef::IPC_GROUP_SRC_PATH_MODE) != 0) {
816+ return 0;
817+ }
818+ std::string sandboxPath = sandboxPackagePath + SandboxCommonDef::g_ipcGroupSandboxPathPrefix + groupId;
819+ SharedMountArgs arg = {.srcPath = srcPath.c_str(), .destPath = sandboxPath.c_str()};
820+ int32_t mountRet = SandboxCommon::DoAppSandboxMountOnce(appProperty, &arg);
821+ APPSPAWN_CHECK_ONLY_LOG(mountRet == 0, "mount ipcGroup %{public}s failed, ret %{public}d",
822+ srcPath.c_str(), mountRet);
823+ return 0;
824+}
825+ 
826+int32_t SandboxCore::MountIPCGroup(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath)
827+{
828+ if (appProperty == nullptr || sandboxPackagePath == "") {
829+ return 0;
830+ }
831+ cJSON *ipcGroupRoot = GetJsonObjFromProperty(appProperty, MSG_EXT_NAME_IPC_GROUP);
832+ APPSPAWN_CHECK_ONLY_EXPER(ipcGroupRoot != nullptr, return 0);
833+ APPSPAWN_CHECK(cJSON_IsArray(ipcGroupRoot), cJSON_Delete(ipcGroupRoot); return 0, "ipcGroupRoot is not array");
834+ AppSpawnMsgDacInfo *dacInfo = reinterpret_cast<AppSpawnMsgDacInfo *>(GetAppProperty(appProperty, TLV_DAC_INFO));
835+ if (dacInfo == nullptr) {
836+ cJSON_Delete(ipcGroupRoot);
837+ return 0;
838+ }
839+ std::string userId = std::to_string(dacInfo->uid / UID_BASE);
840+ auto processor = [&appProperty, &sandboxPackagePath, &userId](cJSON *item) {
841+ return ProcessIPCGroupItem(item, appProperty, sandboxPackagePath, userId);
842+ };
843+ int32_t ret = SandboxCommon::HandleArrayForeach(ipcGroupRoot, processor);
844+ cJSON_Delete(ipcGroupRoot);
soulrequiem
soulrequiemsoulrequiem3 天前

low modules/sandbox/normal/sandbox_core.cpp:848

问题:EnsureDirWithMode 失败(mkdir 失败路径)时 continue,该项 IPC 组不挂载但整体 ret=0,应用启动成功,直到运行时通信失败才暴露。与数据非法(ret=-1 启动失败)的容错策略不一致。

证据:if (EnsureDirWithMode(...) != 0) { continue; } 不置 ret。

建议:建议区分环境错误与数据错误的日志级别,或确认该容错策略是有意设计并在注释中说明。

likedislike
845+ return ret;
846+}
847+ 
759int32_t SandboxCore::ProcessCreateOnDaemonMount(cJSON *mntPoint, MountPointProcessParams &params)848int32_t SandboxCore::ProcessCreateOnDaemonMount(cJSON *mntPoint, MountPointProcessParams &params)
760{849{
761 const char *srcPathChr = GetStringFromJsonObj(mntPoint, SandboxCommonDef::g_srcPath);850 const char *srcPathChr = GetStringFromJsonObj(mntPoint, SandboxCommonDef::g_srcPath);
@@ -789,21 +878,8 @@ int32_t SandboxCore::ProcessCreateOnDaemonMount(cJSON *mntPoint, MountPointProce
789 mode = (mode_t)cJSON_GetNumberValue(item);878 mode = (mode_t)cJSON_GetNumberValue(item);
790 }879 }
791 880 
792- struct stat statBuff;881+ if (EnsureDirWithMode(srcPath, uid, gid, mode) != 0) {
793- int ret = stat(srcPath.c_str(), &statBuff);882+ return 0;
794- if (ret < 0 || statBuff.st_uid != uid || statBuff.st_gid != gid ||
795- (statBuff.st_mode & SandboxCommonDef::ALL_FILE_MODE_BITS) != mode) {
796- ret = SandboxCommon::CreateDirRecursive(srcPath, SandboxCommonDef::FILE_MODE);
797- APPSPAWN_CHECK(ret == 0, return 0, "mkdir %{public}s failed, errno %{public}d", srcPath.c_str(), errno);
798- if (chmod(srcPath.c_str(), mode) < 0 || chown(srcPath.c_str(), uid, gid) < 0) {
799- if (stat(srcPath.c_str(), &statBuff) < 0) {
800- APPSPAWN_LOGI("stat srcPath failed, path: %{public}s", srcPath.c_str());
801- } else if (statBuff.st_uid != uid || statBuff.st_gid != gid ||
802- (statBuff.st_mode & SandboxCommonDef::ALL_FILE_MODE_BITS) != mode) {
803- APPSPAWN_LOGI("chmod or chown failed. statBuff.st_uid = %{public}d, statBuff.st_gid = %{public}d, \
804- statBuff.st_mode = %{public}d", statBuff.st_uid, statBuff.st_gid, statBuff.st_mode);
805- }
806- }
807 }883 }
808 return ProcessMountPoint(mntPoint, params);884 return ProcessMountPoint(mntPoint, params);
809}885}
@@ -919,28 +995,7 @@ int32_t SandboxCore::ProcessCreateOnlyOnDaemon(cJSON *pathItem, MountPointProces
919 APPSPAWN_CHECK(ParseSrcPathInfo(pathItem, uid, gid, mode, restorecon), return 0,995 APPSPAWN_CHECK(ParseSrcPathInfo(pathItem, uid, gid, mode, restorecon), return 0,
920 "ProcessCreateOnlyOnDaemon: Invalid json object");996 "ProcessCreateOnlyOnDaemon: Invalid json object");
921 997 
922- struct stat statBuff;998+ (void)EnsureDirWithMode(srcPath, uid, gid, mode, restorecon);
923- int ret = stat(srcPath.c_str(), &statBuff);
924- if (ret < 0 || statBuff.st_uid != uid || statBuff.st_gid != gid ||
925- (statBuff.st_mode & SandboxCommonDef::ALL_FILE_MODE_BITS) != mode) {
926- ret = SandboxCommon::CreateDirRecursive(srcPath, SandboxCommonDef::FILE_MODE);
927- APPSPAWN_CHECK(ret == 0, return 0, "ProcessCreateOnlyOnDaemon: mkdir failed, errno %{public}d", errno);
928- if (restorecon && RestoreconRecurse(srcPath.c_str())) {
929- APPSPAWN_LOGW("ProcessCreateOnlyOnDaemon: restorecon failed for %{public}s", srcPath.c_str());
930- }
931- if (chmod(srcPath.c_str(), mode) < 0 || chown(srcPath.c_str(), uid, gid) < 0) {
932- APPSPAWN_LOGE("ProcessCreateOnlyOnDaemon: chmod or chown failed for %{public}s, errno %{public}d",
933- srcPath.c_str(), errno);
934- if (stat(srcPath.c_str(), &statBuff) < 0) {
935- APPSPAWN_LOGE("ProcessCreateOnlyOnDaemon: stat srcPath failed, path: %{public}s", srcPath.c_str());
936- } else if (statBuff.st_uid != uid || statBuff.st_gid != gid ||
937- (statBuff.st_mode & SandboxCommonDef::ALL_FILE_MODE_BITS) != mode) {
938- APPSPAWN_LOGE("ProcessCreateOnlyOnDaemon: chmod or chown mismatch, expected uid=%{public}d, \
939- gid=%{public}d, mode=%{public}d; actual uid=%{public}d, gid=%{public}d, mode=%{public}d",
940- uid, gid, mode, statBuff.st_uid, statBuff.st_gid, statBuff.st_mode);
941- }
942- }
943- }
944 return 0;999 return 0;
945}1000}
946 1001 
@@ -1201,6 +1256,9 @@ int32_t SandboxCore::SetCommonAppSandboxProperty(const AppSpawningCtx *appProper
1201 ret = MountAllGroup(appProperty, sandboxPackagePath);1256 ret = MountAllGroup(appProperty, sandboxPackagePath);
1202 APPSPAWN_CHECK(ret == 0, return ret, "mount groupList failed, %{public}s", sandboxPackagePath.c_str());1257 APPSPAWN_CHECK(ret == 0, return ret, "mount groupList failed, %{public}s", sandboxPackagePath.c_str());
1203 1258 
1259+ ret = MountIPCGroup(appProperty, sandboxPackagePath);
1260+ APPSPAWN_CHECK(ret == 0, return ret, "mount ipcGroup failed, %{public}s", sandboxPackagePath.c_str());
1261+ 
1204 AppSpawnMsgDomainInfo *info =1262 AppSpawnMsgDomainInfo *info =
1205 reinterpret_cast<AppSpawnMsgDomainInfo *>(GetAppProperty(appProperty, TLV_DOMAIN_INFO));1263 reinterpret_cast<AppSpawnMsgDomainInfo *>(GetAppProperty(appProperty, TLV_DOMAIN_INFO));
1206 APPSPAWN_CHECK(info != nullptr, return -1, "No domain info %{public}s", sandboxPackagePath.c_str());1264 APPSPAWN_CHECK(info != nullptr, return -1, "No domain info %{public}s", sandboxPackagePath.c_str());
@@ -121,6 +121,7 @@ private:
121 // 处理可变参数的挂载121 // 处理可变参数的挂载
122 static int32_t MountAllHsp(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath, cJSON *hspRoot);122 static int32_t MountAllHsp(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath, cJSON *hspRoot);
123 static int32_t MountAllGroup(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath);123 static int32_t MountAllGroup(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath);
124+ static int32_t MountIPCGroup(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath);
124 125 
125 // 沙箱回调函数126 // 沙箱回调函数
126 static int32_t ProcessMountPoint(cJSON *mntPoint, MountPointProcessParams &params);127 static int32_t ProcessMountPoint(cJSON *mntPoint, MountPointProcessParams &params);
@@ -34,6 +34,7 @@ constexpr static mode_t BASIC_MOUNT_FLAGS = MS_REC | MS_BIND;
34constexpr int32_t MAX_MOUNT_TIME = 5000; // 5000us34constexpr int32_t MAX_MOUNT_TIME = 5000; // 5000us
35constexpr int32_t LOCK_STATUS_SIZE = 16;35constexpr int32_t LOCK_STATUS_SIZE = 16;
36constexpr mode_t ALL_FILE_MODE_BITS = 07777;36constexpr mode_t ALL_FILE_MODE_BITS = 07777;
37+constexpr mode_t IPC_GROUP_SRC_PATH_MODE = 01771;
37constexpr int32_t MAX_MOUNT_INVALID_COUNT = 8;38constexpr int32_t MAX_MOUNT_INVALID_COUNT = 8;
38constexpr int32_t MIN_PARAM_SRC_PATH_LEN = 2;39constexpr int32_t MIN_PARAM_SRC_PATH_LEN = 2;
39 40 
@@ -126,6 +127,12 @@ const std::string g_hspList_key_modules = "modules";
126const std::string g_hspList_key_versions = "versions";127const std::string g_hspList_key_versions = "versions";
127const std::string g_sandboxHspInstallPath = "/data/storage/el1/bundle/";128const std::string g_sandboxHspInstallPath = "/data/storage/el1/bundle/";
128 129 
130+/* IPCGroup */
131+const std::string g_ipcGroupSrcPathPrefix = "/mnt/sandbox/shm/";
132+const std::string g_ipcGroupSandboxPathPrefix = "/dev/group/shm/";
133+const std::string g_ipcGroupList_key_groupId = "ipcGroupId";
134+const std::string g_ipcGroupList_key_groupGid = "ipcGroupGid";
135+ 
129/* DataGroup */136/* DataGroup */
130const std::string DATA_GROUP_SOCKET_TYPE = "DataGroup";137const std::string DATA_GROUP_SOCKET_TYPE = "DataGroup";
131const std::string g_groupList_key_dataGroupId = "dataGroupId";138const std::string g_groupList_key_dataGroupId = "dataGroupId";
@@ -18,6 +18,7 @@
18#include <memory>18#include <memory>
19#include <string>19#include <string>
20#include <vector>20#include <vector>
21+#include <unistd.h>
21 22 
22#include "appspawn_server.h"23#include "appspawn_server.h"
23#include "appspawn_service.h"24#include "appspawn_service.h"
@@ -541,4 +542,700 @@ HWTEST_F(AppSpawnSandboxCoreTest, SetPermissionAppSandboxProperty_01, TestSize.L
541 DeleteAppSpawningCtx(appProperty);542 DeleteAppSpawningCtx(appProperty);
542}543}
543 544 
545+/**
soulrequiem
soulrequiemsoulrequiem3 天前

low test/unittest/app_spawn_standard_test/app_spawn_sandbox_normal_test/app_spawn_sandbox_core_test.cpp:545

问题:测试 10/11/15-18 真实创建 /mnt/sandbox/shm/100/group/* 且可能真实 bind mount(设备 root 下 DoAppSandboxMountOnce 非 stub 路径会成功),但仅 rmdir 一层且无 umount,重复执行残留挂载点与父目录。另外测试用硬编码 "IPCGroup" 字符串而非 MSG_EXT_NAME_IPC_GROUP 宏。

证据:MountIPCGroup_10/11 注释自述 mount will likely fail in test env,但设备 root 环境下路径可达时实际会成功。

建议:teardown 中 umount 沙箱内挂载点并递归清理父目录;字符串统一使用宏。

likedislike
546+ * @tc.name: MountIPCGroup_01
547+ * @tc.desc: Test MountIPCGroup with appProperty nullptr
548+ * Branch: appProperty == nullptrreturn 0
549+ * @tc.type: FUNC
550+ * @tc.require: issueI5NTX6
551+ */
552+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_01, TestSize.Level0)
553+{
554+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
555+ int ret = AppSpawn::SandboxCore::MountIPCGroup(nullptr, sandboxPackagePath);
556+ EXPECT_EQ(ret, 0);
557+}
558+ 
559+/**
560+ * @tc.name: MountIPCGroup_02
561+ * @tc.desc: Test MountIPCGroup with empty sandboxPackagePath
562+ * Branch: sandboxPackagePath == ""return 0
563+ * @tc.type: FUNC
564+ * @tc.require: issueI5NTX6
565+ */
566+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_02, TestSize.Level0)
567+{
568+ g_testHelperCore.SetProcessName("com.ohos.test.app");
569+ g_testHelperCore.SetTestApl("normal");
570+ 
571+ AppSpawningCtx *appProperty = GetTestAppPropertyCore();
572+ ASSERT_NE(appProperty, nullptr);
573+ 
574+ std::string sandboxPackagePath = "";
575+ int ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
576+ EXPECT_EQ(ret, 0);
577+ 
578+ DeleteAppSpawningCtx(appProperty);
579+}
580+ 
581+/**
582+ * @tc.name: MountIPCGroup_03
583+ * @tc.desc: Test MountIPCGroup with no IPCGroup ext info
584+ * Branch: ipcGroupRoot == nullptrreturn 0
585+ * @tc.type: FUNC
586+ * @tc.require: issueI5NTX6
587+ */
588+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_03, TestSize.Level0)
589+{
590+ g_testHelperCore.SetProcessName("com.ohos.test.app");
591+ g_testHelperCore.SetTestApl("normal");
592+ 
593+ AppSpawningCtx *appProperty = GetTestAppPropertyCore();
594+ ASSERT_NE(appProperty, nullptr);
595+ 
596+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
597+ int ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
598+ EXPECT_EQ(ret, 0);
599+ 
600+ DeleteAppSpawningCtx(appProperty);
601+}
602+ 
603+/**
604+ * @tc.name: MountIPCGroup_04
605+ * @tc.desc: Test MountIPCGroup with empty IPCGroup array
606+ * Branch: HandleArrayForeach iterates nothing → return 0
607+ * @tc.type: FUNC
608+ * @tc.require: issueI5NTX6
609+ */
610+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_04, TestSize.Level0)
611+{
612+ AppSpawnClientHandle clientHandle = nullptr;
613+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
614+ ASSERT_EQ(ret, 0);
615+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
616+ clientHandle, MSG_APP_SPAWN, 0);
617+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
618+ 
619+ const char *appGroupInfo = R"([])";
620+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
621+ ASSERT_EQ(ret, 0);
622+ 
623+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
624+ clientHandle, reqHandle);
625+ ASSERT_NE(appProperty, nullptr);
626+ 
627+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
628+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
629+ EXPECT_EQ(ret, 0);
630+ 
631+ DeleteAppSpawningCtx(appProperty);
632+}
633+ 
634+/**
635+ * @tc.name: MountIPCGroup_05
636+ * @tc.desc: Test MountIPCGroup with array item missing ipcGroupId
637+ * Branch: ProcessIPCGroupItem groupIdItem == nullptrreturn -1, abort
638+ * @tc.type: FUNC
639+ * @tc.require: issueI5NTX6
640+ */
641+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_05, TestSize.Level0)
642+{
643+ AppSpawnClientHandle clientHandle = nullptr;
644+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
645+ ASSERT_EQ(ret, 0);
646+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
647+ clientHandle, MSG_APP_SPAWN, 0);
648+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
649+ 
650+ const char *appGroupInfo = R"([{"ipcGroupGid":"3000"}])";
651+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
652+ ASSERT_EQ(ret, 0);
653+ 
654+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
655+ clientHandle, reqHandle);
656+ ASSERT_NE(appProperty, nullptr);
657+ 
658+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
659+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
660+ // ProcessIPCGroupItem: groupIdItem == nullptr → return -1, abort
661+ EXPECT_EQ(ret, -1);
662+ 
663+ DeleteAppSpawningCtx(appProperty);
664+}
665+ 
666+/**
667+ * @tc.name: MountIPCGroup_06
668+ * @tc.desc: Test MountIPCGroup with ipcGroupId as non-string type (number)
669+ * Branch: ProcessIPCGroupItem !cJSON_IsString(groupIdItem) → return -1, abort
670+ * @tc.type: FUNC
671+ * @tc.require: issueI5NTX6
672+ */
673+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_06, TestSize.Level0)
674+{
675+ AppSpawnClientHandle clientHandle = nullptr;
676+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
677+ ASSERT_EQ(ret, 0);
678+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
679+ clientHandle, MSG_APP_SPAWN, 0);
680+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
681+ 
682+ const char *appGroupInfo = R"([{"ipcGroupId":12345,"ipcGroupGid":"3000"}])";
683+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
684+ ASSERT_EQ(ret, 0);
685+ 
686+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
687+ clientHandle, reqHandle);
688+ ASSERT_NE(appProperty, nullptr);
689+ 
690+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
691+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
692+ // ProcessIPCGroupItem: !cJSON_IsString → return -1, abort
693+ EXPECT_EQ(ret, -1);
694+ 
695+ DeleteAppSpawningCtx(appProperty);
696+}
697+ 
698+/**
699+ * @tc.name: MountIPCGroup_07
700+ * @tc.desc: Test MountIPCGroup with empty string ipcGroupId
701+ * Branch: ProcessIPCGroupItem strlen == 0return -1, abort
702+ * @tc.type: FUNC
703+ * @tc.require: issueI5NTX6
704+ */
705+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_07, TestSize.Level0)
706+{
707+ AppSpawnClientHandle clientHandle = nullptr;
708+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
709+ ASSERT_EQ(ret, 0);
710+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
711+ clientHandle, MSG_APP_SPAWN, 0);
712+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
713+ 
714+ const char *appGroupInfo = R"([{"ipcGroupId":"","ipcGroupGid":"3000"}])";
715+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
716+ ASSERT_EQ(ret, 0);
717+ 
718+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
719+ clientHandle, reqHandle);
720+ ASSERT_NE(appProperty, nullptr);
721+ 
722+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
723+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
724+ // ProcessIPCGroupItem: strlen == 0 → return -1, abort
725+ EXPECT_EQ(ret, -1);
726+ 
727+ DeleteAppSpawningCtx(appProperty);
728+}
729+ 
730+/**
731+ * @tc.name: MountIPCGroup_08
732+ * @tc.desc: Test MountIPCGroup with array item missing ipcGroupGid
733+ * Branch: ProcessIPCGroupItem groupGidItem == nullptrreturn -1, abort
734+ * @tc.type: FUNC
735+ * @tc.require: issueI5NTX6
736+ */
737+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_08, TestSize.Level0)
738+{
739+ AppSpawnClientHandle clientHandle = nullptr;
740+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
741+ ASSERT_EQ(ret, 0);
742+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
743+ clientHandle, MSG_APP_SPAWN, 0);
744+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
745+ 
746+ const char *appGroupInfo = R"([{"ipcGroupId":"308"}])";
747+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
748+ ASSERT_EQ(ret, 0);
749+ 
750+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
751+ clientHandle, reqHandle);
752+ ASSERT_NE(appProperty, nullptr);
753+ 
754+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
755+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
756+ // ProcessIPCGroupItem: groupGidItem == nullptr → return -1, abort
757+ EXPECT_EQ(ret, -1);
758+ 
759+ DeleteAppSpawningCtx(appProperty);
760+}
761+ 
762+/**
763+ * @tc.name: MountIPCGroup_09
764+ * @tc.desc: Test MountIPCGroup with ipcGroupGid as non-string type (number)
765+ * Branch: ProcessIPCGroupItem !cJSON_IsString(groupGidItem) → return -1, abort
766+ * @tc.type: FUNC
767+ * @tc.require: issueI5NTX6
768+ */
769+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_09, TestSize.Level0)
770+{
771+ AppSpawnClientHandle clientHandle = nullptr;
772+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
773+ ASSERT_EQ(ret, 0);
774+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
775+ clientHandle, MSG_APP_SPAWN, 0);
776+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
777+ 
778+ const char *appGroupInfo = R"([{"ipcGroupId":"309","ipcGroupGid":3000}])";
779+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
780+ ASSERT_EQ(ret, 0);
781+ 
782+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
783+ clientHandle, reqHandle);
784+ ASSERT_NE(appProperty, nullptr);
785+ 
786+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
787+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
788+ // ProcessIPCGroupItem: !cJSON_IsString(groupGidItem) → return -1, abort
789+ EXPECT_EQ(ret, -1);
790+ 
791+ DeleteAppSpawningCtx(appProperty);
792+}
793+ 
794+/**
795+ * @tc.name: MountIPCGroup_10
796+ * @tc.desc: Test MountIPCGroup with valid single-element IPCGroup array
797+ * Branch: ProcessIPCGroupItem valid → EnsureDirWithMode + mount → return 0
798+ * @tc.type: FUNC
799+ * @tc.require: issueI5NTX6
800+ */
801+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_10, TestSize.Level0)
802+{
803+ AppSpawnClientHandle clientHandle = nullptr;
804+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
805+ ASSERT_EQ(ret, 0);
806+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
807+ clientHandle, MSG_APP_SPAWN, 0);
808+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
809+ 
810+ const char *appGroupInfo =
811+ R"([{"ipcGroupId":"123","ipcGroupGid":"3000"}])";
812+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
813+ ASSERT_EQ(ret, 0);
814+ 
815+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
816+ clientHandle, reqHandle);
817+ ASSERT_NE(appProperty, nullptr);
818+ 
819+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
820+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
821+ // Valid data: srcPath = /mnt/sandbox/shm/100/group/123
822+ EXPECT_EQ(ret, 0);
823+ 
824+ rmdir("/mnt/sandbox/shm/100/group/123");
825+ DeleteAppSpawningCtx(appProperty);
826+}
827+ 
828+/**
829+ * @tc.name: MountIPCGroup_11
830+ * @tc.desc: Test MountIPCGroup with multi-element IPCGroup array
831+ * Branch: HandleArrayForeach iterates all items, all valid → return 0
832+ * @tc.type: FUNC
833+ * @tc.require: issueI5NTX6
834+ */
835+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_11, TestSize.Level0)
836+{
837+ AppSpawnClientHandle clientHandle = nullptr;
838+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
839+ ASSERT_EQ(ret, 0);
840+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
841+ clientHandle, MSG_APP_SPAWN, 0);
842+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
843+ 
844+ const char *appGroupInfo =
845+ R"([{"ipcGroupId":"133","ipcGroupGid":"3000"},)"
846+ R"({"ipcGroupId":"456","ipcGroupGid":"4000"}])";
847+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
848+ ASSERT_EQ(ret, 0);
849+ 
850+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
851+ clientHandle, reqHandle);
852+ ASSERT_NE(appProperty, nullptr);
853+ 
854+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
855+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
856+ EXPECT_EQ(ret, 0);
857+ 
858+ rmdir("/mnt/sandbox/shm/100/group/133");
859+ rmdir("/mnt/sandbox/shm/100/group/456");
860+ DeleteAppSpawningCtx(appProperty);
861+}
862+ 
863+/**
864+ * @tc.name: MountIPCGroup_12
865+ * @tc.desc: Test MountIPCGroup with first item valid, second item invalid
866+ * Branch: HandleArrayForeach aborts on second item → return -1
867+ * @tc.type: FUNC
868+ * @tc.require: issueI5NTX6
869+ */
870+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_12, TestSize.Level0)
871+{
872+ AppSpawnClientHandle clientHandle = nullptr;
873+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
874+ ASSERT_EQ(ret, 0);
875+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
876+ clientHandle, MSG_APP_SPAWN, 0);
877+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
878+ 
879+ const char *appGroupInfo =
880+ R"([{"ipcGroupId":"140","ipcGroupGid":"3000"},)"
881+ R"({"ipcGroupId":"abc","ipcGroupGid":"4000"}])";
882+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
883+ ASSERT_EQ(ret, 0);
884+ 
885+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
886+ clientHandle, reqHandle);
887+ ASSERT_NE(appProperty, nullptr);
888+ 
889+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
890+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
891+ // item 0 valid → return 0, item 1 non-numeric groupId → return -1 → abort
892+ EXPECT_EQ(ret, -1);
893+ 
894+ rmdir("/mnt/sandbox/shm/100/group/140");
895+ DeleteAppSpawningCtx(appProperty);
896+}
897+ 
898+/**
899+ * @tc.name: MountIPCGroup_13
900+ * @tc.desc: Test MountIPCGroup with ipcGroupGid as non-numeric string
901+ * Branch: ProcessIPCGroupItem atoi == 0 → groupGid == 0return -1, abort
902+ * @tc.type: FUNC
903+ * @tc.require: issueI5NTX6
904+ */
905+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_13, TestSize.Level0)
906+{
907+ AppSpawnClientHandle clientHandle = nullptr;
908+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
909+ ASSERT_EQ(ret, 0);
910+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
911+ clientHandle, MSG_APP_SPAWN, 0);
912+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
913+ 
914+ const char *appGroupInfo =
915+ R"([{"ipcGroupId":"312","ipcGroupGid":"not_a_number"}])";
916+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
917+ ASSERT_EQ(ret, 0);
918+ 
919+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
920+ clientHandle, reqHandle);
921+ ASSERT_NE(appProperty, nullptr);
922+ 
923+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
924+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
925+ // ProcessIPCGroupItem: atoi == 0 → groupGid == 0 → return -1, abort
926+ EXPECT_EQ(ret, -1);
927+ 
928+ DeleteAppSpawningCtx(appProperty);
929+}
930+ 
931+/**
932+ * @tc.name: MountIPCGroup_14
933+ * @tc.desc: Test MountIPCGroup with non-numeric ipcGroupId
934+ * Branch: ProcessIPCGroupItem find_first_not_of != npos → return -1, abort
935+ * @tc.type: FUNC
936+ * @tc.require: issueI5NTX6
937+ */
938+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_14, TestSize.Level0)
939+{
940+ AppSpawnClientHandle clientHandle = nullptr;
941+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
942+ ASSERT_EQ(ret, 0);
943+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
944+ clientHandle, MSG_APP_SPAWN, 0);
945+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
946+ 
947+ const char *appGroupInfo =
948+ R"([{"ipcGroupId":"123abc","ipcGroupGid":"3000"}])";
949+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
950+ ASSERT_EQ(ret, 0);
951+ 
952+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
953+ clientHandle, reqHandle);
954+ ASSERT_NE(appProperty, nullptr);
955+ 
956+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
957+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
958+ // ProcessIPCGroupItem: non-numeric groupId → return -1, abort
959+ EXPECT_EQ(ret, -1);
960+ 
961+ DeleteAppSpawningCtx(appProperty);
962+}
963+ 
964+/**
965+ * @tc.name: MountIPCGroup_15
966+ * @tc.desc: Test MountIPCGroup with appProperty missing DAC info
967+ * Branch: dacInfo == nullptr → cJSON_Delete + return 0
968+ * @tc.type: FUNC
969+ * @tc.require: issueI5NTX6
970+ */
971+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_15, TestSize.Level0)
972+{
973+ AppSpawnClientHandle clientHandle = nullptr;
974+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
975+ ASSERT_EQ(ret, 0);
976+ // MSG_DUMP: valid msgType but not spawn type → CreateMsg skips AddDacInfo → no TLV_DAC_INFO
977+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
978+ clientHandle, MSG_DUMP, 0);
979+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
980+ 
981+ const char *appGroupInfo =
982+ R"([{"ipcGroupId":"316","ipcGroupGid":"3000"}])";
983+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
984+ ASSERT_EQ(ret, 0);
985+ 
986+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
987+ clientHandle, reqHandle);
988+ ASSERT_NE(appProperty, nullptr);
989+ 
990+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
991+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
992+ // dacInfo == nullptr → cJSON_Delete + return 0, HandleArrayForeach not reached
993+ EXPECT_EQ(ret, 0);
994+ 
995+ DeleteAppSpawningCtx(appProperty);
996+}
997+ 
998+/**
999+ * @tc.name: MountIPCGroup_16
1000+ * @tc.desc: Test MountIPCGroup with pre-existing src dir owned by non-root
1001+ * Branch: EnsureDirWithMode stat ok, uid mismatch → recreate → mount → return 0
1002+ * @tc.type: FUNC
1003+ * @tc.require: issueI5NTX6
1004+ */
1005+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_16, TestSize.Level0)
1006+{
1007+ AppSpawnClientHandle clientHandle = nullptr;
1008+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
1009+ ASSERT_EQ(ret, 0);
1010+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
1011+ clientHandle, MSG_APP_SPAWN, 0);
1012+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
1013+ 
1014+ const char *appGroupInfo =
1015+ R"([{"ipcGroupId":"3017","ipcGroupGid":"3000"}])";
1016+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
1017+ ASSERT_EQ(ret, 0);
1018+ 
1019+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
1020+ clientHandle, reqHandle);
1021+ ASSERT_NE(appProperty, nullptr);
1022+ 
1023+ // Pre-create src dir with wrong owner (uid=1000, not root)
1024+ std::string srcPath = "/mnt/sandbox/shm/100/group/3017";
1025+ SandboxCommon::CreateDirRecursive(srcPath, SandboxCommonDef::FILE_MODE);
1026+ chown(srcPath.c_str(), 1000, 1000);
1027+ 
1028+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
1029+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
1030+ // EnsureDirWithMode: stat ok, uid=1000 != 0 → recreate → mount → ret=0
1031+ EXPECT_EQ(ret, 0);
1032+ 
1033+ rmdir(srcPath.c_str());
1034+ DeleteAppSpawningCtx(appProperty);
1035+}
1036+ 
1037+/**
1038+ * @tc.name: MountIPCGroup_17
1039+ * @tc.desc: Test MountIPCGroup with pre-existing src dir, correct uid but wrong gid
1040+ * Branch: EnsureDirWithMode stat ok, gid mismatch → recreate → mount → return 0
1041+ * @tc.type: FUNC
1042+ * @tc.require: issueI5NTX6
1043+ */
1044+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_17, TestSize.Level0)
1045+{
1046+ AppSpawnClientHandle clientHandle = nullptr;
1047+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
1048+ ASSERT_EQ(ret, 0);
1049+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
1050+ clientHandle, MSG_APP_SPAWN, 0);
1051+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
1052+ 
1053+ const char *appGroupInfo =
1054+ R"([{"ipcGroupId":"3018","ipcGroupGid":"3000"}])";
1055+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
1056+ ASSERT_EQ(ret, 0);
1057+ 
1058+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
1059+ clientHandle, reqHandle);
1060+ ASSERT_NE(appProperty, nullptr);
1061+ 
1062+ // Pre-create src dir as root → uid=0, gid=0 (gid != groupGid 3000)
1063+ std::string srcPath = "/mnt/sandbox/shm/100/group/3018";
1064+ SandboxCommon::CreateDirRecursive(srcPath, SandboxCommonDef::FILE_MODE);
1065+ 
1066+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
1067+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
1068+ // EnsureDirWithMode: stat ok, uid==0, gid=0 != 3000 → recreate → mount → ret=0
1069+ EXPECT_EQ(ret, 0);
1070+ 
1071+ rmdir(srcPath.c_str());
1072+ DeleteAppSpawningCtx(appProperty);
1073+}
1074+ 
1075+/**
1076+ * @tc.name: MountIPCGroup_18
1077+ * @tc.desc: Test MountIPCGroup with pre-existing src dir, correct owner but wrong mode
1078+ * Branch: EnsureDirWithMode stat ok, mode mismatch → recreate → mount → return 0
1079+ * @tc.type: FUNC
1080+ * @tc.require: issueI5NTX6
1081+ */
1082+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_18, TestSize.Level0)
1083+{
1084+ AppSpawnClientHandle clientHandle = nullptr;
1085+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
1086+ ASSERT_EQ(ret, 0);
1087+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
1088+ clientHandle, MSG_APP_SPAWN, 0);
1089+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
1090+ 
1091+ const char *appGroupInfo =
1092+ R"([{"ipcGroupId":"3019","ipcGroupGid":"3000"}])";
1093+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
1094+ ASSERT_EQ(ret, 0);
1095+ 
1096+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
1097+ clientHandle, reqHandle);
1098+ ASSERT_NE(appProperty, nullptr);
1099+ 
1100+ // Pre-create src dir with correct owner but wrong mode
1101+ std::string srcPath = "/mnt/sandbox/shm/100/group/3019";
1102+ SandboxCommon::CreateDirRecursive(srcPath, SandboxCommonDef::FILE_MODE);
1103+ chown(srcPath.c_str(), 0, 3000);
1104+ chmod(srcPath.c_str(), 0755);
1105+ 
1106+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
1107+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
1108+ // EnsureDirWithMode: stat ok, uid==0, gid==3000, mode=0755 != 01771 → recreate → mount → ret=0
1109+ EXPECT_EQ(ret, 0);
1110+ 
1111+ rmdir(srcPath.c_str());
1112+ DeleteAppSpawningCtx(appProperty);
1113+}
1114+ 
1115+/**
1116+ * @tc.name: MountIPCGroup_19
1117+ * @tc.desc: Test MountIPCGroup with pre-existing src dir, all metadata correct
1118+ * Branch: EnsureDirWithMode stat ok, all match → skip creation → mount → return 0
1119+ * @tc.type: FUNC
1120+ * @tc.require: issueI5NTX6
1121+ */
1122+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_19, TestSize.Level0)
1123+{
1124+ AppSpawnClientHandle clientHandle = nullptr;
1125+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
1126+ ASSERT_EQ(ret, 0);
1127+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
1128+ clientHandle, MSG_APP_SPAWN, 0);
1129+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
1130+ 
1131+ const char *appGroupInfo =
1132+ R"([{"ipcGroupId":"3020","ipcGroupGid":"3000"}])";
1133+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
1134+ ASSERT_EQ(ret, 0);
1135+ 
1136+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
1137+ clientHandle, reqHandle);
1138+ ASSERT_NE(appProperty, nullptr);
1139+ 
1140+ // Pre-create src dir with fully correct metadata
1141+ std::string srcPath = "/mnt/sandbox/shm/100/group/3020";
1142+ SandboxCommon::CreateDirRecursive(srcPath, SandboxCommonDef::FILE_MODE);
1143+ chown(srcPath.c_str(), 0, 3000);
1144+ chmod(srcPath.c_str(), SandboxCommonDef::IPC_GROUP_SRC_PATH_MODE);
1145+ 
1146+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
1147+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
1148+ // EnsureDirWithMode: stat ok, all match → skip creation → mount → ret=0
1149+ EXPECT_EQ(ret, 0);
1150+ 
1151+ rmdir(srcPath.c_str());
1152+ DeleteAppSpawningCtx(appProperty);
1153+}
1154+ 
1155+/**
1156+ * @tc.name: MountIPCGroup_20
1157+ * @tc.desc: Test MountIPCGroup with mount failure (non-fatal)
1158+ * Branch: ProcessIPCGroupItem mount fails → log only, return 0 (continue)
1159+ * @tc.type: FUNC
1160+ * @tc.require: issueI5NTX6
1161+ */
1162+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_20, TestSize.Level0)
1163+{
1164+ AppSpawnClientHandle clientHandle = nullptr;
1165+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
1166+ ASSERT_EQ(ret, 0);
1167+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
1168+ clientHandle, MSG_APP_SPAWN, 0);
1169+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
1170+ 
1171+ const char *appGroupInfo =
1172+ R"([{"ipcGroupId":"3021","ipcGroupGid":"3000"}])";
1173+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
1174+ ASSERT_EQ(ret, 0);
1175+ 
1176+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
1177+ clientHandle, reqHandle);
1178+ ASSERT_NE(appProperty, nullptr);
1179+ 
1180+ // Configure MountStub to return failure:
1181+ // originPath must MATCH the actual srcPath so the if-check passes,
1182+ // then destinationPath mismatches → result=0 → errno=-EINVAL → mount fails
1183+ StubNode *node = GetStubNode(STUB_MOUNT);
1184+ MountTestArg mountArg = {
1185+ "/mnt/sandbox/shm/100/group/3021", // matches actual srcPath
1186+ "/wrong_dest", // mismatches actual destPath → failure
1187+ "", // fsType (non-NULL, printf-safe)
1188+ 0, // mountFlags (mismatches MS_REC|MS_BIND)
1189+ "", // options (non-NULL, printf-safe)
1190+ 0 // mountSharedFlag
1191+ };
1192+ node->arg = &mountArg;
1193+ node->flags |= STUB_NEED_CHECK;
1194+ 
1195+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
1196+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
1197+ // mount fails → log only, return 0 (continue) → ret stays 0
1198+ EXPECT_EQ(ret, 0);
1199+ 
1200+ // Restore MountStub
1201+ node->flags &= ~STUB_NEED_CHECK;
1202+ node->arg = nullptr;
1203+ 
1204+ // Cleanup
1205+ rmdir("/mnt/sandbox/shm/100/group/3021");
1206+ DeleteAppSpawningCtx(appProperty);
1207+}
1208+ 
1209+/**
1210+ * @tc.name: MountIPCGroup_21
1211+ * @tc.desc: Test MountIPCGroup with IPCGroup ext info not an array
1212+ * Branch: !cJSON_IsArray(ipcGroupRoot) → cJSON_Delete + return 0
1213+ * @tc.type: FUNC
1214+ * @tc.require: issueI5NTX6
1215+ */
1216+HWTEST_F(AppSpawnSandboxCoreTest, MountIPCGroup_21, TestSize.Level0)
1217+{
1218+ AppSpawnClientHandle clientHandle = nullptr;
1219+ int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
1220+ ASSERT_EQ(ret, 0);
1221+ AppSpawnReqMsgHandle reqHandle = g_testHelperCore.CreateMsg(
1222+ clientHandle, MSG_APP_SPAWN, 0);
1223+ ASSERT_NE(reqHandle, INVALID_REQ_HANDLE);
1224+ 
1225+ const char *appGroupInfo = R"({})";
1226+ ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_IPC_GROUP, appGroupInfo);
1227+ ASSERT_EQ(ret, 0);
1228+ 
1229+ AppSpawningCtx *appProperty = g_testHelperCore.GetAppProperty(
1230+ clientHandle, reqHandle);
1231+ ASSERT_NE(appProperty, nullptr);
1232+ 
1233+ std::string sandboxPackagePath = "/mnt/sandbox/100/com.test.app";
1234+ ret = AppSpawn::SandboxCore::MountIPCGroup(appProperty, sandboxPackagePath);
1235+ // !cJSON_IsArray → cJSON_Delete + return 0
1236+ EXPECT_EQ(ret, 0);
1237+ 
1238+ DeleteAppSpawningCtx(appProperty);
1239+}
1240+ 
544} // namespace OHOS1241} // namespace OHOS