| @@ -1518,10 +1518,12 @@ int32_t SandboxCore::SetDecPolicyWithPermission(const AppSpawningCtx *appPropert | |||
| 1518 | APPSPAWN_CHECK(tokenInfo != nullptr, return APPSPAWN_MSG_INVALID, "Get token id failed."); | 1518 | APPSPAWN_CHECK(tokenInfo != nullptr, return APPSPAWN_MSG_INVALID, "Get token id failed."); |
| 1519 | 1519 | ||
| 1520 | DecPolicyInfo decPolicyInfo = {0}; | 1520 | DecPolicyInfo decPolicyInfo = {0}; |
| 1521 | - decPolicyInfo.pathNum = mountConfig.decPaths.size(); | 1521 | + uint32_t totalPaths = mountConfig.decPaths.size(); |
| 1522 | - // Kernel supports at most KERNEL_BATCH_SIZE DEC policies per request | 1522 | + decPolicyInfo.pathNum = (totalPaths > MAX_CONFIG_POLICY_NUM) ? MAX_CONFIG_POLICY_NUM : totalPaths; |
| 1523 | - APPSPAWN_CHECK(decPolicyInfo.pathNum <= KERNEL_BATCH_SIZE, return APPSPAWN_SANDBOX_DEC_OUT_BOUND, | 1523 | + if (totalPaths > MAX_CONFIG_POLICY_NUM) { |
| 1524 | - "dec policy out of bound %{public}d", decPolicyInfo.pathNum); | 1524 | + APPSPAWN_LOGW("dec policy %{public}u exceeds max %{public}d, truncating to first %{public}d", |
| 1525 | + totalPaths, MAX_CONFIG_POLICY_NUM, MAX_CONFIG_POLICY_NUM); | ||
| 1526 | + } | ||
W | |||
| 1525 | int ret = 0; | 1527 | int ret = 0; |
| 1526 | for (uint32_t i = 0; i < decPolicyInfo.pathNum; i++) { | 1528 | for (uint32_t i = 0; i < decPolicyInfo.pathNum; i++) { |
| 1527 | PathInfo pathInfo = {0}; | 1529 | PathInfo pathInfo = {0}; |
| @@ -1557,9 +1559,12 @@ int32_t SandboxCore::SetDecReadOnlyPolicyWithPermission( | |||
| 1557 | reinterpret_cast<AppSpawnMsgAccessToken *>(GetAppProperty(appProperty, TLV_ACCESS_TOKEN_INFO)); | 1559 | reinterpret_cast<AppSpawnMsgAccessToken *>(GetAppProperty(appProperty, TLV_ACCESS_TOKEN_INFO)); |
| 1558 | APPSPAWN_CHECK(tokenInfo != nullptr, return APPSPAWN_MSG_INVALID, "Get token id failed."); | 1560 | APPSPAWN_CHECK(tokenInfo != nullptr, return APPSPAWN_MSG_INVALID, "Get token id failed."); |
| 1559 | DecPolicyInfo decPolicyInfo = {0}; | 1561 | DecPolicyInfo decPolicyInfo = {0}; |
| 1560 | - decPolicyInfo.pathNum = mountConfig.decReadOnlyPaths.size(); | 1562 | + uint32_t totalReadOnlyPaths = mountConfig.decReadOnlyPaths.size(); |
| 1561 | - APPSPAWN_CHECK(decPolicyInfo.pathNum <= KERNEL_BATCH_SIZE, return APPSPAWN_SANDBOX_DEC_OUT_BOUND, | 1563 | + decPolicyInfo.pathNum = (totalReadOnlyPaths > MAX_CONFIG_POLICY_NUM) ? MAX_CONFIG_POLICY_NUM : totalReadOnlyPaths; |
| 1562 | - "dec read-only policy out of bound %{public}d", decPolicyInfo.pathNum); | 1564 | + if (totalReadOnlyPaths > MAX_CONFIG_POLICY_NUM) { |
| 1565 | + APPSPAWN_LOGW("dec read-only policy %{public}u exceeds max %{public}d, truncating to first %{public}d", | ||
| 1566 | + totalReadOnlyPaths, MAX_CONFIG_POLICY_NUM, MAX_CONFIG_POLICY_NUM); | ||
| 1567 | + } | ||
| 1563 | int ret = 0; | 1568 | int ret = 0; |
| 1564 | for (uint32_t i = 0; i < decPolicyInfo.pathNum; i++) { | 1569 | for (uint32_t i = 0; i < decPolicyInfo.pathNum; i++) { |
| 1565 | PathInfo pathInfo = {0}; | 1570 | PathInfo pathInfo = {0}; |
| @@ -1607,7 +1612,7 @@ void SandboxCore::SetDecDenyWithDir(const AppSpawningCtx *appProperty) | |||
| 1607 | if (CheckAppPermissionFlagSet(appProperty, static_cast<uint32_t>(index))) { | 1612 | if (CheckAppPermissionFlagSet(appProperty, static_cast<uint32_t>(index))) { |
| 1608 | continue; | 1613 | continue; |
| 1609 | } | 1614 | } |
| 1610 | - APPSPAWN_CHECK(j < KERNEL_BATCH_SIZE, return, "dec policy out of bound currentIndex %{public}d", j); | 1615 | + APPSPAWN_CHECK(j < MAX_CONFIG_POLICY_NUM, return, "dec policy out of bound currentIndex %{public}d", j); |
| 1611 | PathInfo pathInfo = {0}; | 1616 | PathInfo pathInfo = {0}; |
| 1612 | pathInfo.path = const_cast<char *>(DEC_DENY_PATH_MAP[i].decPath); | 1617 | pathInfo.path = const_cast<char *>(DEC_DENY_PATH_MAP[i].decPath); |
| 1613 | pathInfo.pathLen = static_cast<uint32_t>(strlen(pathInfo.path)); | 1618 | pathInfo.pathLen = static_cast<uint32_t>(strlen(pathInfo.path)); |
| @@ -25,6 +25,24 @@ | |||
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | 27 | ||
| 28 | +// Kernel ABI batch type for DEC ioctl. path capacity is fixed to KERNEL_BATCH_SIZE. | ||
| 29 | +// Used by all DEC batch ioctl commands to keep _IOWR/_IOW size consistent with the kernel. | ||
| 30 | +typedef struct IoctlDecPolicyBatch { | ||
| 31 | + uint64_t tokenId; | ||
| 32 | + uint64_t timestamp; | ||
| 33 | + PathInfo path[KERNEL_BATCH_SIZE]; | ||
| 34 | + uint32_t pathNum; | ||
| 35 | + int32_t userId; | ||
| 36 | + uint64_t reserved[DEC_POLICY_HEADER_RESERVED]; | ||
| 37 | + bool flag; | ||
| 38 | +} IoctlDecPolicyBatch; | ||
| 39 | + | ||
| 40 | +// Internal ioctl commands, all based on IoctlDecPolicyBatch (path[KERNEL_BATCH_SIZE]). | ||
| 41 | + | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + | ||
| 45 | + | ||
| 28 | static const char *g_decConstraintDir[] = { | 46 | static const char *g_decConstraintDir[] = { |
| 29 | "/storage/Users", | 47 | "/storage/Users", |
| 30 | "/storage/External", | 48 | "/storage/External", |
| @@ -47,28 +65,35 @@ APPSPAWN_STATIC int SetIgnoreCaseDirs(AppSpawnMgr *content) | |||
| 47 | 65 | ||
| 48 | uint32_t pathNum = 0; | 66 | uint32_t pathNum = 0; |
| 49 | const DecIgnoreCaseInfo *setInfo = GetDecIgnoreCaseList(IsNoShareFsEnable(), &pathNum); | 67 | const DecIgnoreCaseInfo *setInfo = GetDecIgnoreCaseList(IsNoShareFsEnable(), &pathNum); |
| 50 | - APPSPAWN_CHECK(setInfo != NULL && pathNum > 0, return 0, "invalid dec ignore case list"); | 68 | + APPSPAWN_CHECK(setInfo != NULL && pathNum > 0 && pathNum <= MAX_POLICY_NUM, return 0, |
| 69 | + "invalid dec ignore case list %{public}u", pathNum); | ||
| 51 | const char *decFilename = "/dev/dec"; | 70 | const char *decFilename = "/dev/dec"; |
| 52 | int fd = open(decFilename, O_RDWR); | 71 | int fd = open(decFilename, O_RDWR); |
| 53 | APPSPAWN_CHECK(fd >= 0, return 0, "Open dec file failed errno %{public}d", errno); | 72 | APPSPAWN_CHECK(fd >= 0, return 0, "Open dec file failed errno %{public}d", errno); |
| 54 | 73 | ||
| 55 | - DecPolicyInfo decPolicyInfos = {0}; | 74 | + uint32_t batches = (pathNum + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; |
| 56 | - decPolicyInfos.tokenId = 0; | 75 | + for (uint32_t batch = 0; batch < batches; batch++) { |
| 57 | - decPolicyInfos.pathNum = pathNum; | 76 | + uint32_t start = batch * KERNEL_BATCH_SIZE; |
| 58 | - decPolicyInfos.flag = 0; | 77 | + uint32_t end = start + KERNEL_BATCH_SIZE; |
W 🤖 AI 代码检视意见 | 🛡️ Reliability | ✅ Low | 行号区间: L73-L76 问题描述:
在SetIgnoreCaseDirs、SetDenyConstraintDirs、SetForcedPrefixDirs中均使用 💡 查看修复建议(点击展开)修改建议:在计算批次数前增加pathNum上限校验,或者使用安全的除法上取整宏避免溢出风险。
![]() ![]() | |||
| 59 | - | 78 | + APPSPAWN_ONLY_EXPER(end > pathNum, end = pathNum); |
| 60 | - for (uint32_t i = 0; i < pathNum; i++) { | 79 | + IoctlDecPolicyBatch decPolicyInfos = {0}; |
| 61 | - PathInfo pathInfo = { | 80 | + decPolicyInfos.pathNum = end - start; |
| 62 | - .path = (char *)setInfo[i].path, | 81 | + for (uint32_t i = start; i < end; i++) { |
| 63 | - .pathLen = (uint32_t)strlen(setInfo[i].path), | 82 | + PathInfo pathInfo = { |
| 64 | - .mode = (uint32_t)setInfo[i].mode, | 83 | + .path = (char *)setInfo[i].path, |
| 65 | - .flag = false | 84 | + .pathLen = (uint32_t)strlen(setInfo[i].path), |
| 66 | - }; | 85 | + .mode = (uint32_t)setInfo[i].mode, |
| 67 | - APPSPAWN_LOGV("set ignore case dec policy %{public}s %{public}d", setInfo[i].path, setInfo[i].mode); | 86 | + .flag = false |
| 68 | - decPolicyInfos.path[i] = pathInfo; | 87 | + }; |
W 🤖 AI 代码检视意见 | 🔒 Security | ✅ Low | 行号区间: L84-L88 问题描述:
SetIgnoreCaseDirs、SetDenyConstraintDirs、SetForcedPrefixDirs函数中均存在 💡 查看修复建议(点击展开)修改建议:PathInfo.path字段类型保持为char*,但在赋值时显式说明这是只读借用,或者使用局部缓冲区拷贝,避免对只读数据去const。
![]() ![]() | |||
| 88 | + APPSPAWN_LOGV("set ignore case dec policy %{public}s %{public}d", setInfo[i].path, setInfo[i].mode); | ||
| 89 | + decPolicyInfos.path[i - start] = pathInfo; | ||
| 90 | + } | ||
| 91 | + int ret = ioctl(fd, SET_DEC_IGNORE_CASE_CMD, &decPolicyInfos); | ||
| 92 | + APPSPAWN_CHECK(ret >= 0, continue, "set dec ignore failed errno %{public}d", errno); | ||
| 93 | + for (uint32_t i = start; i < end; i++) { | ||
| 94 | + APPSPAWN_DUMPI("set dec ignore case %{public}s", setInfo[i].path); | ||
| 95 | + } | ||
| 69 | } | 96 | } |
| 70 | - int ret = ioctl(fd, SET_DEC_IGNORE_CASE_CMD, &decPolicyInfos); | ||
| 71 | - APPSPAWN_CHECK_ONLY_LOG(ret >= 0, "set dec ignore failed errno %{public}d", errno); | ||
| 72 | close(fd); | 97 | close(fd); |
| 73 | return 0; | 98 | return 0; |
| 74 | } | 99 | } |
| @@ -99,6 +124,11 @@ void SetDecPolicyInfos(DecPolicyInfo *decPolicyInfos) | |||
| 99 | if (decPolicyInfos == NULL || decPolicyInfos->pathNum == 0) { | 124 | if (decPolicyInfos == NULL || decPolicyInfos->pathNum == 0) { |
| 100 | return; | 125 | return; |
| 101 | } | 126 | } |
| 127 | + // Defensive clamp: DecPolicyInfo.path[] capacity is MAX_CONFIG_POLICY_NUM | ||
| 128 | + APPSPAWN_CHECK_LOGW(decPolicyInfos->pathNum <= MAX_CONFIG_POLICY_NUM, | ||
| 129 | + decPolicyInfos->pathNum = MAX_CONFIG_POLICY_NUM, | ||
| 130 | + "DecPolicy pathNum %{public}u exceeds path capacity %{public}d, clamp", | ||
| 131 | + decPolicyInfos->pathNum, MAX_CONFIG_POLICY_NUM); | ||
| 102 | 132 | ||
| 103 | if (g_decPolicyInfos == NULL) { | 133 | if (g_decPolicyInfos == NULL) { |
| 104 | g_decPolicyInfos = (GlobalDecPolicyInfo *)calloc(1, sizeof(GlobalDecPolicyInfo)); | 134 | g_decPolicyInfos = (GlobalDecPolicyInfo *)calloc(1, sizeof(GlobalDecPolicyInfo)); |
| @@ -108,35 +138,37 @@ void SetDecPolicyInfos(DecPolicyInfo *decPolicyInfos) | |||
| 108 | } | 138 | } |
| 109 | } | 139 | } |
| 110 | 140 | ||
| 111 | - APPSPAWN_CHECK(g_decPolicyInfos->pathNum + decPolicyInfos->pathNum <= MAX_POLICY_NUM, | 141 | + if (g_decPolicyInfos->pathNum + decPolicyInfos->pathNum > MAX_POLICY_NUM) { |
| 112 | - DestroyDecPolicyInfos(g_decPolicyInfos); | 142 | + APPSPAWN_LOGW("DecPolicy exceeds MAX_POLICY_NUM %{public}d, cur=%{public}u, add=%{public}u, partial apply", |
| 113 | - g_decPolicyInfos = NULL; | 143 | + MAX_POLICY_NUM, g_decPolicyInfos->pathNum, decPolicyInfos->pathNum); |
| 114 | - return, "Out of MAX_POLICY_NUM %{public}d, %{public}d", g_decPolicyInfos->pathNum, decPolicyInfos->pathNum); | 144 | + } |
| 115 | for (uint32_t i = 0; i < decPolicyInfos->pathNum; i++) { | 145 | for (uint32_t i = 0; i < decPolicyInfos->pathNum; i++) { |
| 146 | + if (g_decPolicyInfos->pathNum >= MAX_POLICY_NUM) { | ||
| 147 | + APPSPAWN_LOGW("DecPolicy full at MAX_POLICY_NUM %{public}d, skip remaining", MAX_POLICY_NUM); | ||
| 148 | + break; | ||
| 149 | + } | ||
| 116 | PathInfo pathInfo = {0}; | 150 | PathInfo pathInfo = {0}; |
| 117 | if (decPolicyInfos->path[i].path == NULL) { | 151 | if (decPolicyInfos->path[i].path == NULL) { |
| 118 | - DestroyDecPolicyInfos(g_decPolicyInfos); | 152 | + APPSPAWN_LOGW("DecPolicy path[%{public}u] is NULL, skip", i); |
| 119 | - g_decPolicyInfos = NULL; | 153 | + continue; |
| 120 | - return; | ||
| 121 | } | 154 | } |
| 122 | pathInfo.path = strdup(decPolicyInfos->path[i].path); | 155 | pathInfo.path = strdup(decPolicyInfos->path[i].path); |
W 🤖 AI 代码检视意见 | 🔒 Security | ⚠️ High | 行号区间: L138-L148 问题描述:
DecPolicyInfo结构体中path[]数组容量为MAX_CONFIG_POLICY_NUM(32),但SetDecPolicyInfos函数中的循环条件为 💡 查看修复建议(点击展开)修改建议:在循环开始前对decPolicyInfos->pathNum做上限校验,确保不超过MAX_CONFIG_POLICY_NUM,避免越界读取。
![]() ![]() | |||
| 123 | if (pathInfo.path == NULL) { | 156 | if (pathInfo.path == NULL) { |
| 124 | - DestroyDecPolicyInfos(g_decPolicyInfos); | 157 | + APPSPAWN_LOGW("DecPolicy path[%{public}u] %{public}s strdup failed, skip", |
| 125 | - g_decPolicyInfos = NULL; | 158 | + i, decPolicyInfos->path[i].path); |
| 126 | - return; | 159 | + continue; |
| 127 | } | 160 | } |
| 128 | pathInfo.pathLen = (uint32_t)strlen(pathInfo.path); | 161 | pathInfo.pathLen = (uint32_t)strlen(pathInfo.path); |
| 129 | pathInfo.mode = decPolicyInfos->path[i].mode; | 162 | pathInfo.mode = decPolicyInfos->path[i].mode; |
| 130 | - uint32_t index = g_decPolicyInfos->pathNum + i; | 163 | + g_decPolicyInfos->path[g_decPolicyInfos->pathNum] = pathInfo; |
| 131 | - g_decPolicyInfos->path[index] = pathInfo; | 164 | + g_decPolicyInfos->pathNum++; |
| 132 | } | 165 | } |
| 133 | g_decPolicyInfos->tokenId = decPolicyInfos->tokenId; | 166 | g_decPolicyInfos->tokenId = decPolicyInfos->tokenId; |
| 134 | - g_decPolicyInfos->pathNum += decPolicyInfos->pathNum; | ||
| 135 | g_decPolicyInfos->flag = false; | 167 | g_decPolicyInfos->flag = false; |
| 136 | g_decPolicyInfos->userId = 0; | 168 | g_decPolicyInfos->userId = 0; |
| 137 | } | 169 | } |
| 138 | 170 | ||
| 139 | -static int SetDenyConstraintDirs(AppSpawnMgr *content) | 171 | +APPSPAWN_STATIC int SetDenyConstraintDirs(AppSpawnMgr *content) |
| 140 | { | 172 | { |
| 141 | UNUSED(content); | 173 | UNUSED(content); |
| 142 | const char *decFilename = "/dev/dec"; | 174 | const char *decFilename = "/dev/dec"; |
| @@ -144,29 +176,31 @@ static int SetDenyConstraintDirs(AppSpawnMgr *content) | |||
| 144 | APPSPAWN_CHECK(fd >= 0, return 0, "Open dec file failed errno %{public}d", errno); | 176 | APPSPAWN_CHECK(fd >= 0, return 0, "Open dec file failed errno %{public}d", errno); |
| 145 | 177 | ||
| 146 | uint32_t decDirsSize = ARRAY_LENGTH(g_decConstraintDir); | 178 | uint32_t decDirsSize = ARRAY_LENGTH(g_decConstraintDir); |
| 147 | - DecPolicyInfo decPolicyInfos = {0}; | 179 | + uint32_t batches = (decDirsSize + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; |
| 148 | - decPolicyInfos.tokenId = 0; | 180 | + for (uint32_t batch = 0; batch < batches; batch++) { |
| 149 | - decPolicyInfos.pathNum = decDirsSize; | 181 | + uint32_t start = batch * KERNEL_BATCH_SIZE; |
| 150 | - decPolicyInfos.flag = 0; | 182 | + uint32_t end = start + KERNEL_BATCH_SIZE; |
| 151 | - | 183 | + APPSPAWN_ONLY_EXPER(end > decDirsSize, end = decDirsSize); |
| 152 | - for (uint32_t i = 0; i < decDirsSize; i++) { | 184 | + IoctlDecPolicyBatch decPolicyInfos = {0}; |
| 153 | - PathInfo pathInfo = {(char *)g_decConstraintDir[i], (uint32_t)strlen(g_decConstraintDir[i]), SANDBOX_MODE_READ}; | 185 | + decPolicyInfos.pathNum = end - start; |
| 154 | - decPolicyInfos.path[i] = pathInfo; | 186 | + for (uint32_t i = start; i < end; i++) { |
| 155 | - } | 187 | + PathInfo pathInfo = {(char *)g_decConstraintDir[i], |
| 156 | - | 188 | + (uint32_t)strlen(g_decConstraintDir[i]), SANDBOX_MODE_READ}; |
| 157 | - if (ioctl(fd, CONSTRAINT_DEC_POLICY_CMD, &decPolicyInfos) < 0) { | 189 | + decPolicyInfos.path[i - start] = pathInfo; |
| 158 | - APPSPAWN_LOGE("set deny constraint sandbox policy failed errno %{public}d", errno); | 190 | + } |
| 159 | - } else { | 191 | + int ret = ioctl(fd, CONSTRAINT_DEC_POLICY_CMD, &decPolicyInfos); |
| 192 | + APPSPAWN_CHECK(ret >= 0, continue, | ||
| 193 | + "set deny constraint sandbox policy failed errno %{public}d", errno); | ||
| 160 | APPSPAWN_LOGI("set CONSTRAINT_DEC_POLICY_CMD sandbox policy success"); | 194 | APPSPAWN_LOGI("set CONSTRAINT_DEC_POLICY_CMD sandbox policy success"); |
| 161 | - for (uint32_t i = 0; i < decPolicyInfos.pathNum; i++) { | 195 | + for (uint32_t i = start; i < end; i++) { |
| 162 | - APPSPAWN_DUMPI("%{public}s", decPolicyInfos.path[i].path); | 196 | + APPSPAWN_DUMPI("%{public}s", g_decConstraintDir[i]); |
| 163 | } | 197 | } |
| 164 | } | 198 | } |
| 165 | close(fd); | 199 | close(fd); |
| 166 | return 0; | 200 | return 0; |
| 167 | } | 201 | } |
| 168 | 202 | ||
| 169 | -static int SetForcedPrefixDirs(AppSpawnMgr *content) | 203 | +APPSPAWN_STATIC int SetForcedPrefixDirs(AppSpawnMgr *content) |
| 170 | { | 204 | { |
| 171 | UNUSED(content); | 205 | UNUSED(content); |
| 172 | const char *decFilename = "/dev/dec"; | 206 | const char *decFilename = "/dev/dec"; |
| @@ -174,22 +208,24 @@ static int SetForcedPrefixDirs(AppSpawnMgr *content) | |||
| 174 | APPSPAWN_CHECK(fd >= 0, return 0, "Open dec file failed errno %{public}d", errno); | 208 | APPSPAWN_CHECK(fd >= 0, return 0, "Open dec file failed errno %{public}d", errno); |
| 175 | 209 | ||
| 176 | uint32_t decDirsSize = ARRAY_LENGTH(g_decForcedPrefix); | 210 | uint32_t decDirsSize = ARRAY_LENGTH(g_decForcedPrefix); |
| 177 | - DecPolicyInfo decPolicyInfos = {0}; | 211 | + uint32_t batches = (decDirsSize + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; |
| 178 | - decPolicyInfos.tokenId = 0; | 212 | + for (uint32_t batch = 0; batch < batches; batch++) { |
| 179 | - decPolicyInfos.pathNum = decDirsSize; | 213 | + uint32_t start = batch * KERNEL_BATCH_SIZE; |
| 180 | - decPolicyInfos.flag = 0; | 214 | + uint32_t end = start + KERNEL_BATCH_SIZE; |
| 181 | - | 215 | + APPSPAWN_ONLY_EXPER(end > decDirsSize, end = decDirsSize); |
| 182 | - for (uint32_t i = 0; i < decDirsSize; i++) { | 216 | + IoctlDecPolicyBatch decPolicyInfos = {0}; |
| 183 | - PathInfo pathInfo = {(char *)g_decForcedPrefix[i], (uint32_t)strlen(g_decForcedPrefix[i]), SANDBOX_MODE_READ}; | 217 | + decPolicyInfos.pathNum = end - start; |
| 184 | - decPolicyInfos.path[i] = pathInfo; | 218 | + for (uint32_t i = start; i < end; i++) { |
| 185 | - } | 219 | + PathInfo pathInfo = {(char *)g_decForcedPrefix[i], |
| 186 | - | 220 | + (uint32_t)strlen(g_decForcedPrefix[i]), SANDBOX_MODE_READ}; |
| 187 | - if (ioctl(fd, SET_DEC_PREFIX_CMD, &decPolicyInfos) < 0) { | 221 | + decPolicyInfos.path[i - start] = pathInfo; |
| 188 | - APPSPAWN_LOGE("set forced prefix sandbox policy failed errno %{public}d", errno); | 222 | + } |
| 189 | - } else { | 223 | + int ret = ioctl(fd, SET_DEC_PREFIX_CMD, &decPolicyInfos); |
| 224 | + APPSPAWN_CHECK(ret >= 0, continue, | ||
| 225 | + "set forced prefix sandbox policy failed errno %{public}d", errno); | ||
| 190 | APPSPAWN_LOGI("set SET_DEC_PREFIX_CMD sandbox policy success"); | 226 | APPSPAWN_LOGI("set SET_DEC_PREFIX_CMD sandbox policy success"); |
| 191 | - for (uint32_t i = 0; i < decPolicyInfos.pathNum; i++) { | 227 | + for (uint32_t i = start; i < end; i++) { |
| 192 | - APPSPAWN_DUMPI("%{public}s", decPolicyInfos.path[i].path); | 228 | + APPSPAWN_DUMPI("%{public}s", g_decForcedPrefix[i]); |
| 193 | } | 229 | } |
| 194 | } | 230 | } |
| 195 | close(fd); | 231 | close(fd); |
| @@ -197,13 +233,13 @@ static int SetForcedPrefixDirs(AppSpawnMgr *content) | |||
| 197 | } | 233 | } |
| 198 | 234 | ||
| 199 | /** | 235 | /** |
| 200 | - * @brief 下发单批次DEC策略到内核 | 236 | + * @brief Deliver a single batch of DEC policies to the kernel. |
| 201 | - * @param fd dec设备文件描述符 | 237 | + * @param fd DEC device file descriptor. |
| 202 | - * @param decPolicyInfos 完整的策略信息 | 238 | + * @param decPolicyInfos Full policy info. |
| 203 | - * @param timestamp 时间戳 | 239 | + * @param timestamp Timestamp. |
| 204 | - * @param start 起始路径索引 | 240 | + * @param start Starting path index. |
| 205 | - * @param count 本批次路径数量 | 241 | + * @param count Number of paths in this batch. |
| 206 | - * @return 0成功,负数失败 | 242 | + * @return 0 on success, negative on failure. |
| 207 | */ | 243 | */ |
| 208 | APPSPAWN_STATIC int SetDecPolicyBatch(int fd, GlobalDecPolicyInfo *decPolicyInfos, | 244 | APPSPAWN_STATIC int SetDecPolicyBatch(int fd, GlobalDecPolicyInfo *decPolicyInfos, |
| 209 | uint64_t timestamp, uint32_t start, uint32_t count) | 245 | uint64_t timestamp, uint32_t start, uint32_t count) |
| @@ -211,7 +247,7 @@ APPSPAWN_STATIC int SetDecPolicyBatch(int fd, GlobalDecPolicyInfo *decPolicyInfo | |||
| 211 | APPSPAWN_CHECK(decPolicyInfos != NULL && count > 0 && count <= KERNEL_BATCH_SIZE, | 247 | APPSPAWN_CHECK(decPolicyInfos != NULL && count > 0 && count <= KERNEL_BATCH_SIZE, |
| 212 | return -1, "Invalid param"); | 248 | return -1, "Invalid param"); |
| 213 | 249 | ||
| 214 | - DecPolicyInfo batchInfo = {0}; | 250 | + IoctlDecPolicyBatch batchInfo = {0}; |
| 215 | batchInfo.tokenId = decPolicyInfos->tokenId; | 251 | batchInfo.tokenId = decPolicyInfos->tokenId; |
| 216 | batchInfo.timestamp = timestamp; | 252 | batchInfo.timestamp = timestamp; |
| 217 | batchInfo.pathNum = count; | 253 | batchInfo.pathNum = count; |
| @@ -222,8 +258,10 @@ APPSPAWN_STATIC int SetDecPolicyBatch(int fd, GlobalDecPolicyInfo *decPolicyInfo | |||
| 222 | APPSPAWN_CHECK(memRet == EOK, return -1, "Failed to memcpy_s reserved"); | 258 | APPSPAWN_CHECK(memRet == EOK, return -1, "Failed to memcpy_s reserved"); |
| 223 | 259 | ||
| 224 | for (uint32_t i = 0; i < count; i++) { | 260 | for (uint32_t i = 0; i < count; i++) { |
| 225 | - APPSPAWN_LOGV("SetDecPolicyBatch: [%{public}u] %{public}u %{public}u %{public}u %{public}s", | 261 | + APPSPAWN_LOGV("SetDecPolicyBatch: ts %{public}llu idx %{public}u mode %{public}u " |
| 226 | - start + i, decPolicyInfos->path[start + i].mode, decPolicyInfos->path[start + i].flag, | 262 | + "flag %{public}u len %{public}u path %{public}s", |
| 263 | + (unsigned long long)batchInfo.timestamp, start + i, | ||
| 264 | + decPolicyInfos->path[start + i].mode, decPolicyInfos->path[start + i].flag, | ||
| 227 | decPolicyInfos->path[start + i].pathLen, decPolicyInfos->path[start + i].path); | 265 | decPolicyInfos->path[start + i].pathLen, decPolicyInfos->path[start + i].path); |
| 228 | batchInfo.path[i].path = decPolicyInfos->path[start + i].path; | 266 | batchInfo.path[i].path = decPolicyInfos->path[start + i].path; |
| 229 | batchInfo.path[i].pathLen = decPolicyInfos->path[start + i].pathLen; | 267 | batchInfo.path[i].pathLen = decPolicyInfos->path[start + i].pathLen; |
| @@ -241,6 +279,10 @@ APPSPAWN_STATIC int SetDecPolicyBatch(int fd, GlobalDecPolicyInfo *decPolicyInfo | |||
| 241 | void SetDecPolicy(void) | 279 | void SetDecPolicy(void) |
| 242 | { | 280 | { |
| 243 | APPSPAWN_CHECK(g_decPolicyInfos != NULL, return, "Invalid g_decPolicyInfos"); | 281 | APPSPAWN_CHECK(g_decPolicyInfos != NULL, return, "Invalid g_decPolicyInfos"); |
| 282 | + // Defensive check before open: invalid pathNum must not leak fd or stale global state | ||
| 283 | + APPSPAWN_CHECK(g_decPolicyInfos->pathNum <= MAX_POLICY_NUM, DestroyDecPolicyInfos(g_decPolicyInfos); | ||
| 284 | + g_decPolicyInfos = NULL; | ||
| 285 | + return, "DecPolicy pathNum invalid %{public}u", g_decPolicyInfos->pathNum); | ||
| 244 | const char *decFilename = "/dev/dec"; | 286 | const char *decFilename = "/dev/dec"; |
| 245 | int fd = open(decFilename, O_RDWR); | 287 | int fd = open(decFilename, O_RDWR); |
| 246 | if (fd < 0) { | 288 | if (fd < 0) { |
| @@ -41,17 +41,14 @@ extern "C" { | |||
| 41 | 41 | ||
| 42 | 42 | ||
| 43 | 43 | ||
| 44 | -#define SET_DEC_POLICY_CMD _IOWR(HM_DEC_IOCTL_BASE, HM_SET_POLICY_ID, DecPolicyInfo) | 44 | +// All ioctl cmd macros are defined internally in sandbox_dec.c (based on IoctlDecPolicyBatch), |
| 45 | -#define DEL_DEC_POLICY_CMD _IOWR(HM_DEC_IOCTL_BASE, HM_DEL_POLICY_ID, DecPolicyInfo) // 忽略flag和mode | 45 | +// external code must use the public functions instead of calling ioctl directly. |
| 46 | - | ||
| 47 | - | ||
| 48 | - | ||
| 49 | - | ||
| 50 | - | ||
| 51 | - | ||
| 52 | 46 | ||
| 53 | -#define MAX_POLICY_NUM 64 | 47 | +#define MAX_POLICY_NUM 256 |
| 48 | +// Kernel ABI: paths per single ioctl (IoctlDecPolicyBatch.path[]). Do NOT modify. | ||
| 54 | 49 | ||
| 50 | +// Max rules collected per config (independent of KERNEL_BATCH_SIZE, adjustable >= 1). | ||
| 51 | + | ||
| 55 | 52 | ||
| 56 | 53 | ||
| 57 | 54 | ||
| @@ -68,7 +65,7 @@ typedef struct PathInfo { | |||
| 68 | typedef struct DecPolicyInfo { | 65 | typedef struct DecPolicyInfo { |
| 69 | uint64_t tokenId; | 66 | uint64_t tokenId; |
| 70 | uint64_t timestamp; | 67 | uint64_t timestamp; |
| 71 | - PathInfo path[KERNEL_BATCH_SIZE]; | 68 | + PathInfo path[MAX_CONFIG_POLICY_NUM]; |
| 72 | uint32_t pathNum; | 69 | uint32_t pathNum; |
| 73 | int32_t userId; | 70 | int32_t userId; |
| 74 | uint64_t reserved[DEC_POLICY_HEADER_RESERVED]; | 71 | uint64_t reserved[DEC_POLICY_HEADER_RESERVED]; |
| @@ -2409,6 +2409,388 @@ HWTEST_F(AppSpawnSandboxTest, App_Spawn_Sandbox_dec_06, TestSize.Level0) | |||
| 2409 | DeleteAppSpawningCtx(appProperty); | 2409 | DeleteAppSpawningCtx(appProperty); |
| 2410 | } | 2410 | } |
| 2411 | 2411 | ||
| 2412 | +/** | ||
| 2413 | + * @tc.name: App_Spawn_Sandbox_dec_07 | ||
| 2414 | + * @tc.desc: SetDecPolicyWithPermission truncates to MAX_CONFIG_POLICY_NUM when decPaths exceed limit | ||
| 2415 | + * @tc.type: FUNC | ||
| 2416 | + */ | ||
| 2417 | +HWTEST_F(AppSpawnSandboxTest, App_Spawn_Sandbox_dec_07, TestSize.Level0) | ||
| 2418 | +{ | ||
| 2419 | + const int excessCount = MAX_CONFIG_POLICY_NUM + 5; | ||
| 2420 | + std::string decPaths; | ||
| 2421 | + for (int i = 0; i < excessCount; i++) { | ||
| 2422 | + if (i > 0) { | ||
| 2423 | + decPaths += ", "; | ||
| 2424 | + } | ||
| 2425 | + decPaths += "\"/storage/test/path_" + std::to_string(i) + "\""; | ||
| 2426 | + } | ||
| 2427 | + std::string mJsconfig = | ||
| 2428 | + "{ \"mount-paths\": [{ \"src-path\": \"\", \"sandbox-path\": \"\", " | ||
| 2429 | + "\"sandbox-flags-customized\": [ \"MS_NODEV\", \"MS_RDONLY\" ], " | ||
| 2430 | + "\"dec-paths\": [ " + | ||
| 2431 | + decPaths + | ||
| 2432 | + " ] }] }"; | ||
| 2433 | + cJSON *j_config = cJSON_Parse(mJsconfig.c_str()); | ||
| 2434 | + ASSERT_NE(j_config, nullptr); | ||
| 2435 | + AppSpawn::SandboxCommon::StoreCJsonConfig(j_config, SandboxCommonDef::SANDBOX_APP_JSON_CONFIG); | ||
| 2436 | + | ||
| 2437 | + int ret = 0; | ||
| 2438 | + AppSpawningCtx *appProperty = GetTestAppProperty(); | ||
| 2439 | + do { | ||
| 2440 | + cJSON *mountPoints = cJSON_GetObjectItemCaseSensitive(j_config, "mount-paths"); | ||
| 2441 | + APPSPAWN_CHECK(mountPoints != nullptr && cJSON_IsArray(mountPoints), ret = -1; | ||
| 2442 | + break, "Invalid mountPaths config"); | ||
W 🤖 AI 代码检视意见 | 🛡️ Reliability | ℹ️ Medium | 行号区间: L2441-L2442 问题描述:
测试代码中多处使用 💡 查看修复建议(点击展开)修改建议:将逻辑或(||)改为逻辑与(&&),确保mountPoints既非空且为数组类型时才通过校验。
![]() ![]() | |||
| 2443 | + | ||
| 2444 | + for (int i = 0; i < cJSON_GetArraySize(mountPoints); ++i) { | ||
| 2445 | + cJSON *mntPoint = cJSON_GetArrayItem(mountPoints, i); | ||
| 2446 | + APPSPAWN_CHECK(mntPoint != nullptr, ret = -2; break, "Invalid mntPoint config"); | ||
| 2447 | + SandboxMountConfig mountConfig = {0}; | ||
| 2448 | + AppSpawn::SandboxCommon::GetSandboxMountConfig(appProperty, "permission", mntPoint, mountConfig); | ||
| 2449 | + | ||
| 2450 | + int decPathSize = mountConfig.decPaths.size(); | ||
| 2451 | + EXPECT_EQ(decPathSize, excessCount); | ||
| 2452 | + ret = AppSpawn::SandboxCore::SetDecPolicyWithPermission(appProperty, mountConfig); | ||
| 2453 | + EXPECT_EQ(ret, 0); | ||
| 2454 | + } | ||
| 2455 | + } while (0); | ||
| 2456 | + cJSON_Delete(j_config); | ||
| 2457 | + DeleteAppSpawningCtx(appProperty); | ||
| 2458 | +} | ||
| 2459 | + | ||
| 2460 | +/** | ||
| 2461 | + * @tc.name: App_Spawn_Sandbox_dec_08 | ||
| 2462 | + * @tc.desc: SetDecReadOnlyPolicyWithPermission truncates to MAX_CONFIG_POLICY_NUM when decReadOnlyPaths exceed limit | ||
| 2463 | + * @tc.type: FUNC | ||
| 2464 | + */ | ||
| 2465 | +HWTEST_F(AppSpawnSandboxTest, App_Spawn_Sandbox_dec_08, TestSize.Level0) | ||
| 2466 | +{ | ||
| 2467 | + const int excessCount = MAX_CONFIG_POLICY_NUM + 3; | ||
| 2468 | + std::string decPaths; | ||
| 2469 | + for (int i = 0; i < excessCount; i++) { | ||
| 2470 | + if (i > 0) { | ||
| 2471 | + decPaths += ", "; | ||
| 2472 | + } | ||
| 2473 | + decPaths += "\"/storage/readonly/path_" + std::to_string(i) + "\""; | ||
| 2474 | + } | ||
| 2475 | + std::string mJsconfig = | ||
| 2476 | + "{ \"mount-paths\": [{ \"src-path\": \"\", \"sandbox-path\": \"\", " | ||
| 2477 | + "\"sandbox-flags-customized\": [ \"MS_NODEV\", \"MS_RDONLY\" ], " | ||
| 2478 | + "\"dec-readonly-paths\": [ " + | ||
| 2479 | + decPaths + | ||
| 2480 | + " ] }] }"; | ||
| 2481 | + cJSON *j_config = cJSON_Parse(mJsconfig.c_str()); | ||
| 2482 | + ASSERT_NE(j_config, nullptr); | ||
| 2483 | + AppSpawn::SandboxCommon::StoreCJsonConfig(j_config, SandboxCommonDef::SANDBOX_APP_JSON_CONFIG); | ||
| 2484 | + | ||
| 2485 | + int ret = 0; | ||
| 2486 | + AppSpawningCtx *appProperty = GetTestAppProperty(); | ||
| 2487 | + do { | ||
| 2488 | + cJSON *mountPoints = cJSON_GetObjectItemCaseSensitive(j_config, "mount-paths"); | ||
| 2489 | + APPSPAWN_CHECK(mountPoints != nullptr && cJSON_IsArray(mountPoints), ret = -1; | ||
| 2490 | + break, "Invalid mountPaths config"); | ||
| 2491 | + | ||
| 2492 | + for (int i = 0; i < cJSON_GetArraySize(mountPoints); ++i) { | ||
| 2493 | + cJSON *mntPoint = cJSON_GetArrayItem(mountPoints, i); | ||
| 2494 | + APPSPAWN_CHECK(mntPoint != nullptr, ret = -2; break, "Invalid mntPoint config"); | ||
| 2495 | + SandboxMountConfig mountConfig = {0}; | ||
| 2496 | + AppSpawn::SandboxCommon::GetSandboxMountConfig(appProperty, "permission", mntPoint, mountConfig); | ||
| 2497 | + | ||
| 2498 | + int decReadOnlyPathSize = mountConfig.decReadOnlyPaths.size(); | ||
| 2499 | + EXPECT_EQ(decReadOnlyPathSize, excessCount); | ||
| 2500 | + ret = AppSpawn::SandboxCore::SetDecReadOnlyPolicyWithPermission(appProperty, mountConfig); | ||
| 2501 | + EXPECT_EQ(ret, 0); | ||
| 2502 | + } | ||
| 2503 | + } while (0); | ||
| 2504 | + cJSON_Delete(j_config); | ||
| 2505 | + DeleteAppSpawningCtx(appProperty); | ||
| 2506 | +} | ||
| 2507 | + | ||
| 2508 | +/** | ||
| 2509 | + * @tc.name: App_Spawn_Sandbox_dec_09 | ||
| 2510 | + * @tc.desc: SetDecPolicyWithPermission with exactly MAX_CONFIG_POLICY_NUM paths (boundary) | ||
| 2511 | + * @tc.type: FUNC | ||
| 2512 | + */ | ||
| 2513 | +HWTEST_F(AppSpawnSandboxTest, App_Spawn_Sandbox_dec_09, TestSize.Level0) | ||
| 2514 | +{ | ||
| 2515 | + std::string decPaths; | ||
| 2516 | + for (int i = 0; i < MAX_CONFIG_POLICY_NUM; i++) { | ||
| 2517 | + if (i > 0) { | ||
| 2518 | + decPaths += ", "; | ||
| 2519 | + } | ||
| 2520 | + decPaths += "\"/storage/boundary/path_" + std::to_string(i) + "\""; | ||
| 2521 | + } | ||
| 2522 | + std::string mJsconfig = | ||
| 2523 | + "{ \"mount-paths\": [{ \"src-path\": \"\", \"sandbox-path\": \"\", " | ||
| 2524 | + "\"sandbox-flags-customized\": [ \"MS_NODEV\", \"MS_RDONLY\" ], " | ||
| 2525 | + "\"dec-paths\": [ " + | ||
| 2526 | + decPaths + | ||
| 2527 | + " ] }] }"; | ||
| 2528 | + cJSON *j_config = cJSON_Parse(mJsconfig.c_str()); | ||
| 2529 | + ASSERT_NE(j_config, nullptr); | ||
| 2530 | + AppSpawn::SandboxCommon::StoreCJsonConfig(j_config, SandboxCommonDef::SANDBOX_APP_JSON_CONFIG); | ||
| 2531 | + | ||
| 2532 | + int ret = 0; | ||
| 2533 | + AppSpawningCtx *appProperty = GetTestAppProperty(); | ||
| 2534 | + do { | ||
| 2535 | + cJSON *mountPoints = cJSON_GetObjectItemCaseSensitive(j_config, "mount-paths"); | ||
| 2536 | + APPSPAWN_CHECK(mountPoints != nullptr && cJSON_IsArray(mountPoints), ret = -1; | ||
| 2537 | + break, "Invalid mountPaths config"); | ||
| 2538 | + | ||
| 2539 | + for (int i = 0; i < cJSON_GetArraySize(mountPoints); ++i) { | ||
| 2540 | + cJSON *mntPoint = cJSON_GetArrayItem(mountPoints, i); | ||
| 2541 | + APPSPAWN_CHECK(mntPoint != nullptr, ret = -2; break, "Invalid mntPoint config"); | ||
| 2542 | + SandboxMountConfig mountConfig = {0}; | ||
| 2543 | + AppSpawn::SandboxCommon::GetSandboxMountConfig(appProperty, "permission", mntPoint, mountConfig); | ||
| 2544 | + | ||
| 2545 | + int decPathSize = mountConfig.decPaths.size(); | ||
| 2546 | + EXPECT_EQ(decPathSize, MAX_CONFIG_POLICY_NUM); | ||
| 2547 | + ret = AppSpawn::SandboxCore::SetDecPolicyWithPermission(appProperty, mountConfig); | ||
| 2548 | + EXPECT_EQ(ret, 0); | ||
| 2549 | + } | ||
| 2550 | + } while (0); | ||
| 2551 | + cJSON_Delete(j_config); | ||
| 2552 | + DeleteAppSpawningCtx(appProperty); | ||
| 2553 | +} | ||
| 2554 | + | ||
| 2555 | +/** | ||
| 2556 | + * @tc.name: App_Spawn_Sandbox_dec_10 | ||
| 2557 | + * @tc.desc: SetDecPolicyWithPermission with MAX_CONFIG_POLICY_NUM-1 paths (under limit, no truncation) | ||
| 2558 | + * @tc.type: FUNC | ||
| 2559 | + */ | ||
| 2560 | +HWTEST_F(AppSpawnSandboxTest, App_Spawn_Sandbox_dec_10, TestSize.Level0) | ||
| 2561 | +{ | ||
| 2562 | + const int underCount = MAX_CONFIG_POLICY_NUM - 1; | ||
| 2563 | + std::string decPaths; | ||
| 2564 | + for (int i = 0; i < underCount; i++) { | ||
| 2565 | + if (i > 0) { | ||
| 2566 | + decPaths += ", "; | ||
| 2567 | + } | ||
| 2568 | + decPaths += "\"/storage/under/path_" + std::to_string(i) + "\""; | ||
| 2569 | + } | ||
| 2570 | + std::string mJsconfig = | ||
| 2571 | + "{ \"mount-paths\": [{ \"src-path\": \"\", \"sandbox-path\": \"\", " | ||
| 2572 | + "\"sandbox-flags-customized\": [ \"MS_NODEV\", \"MS_RDONLY\" ], " | ||
| 2573 | + "\"dec-paths\": [ " + | ||
| 2574 | + decPaths + | ||
| 2575 | + " ] }] }"; | ||
| 2576 | + cJSON *j_config = cJSON_Parse(mJsconfig.c_str()); | ||
| 2577 | + ASSERT_NE(j_config, nullptr); | ||
| 2578 | + AppSpawn::SandboxCommon::StoreCJsonConfig(j_config, SandboxCommonDef::SANDBOX_APP_JSON_CONFIG); | ||
| 2579 | + | ||
| 2580 | + int ret = 0; | ||
| 2581 | + AppSpawningCtx *appProperty = GetTestAppProperty(); | ||
| 2582 | + do { | ||
| 2583 | + cJSON *mountPoints = cJSON_GetObjectItemCaseSensitive(j_config, "mount-paths"); | ||
| 2584 | + APPSPAWN_CHECK(mountPoints != nullptr && cJSON_IsArray(mountPoints), ret = -1; | ||
| 2585 | + break, "Invalid mountPaths config"); | ||
| 2586 | + | ||
| 2587 | + for (int i = 0; i < cJSON_GetArraySize(mountPoints); ++i) { | ||
| 2588 | + cJSON *mntPoint = cJSON_GetArrayItem(mountPoints, i); | ||
| 2589 | + APPSPAWN_CHECK(mntPoint != nullptr, ret = -2; break, "Invalid mntPoint config"); | ||
| 2590 | + SandboxMountConfig mountConfig = {0}; | ||
| 2591 | + AppSpawn::SandboxCommon::GetSandboxMountConfig(appProperty, "permission", mntPoint, mountConfig); | ||
| 2592 | + | ||
| 2593 | + int decPathSize = mountConfig.decPaths.size(); | ||
| 2594 | + EXPECT_EQ(decPathSize, underCount); | ||
| 2595 | + ret = AppSpawn::SandboxCore::SetDecPolicyWithPermission(appProperty, mountConfig); | ||
| 2596 | + EXPECT_EQ(ret, 0); | ||
| 2597 | + } | ||
| 2598 | + } while (0); | ||
| 2599 | + cJSON_Delete(j_config); | ||
| 2600 | + DeleteAppSpawningCtx(appProperty); | ||
| 2601 | +} | ||
| 2602 | + | ||
| 2603 | +/** | ||
| 2604 | + * @tc.name: App_Spawn_Sandbox_dec_11 | ||
| 2605 | + * @tc.desc: SetDecReadOnlyPolicyWithPermission with exactly MAX_CONFIG_POLICY_NUM paths (boundary, no truncation) | ||
| 2606 | + * @tc.type: FUNC | ||
| 2607 | + */ | ||
| 2608 | +HWTEST_F(AppSpawnSandboxTest, App_Spawn_Sandbox_dec_11, TestSize.Level0) | ||
| 2609 | +{ | ||
| 2610 | + std::string decPaths; | ||
| 2611 | + for (int i = 0; i < MAX_CONFIG_POLICY_NUM; i++) { | ||
| 2612 | + if (i > 0) { | ||
| 2613 | + decPaths += ", "; | ||
| 2614 | + } | ||
| 2615 | + decPaths += "\"/storage/readonly/boundary_" + std::to_string(i) + "\""; | ||
| 2616 | + } | ||
| 2617 | + std::string mJsconfig = | ||
| 2618 | + "{ \"mount-paths\": [{ \"src-path\": \"\", \"sandbox-path\": \"\", " | ||
| 2619 | + "\"sandbox-flags-customized\": [ \"MS_NODEV\", \"MS_RDONLY\" ], " | ||
| 2620 | + "\"dec-readonly-paths\": [ " + | ||
| 2621 | + decPaths + | ||
| 2622 | + " ] }] }"; | ||
| 2623 | + cJSON *j_config = cJSON_Parse(mJsconfig.c_str()); | ||
| 2624 | + ASSERT_NE(j_config, nullptr); | ||
| 2625 | + AppSpawn::SandboxCommon::StoreCJsonConfig(j_config, SandboxCommonDef::SANDBOX_APP_JSON_CONFIG); | ||
| 2626 | + | ||
| 2627 | + int ret = 0; | ||
| 2628 | + AppSpawningCtx *appProperty = GetTestAppProperty(); | ||
| 2629 | + do { | ||
| 2630 | + cJSON *mountPoints = cJSON_GetObjectItemCaseSensitive(j_config, "mount-paths"); | ||
| 2631 | + APPSPAWN_CHECK(mountPoints != nullptr && cJSON_IsArray(mountPoints), ret = -1; | ||
| 2632 | + break, "Invalid mountPaths config"); | ||
| 2633 | + | ||
| 2634 | + for (int i = 0; i < cJSON_GetArraySize(mountPoints); ++i) { | ||
| 2635 | + cJSON *mntPoint = cJSON_GetArrayItem(mountPoints, i); | ||
| 2636 | + APPSPAWN_CHECK(mntPoint != nullptr, ret = -2; break, "Invalid mntPoint config"); | ||
| 2637 | + SandboxMountConfig mountConfig = {0}; | ||
| 2638 | + AppSpawn::SandboxCommon::GetSandboxMountConfig(appProperty, "permission", mntPoint, mountConfig); | ||
| 2639 | + | ||
| 2640 | + int decReadOnlyPathSize = mountConfig.decReadOnlyPaths.size(); | ||
| 2641 | + EXPECT_EQ(decReadOnlyPathSize, MAX_CONFIG_POLICY_NUM); | ||
| 2642 | + ret = AppSpawn::SandboxCore::SetDecReadOnlyPolicyWithPermission(appProperty, mountConfig); | ||
| 2643 | + EXPECT_EQ(ret, 0); | ||
| 2644 | + } | ||
| 2645 | + } while (0); | ||
| 2646 | + cJSON_Delete(j_config); | ||
| 2647 | + DeleteAppSpawningCtx(appProperty); | ||
| 2648 | +} | ||
| 2649 | + | ||
| 2650 | +/** | ||
| 2651 | + * @tc.name: App_Spawn_Sandbox_dec_12 | ||
| 2652 | + * @tc.desc: SetDecReadOnlyPolicyWithPermission with MAX_CONFIG_POLICY_NUM-1 paths (under limit, no truncation) | ||
| 2653 | + * @tc.type: FUNC | ||
| 2654 | + */ | ||
| 2655 | +HWTEST_F(AppSpawnSandboxTest, App_Spawn_Sandbox_dec_12, TestSize.Level0) | ||
| 2656 | +{ | ||
| 2657 | + const int underCount = MAX_CONFIG_POLICY_NUM - 1; | ||
| 2658 | + std::string decPaths; | ||
| 2659 | + for (int i = 0; i < underCount; i++) { | ||
| 2660 | + if (i > 0) { | ||
| 2661 | + decPaths += ", "; | ||
| 2662 | + } | ||
| 2663 | + decPaths += "\"/storage/readonly/under_" + std::to_string(i) + "\""; | ||
| 2664 | + } | ||
| 2665 | + std::string mJsconfig = | ||
| 2666 | + "{ \"mount-paths\": [{ \"src-path\": \"\", \"sandbox-path\": \"\", " | ||
| 2667 | + "\"sandbox-flags-customized\": [ \"MS_NODEV\", \"MS_RDONLY\" ], " | ||
| 2668 | + "\"dec-readonly-paths\": [ " + | ||
| 2669 | + decPaths + | ||
| 2670 | + " ] }] }"; | ||
| 2671 | + cJSON *j_config = cJSON_Parse(mJsconfig.c_str()); | ||
| 2672 | + ASSERT_NE(j_config, nullptr); | ||
| 2673 | + AppSpawn::SandboxCommon::StoreCJsonConfig(j_config, SandboxCommonDef::SANDBOX_APP_JSON_CONFIG); | ||
| 2674 | + | ||
| 2675 | + int ret = 0; | ||
| 2676 | + AppSpawningCtx *appProperty = GetTestAppProperty(); | ||
| 2677 | + do { | ||
| 2678 | + cJSON *mountPoints = cJSON_GetObjectItemCaseSensitive(j_config, "mount-paths"); | ||
| 2679 | + APPSPAWN_CHECK(mountPoints != nullptr && cJSON_IsArray(mountPoints), ret = -1; | ||
| 2680 | + break, "Invalid mountPaths config"); | ||
| 2681 | + | ||
| 2682 | + for (int i = 0; i < cJSON_GetArraySize(mountPoints); ++i) { | ||
| 2683 | + cJSON *mntPoint = cJSON_GetArrayItem(mountPoints, i); | ||
| 2684 | + APPSPAWN_CHECK(mntPoint != nullptr, ret = -2; break, "Invalid mntPoint config"); | ||
| 2685 | + SandboxMountConfig mountConfig = {0}; | ||
| 2686 | + AppSpawn::SandboxCommon::GetSandboxMountConfig(appProperty, "permission", mntPoint, mountConfig); | ||
| 2687 | + | ||
| 2688 | + int decReadOnlyPathSize = mountConfig.decReadOnlyPaths.size(); | ||
| 2689 | + EXPECT_EQ(decReadOnlyPathSize, underCount); | ||
| 2690 | + ret = AppSpawn::SandboxCore::SetDecReadOnlyPolicyWithPermission(appProperty, mountConfig); | ||
| 2691 | + EXPECT_EQ(ret, 0); | ||
| 2692 | + } | ||
| 2693 | + } while (0); | ||
| 2694 | + cJSON_Delete(j_config); | ||
| 2695 | + DeleteAppSpawningCtx(appProperty); | ||
| 2696 | +} | ||
| 2697 | + | ||
| 2698 | +/** | ||
| 2699 | + * @tc.name: App_Spawn_Sandbox_dec_13 | ||
| 2700 | + * @tc.desc: SetDecPolicyWithPermission with exactly MAX_CONFIG_POLICY_NUM+1 paths (truncates by 1) | ||
| 2701 | + * @tc.type: FUNC | ||
| 2702 | + */ | ||
| 2703 | +HWTEST_F(AppSpawnSandboxTest, App_Spawn_Sandbox_dec_13, TestSize.Level0) | ||
| 2704 | +{ | ||
| 2705 | + const int count = MAX_CONFIG_POLICY_NUM + 1; | ||
| 2706 | + std::string decPaths; | ||
| 2707 | + for (int i = 0; i < count; i++) { | ||
| 2708 | + if (i > 0) { | ||
| 2709 | + decPaths += ", "; | ||
| 2710 | + } | ||
| 2711 | + decPaths += "\"/storage/just_over/path_" + std::to_string(i) + "\""; | ||
| 2712 | + } | ||
| 2713 | + std::string mJsconfig = | ||
| 2714 | + "{ \"mount-paths\": [{ \"src-path\": \"\", \"sandbox-path\": \"\", " | ||
| 2715 | + "\"sandbox-flags-customized\": [ \"MS_NODEV\", \"MS_RDONLY\" ], " | ||
| 2716 | + "\"dec-paths\": [ " + | ||
| 2717 | + decPaths + | ||
| 2718 | + " ] }] }"; | ||
| 2719 | + cJSON *j_config = cJSON_Parse(mJsconfig.c_str()); | ||
| 2720 | + ASSERT_NE(j_config, nullptr); | ||
| 2721 | + AppSpawn::SandboxCommon::StoreCJsonConfig(j_config, SandboxCommonDef::SANDBOX_APP_JSON_CONFIG); | ||
| 2722 | + | ||
| 2723 | + int ret = 0; | ||
| 2724 | + AppSpawningCtx *appProperty = GetTestAppProperty(); | ||
| 2725 | + do { | ||
| 2726 | + cJSON *mountPoints = cJSON_GetObjectItemCaseSensitive(j_config, "mount-paths"); | ||
| 2727 | + APPSPAWN_CHECK(mountPoints != nullptr && cJSON_IsArray(mountPoints), ret = -1; | ||
| 2728 | + break, "Invalid mountPaths config"); | ||
| 2729 | + | ||
| 2730 | + for (int i = 0; i < cJSON_GetArraySize(mountPoints); ++i) { | ||
| 2731 | + cJSON *mntPoint = cJSON_GetArrayItem(mountPoints, i); | ||
| 2732 | + APPSPAWN_CHECK(mntPoint != nullptr, ret = -2; break, "Invalid mntPoint config"); | ||
| 2733 | + SandboxMountConfig mountConfig = {0}; | ||
| 2734 | + AppSpawn::SandboxCommon::GetSandboxMountConfig(appProperty, "permission", mntPoint, mountConfig); | ||
| 2735 | + | ||
| 2736 | + int decPathSize = mountConfig.decPaths.size(); | ||
| 2737 | + EXPECT_EQ(decPathSize, count); | ||
| 2738 | + ret = AppSpawn::SandboxCore::SetDecPolicyWithPermission(appProperty, mountConfig); | ||
| 2739 | + EXPECT_EQ(ret, 0); | ||
| 2740 | + } | ||
| 2741 | + } while (0); | ||
| 2742 | + cJSON_Delete(j_config); | ||
| 2743 | + DeleteAppSpawningCtx(appProperty); | ||
| 2744 | +} | ||
| 2745 | + | ||
| 2746 | +/** | ||
| 2747 | + * @tc.name: App_Spawn_Sandbox_dec_14 | ||
| 2748 | + * @tc.desc: SetDecReadOnlyPolicyWithPermission with exactly MAX_CONFIG_POLICY_NUM+1 paths (truncates by 1) | ||
| 2749 | + * @tc.type: FUNC | ||
| 2750 | + */ | ||
| 2751 | +HWTEST_F(AppSpawnSandboxTest, App_Spawn_Sandbox_dec_14, TestSize.Level0) | ||
| 2752 | +{ | ||
| 2753 | + const int count = MAX_CONFIG_POLICY_NUM + 1; | ||
| 2754 | + std::string decPaths; | ||
| 2755 | + for (int i = 0; i < count; i++) { | ||
| 2756 | + if (i > 0) { | ||
| 2757 | + decPaths += ", "; | ||
| 2758 | + } | ||
| 2759 | + decPaths += "\"/storage/readonly/just_over_" + std::to_string(i) + "\""; | ||
| 2760 | + } | ||
| 2761 | + std::string mJsconfig = | ||
| 2762 | + "{ \"mount-paths\": [{ \"src-path\": \"\", \"sandbox-path\": \"\", " | ||
| 2763 | + "\"sandbox-flags-customized\": [ \"MS_NODEV\", \"MS_RDONLY\" ], " | ||
| 2764 | + "\"dec-readonly-paths\": [ " + | ||
| 2765 | + decPaths + | ||
| 2766 | + " ] }] }"; | ||
| 2767 | + cJSON *j_config = cJSON_Parse(mJsconfig.c_str()); | ||
| 2768 | + ASSERT_NE(j_config, nullptr); | ||
| 2769 | + AppSpawn::SandboxCommon::StoreCJsonConfig(j_config, SandboxCommonDef::SANDBOX_APP_JSON_CONFIG); | ||
| 2770 | + | ||
| 2771 | + int ret = 0; | ||
| 2772 | + AppSpawningCtx *appProperty = GetTestAppProperty(); | ||
| 2773 | + do { | ||
| 2774 | + cJSON *mountPoints = cJSON_GetObjectItemCaseSensitive(j_config, "mount-paths"); | ||
| 2775 | + APPSPAWN_CHECK(mountPoints != nullptr && cJSON_IsArray(mountPoints), ret = -1; | ||
| 2776 | + break, "Invalid mountPaths config"); | ||
| 2777 | + | ||
| 2778 | + for (int i = 0; i < cJSON_GetArraySize(mountPoints); ++i) { | ||
| 2779 | + cJSON *mntPoint = cJSON_GetArrayItem(mountPoints, i); | ||
| 2780 | + APPSPAWN_CHECK(mntPoint != nullptr, ret = -2; break, "Invalid mntPoint config"); | ||
| 2781 | + SandboxMountConfig mountConfig = {0}; | ||
| 2782 | + AppSpawn::SandboxCommon::GetSandboxMountConfig(appProperty, "permission", mntPoint, mountConfig); | ||
| 2783 | + | ||
| 2784 | + int decReadOnlyPathSize = mountConfig.decReadOnlyPaths.size(); | ||
| 2785 | + EXPECT_EQ(decReadOnlyPathSize, count); | ||
| 2786 | + ret = AppSpawn::SandboxCore::SetDecReadOnlyPolicyWithPermission(appProperty, mountConfig); | ||
| 2787 | + EXPECT_EQ(ret, 0); | ||
| 2788 | + } | ||
| 2789 | + } while (0); | ||
| 2790 | + cJSON_Delete(j_config); | ||
| 2791 | + DeleteAppSpawningCtx(appProperty); | ||
| 2792 | +} | ||
| 2793 | + | ||
| 2412 | /** | 2794 | /** |
| 2413 | * @tc.name: App_Spawn_Sandbox_Shared_Mount_01 | 2795 | * @tc.name: App_Spawn_Sandbox_Shared_Mount_01 |
| 2414 | * @tc.desc: [IsValidDataGroupItem] input valid param | 2796 | * @tc.desc: [IsValidDataGroupItem] input valid param |
| @@ -99,4 +99,40 @@ HWTEST_F(DecApiTest, App_Spawn_DecApi_GetIgnoreCaseDirs_002, TestSize.Level1) | |||
| 99 | } | 99 | } |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | +/** | ||
| 103 | + * @tc.name: App_Spawn_DecApi_GetDecPathMap_EmptyConfig | ||
| 104 | + * @tc.desc: Verify GetDecPathMap returns empty map when sandbox config is absent or empty | ||
| 105 | + * @tc.type: FUNC | ||
| 106 | + * @tc.level: Level0 | ||
| 107 | + */ | ||
| 108 | +HWTEST_F(DecApiTest, App_Spawn_DecApi_GetDecPathMap_EmptyConfig, TestSize.Level0) | ||
| 109 | +{ | ||
| 110 | + std::map<std::string, std::vector<std::string>> decMap = GetDecPathMap(); | ||
| 111 | + GTEST_LOG_(INFO) << "GetDecPathMap returned " << decMap.size() << " entries"; | ||
| 112 | + for (const auto& [perm, paths] : decMap) { | ||
| 113 | + EXPECT_FALSE(perm.empty()); | ||
| 114 | + for (const auto& p : paths) { | ||
| 115 | + EXPECT_FALSE(p.empty()); | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +/** | ||
| 121 | + * @tc.name: App_Spawn_DecApi_GetIgnoreCaseDirs_NoShareFsFalse | ||
| 122 | + * @tc.desc: Verify GetIgnoreCaseDirs returns 2 entries when noShareFsEnabled is false | ||
| 123 | + * @tc.type: FUNC | ||
| 124 | + * @tc.level: Level0 | ||
| 125 | + */ | ||
| 126 | +HWTEST_F(DecApiTest, App_Spawn_DecApi_GetIgnoreCaseDirs_NoShareFsFalse, TestSize.Level0) | ||
| 127 | +{ | ||
| 128 | + SetNoShareFsEnable(false); | ||
| 129 | + std::vector<std::pair<std::string, int>> dirs = GetIgnoreCaseDirs(); | ||
| 130 | + EXPECT_EQ(dirs.size(), 2u); | ||
| 131 | + for (const auto& [path, mode] : dirs) { | ||
| 132 | + EXPECT_FALSE(path.empty()); | ||
| 133 | + EXPECT_TRUE(mode == 0 || mode == 1); | ||
| 134 | + } | ||
| 135 | + SetNoShareFsEnable(true); | ||
| 136 | +} | ||
| 137 | + | ||
| 102 | } // namespace OHOS | 138 | } // namespace OHOS |
| @@ -142,8 +142,8 @@ HWTEST_F(DecUtilTest, App_Spawn_DecUtil_GetIgnoreCaseDirs_MultipleCalls, TestSiz | |||
| 142 | */ | 142 | */ |
| 143 | HWTEST_F(DecUtilTest, App_Spawn_DecUtil_Macro_MAX_POLICY_NUM_001, TestSize.Level0) | 143 | HWTEST_F(DecUtilTest, App_Spawn_DecUtil_Macro_MAX_POLICY_NUM_001, TestSize.Level0) |
| 144 | { | 144 | { |
| 145 | - // TC001: Verify MAX_POLICY_NUM is 64 to ensure policy capacity meets requirement | 145 | + // Verify MAX_POLICY_NUM meets minimum capacity requirement |
| 146 | - EXPECT_EQ(MAX_POLICY_NUM, 64); | 146 | + EXPECT_GE(MAX_POLICY_NUM, 64); |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | /** | 149 | /** |
| @@ -157,6 +157,18 @@ HWTEST_F(DecUtilTest, App_Spawn_DecUtil_Macro_KERNEL_BATCH_SIZE_001, TestSize.Le | |||
| 157 | EXPECT_EQ(KERNEL_BATCH_SIZE, 8); | 157 | EXPECT_EQ(KERNEL_BATCH_SIZE, 8); |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | +/** | ||
| 161 | +* @tc.name: App_Spawn_DecUtil_Macro_MAX_CONFIG_POLICY_NUM_001 | ||
| 162 | +* @tc.desc: Verify MAX_CONFIG_POLICY_NUM is within valid range [1, MAX_POLICY_NUM) | ||
| 163 | +* @tc.type: FUNC | ||
| 164 | +*/ | ||
| 165 | +HWTEST_F(DecUtilTest, App_Spawn_DecUtil_Macro_MAX_CONFIG_POLICY_NUM_001, TestSize.Level0) | ||
| 166 | +{ | ||
| 167 | + // MAX_CONFIG_POLICY_NUM >= 1 and < MAX_POLICY_NUM | ||
| 168 | + EXPECT_GE(MAX_CONFIG_POLICY_NUM, 1); | ||
| 169 | + EXPECT_LT(MAX_CONFIG_POLICY_NUM, MAX_POLICY_NUM); | ||
| 170 | +} | ||
| 171 | + | ||
| 160 | /** | 172 | /** |
| 161 | * @tc.name: App_Spawn_DecUtil_GetDecIgnoreCaseList_True_001 | 173 | * @tc.name: App_Spawn_DecUtil_GetDecIgnoreCaseList_True_001 |
| 162 | * @tc.desc: Verify GetDecIgnoreCaseList returns the full list when noShareFsEnabled is true | 174 | * @tc.desc: Verify GetDecIgnoreCaseList returns the full list when noShareFsEnabled is true |
| @@ -48,6 +48,7 @@ if (!defined(ohos_lite)) { | |||
| 48 | "-Wl,--wrap=close", | 48 | "-Wl,--wrap=close", |
| 49 | "-Wl,--wrap=clock_gettime", | 49 | "-Wl,--wrap=clock_gettime", |
| 50 | "-Wl,--wrap=AddServerStageHook", | 50 | "-Wl,--wrap=AddServerStageHook", |
| 51 | + "-Wl,--wrap=strdup", | ||
| 51 | ] | 52 | ] |
| 52 | 53 | ||
| 53 | deps = [ "${appspawn_path}/util:libappspawn_util" ] | 54 | deps = [ "${appspawn_path}/util:libappspawn_util" ] |
| @@ -23,15 +23,21 @@ | |||
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | + | ||
| 26 | 27 | ||
| 27 | 28 | ||
| 28 | using namespace testing; | 29 | using namespace testing; |
| 29 | using namespace testing::ext; | 30 | using namespace testing::ext; |
| 30 | 31 | ||
| 32 | +typedef struct TagAppSpawnMgr AppSpawnMgr; | ||
| 33 | + | ||
| 31 | // APPSPAWN_STATIC expands to empty under APPSPAWN_TEST, expose static functions | 34 | // APPSPAWN_STATIC expands to empty under APPSPAWN_TEST, expose static functions |
| 32 | extern "C" { | 35 | extern "C" { |
| 33 | int SetDecPolicyBatch(int fd, GlobalDecPolicyInfo *decPolicyInfos, | 36 | int SetDecPolicyBatch(int fd, GlobalDecPolicyInfo *decPolicyInfos, |
| 34 | uint64_t timestamp, uint32_t start, uint32_t count); | 37 | uint64_t timestamp, uint32_t start, uint32_t count); |
| 38 | +int SetDenyConstraintDirs(AppSpawnMgr *content); | ||
| 39 | +int SetForcedPrefixDirs(AppSpawnMgr *content); | ||
| 40 | +int SetIgnoreCaseDirs(AppSpawnMgr *content); | ||
| 35 | } | 41 | } |
| 36 | 42 | ||
| 37 | // ==================== Mock constants ==================== | 43 | // ==================== Mock constants ==================== |
| @@ -47,6 +53,10 @@ static int g_mockIoctlReturn = 0; | |||
| 47 | static int g_mockIoctlCallCount = 0; | 53 | static int g_mockIoctlCallCount = 0; |
| 48 | static uint32_t g_mockIoctlFailAfterCount = 0; // fail after N successful calls | 54 | static uint32_t g_mockIoctlFailAfterCount = 0; // fail after N successful calls |
| 49 | static const void *g_lastIoctlData = nullptr; | 55 | static const void *g_lastIoctlData = nullptr; |
| 56 | +static unsigned long g_lastIoctlReq = 0; | ||
| 57 | + | ||
| 58 | +static const int MAX_IOCTL_RECORDS = (MAX_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; | ||
| 59 | +static uint32_t g_ioctlPathNums[MAX_IOCTL_RECORDS]; | ||
W 🤖 AI 代码检视意见 | ✨ Quality | ✅ Low | 行号区间: L58-L59 问题描述: g_ioctlPathNums数组容量MAX_IOCTL_RECORDS硬编码为64。当前MAX_POLICY_NUM=256对应批次数32,记录数足够。但若未来MAX_POLICY_NUM进一步增大(如512、1024),超出64批后超出部分的pathNum不会被记录,测试TC145等会因数组越界保护而静默跳过记录,测试可能仍通过但实际未验证。建议将MAX_IOCTL_RECORDS与MAX_POLICY_NUM关联以避免维护遗漏。 💡 查看修复建议(点击展开)修改建议:将MAX_IOCTL_RECORDS与MAX_POLICY_NUM/KERNEL_BATCH_SIZE关联,确保记录容量永远足够。
![]() ![]() | |||
| 50 | 60 | ||
| 51 | static int g_mockOpenReturn = MOCK_OPEN_RETURN_FD; | 61 | static int g_mockOpenReturn = MOCK_OPEN_RETURN_FD; |
| 52 | static const char *MOCK_OPEN_PATH = nullptr; | 62 | static const char *MOCK_OPEN_PATH = nullptr; |
| @@ -54,8 +64,33 @@ static const char *MOCK_OPEN_PATH = nullptr; | |||
| 54 | static int g_mockClockTimeSec = MOCK_CLOCK_TIME_SEC; | 64 | static int g_mockClockTimeSec = MOCK_CLOCK_TIME_SEC; |
| 55 | static int g_mockClockTimeNsec = MOCK_CLOCK_TIME_NSEC; | 65 | static int g_mockClockTimeNsec = MOCK_CLOCK_TIME_NSEC; |
| 56 | 66 | ||
| 67 | +static bool g_mockStrdupShouldFail = false; | ||
| 68 | + | ||
| 57 | // ==================== Wrap functions ==================== | 69 | // ==================== Wrap functions ==================== |
| 58 | 70 | ||
| 71 | +// Mirror of IoctlDecPolicyBatch in sandbox_dec.c for reading pathNum in mock ioctl | ||
| 72 | +struct MockIoctlBatch { | ||
| 73 | + uint64_t tokenId; | ||
| 74 | + uint64_t timestamp; | ||
| 75 | + PathInfo path[KERNEL_BATCH_SIZE]; | ||
| 76 | + uint32_t pathNum; | ||
| 77 | + int32_t userId; | ||
| 78 | + uint64_t reserved[DEC_POLICY_HEADER_RESERVED]; | ||
| 79 | + bool flag; | ||
| 80 | +}; | ||
| 81 | + | ||
| 82 | +// Mirror of batch ioctl commands in sandbox_dec.c (based on MockIoctlBatch layout) | ||
| 83 | + | ||
| 84 | + | ||
| 85 | + | ||
| 86 | + | ||
| 87 | + | ||
| 88 | +static bool IsBatchIoctlCmd(unsigned long request) | ||
| 89 | +{ | ||
| 90 | + return request == MOCK_SET_DEC_POLICY_CMD || request == MOCK_CONSTRAINT_DEC_POLICY_CMD || | ||
| 91 | + request == MOCK_SET_DEC_PREFIX_CMD || request == MOCK_SET_DEC_IGNORE_CASE_CMD; | ||
| 92 | +} | ||
| 93 | + | ||
| 59 | extern "C" { | 94 | extern "C" { |
| 60 | int __wrap_open(const char *pathname, int flags, ...) | 95 | int __wrap_open(const char *pathname, int flags, ...) |
| 61 | { | 96 | { |
| @@ -77,16 +112,18 @@ int __wrap_AddServerStageHook(AppSpawnHookStage stage, int prio, ServerStageHook | |||
| 77 | int __wrap_ioctl(int fd, unsigned long request, ...) | 112 | int __wrap_ioctl(int fd, unsigned long request, ...) |
| 78 | { | 113 | { |
| 79 | g_mockIoctlCallCount++; | 114 | g_mockIoctlCallCount++; |
| 115 | + g_lastIoctlReq = request; | ||
| 80 | va_list args; | 116 | va_list args; |
| 81 | va_start(args, request); | 117 | va_start(args, request); |
| 82 | void *arg = va_arg(args, void *); | 118 | void *arg = va_arg(args, void *); |
| 83 | va_end(args); | 119 | va_end(args); |
| 84 | - | ||
| 85 | - if (g_lastIoctlData != nullptr) { | ||
| 86 | - g_lastIoctlData = arg; | ||
| 87 | - } | ||
| 88 | g_lastIoctlData = arg; | 120 | g_lastIoctlData = arg; |
| 89 | 121 | ||
| 122 | + if (g_mockIoctlCallCount <= MAX_IOCTL_RECORDS && arg != nullptr && IsBatchIoctlCmd(request)) { | ||
| 123 | + MockIoctlBatch *batch = reinterpret_cast<MockIoctlBatch *>(arg); | ||
| 124 | + g_ioctlPathNums[g_mockIoctlCallCount - 1] = batch->pathNum; | ||
| 125 | + } | ||
W 🤖 AI 代码检视意见 | 🛡️ Reliability | ✅ Low | 行号区间: L110-L113 问题描述: 在__wrap_ioctl中,对所有ioctl调用均假设arg指向MockIoctlBatch结构并读取pathNum字段。若被测代码未来调用其他ioctl命令(如DESTORY_DEC_POLICY_CMD使用uint64_t参数),将uint64_t缓冲指针强转为MockIoctlBatch*并读取pathNum属于类型混淆,虽然不会崩溃但记录的pathNum值无意义。当前测试覆盖的命令均为batch类型所以未暴露,但缺乏防御性。 💡 查看修复建议(点击展开)修改建议:通过request参数判断是否为batch型ioctl命令,仅对batch命令记录pathNum,避免对非batch命令做类型强转读取。
![]() ![]() | |||
| 126 | + | ||
| 90 | if (g_mockIoctlFailAfterCount > 0 && g_mockIoctlCallCount > g_mockIoctlFailAfterCount) { | 127 | if (g_mockIoctlFailAfterCount > 0 && g_mockIoctlCallCount > g_mockIoctlFailAfterCount) { |
| 91 | errno = EINVAL; | 128 | errno = EINVAL; |
| 92 | return -1; | 129 | return -1; |
| @@ -102,6 +139,16 @@ int __wrap_clock_gettime(clockid_t clk_id, struct timespec *ts) | |||
| 102 | } | 139 | } |
| 103 | return 0; | 140 | return 0; |
| 104 | } | 141 | } |
| 142 | + | ||
| 143 | +char *__real_strdup(const char *s); | ||
| 144 | +char *__wrap_strdup(const char *s) | ||
| 145 | +{ | ||
| 146 | + if (g_mockStrdupShouldFail) { | ||
| 147 | + errno = ENOMEM; | ||
| 148 | + return nullptr; | ||
| 149 | + } | ||
| 150 | + return __real_strdup(s); | ||
| 151 | +} | ||
| 105 | } | 152 | } |
| 106 | 153 | ||
| 107 | // ==================== Test helpers ==================== | 154 | // ==================== Test helpers ==================== |
| @@ -130,13 +177,18 @@ public: | |||
| 130 | g_mockIoctlCallCount = 0; | 177 | g_mockIoctlCallCount = 0; |
| 131 | g_mockIoctlFailAfterCount = 0; | 178 | g_mockIoctlFailAfterCount = 0; |
| 132 | g_lastIoctlData = nullptr; | 179 | g_lastIoctlData = nullptr; |
| 180 | + g_lastIoctlReq = 0; | ||
| 133 | g_mockOpenReturn = MOCK_OPEN_RETURN_FD; | 181 | g_mockOpenReturn = MOCK_OPEN_RETURN_FD; |
| 134 | MOCK_OPEN_PATH = nullptr; | 182 | MOCK_OPEN_PATH = nullptr; |
| 135 | g_mockClockTimeSec = MOCK_CLOCK_TIME_SEC; | 183 | g_mockClockTimeSec = MOCK_CLOCK_TIME_SEC; |
| 136 | g_mockClockTimeNsec = MOCK_CLOCK_TIME_NSEC; | 184 | g_mockClockTimeNsec = MOCK_CLOCK_TIME_NSEC; |
| 185 | + g_mockStrdupShouldFail = false; | ||
| 186 | + for (int i = 0; i < MAX_IOCTL_RECORDS; i++) { | ||
| 187 | + g_ioctlPathNums[i] = 0; | ||
| 188 | + } | ||
| 137 | } | 189 | } |
| 138 | 190 | ||
| 139 | - // Helper: create DecPolicyInfo with N paths (max KERNEL_BATCH_SIZE per call) | 191 | + // Helper: create DecPolicyInfo with N paths (up to MAX_CONFIG_POLICY_NUM per call) |
| 140 | // pathOffset: starting index for path naming (for multi-batch tests) | 192 | // pathOffset: starting index for path naming (for multi-batch tests) |
| 141 | void FillPolicyInfo(DecPolicyInfo &info, uint32_t pathCount, uint32_t pathOffset = 0) | 193 | void FillPolicyInfo(DecPolicyInfo &info, uint32_t pathCount, uint32_t pathOffset = 0) |
| 142 | { | 194 | { |
| @@ -144,9 +196,9 @@ public: | |||
| 144 | if (ret != EOK) { | 196 | if (ret != EOK) { |
| 145 | return; | 197 | return; |
| 146 | } | 198 | } |
| 147 | - // Limit to KERNEL_BATCH_SIZE to avoid buffer overflow | 199 | + // Limit to MAX_CONFIG_POLICY_NUM (DecPolicyInfo.path[] capacity) |
| 148 | - if (pathCount > KERNEL_BATCH_SIZE) { | 200 | + if (pathCount > MAX_CONFIG_POLICY_NUM) { |
| 149 | - pathCount = KERNEL_BATCH_SIZE; | 201 | + pathCount = MAX_CONFIG_POLICY_NUM; |
| 150 | } | 202 | } |
| 151 | info.tokenId = MOCK_TOKEN_ID; | 203 | info.tokenId = MOCK_TOKEN_ID; |
| 152 | info.pathNum = pathCount; | 204 | info.pathNum = pathCount; |
| @@ -240,18 +292,15 @@ HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_16Paths_2Batches_001, TestSize. | |||
| 240 | * @tc.desc: Verify SetDecPolicy delivers 64 paths in 8 batches (MAX_POLICY_NUM) | 292 | * @tc.desc: Verify SetDecPolicy delivers 64 paths in 8 batches (MAX_POLICY_NUM) |
| 241 | * @tc.type: FUNC | 293 | * @tc.type: FUNC |
| 242 | */ | 294 | */ |
| 243 | -HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_64Paths_8Batches_001, TestSize.Level1) | 295 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_MaxPaths_Batches_001, TestSize.Level1) |
| 244 | { | 296 | { |
| 245 | - // Use FillMultiplePolicyInfos to add 64 paths in 8 batches | ||
| 246 | FillMultiplePolicyInfos(MAX_POLICY_NUM); | 297 | FillMultiplePolicyInfos(MAX_POLICY_NUM); |
| 247 | 298 | ||
| 248 | g_mockIoctlCallCount = 0; | 299 | g_mockIoctlCallCount = 0; |
| 249 | SetDecPolicy(); | 300 | SetDecPolicy(); |
| 250 | 301 | ||
| 251 | - // Expect 8 ioctl calls (64 / 8 = 8 batches) | ||
| 252 | uint32_t expectedBatches = (MAX_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; | 302 | uint32_t expectedBatches = (MAX_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; |
| 253 | EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); | 303 | EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); |
| 254 | - EXPECT_EQ(expectedBatches, 8u); | ||
| 255 | } | 304 | } |
| 256 | 305 | ||
| 257 | // ==================== TC104: Timestamp consistency ==================== | 306 | // ==================== TC104: Timestamp consistency ==================== |
| @@ -382,7 +431,7 @@ HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_NormalAdd_001, TestSize.Le | |||
| 382 | 431 | ||
| 383 | /** | 432 | /** |
| 384 | * @tc.name: SandboxDec_SetDecPolicyInfos_ExceedLimit_001 | 433 | * @tc.name: SandboxDec_SetDecPolicyInfos_ExceedLimit_001 |
| 385 | - * @tc.desc: Verify SetDecPolicyInfos rejects paths exceeding MAX_POLICY_NUM | 434 | + * @tc.desc: Verify SetDecPolicyInfos keeps existing policies when exceeding MAX_POLICY_NUM |
| 386 | * @tc.type: FUNC | 435 | * @tc.type: FUNC |
| 387 | */ | 436 | */ |
| 388 | HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_ExceedLimit_001, TestSize.Level1) | 437 | HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_ExceedLimit_001, TestSize.Level1) |
| @@ -390,15 +439,16 @@ HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_ExceedLimit_001, TestSize. | |||
| 390 | // First add MAX_POLICY_NUM paths using FillMultiplePolicyInfos | 439 | // First add MAX_POLICY_NUM paths using FillMultiplePolicyInfos |
| 391 | FillMultiplePolicyInfos(MAX_POLICY_NUM); | 440 | FillMultiplePolicyInfos(MAX_POLICY_NUM); |
| 392 | 441 | ||
| 393 | - // Try to add 1 more path - should be rejected and g_decPolicyInfos destroyed | 442 | + // Try to add 1 more path - should be skipped (full), existing 64 retained |
| 394 | DecPolicyInfo infoExtra; | 443 | DecPolicyInfo infoExtra; |
| 395 | FillPolicyInfo(infoExtra, 1); | 444 | FillPolicyInfo(infoExtra, 1); |
| 396 | SetDecPolicyInfos(&infoExtra); | 445 | SetDecPolicyInfos(&infoExtra); |
| 397 | 446 | ||
| 398 | - // SetDecPolicy should not call ioctl since g_decPolicyInfos was destroyed | 447 | + // SetDecPolicy should still call ioctl for the retained paths |
| 399 | g_mockIoctlCallCount = 0; | 448 | g_mockIoctlCallCount = 0; |
| 400 | SetDecPolicy(); | 449 | SetDecPolicy(); |
| 401 | - EXPECT_EQ(g_mockIoctlCallCount, 0); | 450 | + uint32_t expectedBatches = (MAX_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; |
| 451 | + EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); | ||
| 402 | 452 | ||
| 403 | FreePolicyInfo(infoExtra); | 453 | FreePolicyInfo(infoExtra); |
| 404 | } | 454 | } |
| @@ -439,18 +489,24 @@ HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyBatch_InvalidParams_001, TestSiz | |||
| 439 | */ | 489 | */ |
| 440 | HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_ZeroPathNum_001, TestSize.Level1) | 490 | HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_ZeroPathNum_001, TestSize.Level1) |
| 441 | { | 491 | { |
| 492 | + // Pre-fill 8 paths, then zero pathNum input must not touch existing g_decPolicyInfos | ||
| 493 | + DecPolicyInfo pre; | ||
| 494 | + FillPolicyInfo(pre, KERNEL_BATCH_SIZE); | ||
| 495 | + SetDecPolicyInfos(&pre); | ||
| 496 | + FreePolicyInfo(pre); | ||
| 497 | + | ||
| 442 | DecPolicyInfo info; | 498 | DecPolicyInfo info; |
| 443 | errno_t rc = memset_s(&info, sizeof(DecPolicyInfo), 0, sizeof(DecPolicyInfo)); | 499 | errno_t rc = memset_s(&info, sizeof(DecPolicyInfo), 0, sizeof(DecPolicyInfo)); |
| 444 | ASSERT_EQ(rc, EOK); | 500 | ASSERT_EQ(rc, EOK); |
| 445 | info.pathNum = 0; | 501 | info.pathNum = 0; |
| 446 | 502 | ||
| 447 | - // Should not crash and not store anything | ||
| 448 | SetDecPolicyInfos(&info); | 503 | SetDecPolicyInfos(&info); |
| 449 | 504 | ||
| 450 | - // SetDecPolicy should not call ioctl since no policies were stored | 505 | + // Existing 8 paths retained: SetDecPolicy still delivers 1 batch |
| 451 | g_mockIoctlCallCount = 0; | 506 | g_mockIoctlCallCount = 0; |
| 452 | SetDecPolicy(); | 507 | SetDecPolicy(); |
| 453 | - EXPECT_EQ(g_mockIoctlCallCount, 0); | 508 | + EXPECT_EQ(g_mockIoctlCallCount, 1); |
| 509 | + EXPECT_EQ(g_ioctlPathNums[0], KERNEL_BATCH_SIZE); | ||
| 454 | } | 510 | } |
| 455 | 511 | ||
| 456 | // ==================== TC114: 1 path, 1 batch ==================== | 512 | // ==================== TC114: 1 path, 1 batch ==================== |
| @@ -495,4 +551,907 @@ HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_9Paths_2Batches_001, TestSize.L | |||
| 495 | EXPECT_EQ(g_mockIoctlCallCount, 2); | 551 | EXPECT_EQ(g_mockIoctlCallCount, 2); |
| 496 | } | 552 | } |
| 497 | 553 | ||
| 554 | +// ==================== TC116: 32 paths in single call, 4 batches ==================== | ||
| 555 | + | ||
| 556 | +/** | ||
| 557 | +* @tc.name: SandboxDec_SetDecPolicy_32Paths_SingleCall_001 | ||
| 558 | +* @tc.desc: SetDecPolicyInfos accepts 32 paths in one call, delivers 4 batches | ||
| 559 | +* @tc.type: FUNC | ||
| 560 | +*/ | ||
| 561 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_32Paths_SingleCall_001, TestSize.Level1) | ||
| 562 | +{ | ||
| 563 | + DecPolicyInfo info; | ||
| 564 | + FillPolicyInfo(info, MAX_CONFIG_POLICY_NUM); | ||
| 565 | + | ||
| 566 | + SetDecPolicyInfos(&info); | ||
| 567 | + | ||
| 568 | + g_mockIoctlCallCount = 0; | ||
| 569 | + SetDecPolicy(); | ||
| 570 | + | ||
| 571 | + // 32 paths: 4 batches of 8 | ||
| 572 | + uint32_t expectedBatches = (MAX_CONFIG_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; | ||
| 573 | + EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); | ||
| 574 | + EXPECT_EQ(expectedBatches, 4u); | ||
| 575 | + | ||
| 576 | + FreePolicyInfo(info); | ||
| 577 | +} | ||
| 578 | + | ||
| 579 | +// ==================== TC117: exceed MAX_POLICY_NUM (global overflow) ==================== | ||
| 580 | + | ||
| 581 | +/** | ||
| 582 | +* @tc.name: SandboxDec_SetDecPolicyInfos_ExceedGlobalLimit_001 | ||
| 583 | +* @tc.desc: Verify SetDecPolicyInfos partially applies when global pathNum would exceed MAX_POLICY_NUM | ||
| 584 | +* @tc.type: FUNC | ||
| 585 | +*/ | ||
| 586 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_ExceedGlobalLimit_001, TestSize.Level1) | ||
| 587 | +{ | ||
| 588 | + // Fill global to MAX_POLICY_NUM - 1 | ||
| 589 | + FillMultiplePolicyInfos(MAX_POLICY_NUM - 1); | ||
| 590 | + | ||
| 591 | + // Add MAX_CONFIG_POLICY_NUM more => only 1 fits (64-63=1), rest skipped | ||
| 592 | + DecPolicyInfo info; | ||
| 593 | + FillPolicyInfo(info, MAX_CONFIG_POLICY_NUM); | ||
| 594 | + | ||
| 595 | + SetDecPolicyInfos(&info); | ||
| 596 | + | ||
| 597 | + // g_decPolicyInfos retained at MAX_POLICY_NUM, SetDecPolicy calls expected batches | ||
| 598 | + g_mockIoctlCallCount = 0; | ||
| 599 | + SetDecPolicy(); | ||
| 600 | + uint32_t expectedBatches = (MAX_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; | ||
| 601 | + EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); | ||
| 602 | + | ||
| 603 | + FreePolicyInfo(info); | ||
| 604 | +} | ||
| 605 | + | ||
| 606 | +// ==================== TC118: DestroyDecPolicyInfos(nullptr) ==================== | ||
| 607 | + | ||
| 608 | +/** | ||
| 609 | + * @tc.name: SandboxDec_DestroyDecPolicyInfos_Null_001 | ||
| 610 | + * @tc.desc: Verify DestroyDecPolicyInfos handles NULL input without crash | ||
| 611 | + * @tc.type: FUNC | ||
| 612 | + */ | ||
| 613 | +HWTEST_F(SandboxDecTest, SandboxDec_DestroyDecPolicyInfos_Null_001, TestSize.Level1) | ||
| 614 | +{ | ||
| 615 | + // NULL input: early return, no crash, no state change | ||
| 616 | + DestroyDecPolicyInfos(nullptr); | ||
| 617 | + EXPECT_EQ(g_mockIoctlCallCount, 0); | ||
| 618 | + | ||
| 619 | + // Fill 8 paths, then destroy valid g_decPolicyInfos: global state cleared | ||
| 620 | + DecPolicyInfo info; | ||
| 621 | + FillPolicyInfo(info, KERNEL_BATCH_SIZE); | ||
| 622 | + SetDecPolicyInfos(&info); | ||
| 623 | + FreePolicyInfo(info); | ||
| 624 | + | ||
| 625 | + SetDecPolicy(); // consumes and destroys g_decPolicyInfos internally | ||
| 626 | + g_mockIoctlCallCount = 0; | ||
| 627 | + | ||
| 628 | + // After destroy, SetDecPolicy early-returns: no ioctl | ||
| 629 | + SetDecPolicy(); | ||
| 630 | + EXPECT_EQ(g_mockIoctlCallCount, 0); | ||
| 631 | +} | ||
| 632 | + | ||
| 633 | +// ==================== TC119: SetDecPolicyInfos(nullptr) ==================== | ||
| 634 | + | ||
| 635 | +/** | ||
| 636 | + * @tc.name: SandboxDec_SetDecPolicyInfos_Null_001 | ||
| 637 | + * @tc.desc: Verify SetDecPolicyInfos handles NULL input and SetDecPolicy does nothing | ||
| 638 | + * @tc.type: FUNC | ||
| 639 | + */ | ||
| 640 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_Null_001, TestSize.Level1) | ||
| 641 | +{ | ||
| 642 | + // Pre-fill 8 paths, then NULL input must not touch existing g_decPolicyInfos | ||
| 643 | + DecPolicyInfo pre; | ||
| 644 | + FillPolicyInfo(pre, KERNEL_BATCH_SIZE); | ||
| 645 | + SetDecPolicyInfos(&pre); | ||
| 646 | + FreePolicyInfo(pre); | ||
| 647 | + | ||
| 648 | + SetDecPolicyInfos(nullptr); | ||
| 649 | + | ||
| 650 | + // Existing 8 paths retained: SetDecPolicy still delivers 1 batch | ||
| 651 | + g_mockIoctlCallCount = 0; | ||
| 652 | + SetDecPolicy(); | ||
| 653 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 654 | + EXPECT_EQ(g_ioctlPathNums[0], KERNEL_BATCH_SIZE); | ||
| 655 | +} | ||
| 656 | + | ||
| 657 | +// ==================== TC120: SetDecPolicyInfos path[i].path==NULL ==================== | ||
| 658 | + | ||
| 659 | +/** | ||
| 660 | + * @tc.name: SandboxDec_SetDecPolicyInfos_NullPath_001 | ||
| 661 | + * @tc.desc: Verify SetDecPolicyInfos skips NULL path and continues | ||
| 662 | + * @tc.type: FUNC | ||
| 663 | + */ | ||
| 664 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_NullPath_001, TestSize.Level1) | ||
| 665 | +{ | ||
| 666 | + DecPolicyInfo info; | ||
| 667 | + errno_t rc = memset_s(&info, sizeof(DecPolicyInfo), 0, sizeof(DecPolicyInfo)); | ||
| 668 | + ASSERT_EQ(rc, EOK); | ||
| 669 | + info.pathNum = 2; | ||
| 670 | + info.path[0].path = nullptr; | ||
| 671 | + info.path[1].path = strdup("/data/test/null_path_1"); | ||
| 672 | + | ||
| 673 | + SetDecPolicyInfos(&info); | ||
| 674 | + | ||
| 675 | + // path[0] NULL skipped, path[1] added => 1 path in g_decPolicyInfos | ||
| 676 | + g_mockIoctlCallCount = 0; | ||
| 677 | + SetDecPolicy(); | ||
| 678 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 679 | + | ||
| 680 | + free(info.path[1].path); | ||
| 681 | +} | ||
| 682 | + | ||
| 683 | +// ==================== TC121: SetDenyConstraintDirs normal ==================== | ||
| 684 | + | ||
| 685 | +/** | ||
| 686 | + * @tc.name: SandboxDec_SetDenyConstraintDirs_Normal_001 | ||
| 687 | + * @tc.desc: Verify SetDenyConstraintDirs delivers 8 constraint dirs in 1 batch | ||
| 688 | + * @tc.type: FUNC | ||
| 689 | + */ | ||
| 690 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDenyConstraintDirs_Normal_001, TestSize.Level1) | ||
| 691 | +{ | ||
| 692 | + g_mockIoctlCallCount = 0; | ||
| 693 | + int ret = SetDenyConstraintDirs(nullptr); | ||
| 694 | + EXPECT_EQ(ret, 0); | ||
| 695 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 696 | + // g_decConstraintDir has exactly KERNEL_BATCH_SIZE entries: no end>size clip, full batch | ||
| 697 | + EXPECT_EQ(g_ioctlPathNums[0], KERNEL_BATCH_SIZE); | ||
| 698 | + EXPECT_NE(MOCK_OPEN_PATH, nullptr); | ||
| 699 | +} | ||
| 700 | + | ||
| 701 | +// ==================== TC122: SetDenyConstraintDirs open fail ==================== | ||
| 702 | + | ||
| 703 | +/** | ||
| 704 | + * @tc.name: SandboxDec_SetDenyConstraintDirs_OpenFail_001 | ||
| 705 | + * @tc.desc: Verify SetDenyConstraintDirs handles open failure gracefully | ||
| 706 | + * @tc.type: FUNC | ||
| 707 | + */ | ||
| 708 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDenyConstraintDirs_OpenFail_001, TestSize.Level1) | ||
| 709 | +{ | ||
| 710 | + g_mockOpenReturn = -1; | ||
| 711 | + g_mockIoctlCallCount = 0; | ||
| 712 | + | ||
| 713 | + int ret = SetDenyConstraintDirs(nullptr); | ||
| 714 | + EXPECT_EQ(ret, 0); | ||
| 715 | + EXPECT_EQ(g_mockIoctlCallCount, 0); | ||
| 716 | +} | ||
| 717 | + | ||
| 718 | +// ==================== TC123: SetDenyConstraintDirs ioctl fail ==================== | ||
| 719 | + | ||
| 720 | +/** | ||
| 721 | + * @tc.name: SandboxDec_SetDenyConstraintDirs_IoctlFail_001 | ||
| 722 | + * @tc.desc: Verify SetDenyConstraintDirs fail-open when ioctl fails | ||
| 723 | + * @tc.type: FUNC | ||
| 724 | + */ | ||
| 725 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDenyConstraintDirs_IoctlFail_001, TestSize.Level1) | ||
| 726 | +{ | ||
| 727 | + g_mockIoctlReturn = -1; | ||
| 728 | + g_mockIoctlCallCount = 0; | ||
| 729 | + | ||
| 730 | + int ret = SetDenyConstraintDirs(nullptr); | ||
| 731 | + EXPECT_EQ(ret, 0); | ||
| 732 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 733 | +} | ||
| 734 | + | ||
| 735 | +// ==================== TC124: SetForcedPrefixDirs normal ==================== | ||
| 736 | + | ||
| 737 | +/** | ||
| 738 | + * @tc.name: SandboxDec_SetForcedPrefixDirs_Normal_001 | ||
| 739 | + * @tc.desc: Verify SetForcedPrefixDirs delivers 1 prefix dir in 1 batch | ||
| 740 | + * @tc.type: FUNC | ||
| 741 | + */ | ||
| 742 | +HWTEST_F(SandboxDecTest, SandboxDec_SetForcedPrefixDirs_Normal_001, TestSize.Level1) | ||
| 743 | +{ | ||
| 744 | + g_mockIoctlCallCount = 0; | ||
| 745 | + int ret = SetForcedPrefixDirs(nullptr); | ||
| 746 | + EXPECT_EQ(ret, 0); | ||
| 747 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 748 | + // g_decForcedPrefix has 1 entry: end>size clip triggers, partial batch with pathNum=1 | ||
| 749 | + EXPECT_EQ(g_ioctlPathNums[0], 1u); | ||
| 750 | + EXPECT_NE(MOCK_OPEN_PATH, nullptr); | ||
| 751 | +} | ||
| 752 | + | ||
| 753 | +// ==================== TC125: SetForcedPrefixDirs open fail ==================== | ||
| 754 | + | ||
| 755 | +/** | ||
| 756 | + * @tc.name: SandboxDec_SetForcedPrefixDirs_OpenFail_001 | ||
| 757 | + * @tc.desc: Verify SetForcedPrefixDirs handles open failure gracefully | ||
| 758 | + * @tc.type: FUNC | ||
| 759 | + */ | ||
| 760 | +HWTEST_F(SandboxDecTest, SandboxDec_SetForcedPrefixDirs_OpenFail_001, TestSize.Level1) | ||
| 761 | +{ | ||
| 762 | + g_mockOpenReturn = -1; | ||
| 763 | + g_mockIoctlCallCount = 0; | ||
| 764 | + | ||
| 765 | + int ret = SetForcedPrefixDirs(nullptr); | ||
| 766 | + EXPECT_EQ(ret, 0); | ||
| 767 | + EXPECT_EQ(g_mockIoctlCallCount, 0); | ||
| 768 | +} | ||
| 769 | + | ||
| 770 | +// ==================== TC126: SetDecPolicyBatch direct valid call ==================== | ||
| 771 | + | ||
| 772 | +/** | ||
| 773 | + * @tc.name: SandboxDec_SetDecPolicyBatch_Valid_001 | ||
| 774 | + * @tc.desc: Verify SetDecPolicyBatch succeeds with valid parameters | ||
| 775 | + * @tc.type: FUNC | ||
| 776 | + */ | ||
| 777 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyBatch_Valid_001, TestSize.Level1) | ||
| 778 | +{ | ||
| 779 | + GlobalDecPolicyInfo info; | ||
| 780 | + errno_t rc = memset_s(&info, sizeof(GlobalDecPolicyInfo), 0, sizeof(GlobalDecPolicyInfo)); | ||
| 781 | + ASSERT_EQ(rc, EOK); | ||
| 782 | + info.pathNum = 4; | ||
| 783 | + info.path[0].path = (char *)"/data/test/batch0"; | ||
| 784 | + info.path[0].pathLen = static_cast<uint32_t>(strlen("/data/test/batch0")); | ||
| 785 | + info.path[1].path = (char *)"/data/test/batch1"; | ||
| 786 | + info.path[1].pathLen = static_cast<uint32_t>(strlen("/data/test/batch1")); | ||
| 787 | + info.path[2].path = (char *)"/data/test/batch2"; | ||
| 788 | + info.path[2].pathLen = static_cast<uint32_t>(strlen("/data/test/batch2")); | ||
| 789 | + info.path[3].path = (char *)"/data/test/batch3"; | ||
| 790 | + info.path[3].pathLen = static_cast<uint32_t>(strlen("/data/test/batch3")); | ||
| 791 | + | ||
| 792 | + g_mockIoctlCallCount = 0; | ||
| 793 | + int ret = SetDecPolicyBatch(3, &info, 1000, 0, 4); | ||
| 794 | + EXPECT_EQ(ret, 0); | ||
| 795 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 796 | +} | ||
| 797 | + | ||
| 798 | +// ==================== TC127: SetDecPolicyBatch direct ioctl fail ==================== | ||
| 799 | + | ||
| 800 | +/** | ||
| 801 | + * @tc.name: SandboxDec_SetDecPolicyBatch_IoctlFail_001 | ||
| 802 | + * @tc.desc: Verify SetDecPolicyBatch returns negative when ioctl fails | ||
| 803 | + * @tc.type: FUNC | ||
| 804 | + */ | ||
| 805 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyBatch_IoctlFail_001, TestSize.Level1) | ||
| 806 | +{ | ||
| 807 | + GlobalDecPolicyInfo info; | ||
| 808 | + errno_t rc = memset_s(&info, sizeof(GlobalDecPolicyInfo), 0, sizeof(GlobalDecPolicyInfo)); | ||
| 809 | + ASSERT_EQ(rc, EOK); | ||
| 810 | + info.pathNum = 2; | ||
| 811 | + info.path[0].path = (char *)"/data/test/fail0"; | ||
| 812 | + info.path[0].pathLen = static_cast<uint32_t>(strlen("/data/test/fail0")); | ||
| 813 | + info.path[1].path = (char *)"/data/test/fail1"; | ||
| 814 | + info.path[1].pathLen = static_cast<uint32_t>(strlen("/data/test/fail1")); | ||
| 815 | + | ||
| 816 | + g_mockIoctlReturn = -1; | ||
| 817 | + g_mockIoctlCallCount = 0; | ||
| 818 | + int ret = SetDecPolicyBatch(3, &info, 2000, 0, 2); | ||
| 819 | + EXPECT_LT(ret, 0); | ||
| 820 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 821 | +} | ||
| 822 | + | ||
| 823 | +// ==================== TC128: SetDecPolicyBatch count == KERNEL_BATCH_SIZE (boundary pass) ==================== | ||
| 824 | + | ||
| 825 | +/** | ||
| 826 | +* @tc.name: SandboxDec_SetDecPolicyBatch_MaxBatchSize_001 | ||
| 827 | +* @tc.desc: Verify SetDecPolicyBatch succeeds when count == KERNEL_BATCH_SIZE (boundary) | ||
| 828 | +* @tc.type: FUNC | ||
| 829 | +*/ | ||
| 830 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyBatch_MaxBatchSize_001, TestSize.Level1) | ||
| 831 | +{ | ||
| 832 | + GlobalDecPolicyInfo info; | ||
| 833 | + errno_t rc = memset_s(&info, sizeof(GlobalDecPolicyInfo), 0, sizeof(GlobalDecPolicyInfo)); | ||
| 834 | + ASSERT_EQ(rc, EOK); | ||
| 835 | + info.pathNum = KERNEL_BATCH_SIZE; | ||
| 836 | + for (uint32_t i = 0; i < KERNEL_BATCH_SIZE; i++) { | ||
| 837 | + info.path[i].path = (char *)"/data/test/batch_max"; | ||
| 838 | + info.path[i].pathLen = static_cast<uint32_t>(strlen("/data/test/batch_max")); | ||
| 839 | + info.path[i].mode = 0x1; | ||
| 840 | + info.path[i].flag = false; | ||
| 841 | + } | ||
| 842 | + | ||
| 843 | + g_mockIoctlCallCount = 0; | ||
| 844 | + int ret = SetDecPolicyBatch(3, &info, 1000, 0, KERNEL_BATCH_SIZE); | ||
| 845 | + EXPECT_EQ(ret, 0); | ||
| 846 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 847 | +} | ||
| 848 | + | ||
| 849 | +// ==================== TC129: accumulate to exactly MAX_POLICY_NUM ==================== | ||
| 850 | + | ||
| 851 | +/** | ||
| 852 | +* @tc.name: SandboxDec_SetDecPolicyInfos_ExactlyMax_001 | ||
| 853 | +* @tc.desc: Verify SetDecPolicyInfos succeeds when total pathNum == MAX_POLICY_NUM (boundary) | ||
| 854 | +* @tc.type: FUNC | ||
| 855 | +*/ | ||
| 856 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_ExactlyMax_001, TestSize.Level1) | ||
| 857 | +{ | ||
| 858 | + // Fill MAX_POLICY_NUM - KERNEL_BATCH_SIZE = 56 paths first | ||
| 859 | + FillMultiplePolicyInfos(MAX_POLICY_NUM - KERNEL_BATCH_SIZE); | ||
| 860 | + | ||
| 861 | + // Add KERNEL_BATCH_SIZE = 8 more => total = 64 = MAX_POLICY_NUM (boundary, should pass) | ||
| 862 | + DecPolicyInfo info; | ||
| 863 | + FillPolicyInfo(info, KERNEL_BATCH_SIZE); | ||
| 864 | + SetDecPolicyInfos(&info); | ||
| 865 | + | ||
| 866 | + g_mockIoctlCallCount = 0; | ||
| 867 | + SetDecPolicy(); | ||
| 868 | + | ||
| 869 | + uint32_t expectedBatches = (MAX_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; | ||
| 870 | + EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); | ||
| 871 | + FreePolicyInfo(info); | ||
| 872 | +} | ||
| 873 | + | ||
| 874 | +// ==================== TC130: SetDecPolicy 7 paths (non-multiple, end > pathNum, 1 batch) ==================== | ||
| 875 | + | ||
| 876 | +/** | ||
| 877 | +* @tc.name: SandboxDec_SetDecPolicy_7Paths_1Batch_001 | ||
| 878 | +* @tc.desc: Verify SetDecPolicy delivers 7 paths in 1 batch (non-multiple triggers end>pathNum clip) | ||
| 879 | +* @tc.type: FUNC | ||
| 880 | +*/ | ||
| 881 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_7Paths_1Batch_001, TestSize.Level1) | ||
| 882 | +{ | ||
| 883 | + FillMultiplePolicyInfos(7); | ||
| 884 | + | ||
| 885 | + g_mockIoctlCallCount = 0; | ||
| 886 | + SetDecPolicy(); | ||
| 887 | + | ||
| 888 | + // 7 paths: 1 batch, end=8>7 triggers clip to end=7 | ||
| 889 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 890 | +} | ||
| 891 | + | ||
| 892 | +// ==================== TC131: 17 paths, 3 batches, end>pathNum clip ==================== | ||
| 893 | + | ||
| 894 | +/** | ||
| 895 | +* @tc.name: SandboxDec_SetDecPolicy_17Paths_3Batches_001 | ||
| 896 | +* @tc.desc: Verify SetDecPolicy delivers 17 paths in 3 batches (end>pathNum clip on last batch) | ||
| 897 | +* @tc.type: FUNC | ||
| 898 | +*/ | ||
| 899 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_17Paths_3Batches_001, TestSize.Level1) | ||
| 900 | +{ | ||
| 901 | + FillMultiplePolicyInfos(17); | ||
| 902 | + | ||
| 903 | + g_mockIoctlCallCount = 0; | ||
| 904 | + SetDecPolicy(); | ||
| 905 | + | ||
| 906 | + // 17 paths: batch1=8, batch2=8, batch3=1 (end=24>17 clips to 17) | ||
| 907 | + EXPECT_EQ(g_mockIoctlCallCount, 3); | ||
| 908 | +} | ||
| 909 | + | ||
| 910 | +// ==================== TC132: SetIgnoreCaseDirs normal (AppSpawnMode) ==================== | ||
| 911 | + | ||
| 912 | +/** | ||
| 913 | +* @tc.name: SandboxDec_SetIgnoreCaseDirs_Normal_001 | ||
| 914 | +* @tc.desc: Verify SetIgnoreCaseDirs delivers ignore-case dirs in AppSpawn mode | ||
| 915 | +* @tc.type: FUNC | ||
| 916 | +*/ | ||
| 917 | +HWTEST_F(SandboxDecTest, SandboxDec_SetIgnoreCaseDirs_Normal_001, TestSize.Level1) | ||
| 918 | +{ | ||
| 919 | + AppSpawnMgr *mgr = (AppSpawnMgr *)calloc(1, sizeof(AppSpawnMgr)); | ||
| 920 | + ASSERT_NE(mgr, nullptr); | ||
| 921 | + mgr->content.mode = MODE_FOR_APP_SPAWN; | ||
| 922 | + | ||
| 923 | + g_mockIoctlCallCount = 0; | ||
| 924 | + g_mockOpenReturn = MOCK_OPEN_RETURN_FD; | ||
| 925 | + int ret = SetIgnoreCaseDirs(mgr); | ||
| 926 | + | ||
| 927 | + EXPECT_EQ(ret, 0); | ||
| 928 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 929 | + // ignore-case list has 2 or 3 entries (< KERNEL_BATCH_SIZE): end>pathNum clip triggers | ||
| 930 | + EXPECT_GT(g_ioctlPathNums[0], 0u); | ||
| 931 | + EXPECT_LT(g_ioctlPathNums[0], KERNEL_BATCH_SIZE); | ||
| 932 | + EXPECT_NE(MOCK_OPEN_PATH, nullptr); | ||
| 933 | + | ||
| 934 | + free(mgr); | ||
| 935 | +} | ||
| 936 | + | ||
| 937 | +// ==================== TC133: SetIgnoreCaseDirs wrong mode (early return) ==================== | ||
| 938 | + | ||
| 939 | +/** | ||
| 940 | +* @tc.name: SandboxDec_SetIgnoreCaseDirs_WrongMode_001 | ||
| 941 | +* @tc.desc: Verify SetIgnoreCaseDirs returns 0 early when not App/Native spawn mode | ||
| 942 | +* @tc.type: FUNC | ||
| 943 | +*/ | ||
| 944 | +HWTEST_F(SandboxDecTest, SandboxDec_SetIgnoreCaseDirs_WrongMode_001, TestSize.Level1) | ||
| 945 | +{ | ||
| 946 | + AppSpawnMgr *mgr = (AppSpawnMgr *)calloc(1, sizeof(AppSpawnMgr)); | ||
| 947 | + ASSERT_NE(mgr, nullptr); | ||
| 948 | + mgr->content.mode = MODE_FOR_NWEB_SPAWN; | ||
| 949 | + | ||
| 950 | + g_mockIoctlCallCount = 0; | ||
| 951 | + int ret = SetIgnoreCaseDirs(mgr); | ||
| 952 | + | ||
| 953 | + EXPECT_EQ(ret, 0); | ||
| 954 | + EXPECT_EQ(g_mockIoctlCallCount, 0); | ||
| 955 | + | ||
| 956 | + free(mgr); | ||
| 957 | +} | ||
| 958 | + | ||
| 959 | +// ==================== TC134: SetIgnoreCaseDirs open fail ==================== | ||
| 960 | + | ||
| 961 | +/** | ||
| 962 | +* @tc.name: SandboxDec_SetIgnoreCaseDirs_OpenFail_001 | ||
| 963 | +* @tc.desc: Verify SetIgnoreCaseDirs handles open failure gracefully | ||
| 964 | +* @tc.type: FUNC | ||
| 965 | +*/ | ||
| 966 | +HWTEST_F(SandboxDecTest, SandboxDec_SetIgnoreCaseDirs_OpenFail_001, TestSize.Level1) | ||
| 967 | +{ | ||
| 968 | + AppSpawnMgr *mgr = (AppSpawnMgr *)calloc(1, sizeof(AppSpawnMgr)); | ||
| 969 | + ASSERT_NE(mgr, nullptr); | ||
| 970 | + mgr->content.mode = MODE_FOR_NATIVE_SPAWN; | ||
| 971 | + | ||
| 972 | + g_mockOpenReturn = -1; | ||
| 973 | + g_mockIoctlCallCount = 0; | ||
| 974 | + int ret = SetIgnoreCaseDirs(mgr); | ||
| 975 | + | ||
| 976 | + EXPECT_EQ(ret, 0); | ||
| 977 | + EXPECT_EQ(g_mockIoctlCallCount, 0); | ||
| 978 | + | ||
| 979 | + free(mgr); | ||
| 980 | +} | ||
| 981 | + | ||
| 982 | +// ==================== TC135: SetDecPolicyInfos mid-loop NULL path (path[0] valid, path[1] NULL) ==================== | ||
| 983 | + | ||
| 984 | +/** | ||
| 985 | +* @tc.name: SandboxDec_SetDecPolicyInfos_MidLoopNullPath_001 | ||
| 986 | +* @tc.desc: Verify SetDecPolicyInfos keeps already-added path when NULL encountered at i=1 | ||
| 987 | +* @tc.type: FUNC | ||
| 988 | +*/ | ||
| 989 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_MidLoopNullPath_001, TestSize.Level1) | ||
| 990 | +{ | ||
| 991 | + DecPolicyInfo info; | ||
| 992 | + errno_t rc = memset_s(&info, sizeof(DecPolicyInfo), 0, sizeof(DecPolicyInfo)); | ||
| 993 | + ASSERT_EQ(rc, EOK); | ||
| 994 | + info.pathNum = 2; | ||
| 995 | + info.path[0].path = strdup("/data/test/midloop_valid"); | ||
| 996 | + ASSERT_NE(info.path[0].path, nullptr); | ||
| 997 | + info.path[0].pathLen = static_cast<uint32_t>(strlen("/data/test/midloop_valid")); | ||
| 998 | + info.path[0].mode = 0x1; | ||
| 999 | + info.path[1].path = nullptr; | ||
| 1000 | + | ||
| 1001 | + SetDecPolicyInfos(&info); | ||
| 1002 | + | ||
| 1003 | + // path[0] added (pathNum=1), path[1] NULL skipped, g_decPolicyInfos retained | ||
| 1004 | + g_mockIoctlCallCount = 0; | ||
| 1005 | + SetDecPolicy(); | ||
| 1006 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 1007 | + | ||
| 1008 | + free(info.path[0].path); | ||
| 1009 | +} | ||
| 1010 | + | ||
| 1011 | +// ==================== TC136: SetDenyConstraintDirs ioctl success path ==================== | ||
| 1012 | + | ||
| 1013 | +/** | ||
| 1014 | +* @tc.name: SandboxDec_SetDenyConstraintDirs_IoctlSuccess_001 | ||
| 1015 | +* @tc.desc: Verify SetDenyConstraintDirs executes ioctl success branch (ret >= 0) | ||
| 1016 | +* @tc.type: FUNC | ||
| 1017 | +*/ | ||
| 1018 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDenyConstraintDirs_IoctlSuccess_001, TestSize.Level1) | ||
| 1019 | +{ | ||
| 1020 | + g_mockIoctlReturn = 0; | ||
| 1021 | + g_mockIoctlCallCount = 0; | ||
| 1022 | + g_lastIoctlReq = 0; | ||
| 1023 | + | ||
| 1024 | + int ret = SetDenyConstraintDirs(nullptr); | ||
| 1025 | + | ||
| 1026 | + EXPECT_EQ(ret, 0); | ||
| 1027 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 1028 | + EXPECT_NE(g_lastIoctlReq, 0UL); | ||
| 1029 | +} | ||
| 1030 | + | ||
| 1031 | +// ==================== TC137: SetForcedPrefixDirs ioctl success path ==================== | ||
| 1032 | + | ||
| 1033 | +/** | ||
| 1034 | +* @tc.name: SandboxDec_SetForcedPrefixDirs_IoctlSuccess_001 | ||
| 1035 | +* @tc.desc: Verify SetForcedPrefixDirs executes ioctl success branch (ret >= 0) | ||
| 1036 | +* @tc.type: FUNC | ||
| 1037 | +*/ | ||
| 1038 | +HWTEST_F(SandboxDecTest, SandboxDec_SetForcedPrefixDirs_IoctlSuccess_001, TestSize.Level1) | ||
| 1039 | +{ | ||
| 1040 | + g_mockIoctlReturn = 0; | ||
| 1041 | + g_mockIoctlCallCount = 0; | ||
| 1042 | + g_lastIoctlReq = 0; | ||
| 1043 | + | ||
| 1044 | + int ret = SetForcedPrefixDirs(nullptr); | ||
| 1045 | + | ||
| 1046 | + EXPECT_EQ(ret, 0); | ||
| 1047 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 1048 | + EXPECT_NE(g_lastIoctlReq, 0UL); | ||
| 1049 | +} | ||
| 1050 | + | ||
| 1051 | +// ==================== TC138: SetForcedPrefixDirs ioctl fail ==================== | ||
| 1052 | + | ||
| 1053 | +/** | ||
| 1054 | +* @tc.name: SandboxDec_SetForcedPrefixDirs_IoctlFail_001 | ||
| 1055 | +* @tc.desc: Verify SetForcedPrefixDirs handles ioctl failure gracefully (fail-open) | ||
| 1056 | +* @tc.type: FUNC | ||
| 1057 | +*/ | ||
| 1058 | +HWTEST_F(SandboxDecTest, SandboxDec_SetForcedPrefixDirs_IoctlFail_001, TestSize.Level1) | ||
| 1059 | +{ | ||
| 1060 | + g_mockIoctlReturn = -1; | ||
| 1061 | + g_mockIoctlCallCount = 0; | ||
| 1062 | + | ||
| 1063 | + int ret = SetForcedPrefixDirs(nullptr); | ||
| 1064 | + | ||
| 1065 | + EXPECT_EQ(ret, 0); | ||
| 1066 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 1067 | +} | ||
| 1068 | + | ||
| 1069 | +// ==================== TC139: SetIgnoreCaseDirs ioctl fail ==================== | ||
| 1070 | + | ||
| 1071 | +/** | ||
| 1072 | +* @tc.name: SandboxDec_SetIgnoreCaseDirs_IoctlFail_001 | ||
| 1073 | +* @tc.desc: Verify SetIgnoreCaseDirs handles ioctl failure gracefully (fail-open) | ||
| 1074 | +* @tc.type: FUNC | ||
| 1075 | +*/ | ||
| 1076 | +HWTEST_F(SandboxDecTest, SandboxDec_SetIgnoreCaseDirs_IoctlFail_001, TestSize.Level1) | ||
| 1077 | +{ | ||
| 1078 | + AppSpawnMgr *mgr = (AppSpawnMgr *)calloc(1, sizeof(AppSpawnMgr)); | ||
| 1079 | + ASSERT_NE(mgr, nullptr); | ||
| 1080 | + mgr->content.mode = MODE_FOR_APP_SPAWN; | ||
| 1081 | + | ||
| 1082 | + g_mockIoctlReturn = -1; | ||
| 1083 | + g_mockIoctlCallCount = 0; | ||
| 1084 | + g_mockOpenReturn = MOCK_OPEN_RETURN_FD; | ||
| 1085 | + | ||
| 1086 | + int ret = SetIgnoreCaseDirs(mgr); | ||
| 1087 | + | ||
| 1088 | + EXPECT_EQ(ret, 0); | ||
| 1089 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 1090 | + | ||
| 1091 | + free(mgr); | ||
| 1092 | +} | ||
| 1093 | + | ||
| 1094 | +// ==================== TC140: SetDecPolicyBatch with non-zero start ==================== | ||
| 1095 | + | ||
| 1096 | +/** | ||
| 1097 | +* @tc.name: SandboxDec_SetDecPolicyBatch_NonZeroStart_001 | ||
| 1098 | +* @tc.desc: Verify SetDecPolicyBatch correctly indexes paths when start > 0 | ||
| 1099 | +* @tc.type: FUNC | ||
| 1100 | +*/ | ||
| 1101 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyBatch_NonZeroStart_001, TestSize.Level1) | ||
| 1102 | +{ | ||
| 1103 | + GlobalDecPolicyInfo info; | ||
| 1104 | + errno_t rc = memset_s(&info, sizeof(GlobalDecPolicyInfo), 0, sizeof(GlobalDecPolicyInfo)); | ||
| 1105 | + ASSERT_EQ(rc, EOK); | ||
| 1106 | + info.pathNum = KERNEL_BATCH_SIZE * 2; // 16 paths | ||
| 1107 | + for (uint32_t i = 0; i < KERNEL_BATCH_SIZE * 2; i++) { | ||
| 1108 | + info.path[i].path = (char *)"/data/test/start_offset"; | ||
| 1109 | + info.path[i].pathLen = static_cast<uint32_t>(strlen("/data/test/start_offset")); | ||
| 1110 | + info.path[i].mode = 0x1; | ||
| 1111 | + info.path[i].flag = false; | ||
| 1112 | + } | ||
| 1113 | + | ||
| 1114 | + // Batch 2: start=8, count=8 | ||
| 1115 | + g_mockIoctlCallCount = 0; | ||
| 1116 | + int ret = SetDecPolicyBatch(3, &info, 5000, KERNEL_BATCH_SIZE, KERNEL_BATCH_SIZE); | ||
| 1117 | + EXPECT_EQ(ret, 0); | ||
| 1118 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 1119 | +} | ||
| 1120 | + | ||
| 1121 | +// ==================== TC141: SetDecPolicyInfos strdup fail (skip path) ==================== | ||
| 1122 | + | ||
| 1123 | +/** | ||
| 1124 | +* @tc.name: SandboxDec_SetDecPolicyInfos_StrdupFail_001 | ||
| 1125 | +* @tc.desc: Verify SetDecPolicyInfos skips path when strdup fails, retains existing | ||
| 1126 | +* @tc.type: FUNC | ||
| 1127 | +*/ | ||
| 1128 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_StrdupFail_001, TestSize.Level1) | ||
| 1129 | +{ | ||
| 1130 | + // Pre-fill 8 paths successfully | ||
| 1131 | + DecPolicyInfo pre; | ||
| 1132 | + FillPolicyInfo(pre, KERNEL_BATCH_SIZE); | ||
| 1133 | + SetDecPolicyInfos(&pre); | ||
| 1134 | + FreePolicyInfo(pre); | ||
| 1135 | + | ||
| 1136 | + // Then 2 more paths, but strdup fails for both: skipped, existing 8 retained | ||
| 1137 | + DecPolicyInfo info; | ||
| 1138 | + FillPolicyInfo(info, 2, KERNEL_BATCH_SIZE); | ||
| 1139 | + | ||
| 1140 | + g_mockStrdupShouldFail = true; | ||
| 1141 | + SetDecPolicyInfos(&info); | ||
| 1142 | + g_mockStrdupShouldFail = false; | ||
| 1143 | + | ||
| 1144 | + // Still exactly 8 paths = 1 batch | ||
| 1145 | + g_mockIoctlCallCount = 0; | ||
| 1146 | + SetDecPolicy(); | ||
| 1147 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 1148 | + EXPECT_EQ(g_ioctlPathNums[0], KERNEL_BATCH_SIZE); | ||
| 1149 | + | ||
| 1150 | + FreePolicyInfo(info); | ||
| 1151 | +} | ||
| 1152 | + | ||
| 1153 | +// ==================== TC142: 32 paths single call, verify per-batch pathNum [8,8,8,8] ==================== | ||
| 1154 | + | ||
| 1155 | +/** | ||
| 1156 | +* @tc.name: SandboxDec_SetDecPolicy_32Paths_BatchPathNums_001 | ||
| 1157 | +* @tc.desc: Verify SetDecPolicyInfos stores exactly 32 paths, delivered as 4 batches each with pathNum=8 | ||
| 1158 | +* @tc.type: FUNC | ||
| 1159 | +*/ | ||
| 1160 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_32Paths_BatchPathNums_001, TestSize.Level1) | ||
| 1161 | +{ | ||
| 1162 | + DecPolicyInfo info; | ||
| 1163 | + FillPolicyInfo(info, MAX_CONFIG_POLICY_NUM); | ||
| 1164 | + SetDecPolicyInfos(&info); | ||
| 1165 | + | ||
| 1166 | + g_mockIoctlCallCount = 0; | ||
| 1167 | + SetDecPolicy(); | ||
| 1168 | + | ||
| 1169 | + EXPECT_EQ(g_mockIoctlCallCount, 4); | ||
| 1170 | + for (int i = 0; i < 4; i++) { | ||
| 1171 | + EXPECT_EQ(g_ioctlPathNums[i], KERNEL_BATCH_SIZE) | ||
| 1172 | + << "batch " << i << " pathNum mismatch"; | ||
| 1173 | + } | ||
| 1174 | + FreePolicyInfo(info); | ||
| 1175 | +} | ||
| 1176 | + | ||
| 1177 | +// ==================== TC143: 31 paths single call, verify per-batch pathNum [8,8,8,7] ==================== | ||
| 1178 | + | ||
| 1179 | +/** | ||
| 1180 | +* @tc.name: SandboxDec_SetDecPolicy_31Paths_BatchPathNums_001 | ||
| 1181 | +* @tc.desc: Verify 31 paths stored and delivered as 4 batches [8,8,8,7] (no truncation under MAX_CONFIG_POLICY_NUM) | ||
| 1182 | +* @tc.type: FUNC | ||
| 1183 | +*/ | ||
| 1184 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_31Paths_BatchPathNums_001, TestSize.Level1) | ||
| 1185 | +{ | ||
| 1186 | + DecPolicyInfo info; | ||
| 1187 | + FillPolicyInfo(info, MAX_CONFIG_POLICY_NUM - 1); | ||
| 1188 | + SetDecPolicyInfos(&info); | ||
| 1189 | + | ||
| 1190 | + g_mockIoctlCallCount = 0; | ||
| 1191 | + SetDecPolicy(); | ||
| 1192 | + | ||
| 1193 | + EXPECT_EQ(g_mockIoctlCallCount, 4); | ||
| 1194 | + EXPECT_EQ(g_ioctlPathNums[0], KERNEL_BATCH_SIZE); | ||
| 1195 | + EXPECT_EQ(g_ioctlPathNums[1], KERNEL_BATCH_SIZE); | ||
| 1196 | + EXPECT_EQ(g_ioctlPathNums[2], KERNEL_BATCH_SIZE); | ||
| 1197 | + EXPECT_EQ(g_ioctlPathNums[3], MAX_CONFIG_POLICY_NUM - 1 - KERNEL_BATCH_SIZE * 3); | ||
| 1198 | + FreePolicyInfo(info); | ||
| 1199 | +} | ||
| 1200 | + | ||
| 1201 | +// ==================== TC144: 33 paths (32+1), verify per-batch pathNum [8,8,8,8,1] ==================== | ||
| 1202 | + | ||
| 1203 | +/** | ||
| 1204 | +* @tc.name: SandboxDec_SetDecPolicy_33Paths_BatchPathNums_001 | ||
| 1205 | +* @tc.desc: Verify 33 paths (two SetDecPolicyInfos calls: 32+1) delivered as 5 batches [8,8,8,8,1] | ||
| 1206 | +* @tc.type: FUNC | ||
| 1207 | +*/ | ||
| 1208 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_33Paths_BatchPathNums_001, TestSize.Level1) | ||
| 1209 | +{ | ||
| 1210 | + DecPolicyInfo info32; | ||
| 1211 | + FillPolicyInfo(info32, MAX_CONFIG_POLICY_NUM); | ||
| 1212 | + SetDecPolicyInfos(&info32); | ||
| 1213 | + FreePolicyInfo(info32); | ||
| 1214 | + | ||
| 1215 | + DecPolicyInfo info1; | ||
| 1216 | + FillPolicyInfo(info1, 1, MAX_CONFIG_POLICY_NUM); | ||
| 1217 | + SetDecPolicyInfos(&info1); | ||
| 1218 | + FreePolicyInfo(info1); | ||
| 1219 | + | ||
| 1220 | + g_mockIoctlCallCount = 0; | ||
| 1221 | + SetDecPolicy(); | ||
| 1222 | + | ||
| 1223 | + EXPECT_EQ(g_mockIoctlCallCount, 5); | ||
| 1224 | + for (int i = 0; i < 4; i++) { | ||
| 1225 | + EXPECT_EQ(g_ioctlPathNums[i], KERNEL_BATCH_SIZE) | ||
| 1226 | + << "batch " << i << " pathNum mismatch"; | ||
| 1227 | + } | ||
| 1228 | + EXPECT_EQ(g_ioctlPathNums[4], 1u); | ||
| 1229 | +} | ||
| 1230 | + | ||
| 1231 | +// ==================== TC145: MAX_POLICY_NUM paths, verify per-batch pathNum ==================== | ||
| 1232 | + | ||
| 1233 | +/** | ||
| 1234 | +* @tc.name: SandboxDec_SetDecPolicy_MaxPaths_BatchPathNums_001 | ||
| 1235 | +* @tc.desc: Verify MAX_POLICY_NUM paths delivered as expected batches each with pathNum=KERNEL_BATCH_SIZE | ||
| 1236 | +* @tc.type: FUNC | ||
| 1237 | +*/ | ||
| 1238 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_MaxPaths_BatchPathNums_001, TestSize.Level1) | ||
| 1239 | +{ | ||
| 1240 | + FillMultiplePolicyInfos(MAX_POLICY_NUM); | ||
| 1241 | + | ||
| 1242 | + g_mockIoctlCallCount = 0; | ||
| 1243 | + SetDecPolicy(); | ||
| 1244 | + | ||
| 1245 | + uint32_t expectedBatches = (MAX_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; | ||
| 1246 | + EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); | ||
| 1247 | + for (uint32_t i = 0; i < expectedBatches; i++) { | ||
| 1248 | + EXPECT_EQ(g_ioctlPathNums[i], KERNEL_BATCH_SIZE) | ||
| 1249 | + << "batch " << i << " pathNum mismatch"; | ||
| 1250 | + } | ||
| 1251 | +} | ||
| 1252 | + | ||
| 1253 | +// ==================== TC146: 1 path, verify per-batch pathNum [1] ==================== | ||
| 1254 | + | ||
| 1255 | +/** | ||
| 1256 | +* @tc.name: SandboxDec_SetDecPolicy_1Path_BatchPathNum_001 | ||
| 1257 | +* @tc.desc: Verify single path delivered as 1 batch with pathNum=1 | ||
| 1258 | +* @tc.type: FUNC | ||
| 1259 | +*/ | ||
| 1260 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_1Path_BatchPathNum_001, TestSize.Level1) | ||
| 1261 | +{ | ||
| 1262 | + DecPolicyInfo info; | ||
| 1263 | + FillPolicyInfo(info, 1); | ||
| 1264 | + SetDecPolicyInfos(&info); | ||
| 1265 | + | ||
| 1266 | + g_mockIoctlCallCount = 0; | ||
| 1267 | + SetDecPolicy(); | ||
| 1268 | + | ||
| 1269 | + EXPECT_EQ(g_mockIoctlCallCount, 1); | ||
| 1270 | + EXPECT_EQ(g_ioctlPathNums[0], 1u); | ||
| 1271 | + FreePolicyInfo(info); | ||
| 1272 | +} | ||
| 1273 | + | ||
| 1274 | +// ==================== TC147: 9 paths, verify per-batch pathNum [8,1] ==================== | ||
| 1275 | + | ||
| 1276 | +/** | ||
| 1277 | +* @tc.name: SandboxDec_SetDecPolicy_9Paths_BatchPathNums_001 | ||
| 1278 | +* @tc.desc: Verify 9 paths delivered as 2 batches [8,1] | ||
| 1279 | +* @tc.type: FUNC | ||
| 1280 | +*/ | ||
| 1281 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_9Paths_BatchPathNums_001, TestSize.Level1) | ||
| 1282 | +{ | ||
| 1283 | + DecPolicyInfo info9; | ||
| 1284 | + FillPolicyInfo(info9, KERNEL_BATCH_SIZE); | ||
| 1285 | + SetDecPolicyInfos(&info9); | ||
| 1286 | + FreePolicyInfo(info9); | ||
| 1287 | + | ||
| 1288 | + DecPolicyInfo info1; | ||
| 1289 | + FillPolicyInfo(info1, 1, KERNEL_BATCH_SIZE); | ||
| 1290 | + SetDecPolicyInfos(&info1); | ||
| 1291 | + FreePolicyInfo(info1); | ||
| 1292 | + | ||
| 1293 | + g_mockIoctlCallCount = 0; | ||
| 1294 | + SetDecPolicy(); | ||
| 1295 | + | ||
| 1296 | + EXPECT_EQ(g_mockIoctlCallCount, 2); | ||
| 1297 | + EXPECT_EQ(g_ioctlPathNums[0], KERNEL_BATCH_SIZE); | ||
| 1298 | + EXPECT_EQ(g_ioctlPathNums[1], 1u); | ||
| 1299 | +} | ||
| 1300 | + | ||
| 1301 | +// ==================== TC148: fill to exactly MAX_POLICY_NUM, no second-layer clip ==================== | ||
| 1302 | + | ||
| 1303 | +/** | ||
| 1304 | +* @tc.name: SandboxDec_SetDecPolicy_FillExactlyFull_001 | ||
| 1305 | +* @tc.desc: Verify filling global to exactly MAX_POLICY_NUM, no second-layer clip | ||
| 1306 | +* @tc.type: FUNC | ||
| 1307 | +*/ | ||
| 1308 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_FillExactlyFull_001, TestSize.Level1) | ||
| 1309 | +{ | ||
| 1310 | + FillMultiplePolicyInfos(MAX_POLICY_NUM); | ||
| 1311 | + | ||
| 1312 | + g_mockIoctlCallCount = 0; | ||
| 1313 | + SetDecPolicy(); | ||
| 1314 | + | ||
| 1315 | + uint32_t expectedBatches = (MAX_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; | ||
| 1316 | + EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); | ||
| 1317 | + for (uint32_t i = 0; i < expectedBatches; i++) { | ||
| 1318 | + EXPECT_EQ(g_ioctlPathNums[i], KERNEL_BATCH_SIZE) | ||
| 1319 | + << "batch " << i << " pathNum mismatch"; | ||
| 1320 | + } | ||
| 1321 | +} | ||
| 1322 | + | ||
| 1323 | +// ==================== TC149: MAX_POLICY_NUM-1 + MAX_CONFIG_POLICY_NUM, second-layer clip ==================== | ||
| 1324 | + | ||
| 1325 | +/** | ||
| 1326 | +* @tc.name: SandboxDec_SetDecPolicy_SecondLayerClip_001 | ||
| 1327 | +* @tc.desc: Verify partial apply when global + new > MAX_POLICY_NUM (second-layer clip) | ||
| 1328 | +* @tc.type: FUNC | ||
| 1329 | +*/ | ||
| 1330 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_SecondLayerClip_001, TestSize.Level1) | ||
| 1331 | +{ | ||
| 1332 | + FillMultiplePolicyInfos(MAX_POLICY_NUM - 1); | ||
| 1333 | + | ||
| 1334 | + DecPolicyInfo info; | ||
| 1335 | + FillPolicyInfo(info, MAX_CONFIG_POLICY_NUM, MAX_POLICY_NUM - 1); | ||
| 1336 | + SetDecPolicyInfos(&info); | ||
| 1337 | + FreePolicyInfo(info); | ||
| 1338 | + | ||
| 1339 | + g_mockIoctlCallCount = 0; | ||
| 1340 | + SetDecPolicy(); | ||
| 1341 | + | ||
| 1342 | + uint32_t expectedBatches = (MAX_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; | ||
| 1343 | + EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); | ||
| 1344 | + for (uint32_t i = 0; i < expectedBatches; i++) { | ||
| 1345 | + EXPECT_EQ(g_ioctlPathNums[i], KERNEL_BATCH_SIZE) | ||
| 1346 | + << "batch " << i << " pathNum mismatch"; | ||
| 1347 | + } | ||
| 1348 | +} | ||
| 1349 | + | ||
| 1350 | +// ==================== TC150: second-layer clip, verify batch distribution ==================== | ||
| 1351 | + | ||
| 1352 | +/** | ||
| 1353 | +* @tc.name: SandboxDec_SetDecPolicy_ClipBatchDistribution_001 | ||
| 1354 | +* @tc.desc: Verify after second-layer clip, paths distributed as full batches + 1 remainder | ||
| 1355 | +* @tc.type: FUNC | ||
| 1356 | +*/ | ||
| 1357 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicy_ClipBatchDistribution_001, TestSize.Level1) | ||
| 1358 | +{ | ||
| 1359 | + FillMultiplePolicyInfos(MAX_POLICY_NUM - 1); | ||
| 1360 | + DecPolicyInfo info; | ||
| 1361 | + FillPolicyInfo(info, MAX_CONFIG_POLICY_NUM, MAX_POLICY_NUM - 1); | ||
| 1362 | + SetDecPolicyInfos(&info); | ||
| 1363 | + FreePolicyInfo(info); | ||
| 1364 | + | ||
| 1365 | + g_mockIoctlCallCount = 0; | ||
| 1366 | + SetDecPolicy(); | ||
| 1367 | + | ||
| 1368 | + uint32_t expectedBatches = (MAX_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; | ||
| 1369 | + EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); | ||
| 1370 | + uint32_t totalPaths = 0; | ||
| 1371 | + for (uint32_t i = 0; i < expectedBatches; i++) { | ||
| 1372 | + EXPECT_EQ(g_ioctlPathNums[i], KERNEL_BATCH_SIZE) | ||
| 1373 | + << "batch " << i << " pathNum mismatch"; | ||
| 1374 | + totalPaths += g_ioctlPathNums[i]; | ||
| 1375 | + } | ||
| 1376 | + EXPECT_EQ(totalPaths, static_cast<uint32_t>(MAX_POLICY_NUM)); | ||
| 1377 | +} | ||
| 1378 | + | ||
| 1379 | +// ==================== TC151: SetDecPolicyInfos clamp pathNum > MAX_CONFIG_POLICY_NUM ==================== | ||
| 1380 | + | ||
| 1381 | +/** | ||
| 1382 | +* @tc.name: SandboxDec_SetDecPolicyInfos_InputClamp_001 | ||
| 1383 | +* @tc.desc: Verify SetDecPolicyInfos clamps input pathNum to MAX_CONFIG_POLICY_NUM, no OOB read | ||
| 1384 | +* @tc.type: FUNC | ||
| 1385 | +*/ | ||
| 1386 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_InputClamp_001, TestSize.Level1) | ||
| 1387 | +{ | ||
| 1388 | + DecPolicyInfo info; | ||
| 1389 | + errno_t rc = memset_s(&info, sizeof(DecPolicyInfo), 0, sizeof(DecPolicyInfo)); | ||
| 1390 | + ASSERT_EQ(rc, EOK); | ||
| 1391 | + // Only fill real path entries (capacity is MAX_CONFIG_POLICY_NUM) | ||
| 1392 | + for (uint32_t i = 0; i < MAX_CONFIG_POLICY_NUM; i++) { | ||
| 1393 | + std::string pathStr = "/data/test/clamp_" + std::to_string(i); | ||
| 1394 | + info.path[i].path = strdup(pathStr.c_str()); | ||
| 1395 | + info.path[i].pathLen = static_cast<uint32_t>(pathStr.length()); | ||
| 1396 | + info.path[i].mode = 0x1; | ||
| 1397 | + } | ||
| 1398 | + // Lie about pathNum: claims more than path[] capacity | ||
| 1399 | + info.pathNum = MAX_CONFIG_POLICY_NUM + 8; | ||
| 1400 | + info.tokenId = MOCK_TOKEN_ID; | ||
| 1401 | + | ||
| 1402 | + SetDecPolicyInfos(&info); | ||
| 1403 | + | ||
| 1404 | + // Input clamped to MAX_CONFIG_POLICY_NUM, stored paths delivered as batches | ||
| 1405 | + g_mockIoctlCallCount = 0; | ||
| 1406 | + SetDecPolicy(); | ||
| 1407 | + uint32_t expectedBatches = (MAX_CONFIG_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; | ||
| 1408 | + EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); | ||
| 1409 | + uint32_t totalPaths = 0; | ||
| 1410 | + for (uint32_t i = 0; i < expectedBatches; i++) { | ||
| 1411 | + totalPaths += g_ioctlPathNums[i]; | ||
| 1412 | + } | ||
| 1413 | + EXPECT_EQ(totalPaths, static_cast<uint32_t>(MAX_CONFIG_POLICY_NUM)); | ||
| 1414 | + | ||
| 1415 | + for (uint32_t i = 0; i < MAX_CONFIG_POLICY_NUM; i++) { | ||
| 1416 | + free(info.path[i].path); | ||
| 1417 | + } | ||
| 1418 | +} | ||
| 1419 | + | ||
| 1420 | +// ==================== TC152: SetDecPolicyInfos input clamp preserves valid prefix ==================== | ||
| 1421 | + | ||
| 1422 | +/** | ||
| 1423 | +* @tc.name: SandboxDec_SetDecPolicyInfos_InputClampBoundary_001 | ||
| 1424 | +* @tc.desc: Verify input pathNum == MAX_CONFIG_POLICY_NUM + 1 clamps to MAX_CONFIG_POLICY_NUM | ||
| 1425 | +* @tc.type: FUNC | ||
| 1426 | +*/ | ||
| 1427 | +HWTEST_F(SandboxDecTest, SandboxDec_SetDecPolicyInfos_InputClampBoundary_001, TestSize.Level1) | ||
| 1428 | +{ | ||
| 1429 | + DecPolicyInfo info; | ||
| 1430 | + errno_t rc = memset_s(&info, sizeof(DecPolicyInfo), 0, sizeof(DecPolicyInfo)); | ||
| 1431 | + ASSERT_EQ(rc, EOK); | ||
| 1432 | + for (uint32_t i = 0; i < MAX_CONFIG_POLICY_NUM; i++) { | ||
| 1433 | + std::string pathStr = "/data/test/clamp_b_" + std::to_string(i); | ||
| 1434 | + info.path[i].path = strdup(pathStr.c_str()); | ||
| 1435 | + info.path[i].pathLen = static_cast<uint32_t>(pathStr.length()); | ||
| 1436 | + info.path[i].mode = 0x1; | ||
| 1437 | + } | ||
| 1438 | + info.pathNum = MAX_CONFIG_POLICY_NUM + 1; | ||
| 1439 | + | ||
| 1440 | + SetDecPolicyInfos(&info); | ||
| 1441 | + | ||
| 1442 | + g_mockIoctlCallCount = 0; | ||
| 1443 | + SetDecPolicy(); | ||
| 1444 | + uint32_t expectedBatches = (MAX_CONFIG_POLICY_NUM + KERNEL_BATCH_SIZE - 1) / KERNEL_BATCH_SIZE; | ||
| 1445 | + EXPECT_EQ(g_mockIoctlCallCount, static_cast<int>(expectedBatches)); | ||
| 1446 | + uint32_t totalPaths = 0; | ||
| 1447 | + for (uint32_t i = 0; i < expectedBatches; i++) { | ||
| 1448 | + totalPaths += g_ioctlPathNums[i]; | ||
| 1449 | + } | ||
| 1450 | + EXPECT_EQ(totalPaths, static_cast<uint32_t>(MAX_CONFIG_POLICY_NUM)); | ||
| 1451 | + | ||
| 1452 | + for (uint32_t i = 0; i < MAX_CONFIG_POLICY_NUM; i++) { | ||
| 1453 | + free(info.path[i].path); | ||
| 1454 | + } | ||
| 1455 | +} | ||
| 1456 | + | ||
| 498 | } // namespace OHOS | 1457 | } // namespace OHOS |


🤖 AI 代码检视意见 | ✨ Quality | ✅ Low | 行号区间: L1524-L1526
问题描述: 日志
"dec policy %{public}u exceeds max %{public}d, truncating to first %{public}d"中,totalPaths为uint32_t使用%u正确,但MAX_CONFIG_POLICY_NUM为宏定义展开后类型不确定,使用%d假设为有符号int。若MAX_CONFIG_POLICY_NUM被定义为无符号字面量(如32u),传入%d属于未定义行为。建议统一使用%u并显式转换。💡 查看修复建议(点击展开)
修改建议:将MAX_CONFIG_POLICY_NUM显式转换为uint32_t,并统一使用%u格式化符,避免类型不匹配。