已关闭
feat: appspawn 解耦基建 P1+P2(引擎原语抽离 + 策略表框架) #2945
wangfenging创建于 10 天前关闭于 3 天前
feat: appspawn 解耦基建 P1+P2(引擎原语抽离 + 策略表框架) #2945
已关闭
共 12 个文件变更+688-32
| @@ -0,0 +1,36 @@ | |||
| 1 | +{ | ||
| 2 | + "policies": [ | ||
| 3 | + { | ||
| 4 | + "name": "app", | ||
| 5 | + "uidFrom": "tlv:dac", | ||
| 6 | + "gidFrom": "tlv:dac", | ||
| 7 | + "caps": "tlv:caps", | ||
| 8 | + "selinux": "tlv:selinux", | ||
| 9 | + "sandboxCfg": "appdata-sandbox.json", | ||
| 10 | + "sandboxRootFrom": "tlv:bundle", | ||
| 11 | + "execFrom": "tlv:hap_entry", | ||
| 12 | + "notifyAms": true | ||
| 13 | + }, | ||
| 14 | + { | ||
| 15 | + "name": "daemon-owned", | ||
| 16 | + "uid": 0, | ||
| 17 | + "gid": 0, | ||
| 18 | + "caps": "sudo", | ||
| 19 | + "selinux": "sudo", | ||
| 20 | + "sandboxCfg": "appdata-sandbox.json", | ||
| 21 | + "sandboxRootFrom": "ext:owner", | ||
| 22 | + "execFrom": "ext:daemon_bin_path", | ||
| 23 | + "notifyAms": true | ||
| 24 | + }, | ||
| 25 | + { | ||
| 26 | + "name": "daemon-system", | ||
| 27 | + "uid": 0, | ||
| 28 | + "gid": 0, | ||
| 29 | + "caps": "sudo", | ||
| 30 | + "selinux": "sudo", | ||
| 31 | + "sandboxCfg": "appdata-sandbox-daemon-system.json", | ||
| 32 | + "execFrom": "ext:daemon_bin_path", | ||
| 33 | + "notifyAms": true | ||
| 34 | + } | ||
| 35 | + ] | ||
| 36 | +} | ||
| @@ -63,6 +63,12 @@ ohos_prebuilt_etc("appspawn_systemLib.json") { | |||
| 63 | module_install_dir = "etc/appspawn" | 63 | module_install_dir = "etc/appspawn" |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | +ohos_prebuilt_etc("appspawn-spawn-policy.json") { | ||
| 67 | + source = "../appspawn-spawn-policy.json" | ||
| 68 | + part_name = "${part_name}" | ||
| 69 | + module_install_dir = "etc/appspawn" | ||
| 70 | +} | ||
| 71 | + | ||
| 66 | ohos_prebuilt_etc("ohos.startup.appspawn.para") { | 72 | ohos_prebuilt_etc("ohos.startup.appspawn.para") { |
| 67 | source = "ohos.startup.appspawn.para" | 73 | source = "ohos.startup.appspawn.para" |
| 68 | part_name = "${part_name}" | 74 | part_name = "${part_name}" |
| @@ -85,6 +91,7 @@ group("etc_files") { | |||
| 85 | ":appspawn_preload_ets.json", | 91 | ":appspawn_preload_ets.json", |
| 86 | ":appspawn_prelink_dso_list", | 92 | ":appspawn_prelink_dso_list", |
| 87 | ":appspawn_systemLib.json", | 93 | ":appspawn_systemLib.json", |
| 94 | + ":appspawn-spawn-policy.json", | ||
| 88 | ":ohos.startup.appspawn.para", | 95 | ":ohos.startup.appspawn.para", |
| 89 | ":ohos.startup.appspawn.para.dac" | 96 | ":ohos.startup.appspawn.para.dac" |
| 90 | ] | 97 | ] |
| @@ -116,10 +116,10 @@ void SetHapDomainInfo(const AppSpawnMgr *content, const AppSpawningCtx *property | |||
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | 118 | ||
| 119 | -int SetSelinuxCon(const AppSpawnMgr *content, const AppSpawningCtx *property) | 119 | +int SetAppSelinuxCon(const AppSpawnMgr *content, const AppSpawningCtx *property) |
| 120 | { | 120 | { |
| 121 | 121 | ||
| 122 | - APPSPAWN_LOGV("SetSelinuxCon IsDeveloperModeOn %{public}d", IsDeveloperModeOn(property)); | 122 | + APPSPAWN_LOGV("SetAppSelinuxCon IsDeveloperModeOn %{public}d", IsDeveloperModeOn(property)); |
| 123 | if (GetAppSpawnMsgType(property) == MSG_SPAWN_NATIVE_PROCESS) { | 123 | if (GetAppSpawnMsgType(property) == MSG_SPAWN_NATIVE_PROCESS) { |
| 124 | if (!IsDeveloperModeOn(property)) { | 124 | if (!IsDeveloperModeOn(property)) { |
| 125 | APPSPAWN_LOGE("Denied Launching a native process: not in developer mode"); | 125 | APPSPAWN_LOGE("Denied Launching a native process: not in developer mode"); |
| @@ -137,7 +137,7 @@ int SetSelinuxCon(const AppSpawnMgr *content, const AppSpawningCtx *property) | |||
| 137 | int32_t ret = hapContext.HapDomainSetcontext(hapDomainInfo); | 137 | int32_t ret = hapContext.HapDomainSetcontext(hapDomainInfo); |
| 138 | APPSPAWN_CHECK(ret == 0, return APPSPAWN_ACCESS_TOKEN_INVALID, | 138 | APPSPAWN_CHECK(ret == 0, return APPSPAWN_ACCESS_TOKEN_INVALID, |
| 139 | "Set domain context failed, ret: %{public}d %{public}s", ret, GetProcessName(property)); | 139 | "Set domain context failed, ret: %{public}d %{public}s", ret, GetProcessName(property)); |
| 140 | - APPSPAWN_LOGV("SetSelinuxCon success for %{public}s", GetProcessName(property)); | 140 | + APPSPAWN_LOGV("SetAppSelinuxCon success for %{public}s", GetProcessName(property)); |
| 141 | 141 | ||
| 142 | return 0; | 142 | return 0; |
| 143 | } | 143 | } |
| @@ -23,7 +23,7 @@ extern "C" { | |||
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | int SetAppAccessToken(const AppSpawnMgr *content, const AppSpawningCtx *property); | 25 | int SetAppAccessToken(const AppSpawnMgr *content, const AppSpawningCtx *property); |
| 26 | -int SetSelinuxCon(const AppSpawnMgr *content, const AppSpawningCtx *property); | 26 | +int SetAppSelinuxCon(const AppSpawnMgr *content, const AppSpawningCtx *property); |
| 27 | 27 | ||
| 28 | int SetUidGidFilter(const AppSpawnMgr *content); | 28 | int SetUidGidFilter(const AppSpawnMgr *content); |
| 29 | int SetSeccompFilter(const AppSpawnMgr *content, const AppSpawningCtx *property); | 29 | int SetSeccompFilter(const AppSpawnMgr *content, const AppSpawningCtx *property); |
| @@ -41,6 +41,7 @@ | |||
| 41 | 41 | ||
| 42 | 42 | ||
| 43 | 43 | ||
| 44 | + | ||
| 44 | 45 | ||
| 45 | 46 | ||
| 46 | 47 | ||
| @@ -214,7 +215,7 @@ APPSPAWN_STATIC int SetExtPermAmbientFromResult(const ExtPermResult *result) | |||
| 214 | } | 215 | } |
| 215 | 216 | ||
| 216 | 217 | ||
| 217 | -APPSPAWN_STATIC int SetAmbientCapabilities(const AppSpawningCtx *property, const ExtPermResult *result) | 218 | +APPSPAWN_STATIC int SetAppAmbientCapabilities(const AppSpawningCtx *property, const ExtPermResult *result) |
| 218 | { | 219 | { |
| 219 | if (!IsNoShareFsEnable()) { | 220 | if (!IsNoShareFsEnable()) { |
| 220 | return 0; | 221 | return 0; |
| @@ -236,18 +237,8 @@ APPSPAWN_STATIC int SetAmbientCapabilities(const AppSpawningCtx *property, const | |||
| 236 | return ret; | 237 | return ret; |
| 237 | } | 238 | } |
| 238 | 239 | ||
| 239 | -APPSPAWN_STATIC int SetCapabilities(const AppSpawnMgr *content, const AppSpawningCtx *property) | 240 | +APPSPAWN_STATIC int SetAppCapabilities(const AppSpawnMgr *content, const AppSpawningCtx *property) |
| 240 | { | 241 | { |
| 241 | - // init cap | ||
| 242 | - struct __user_cap_header_struct capHeader; | ||
| 243 | - bool isRet = memset_s(&capHeader, sizeof(capHeader), 0, sizeof(capHeader)) != EOK; | ||
| 244 | - APPSPAWN_CHECK(!isRet, return -EINVAL, "Failed to memset cap header"); | ||
| 245 | - | ||
| 246 | - capHeader.version = _LINUX_CAPABILITY_VERSION_3; | ||
| 247 | - capHeader.pid = 0; | ||
| 248 | - struct __user_cap_data_struct capData[2]; | ||
| 249 | - isRet = memset_s(&capData, sizeof(capData), 0, sizeof(capData)) != EOK; | ||
| 250 | - APPSPAWN_CHECK(!isRet, return -EINVAL, "Failed to memset cap data"); | ||
| 251 | bool needExtPerm = IsNoShareFsEnable() && | 242 | bool needExtPerm = IsNoShareFsEnable() && |
| 252 | !CheckAppMsgFlagsSet(property, APP_FLAGS_ISOLATED_SANDBOX_TYPE) && | 243 | !CheckAppMsgFlagsSet(property, APP_FLAGS_ISOLATED_SANDBOX_TYPE) && |
| 253 | (IsAppSpawnMode(content) || IsNativeSpawnMode(content)); | 244 | (IsAppSpawnMode(content) || IsNativeSpawnMode(content)); |
| @@ -255,7 +246,7 @@ APPSPAWN_STATIC int SetCapabilities(const AppSpawnMgr *content, const AppSpawnin | |||
| 255 | if (needExtPerm) { | 246 | if (needExtPerm) { |
| 256 | GetExtPermResult(property, &extResult); | 247 | GetExtPermResult(property, &extResult); |
| 257 | } | 248 | } |
| 258 | - // init inheritable permitted effective zero | 249 | + // compute capability mask (app policy); mechanism moved to engine primitive SetCapabilities |
| 259 | 250 | ||
| 260 | u_int64_t baseCaps = 0; | 251 | u_int64_t baseCaps = 0; |
| 261 | if (needExtPerm) { | 252 | if (needExtPerm) { |
| @@ -272,17 +263,11 @@ APPSPAWN_STATIC int SetCapabilities(const AppSpawnMgr *content, const AppSpawnin | |||
| 272 | const uint64_t permitted = 0x3fffffffff; | 263 | const uint64_t permitted = 0x3fffffffff; |
| 273 | const uint64_t effective = 0x3fffffffff; | 264 | const uint64_t effective = 0x3fffffffff; |
| 274 | 265 | ||
| 275 | - capData[0].inheritable = (__u32)(inheriTable); | 266 | + int ret = SetCapabilities(inheriTable, permitted, effective); |
| 276 | - capData[1].inheritable = (__u32)(inheriTable >> BITLEN32); | 267 | + APPSPAWN_CHECK(ret == 0, return ret, "Failed to capset via primitive, ret: %{public}d", ret); |
| 277 | - capData[0].permitted = (__u32)(permitted); | ||
| 278 | - capData[1].permitted = (__u32)(permitted >> BITLEN32); | ||
| 279 | - capData[0].effective = (__u32)(effective); | ||
| 280 | - capData[1].effective = (__u32)(effective >> BITLEN32); | ||
| 281 | - isRet = capset(&capHeader, &capData[0]) != 0; | ||
| 282 | - APPSPAWN_CHECK(!isRet, return -errno, "Failed to capset errno: %{public}d", errno); | ||
| 283 | 268 | ||
| 284 | if (needExtPerm) { | 269 | if (needExtPerm) { |
| 285 | - isRet = SetAmbientCapabilities(property, &extResult); | 270 | + bool isRet = SetAppAmbientCapabilities(property, &extResult); |
| 286 | APPSPAWN_CHECK(!isRet, return -1, "Failed to set ambient"); | 271 | APPSPAWN_CHECK(!isRet, return -1, "Failed to set ambient"); |
| 287 | } | 272 | } |
| 288 | return 0; | 273 | return 0; |
| @@ -401,7 +386,7 @@ APPSPAWN_STATIC int SetXpmConfig(const AppSpawnMgr *content, const AppSpawningCt | |||
| 401 | return 0; | 386 | return 0; |
| 402 | } | 387 | } |
| 403 | 388 | ||
| 404 | -APPSPAWN_STATIC int SetUidGid(const AppSpawnMgr *content, const AppSpawningCtx *property) | 389 | +APPSPAWN_STATIC int SetAppUidGid(const AppSpawnMgr *content, const AppSpawningCtx *property) |
| 405 | { | 390 | { |
| 406 | AppSpawnMsgDacInfo *dacInfo = (AppSpawnMsgDacInfo *)GetAppProperty(property, TLV_DAC_INFO); | 391 | AppSpawnMsgDacInfo *dacInfo = (AppSpawnMsgDacInfo *)GetAppProperty(property, TLV_DAC_INFO); |
| 407 | APPSPAWN_CHECK(dacInfo != NULL, return APPSPAWN_TLV_NONE, | 392 | APPSPAWN_CHECK(dacInfo != NULL, return APPSPAWN_TLV_NONE, |
| @@ -682,17 +667,17 @@ static int SpawnSetProperties(AppSpawnMgr *content, AppSpawningCtx *property) | |||
| 682 | ret = SetSchedPriority(content, property); | 667 | ret = SetSchedPriority(content, property); |
| 683 | APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); | 668 | APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); |
| 684 | 669 | ||
| 685 | - ret = SetUidGid(content, property); | 670 | + ret = SetAppUidGid(content, property); |
| 686 | APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); | 671 | APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); |
| 687 | 672 | ||
| 688 | ret = SetFileDescriptors(content, property); | 673 | ret = SetFileDescriptors(content, property); |
| 689 | APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); | 674 | APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); |
| 690 | 675 | ||
| 691 | - ret = SetCapabilities(content, property); | 676 | + ret = SetAppCapabilities(content, property); |
| 692 | APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); | 677 | APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); |
| 693 | 678 | ||
| 694 | - StartAppspawnTrace("SetSelinuxCon"); | 679 | + StartAppspawnTrace("SetAppSelinuxCon"); |
| 695 | - ret = SetSelinuxCon(content, property); | 680 | + ret = SetAppSelinuxCon(content, property); |
| 696 | FinishAppspawnTrace(); | 681 | FinishAppspawnTrace(); |
| 697 | APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); | 682 | APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); |
| 698 | 683 | ||
| @@ -0,0 +1,100 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) 2026 Huawei Device Co., Ltd. | ||
| 3 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | + * you may not use this file except in compliance with the License. | ||
| 5 | + * You may obtain a copy of the License at | ||
| 6 | + * | ||
| 7 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | + * | ||
| 9 | + * Unless required by applicable law or agreed to in writing, software | ||
| 10 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | + * See the License for the specific language governing permissions and | ||
| 13 | + * limitations under the License. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +extern "C" { | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + | ||
| 36 | +// 参数来源标记:把"参数从哪来"数据化,共享 Hook 据此取参,见 daemon_spawn_design §6.4/§6.5 | ||
| 37 | +typedef enum { | ||
| 38 | + POLICY_SRC_INVALID = 0, | ||
| 39 | + POLICY_SRC_TLV_DAC, // uid/gid 取自 TLV_DAC_INFO | ||
| 40 | + POLICY_SRC_FIXED, // uid/gid 策略表固定值(daemon=0) | ||
| 41 | + POLICY_SRC_SUDO, // caps = sudo 掩码(默认 0x3fffffffff,TBD-R1 待安全 owner 定) | ||
| 42 | + POLICY_SRC_TLV_CAPS, // caps 取自 TLV | ||
| 43 | + POLICY_SRC_SELINUX_SUDO, // selinux = sudo 域(默认 u:r:sudo:s0,TBD-R2 待 SELinux owner 定) | ||
| 44 | + POLICY_SRC_TLV_SELINUX, // selinux 取自 TLV | ||
| 45 | + POLICY_SRC_TLV_BUNDLE, // 沙箱 root 取自 TLV_BUNDLE_INFO | ||
| 46 | + POLICY_SRC_EXT_OWNER, // 沙箱 root 取自属主 ext | ||
| 47 | + POLICY_SRC_TLV_HAP_ENTRY, // exec 目标取自 TLV hap 入口 | ||
| 48 | + POLICY_SRC_EXT_BIN_PATH, // exec 目标取自 ext:daemon_bin_path | ||
| 49 | +} PolicySrc; | ||
| 50 | + | ||
| 51 | +/** | ||
| 52 | + * @brief 单条孵化策略(策略表条目)。 | ||
| 53 | + * | ||
| 54 | + * 对应 appspawn-spawn-policy.json 的一条 policy。共享 Hook 读 ResolvePolicy() | ||
| 55 | + * 得到此结构,据此取参调引擎原语,见 daemon_spawn_design §6.4/§6.5。 | ||
| 56 | + */ | ||
| 57 | +typedef struct { | ||
| 58 | + char name[SPAWN_POLICY_NAME_LEN]; // "app" / "daemon-owned" / "daemon-system" | ||
| 59 | + PolicySrc uidFrom; | ||
| 60 | + PolicySrc gidFrom; | ||
| 61 | + uid_t uid; // POLICY_SRC_FIXED 时的固定 uid(daemon=0) | ||
| 62 | + gid_t gid; // POLICY_SRC_FIXED 时的固定 gid | ||
| 63 | + PolicySrc capsFrom; // POLICY_SRC_SUDO / POLICY_SRC_TLV_CAPS | ||
| 64 | + uint64_t capsMask; // POLICY_SRC_SUDO 时的掩码(默认 TBD-R1) | ||
| 65 | + PolicySrc selinuxFrom; // POLICY_SRC_SELINUX_SUDO / POLICY_SRC_TLV_SELINUX | ||
| 66 | + char selinuxCtx[SPAWN_POLICY_SELINUX_LEN]; // POLICY_SRC_SELINUX_SUDO 时的 ctx(默认 TBD-R2) | ||
| 67 | + char sandboxCfg[SPAWN_POLICY_CFG_LEN]; // 沙箱配置 JSON 文件名 | ||
| 68 | + PolicySrc sandboxRootFrom; // POLICY_SRC_TLV_BUNDLE / POLICY_SRC_EXT_OWNER | ||
| 69 | + PolicySrc execFrom; // POLICY_SRC_TLV_HAP_ENTRY / POLICY_SRC_EXT_BIN_PATH | ||
| 70 | + bool notifyAms; // 是否回调 ams(取代 isAppspawn 门控,见 §6.6) | ||
| 71 | +} SpawnPolicy; | ||
| 72 | + | ||
| 73 | +/** | ||
| 74 | + * @brief 启动期加载策略表 appspawn-spawn-policy.json。 | ||
| 75 | + * | ||
| 76 | + * 解析 JSON 填充 g_policy 表;文件缺失/解析失败则回退内置默认 app 策略, | ||
| 77 | + * 保证不裸奔。在 main() InitCommonEnv 后调用,见 daemon_spawn_design §10.2 P2。 | ||
| 78 | + * | ||
| 79 | + * @return 0 成功;-1 失败(已回退默认,不致命) | ||
| 80 | + */ | ||
| 81 | +int SpawnPolicyInit(void); | ||
| 82 | + | ||
| 83 | +/** | ||
| 84 | + * @brief 按请求数据解析孵化策略(零类型分支的关键)。 | ||
| 85 | + * | ||
| 86 | + * 粗分类信号 = 消息类型(P4 加 MSG_SPAWN_DAEMON 后启用 daemon 分支), | ||
| 87 | + * 细分类信号 = 请求数据(有无属主 ext)。P2 旁路态:仅返回 app 策略 | ||
| 88 | + * (值与原硬编码一致),daemon 分类在 P4 启用,见 daemon_spawn_design §6.4。 | ||
| 89 | + * | ||
| 90 | + * @param ctx 孵化上下文(含消息类型/TLV/ext) | ||
| 91 | + * @return 命中策略指针(永不为 NULL,未命中回退 app) | ||
| 92 | + */ | ||
| 93 | +const SpawnPolicy *ResolvePolicy(const AppSpawningCtx *ctx); | ||
| 94 | + | ||
| 95 | + | ||
| 96 | + | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | + | ||
| 100 | + | ||
| @@ -0,0 +1,102 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) 2026 Huawei Device Co., Ltd. | ||
| 3 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | + * you may not use this file except in compliance with the License. | ||
| 5 | + * You may obtain a copy of the License at | ||
| 6 | + * | ||
| 7 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | + * | ||
| 9 | + * Unless required by applicable law or agreed to in writing, software | ||
| 10 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | + * See the License for the specific language governing permissions and | ||
| 13 | + * limitations under the License. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +extern "C" { | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +/** | ||
| 30 | + * @brief 设置子进程 uid/gid/补充组(纯机制原语)。 | ||
| 31 | + * | ||
| 32 | + * 仅封装 setgroups→setresgid→setresuid 的内核调用序列与顺序不变量 | ||
| 33 | + * (setresgid 先于 setresuid)。不读 TLV、不感知孵化类型; | ||
| 34 | + * 参数来源(TLV/策略表)由共享 Hook 决定,见 daemon_spawn_design §6.9。 | ||
| 35 | + * | ||
| 36 | + * @param uid 目标 uid;daemon 策略传 0,app 由 Hook 从 TLV_DAC 取 | ||
| 37 | + * @param gid 目标 gid | ||
| 38 | + * @param gids 补充组表;为 NULL 表示无补充组 | ||
| 39 | + * @param gidCount gids 元素数;gids 为 NULL 时忽略 | ||
| 40 | + * @return 0 成功;负数失败(-errno) | ||
| 41 | + */ | ||
| 42 | +int SetUidGid(uid_t uid, gid_t gid, const gid_t *gids, size_t gidCount); | ||
| 43 | + | ||
| 44 | +/** | ||
| 45 | + * @brief 设置进程 capability 集合(纯机制原语)。 | ||
| 46 | + * | ||
| 47 | + * 仅封装 capset 系统调用(inheritable/permitted/effective 三集合)。 | ||
| 48 | + * 掩码由调用方(共享 Hook 读策略表)提供;app 侧的“flag→mask 计算”、 | ||
| 49 | + * ext perm、isolated sandbox 等策略不在此原语,见 daemon_spawn_design §6.9。 | ||
| 50 | + * | ||
| 51 | + * @param inheritable inheritable 集合位图 | ||
| 52 | + * @param permitted permitted 集合位图 | ||
| 53 | + * @param effective effective 集合位图 | ||
| 54 | + * @return 0 成功;负数失败(-errno) | ||
| 55 | + */ | ||
| 56 | +int SetCapabilities(uint64_t inheritable, uint64_t permitted, uint64_t effective); | ||
| 57 | + | ||
| 58 | +/** | ||
| 59 | + * @brief 设置 ambient capability 集合(纯机制原语)。 | ||
| 60 | + * | ||
| 61 | + * 遍历掩码中置位的每个 cap,逐个 prctl(PR_CAP_AMBIENT, RAISE)。 | ||
| 62 | + * 掩码由调用方提供;app 侧的 CAP_DAC_OVERRIDE/CAP_KILL/CAP_FOWNER | ||
| 63 | + * 条件计算不在此原语,见 daemon_spawn_design §6.9。 | ||
| 64 | + * | ||
| 65 | + * @param mask ambient 能力位图 | ||
| 66 | + * @return 0 成功;-1 失败 | ||
| 67 | + */ | ||
| 68 | +int SetAmbientCapabilities(uint64_t mask); | ||
| 69 | + | ||
| 70 | +/** | ||
| 71 | + * @brief 设置子进程 SELinux 上下文(纯机制原语)。 | ||
| 72 | + * | ||
| 73 | + * 仅封装 setcon()。上下文串由调用方(共享 Hook 读策略表)提供; | ||
| 74 | + * app 侧的 HapDomain 解析(provision type/APL→域)不在此原语, | ||
| 75 | + * 由 app Hook 算出 context 后调本原语,见 daemon_spawn_design §6.9。 | ||
| 76 | + * 编译需 WITH_SELINUX;未启用时为空实现返回 0。 | ||
| 77 | + * | ||
| 78 | + * @param context 目标 SELinux 上下文串,如 "u:r:sudo:s0" | ||
| 79 | + * @return 0 成功;-1 失败(或未启用 SELinux 时 0) | ||
| 80 | + */ | ||
| 81 | +int SetSelinuxCon(const char *context); | ||
| 82 | + | ||
| 83 | +/** | ||
| 84 | + * @brief 执行目标二进制(纯机制原语)。 | ||
| 85 | + * | ||
| 86 | + * envp 为 NULL 时走 execv,否则走 execve。路径与参数由调用方 | ||
| 87 | + * (共享 Hook 读策略表 execFrom:app→TLV:hap_entry,daemon→ext:daemon_bin_path) | ||
| 88 | + * 提供,见 daemon_spawn_design §6.9。成功不返回。 | ||
| 89 | + * | ||
| 90 | + * @param path 目标二进制路径 | ||
| 91 | + * @param argv 参数数组(以 NULL 结尾) | ||
| 92 | + * @param envp 环境变量数组;NULL 表示用 execv(继承当前环境) | ||
| 93 | + * @return 失败返回 -errno;成功不返回 | ||
| 94 | + */ | ||
| 95 | +int ExecvTarget(const char *path, char *const argv[], char *const envp[]); | ||
| 96 | + | ||
| 97 | + | ||
| 98 | + | ||
| 99 | +} | ||
| 100 | + | ||
| 101 | + | ||
| 102 | + | ||
| @@ -0,0 +1,222 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) 2026 Huawei Device Co., Ltd. | ||
| 3 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | + * you may not use this file except in compliance with the License. | ||
| 5 | + * You may obtain a copy of the License at | ||
| 6 | + * | ||
| 7 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | + * | ||
| 9 | + * Unless required by applicable law or agreed to in writing, software | ||
| 10 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | + * See the License for the specific language governing permissions and | ||
| 13 | + * limitations under the License. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +// TBD-R1/TBD-R2 默认假设(见 §3.7),安全 owner 确认后改 JSON 即可,零代码 | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | +static SpawnPolicy g_policy[SPAWN_POLICY_MAX]; | ||
| 33 | +static int g_policyCount = 0; | ||
| 34 | +static bool g_policyInited = false; | ||
| 35 | + | ||
| 36 | +// 内置默认 app 策略:JSON 缺失/解析失败时回退,保证不裸奔 | ||
| 37 | +static void LoadDefaultAppPolicy(void) | ||
| 38 | +{ | ||
| 39 | + SpawnPolicy *p = &g_policy[0]; | ||
| 40 | + (void)memset_s(p, sizeof(SpawnPolicy), 0, sizeof(SpawnPolicy)); | ||
| 41 | + (void)strcpy_s(p->name, sizeof(p->name), "app"); | ||
| 42 | + p->uidFrom = POLICY_SRC_TLV_DAC; | ||
| 43 | + p->gidFrom = POLICY_SRC_TLV_DAC; | ||
| 44 | + p->capsFrom = POLICY_SRC_TLV_CAPS; | ||
| 45 | + p->selinuxFrom = POLICY_SRC_TLV_SELINUX; | ||
| 46 | + (void)strcpy_s(p->sandboxCfg, sizeof(p->sandboxCfg), "appdata-sandbox.json"); | ||
| 47 | + p->sandboxRootFrom = POLICY_SRC_TLV_BUNDLE; | ||
| 48 | + p->execFrom = POLICY_SRC_TLV_HAP_ENTRY; | ||
| 49 | + p->notifyAms = true; | ||
| 50 | + g_policyCount = 1; | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +// uid/gid 来源串 -> enum | ||
| 54 | +static PolicySrc ParseUidGidSrc(const cJSON *json, const char *field, int64_t *fixedVal) | ||
| 55 | +{ | ||
| 56 | + const cJSON *src = cJSON_GetObjectItem(json, field); | ||
| 57 | + if (cJSON_IsNumber(src)) { | ||
| 58 | + *fixedVal = (int64_t)src->valuedouble; | ||
| 59 | + return POLICY_SRC_FIXED; | ||
| 60 | + } | ||
| 61 | + if (cJSON_IsString(src) && strcmp(src->valuestring, "tlv:dac") == 0) { | ||
| 62 | + return POLICY_SRC_TLV_DAC; | ||
| 63 | + } | ||
| 64 | + return POLICY_SRC_INVALID; | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +// caps 来源串 -> enum("sudo" 或 "tlv:caps") | ||
| 68 | +static PolicySrc ParseCapsSrc(const cJSON *json, uint64_t *mask) | ||
| 69 | +{ | ||
| 70 | + const cJSON *caps = cJSON_GetObjectItem(json, "caps"); | ||
| 71 | + if (cJSON_IsString(caps)) { | ||
| 72 | + if (strcmp(caps->valuestring, "sudo") == 0) { | ||
| 73 | + *mask = DEFAULT_SUDO_CAPS_MASK; | ||
| 74 | + return POLICY_SRC_SUDO; | ||
| 75 | + } | ||
| 76 | + if (strcmp(caps->valuestring, "tlv:caps") == 0) { | ||
| 77 | + return POLICY_SRC_TLV_CAPS; | ||
| 78 | + } | ||
| 79 | + } | ||
| 80 | + return POLICY_SRC_INVALID; | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +// selinux 来源串 -> enum("sudo" 或 "tlv:selinux") | ||
| 84 | +static PolicySrc ParseSelinuxSrc(const cJSON *json, char *ctx, size_t ctxLen) | ||
| 85 | +{ | ||
| 86 | + const cJSON *se = cJSON_GetObjectItem(json, "selinux"); | ||
| 87 | + if (cJSON_IsString(se)) { | ||
| 88 | + if (strcmp(se->valuestring, "sudo") == 0) { | ||
| 89 | + (void)strcpy_s(ctx, ctxLen, DEFAULT_SUDO_SELINUX_CTX); | ||
| 90 | + return POLICY_SRC_SELINUX_SUDO; | ||
| 91 | + } | ||
| 92 | + if (strcmp(se->valuestring, "tlv:selinux") == 0) { | ||
| 93 | + return POLICY_SRC_TLV_SELINUX; | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | + return POLICY_SRC_INVALID; | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +static PolicySrc ParseSrcStr(const cJSON *json, const char *field) | ||
| 100 | +{ | ||
| 101 | + const cJSON *v = cJSON_GetObjectItem(json, field); | ||
| 102 | + if (!cJSON_IsString(v)) { | ||
| 103 | + return POLICY_SRC_INVALID; | ||
| 104 | + } | ||
| 105 | + const char *s = v->valuestring; | ||
| 106 | + if (strcmp(s, "tlv:bundle") == 0) return POLICY_SRC_TLV_BUNDLE; | ||
| 107 | + if (strcmp(s, "ext:owner") == 0) return POLICY_SRC_EXT_OWNER; | ||
| 108 | + if (strcmp(s, "tlv:hap_entry") == 0) return POLICY_SRC_TLV_HAP_ENTRY; | ||
| 109 | + if (strcmp(s, "ext:daemon_bin_path") == 0) return POLICY_SRC_EXT_BIN_PATH; | ||
| 110 | + return POLICY_SRC_INVALID; | ||
| 111 | +} | ||
| 112 | + | ||
| 113 | +static void ParseOnePolicy(const cJSON *item, SpawnPolicy *p) | ||
| 114 | +{ | ||
| 115 | + (void)memset_s(p, sizeof(SpawnPolicy), 0, sizeof(SpawnPolicy)); | ||
| 116 | + const cJSON *name = cJSON_GetObjectItem(item, "name"); | ||
| 117 | + if (cJSON_IsString(name)) { | ||
| 118 | + (void)strcpy_s(p->name, sizeof(p->name), name->valuestring); | ||
| 119 | + } | ||
| 120 | + int64_t fixedUid = 0; | ||
| 121 | + int64_t fixedGid = 0; | ||
| 122 | + p->uidFrom = ParseUidGidSrc(item, "uidFrom", &fixedUid); | ||
| 123 | + if (p->uidFrom == POLICY_SRC_INVALID) { // 无 uidFrom,看固定 uid | ||
| 124 | + const cJSON *uid = cJSON_GetObjectItem(item, "uid"); | ||
| 125 | + if (cJSON_IsNumber(uid)) { | ||
| 126 | + p->uidFrom = POLICY_SRC_FIXED; | ||
| 127 | + fixedUid = (int64_t)uid->valuedouble; | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + p->gidFrom = ParseUidGidSrc(item, "gidFrom", &fixedGid); | ||
| 131 | + if (p->gidFrom == POLICY_SRC_INVALID) { | ||
| 132 | + const cJSON *gid = cJSON_GetObjectItem(item, "gid"); | ||
| 133 | + if (cJSON_IsNumber(gid)) { | ||
| 134 | + p->gidFrom = POLICY_SRC_FIXED; | ||
| 135 | + fixedGid = (int64_t)gid->valuedouble; | ||
| 136 | + } | ||
| 137 | + } | ||
| 138 | + p->uid = (uid_t)fixedUid; | ||
| 139 | + p->gid = (gid_t)fixedGid; | ||
| 140 | + p->capsFrom = ParseCapsSrc(item, &p->capsMask); | ||
| 141 | + p->selinuxFrom = ParseSelinuxSrc(item, p->selinuxCtx, sizeof(p->selinuxCtx)); | ||
| 142 | + const cJSON *sandboxCfg = cJSON_GetObjectItem(item, "sandboxCfg"); | ||
| 143 | + if (cJSON_IsString(sandboxCfg)) { | ||
| 144 | + (void)strcpy_s(p->sandboxCfg, sizeof(p->sandboxCfg), sandboxCfg->valuestring); | ||
| 145 | + } | ||
| 146 | + p->sandboxRootFrom = ParseSrcStr(item, "sandboxRootFrom"); | ||
| 147 | + p->execFrom = ParseSrcStr(item, "execFrom"); | ||
| 148 | + const cJSON *notify = cJSON_GetObjectItem(item, "notifyAms"); | ||
| 149 | + p->notifyAms = cJSON_IsTrue(notify); | ||
| 150 | +} | ||
| 151 | + | ||
| 152 | +int SpawnPolicyInit(void) | ||
| 153 | +{ | ||
| 154 | + if (g_policyInited) { | ||
| 155 | + return 0; | ||
| 156 | + } | ||
| 157 | + g_policyInited = true; | ||
| 158 | + LoadDefaultAppPolicy(); // 先置默认,JSON 失败也有兜底 | ||
| 159 | + | ||
| 160 | + FILE *fp = fopen(SPAWN_POLICY_PATH, "r"); | ||
| 161 | + APPSPAWN_CHECK(fp != NULL, return -1, | ||
| 162 | + "SpawnPolicy: open %{public}s failed: %{public}d, use default app policy", SPAWN_POLICY_PATH, errno); | ||
| 163 | + char *content = NULL; | ||
| 164 | + if (fseek(fp, 0, SEEK_END) != 0) { | ||
| 165 | + fclose(fp); | ||
| 166 | + return -1; | ||
| 167 | + } | ||
| 168 | + long fsize = ftell(fp); | ||
| 169 | + if (fsize <= 0) { | ||
| 170 | + fclose(fp); | ||
| 171 | + return -1; | ||
| 172 | + } | ||
| 173 | + (void)fseek(fp, 0, SEEK_SET); | ||
| 174 | + content = (char *)calloc(1, (size_t)fsize + 1); | ||
| 175 | + APPSPAWN_CHECK(content != NULL, fclose(fp); return -1, "SpawnPolicy: alloc failed"); | ||
| 176 | + size_t rsize = fread(content, 1, (size_t)fsize, fp); | ||
| 177 | + fclose(fp); | ||
| 178 | + if (rsize == 0) { | ||
| 179 | + free(content); | ||
| 180 | + return -1; | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + cJSON *root = cJSON_Parse(content); | ||
| 184 | + free(content); | ||
| 185 | + APPSPAWN_CHECK(root != NULL, return -1, "SpawnPolicy: parse json failed"); | ||
| 186 | + cJSON *arr = cJSON_GetObjectItem(root, "policies"); | ||
| 187 | + if (cJSON_IsArray(arr)) { | ||
| 188 | + int n = cJSON_GetArraySize(arr); | ||
| 189 | + if (n > SPAWN_POLICY_MAX) { | ||
| 190 | + n = SPAWN_POLICY_MAX; | ||
| 191 | + } | ||
| 192 | + g_policyCount = 0; | ||
| 193 | + for (int i = 0; i < n; i++) { | ||
| 194 | + ParseOnePolicy(cJSON_GetArrayItem(arr, i), &g_policy[g_policyCount]); | ||
| 195 | + if (g_policy[g_policyCount].name[0] != '\0') { | ||
| 196 | + g_policyCount++; | ||
| 197 | + } | ||
| 198 | + } | ||
| 199 | + } | ||
| 200 | + cJSON_Delete(root); | ||
| 201 | + APPSPAWN_LOGI("SpawnPolicy: loaded %{public}d policies from %{public}s", g_policyCount, SPAWN_POLICY_PATH); | ||
| 202 | + return 0; | ||
| 203 | +} | ||
| 204 | + | ||
| 205 | +static const SpawnPolicy *FindPolicyByName(const char *name) | ||
| 206 | +{ | ||
| 207 | + for (int i = 0; i < g_policyCount; i++) { | ||
| 208 | + if (strcmp(g_policy[i].name, name) == 0) { | ||
| 209 | + return &g_policy[i]; | ||
| 210 | + } | ||
| 211 | + } | ||
| 212 | + return NULL; | ||
| 213 | +} | ||
| 214 | + | ||
| 215 | +const SpawnPolicy *ResolvePolicy(const AppSpawningCtx *ctx) | ||
| 216 | +{ | ||
| 217 | + // P2 旁路态:返回 app 策略(值与原硬编码一致),不改变现有孵化行为。 | ||
| 218 | + // P4:粗分类 msgType==MSG_SPAWN_DAEMON → daemon;细分类 有属主 ext → daemon-owned,无 → daemon-system。 | ||
| 219 | + (void)ctx; | ||
| 220 | + const SpawnPolicy *app = FindPolicyByName("app"); | ||
| 221 | + return app != NULL ? app : &g_policy[0]; | ||
| 222 | +} | ||
| @@ -0,0 +1,185 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) 2026 Huawei Device Co., Ltd. | ||
| 3 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | + * you may not use this file except in compliance with the License. | ||
| 5 | + * You may obtain a copy of the License at | ||
| 6 | + * | ||
| 7 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | + * | ||
| 9 | + * Unless required by applicable law or agreed to in writing, software | ||
| 10 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | + * See the License for the specific language governing permissions and | ||
| 13 | + * limitations under the License. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + | ||
| 35 | +/** | ||
| 36 | + * @brief 设置子进程 uid/gid/补充组(纯机制原语)。 | ||
| 37 | + * | ||
| 38 | + * 仅封装 setgroups→setresgid→setresuid 的内核调用序列与顺序不变量 | ||
| 39 | + * (setresgid 先于 setresuid)。不读 TLV、不感知孵化类型; | ||
| 40 | + * 参数来源(TLV/策略表)由共享 Hook 决定,见 daemon_spawn_design §6.9。 | ||
| 41 | + * | ||
| 42 | + * @param uid 目标 uid;daemon 策略传 0,app 由 Hook 从 TLV_DAC 取 | ||
| 43 | + * @param gid 目标 gid | ||
| 44 | + * @param gids 补充组表;为 NULL 表示无补充组 | ||
| 45 | + * @param gidCount gids 元素数;gids 为 NULL 时忽略 | ||
| 46 | + * @return 0 成功;负数失败(-errno) | ||
| 47 | + */ | ||
| 48 | +int SetUidGid(uid_t uid, gid_t gid, const gid_t *gids, size_t gidCount) | ||
| 49 | +{ | ||
| 50 | + if (gids != NULL && gidCount > 0) { | ||
| 51 | + if (setgroups(gidCount, gids) != 0) { | ||
| 52 | + APPSPAWN_LOGE("setgroups failed: %{public}d, size=%{public}zu", errno, gidCount); | ||
| 53 | + return -errno; | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | + if (setresgid(gid, gid, gid) != 0) { | ||
| 57 | + APPSPAWN_LOGE("setresgid(%{public}u) failed: %{public}d", gid, errno); | ||
| 58 | + return -errno; | ||
| 59 | + } | ||
| 60 | + // setresgid 必须先于 setresuid:setresuid 从 0→非0 会清空 effective caps | ||
| 61 | + if (setresuid(uid, uid, uid) != 0) { | ||
| 62 | + APPSPAWN_LOGE("setresuid(%{public}u) failed: %{public}d", uid, errno); | ||
| 63 | + return -errno; | ||
| 64 | + } | ||
| 65 | + return 0; | ||
| 66 | +} | ||
| 67 | + | ||
| 68 | +/** | ||
| 69 | + * @brief 设置进程 capability 集合(纯机制原语)。 | ||
| 70 | + * | ||
| 71 | + * 仅封装 capset 系统调用(inheritable/permitted/effective 三集合)。 | ||
| 72 | + * 掩码由调用方(共享 Hook 读策略表)提供;app 侧的“flag→mask 计算”、 | ||
| 73 | + * ext perm、isolated sandbox 等策略不在此原语,见 daemon_spawn_design §6.9。 | ||
| 74 | + * | ||
| 75 | + * @param inheritable inheritable 集合位图 | ||
| 76 | + * @param permitted permitted 集合位图 | ||
| 77 | + * @param effective effective 集合位图 | ||
| 78 | + * @return 0 成功;负数失败(-errno) | ||
| 79 | + */ | ||
| 80 | +int SetCapabilities(uint64_t inheritable, uint64_t permitted, uint64_t effective) | ||
| 81 | +{ | ||
| 82 | + struct __user_cap_header_struct capHeader; | ||
| 83 | + if (memset_s(&capHeader, sizeof(capHeader), 0, sizeof(capHeader)) != EOK) { | ||
| 84 | + APPSPAWN_LOGE("Failed to memset cap header"); | ||
| 85 | + return -EINVAL; | ||
| 86 | + } | ||
| 87 | + capHeader.version = _LINUX_CAPABILITY_VERSION_3; | ||
| 88 | + capHeader.pid = 0; | ||
| 89 | + struct __user_cap_data_struct capData[2]; | ||
| 90 | + if (memset_s(capData, sizeof(capData), 0, sizeof(capData)) != EOK) { | ||
| 91 | + APPSPAWN_LOGE("Failed to memset cap data"); | ||
| 92 | + return -EINVAL; | ||
| 93 | + } | ||
| 94 | + capData[0].inheritable = (__u32)(inheritable); | ||
| 95 | + capData[1].inheritable = (__u32)(inheritable >> BITLEN32); | ||
| 96 | + capData[0].permitted = (__u32)(permitted); | ||
| 97 | + capData[1].permitted = (__u32)(permitted >> BITLEN32); | ||
| 98 | + capData[0].effective = (__u32)(effective); | ||
| 99 | + capData[1].effective = (__u32)(effective >> BITLEN32); | ||
| 100 | + if (capset(&capHeader, &capData[0]) != 0) { | ||
| 101 | + APPSPAWN_LOGE("Failed to capset errno: %{public}d", errno); | ||
| 102 | + return -errno; | ||
| 103 | + } | ||
| 104 | + return 0; | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +/** | ||
| 108 | + * @brief 设置 ambient capability 集合(纯机制原语)。 | ||
| 109 | + * | ||
| 110 | + * 遍历掩码中置位的每个 cap,逐个 prctl(PR_CAP_AMBIENT, RAISE)。 | ||
| 111 | + * 掩码由调用方提供;app 侧的 CAP_DAC_OVERRIDE/CAP_KILL/CAP_FOWNER | ||
| 112 | + * 条件计算不在此原语,见 daemon_spawn_design §6.9。 | ||
| 113 | + * | ||
| 114 | + * @param mask ambient 能力位图 | ||
| 115 | + * @return 0 成功;-1 失败 | ||
| 116 | + */ | ||
| 117 | +int SetAmbientCapabilities(uint64_t mask) | ||
| 118 | +{ | ||
| 119 | + if (mask == 0) { | ||
| 120 | + return 0; | ||
| 121 | + } | ||
| 122 | + for (int cap = 0; cap < BITLEN32 * (int)(sizeof(uint64_t) / sizeof(uint32_t)); cap++) { | ||
| 123 | + if ((mask & (CAP_TO_MASK(cap))) == 0) { | ||
| 124 | + continue; | ||
| 125 | + } | ||
| 126 | + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) != 0) { | ||
| 127 | + APPSPAWN_LOGE("prctl PR_CAP_AMBIENT raise cap %{public}d failed: %{public}d", cap, errno); | ||
| 128 | + return -1; | ||
| 129 | + } | ||
| 130 | + } | ||
| 131 | + return 0; | ||
| 132 | +} | ||
| 133 | + | ||
| 134 | +/** | ||
| 135 | + * @brief 设置子进程 SELinux 上下文(纯机制原语)。 | ||
| 136 | + * | ||
| 137 | + * 仅封装 setcon()。上下文串由调用方(共享 Hook 读策略表)提供; | ||
| 138 | + * app 侧的 HapDomain 解析(provision type/APL→域)不在此原语, | ||
| 139 | + * 由 app Hook 算出 context 后调本原语,见 daemon_spawn_design §6.9。 | ||
| 140 | + * 编译需 WITH_SELINUX;未启用时为空实现返回 0。 | ||
| 141 | + * | ||
| 142 | + * @param context 目标 SELinux 上下文串,如 "u:r:sudo:s0" | ||
| 143 | + * @return 0 成功;-1 失败(或未启用 SELinux 时 0) | ||
| 144 | + */ | ||
| 145 | +int SetSelinuxCon(const char *context) | ||
| 146 | +{ | ||
| 147 | + if (context == NULL) { | ||
| 148 | + return 0; | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + if (setcon(context) != 0) { | ||
| 152 | + APPSPAWN_LOGE("setcon(%{public}s) failed: %{public}d", context, errno); | ||
| 153 | + return -1; | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + (void)context; | ||
| 157 | + | ||
| 158 | + return 0; | ||
| 159 | +} | ||
| 160 | + | ||
| 161 | +/** | ||
| 162 | + * @brief 执行目标二进制(纯机制原语)。 | ||
| 163 | + * | ||
| 164 | + * envp 为 NULL 时走 execv,否则走 execve。路径与参数由调用方 | ||
| 165 | + * (共享 Hook 读策略表 execFrom:app→TLV:hap_entry,daemon→ext:daemon_bin_path) | ||
| 166 | + * 提供,见 daemon_spawn_design §6.9。成功不返回。 | ||
| 167 | + * | ||
| 168 | + * @param path 目标二进制路径 | ||
| 169 | + * @param argv 参数数组(以 NULL 结尾) | ||
| 170 | + * @param envp 环境变量数组;NULL 表示用 execv(继承当前环境) | ||
| 171 | + * @return 失败返回 -errno;成功不返回 | ||
| 172 | + */ | ||
| 173 | +int ExecvTarget(const char *path, char *const argv[], char *const envp[]) | ||
| 174 | +{ | ||
| 175 | + if (path == NULL || argv == NULL) { | ||
| 176 | + return -EINVAL; | ||
| 177 | + } | ||
| 178 | + if (envp == NULL) { | ||
| 179 | + execv(path, argv); | ||
| 180 | + } else { | ||
| 181 | + execve(path, argv, envp); | ||
| 182 | + } | ||
| 183 | + APPSPAWN_LOGE("exec failed, path: %{public}s errno: %{public}d", path, errno); | ||
| 184 | + return -errno; | ||
| 185 | +} | ||
| @@ -16,5 +16,12 @@ | |||
| 16 | { "name": "DumpAppSpawnMsg" }, | 16 | { "name": "DumpAppSpawnMsg" }, |
| 17 | { "name": "AppSpawnDump" }, | 17 | { "name": "AppSpawnDump" }, |
| 18 | { "name": "RegisterExpandSandboxCfgHandler"}, | 18 | { "name": "RegisterExpandSandboxCfgHandler"}, |
| 19 | - { "name": "GetAppSpawnMgr" } | 19 | + { "name": "GetAppSpawnMgr" }, |
| 20 | + { "name": "SetUidGid" }, | ||
| 21 | + { "name": "SetCapabilities" }, | ||
| 22 | + { "name": "SetAmbientCapabilities" }, | ||
| 23 | + { "name": "SetSelinuxCon" }, | ||
| 24 | + { "name": "ExecvTarget" }, | ||
| 25 | + { "name": "SpawnPolicyInit" }, | ||
| 26 | + { "name": "ResolvePolicy" } | ||
| 20 | ] | 27 | ] |
| @@ -52,6 +52,8 @@ ohos_executable("appspawn") { | |||
| 52 | "${appspawn_path}/common/appspawn_trace.cpp", | 52 | "${appspawn_path}/common/appspawn_trace.cpp", |
| 53 | "${appspawn_path}/modules/common/appspawn_dfx_dump.cpp", | 53 | "${appspawn_path}/modules/common/appspawn_dfx_dump.cpp", |
| 54 | "${appspawn_path}/modules/modulemgr/appspawn_modulemgr.c", | 54 | "${appspawn_path}/modules/modulemgr/appspawn_modulemgr.c", |
| 55 | + "${appspawn_path}/modules/module_engine/spawn_primitives.c", | ||
| 56 | + "${appspawn_path}/modules/module_engine/spawn_policy.c", | ||
| 55 | "${appspawn_path}/standard/appspawn_appmgr.c", | 57 | "${appspawn_path}/standard/appspawn_appmgr.c", |
| 56 | "${appspawn_path}/standard/appspawn_fd_manager.c", | 58 | "${appspawn_path}/standard/appspawn_fd_manager.c", |
| 57 | "${appspawn_path}/standard/appspawn_kickdog.c", | 59 | "${appspawn_path}/standard/appspawn_kickdog.c", |
| @@ -191,6 +193,8 @@ ohos_executable("cjappspawn") { | |||
| 191 | "${appspawn_path}/common/appspawn_server.c", | 193 | "${appspawn_path}/common/appspawn_server.c", |
| 192 | "${appspawn_path}/common/appspawn_trace.cpp", | 194 | "${appspawn_path}/common/appspawn_trace.cpp", |
| 193 | "${appspawn_path}/modules/modulemgr/appspawn_modulemgr.c", | 195 | "${appspawn_path}/modules/modulemgr/appspawn_modulemgr.c", |
| 196 | + "${appspawn_path}/modules/module_engine/spawn_primitives.c", | ||
| 197 | + "${appspawn_path}/modules/module_engine/spawn_policy.c", | ||
| 194 | "${appspawn_path}/standard/appspawn_appmgr.c", | 198 | "${appspawn_path}/standard/appspawn_appmgr.c", |
| 195 | "${appspawn_path}/standard/appspawn_fd_manager.c", | 199 | "${appspawn_path}/standard/appspawn_fd_manager.c", |
| 196 | "${appspawn_path}/standard/appspawn_kickdog.c", | 200 | "${appspawn_path}/standard/appspawn_kickdog.c", |
| @@ -264,6 +268,8 @@ ohos_executable("nativespawn") { | |||
| 264 | "${appspawn_path}/common/appspawn_server.c", | 268 | "${appspawn_path}/common/appspawn_server.c", |
| 265 | "${appspawn_path}/common/appspawn_trace.cpp", | 269 | "${appspawn_path}/common/appspawn_trace.cpp", |
| 266 | "${appspawn_path}/modules/modulemgr/appspawn_modulemgr.c", | 270 | "${appspawn_path}/modules/modulemgr/appspawn_modulemgr.c", |
| 271 | + "${appspawn_path}/modules/module_engine/spawn_primitives.c", | ||
| 272 | + "${appspawn_path}/modules/module_engine/spawn_policy.c", | ||
| 267 | "${appspawn_path}/standard/appspawn_appmgr.c", | 273 | "${appspawn_path}/standard/appspawn_appmgr.c", |
| 268 | "${appspawn_path}/standard/appspawn_fd_manager.c", | 274 | "${appspawn_path}/standard/appspawn_fd_manager.c", |
| 269 | "${appspawn_path}/standard/appspawn_kickdog.c", | 275 | "${appspawn_path}/standard/appspawn_kickdog.c", |
| @@ -352,6 +358,8 @@ ohos_executable("nwebspawn") { | |||
| 352 | "${appspawn_path}/common/appspawn_trace.cpp", | 358 | "${appspawn_path}/common/appspawn_trace.cpp", |
| 353 | "${appspawn_path}/modules/common/appspawn_dfx_dump.cpp", | 359 | "${appspawn_path}/modules/common/appspawn_dfx_dump.cpp", |
| 354 | "${appspawn_path}/modules/modulemgr/appspawn_modulemgr.c", | 360 | "${appspawn_path}/modules/modulemgr/appspawn_modulemgr.c", |
| 361 | + "${appspawn_path}/modules/module_engine/spawn_primitives.c", | ||
| 362 | + "${appspawn_path}/modules/module_engine/spawn_policy.c", | ||
| 355 | "${appspawn_path}/standard/appspawn_appmgr.c", | 363 | "${appspawn_path}/standard/appspawn_appmgr.c", |
| 356 | "${appspawn_path}/standard/appspawn_fd_manager.c", | 364 | "${appspawn_path}/standard/appspawn_fd_manager.c", |
| 357 | "${appspawn_path}/standard/appspawn_kickdog.c", | 365 | "${appspawn_path}/standard/appspawn_kickdog.c", |
| @@ -442,6 +450,8 @@ ohos_executable("hybridspawn") { | |||
| 442 | "${appspawn_path}/common/appspawn_trace.cpp", | 450 | "${appspawn_path}/common/appspawn_trace.cpp", |
| 443 | "${appspawn_path}/modules/common/appspawn_dfx_dump.cpp", | 451 | "${appspawn_path}/modules/common/appspawn_dfx_dump.cpp", |
| 444 | "${appspawn_path}/modules/modulemgr/appspawn_modulemgr.c", | 452 | "${appspawn_path}/modules/modulemgr/appspawn_modulemgr.c", |
| 453 | + "${appspawn_path}/modules/module_engine/spawn_primitives.c", | ||
| 454 | + "${appspawn_path}/modules/module_engine/spawn_policy.c", | ||
| 445 | "${appspawn_path}/standard/appspawn_appmgr.c", | 455 | "${appspawn_path}/standard/appspawn_appmgr.c", |
| 446 | "${appspawn_path}/standard/appspawn_fd_manager.c", | 456 | "${appspawn_path}/standard/appspawn_fd_manager.c", |
| 447 | "${appspawn_path}/standard/appspawn_kickdog.c", | 457 | "${appspawn_path}/standard/appspawn_kickdog.c", |
| @@ -18,6 +18,7 @@ | |||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | + | ||
| 21 | 22 | ||
| 22 | 23 | ||
| 23 | 24 | ||
| @@ -109,6 +110,7 @@ int main(int argc, char *const argv[]) | |||
| 109 | return 0; | 110 | return 0; |
| 110 | } | 111 | } |
| 111 | InitCommonEnv(); | 112 | InitCommonEnv(); |
| 113 | + (void)SpawnPolicyInit(); // 启动期加载策略表(P2 旁路态,仅 app 策略生效,daemon 分类 P4 启用) | ||
| 112 | CheckPreload(argv); | 114 | CheckPreload(argv); |
| 113 | (void)signal(SIGPIPE, SIG_IGN); | 115 | (void)signal(SIGPIPE, SIG_IGN); |
| 114 | uint32_t argvSize = end - start; | 116 | uint32_t argvSize = end - start; |