From 55582482ab75c2b9cadbdd07b05871a6538d6740 Mon Sep 17 00:00:00 2001 From: Qin Fandong Date: Tue, 19 Oct 2021 15:36:51 +0800 Subject: [PATCH] init: support selinux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 此提交使 init 进程有支持 SELinux 的能力。 1. 启动时加载策略并根据策略文件设置进程安全上下文 2. 根据配置文件中的 secon 字段的值设置进程的安全上下文 仅在编译时有宏定义 WITH_SELINUX 时会将此功能引入,而仅在 BUILD.gn 中编译 L2 系统(ohos_executable("init"))时会定义宏 WITH_SELINUX ,因此不影响 L2 以下的系统。 services/BUILD.gn 编译配置,编译此功能时定义宏 -DWITH_SELINUX 并链接到库 libload_policy 、 librestorecon 、 libselinux 。 services/init/standard/init.c 启动时加载策略并根据策略文件设置进程安全上下文。调用接口 load_policy 和 restorencon 。 services/init/include/init_service.h 结构体 Service 中增加了成员字符数组 secon 对应配置文件的新字段 secon 。 services/include/param/init_selinux_param.h 定义了 SELinux 功能需要使用的宏。 services/init/init_service_manager.c 将配置文件的字段 secon 读到内存中。 services/init/standard/init_service.c 根据内存中读到的每个服务的 secon 字段,设置该服务进程的安全上下文。 Signed-off-by: Qin Fandong --- OAT.xml | 1 + README.md | 7 +++++ README_zh.md | 7 +++++ services/BUILD.gn | 15 +++++++++ services/include/param/init_selinux_param.h | 35 +++++++++++++++++++++ services/init/include/init_service.h | 6 ++++ services/init/init_common_service.c | 19 +++++++++++ services/init/init_service_manager.c | 12 ++++++- services/init/standard/init.c | 23 ++++++++++++++ services/init/standard/init_service.c | 2 +- 10 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 services/include/param/init_selinux_param.h diff --git a/OAT.xml b/OAT.xml index 5f8a157..418dc8b 100644 --- a/OAT.xml +++ b/OAT.xml @@ -22,6 +22,7 @@ + diff --git a/README.md b/README.md index 4863f35..9f1b9e1 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ The format and content of the **init.cfg** file are as follows: "path" : "/bin/process1", "uid" : 1, "gid" : 1, + "secon" : "u:r:untrusted_app:s0", "once" : 0, "importance" : 1, "caps" : [0, 1, 2, 5] @@ -83,6 +84,7 @@ The format and content of the **init.cfg** file are as follows: "path" : "/bin/process2", "uid" : 2, "gid" : 2, + "secon" : "u:r:untrusted_app:s0", "once" : 1, "importance" : 0, "caps" : [] @@ -215,6 +217,11 @@ A single job can hold a maximum of 30 commands \(only **start**, **mkdir**, *

Group ID (GID) of the current service process.

+

secon

+ +

Security context of the current service process (no need to set currently).

+ +

once

Whether the current service process is a one-off process.

diff --git a/README_zh.md b/README_zh.md index 2caa463..5f6f6e7 100644 --- a/README_zh.md +++ b/README_zh.md @@ -75,6 +75,7 @@ init将系统启动分为三个阶段: "path" : "/bin/process1", "uid" : 1, "gid" : 1, + "secon" : "u:r:untrusted_app:s0", "once" : 0, "importance" : 1, "caps" : [0, 1, 2, 5] @@ -83,6 +84,7 @@ init将系统启动分为三个阶段: "path" : "/bin/process2", "uid" : 2, "gid" : 2, + "secon" : "u:r:untrusted_app:s0", "once" : 1, "importance" : 0, "caps" : [] @@ -215,6 +217,11 @@ init将系统启动分为三个阶段:

当前服务进程的gid值。

+

secon

+ +

当前服务进程的安全上下文(当前不需要设置该字段)。

+ +

once

当前服务进程是否为一次性进程:

diff --git a/services/BUILD.gn b/services/BUILD.gn index bc814a2..fb284e2 100755 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -127,6 +127,8 @@ if (defined(ohos_lite)) { "//third_party/bounds_checking_function:libsec_static", "//third_party/cJSON:cjson_static", ] + cflags = [] + if (use_musl) { deps += [ "//third_party/mksh:sh", @@ -134,6 +136,19 @@ if (defined(ohos_lite)) { ] } + if (build_selinux) { + include_dirs += [ + "//third_party/selinux/libselinux/include/", + "//base/security/selinux/interfaces/policycoreutils/include/", + ] + deps += [ + "//base/security/selinux:libload_policy", + "//base/security/selinux:librestorecon", + "//third_party/selinux:libselinux", + ] + cflags += [ "-DWITH_SELINUX" ] + } + if (disable_init_two_stages) { defines = [ "DISABLE_INIT_TWO_STAGES" ] } diff --git a/services/include/param/init_selinux_param.h b/services/include/param/init_selinux_param.h new file mode 100644 index 0000000..cf60011 --- /dev/null +++ b/services/include/param/init_selinux_param.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2021 北京万里红科技有限公司 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASE_STARTUP_INIT_SELINUX_PARAM_H +#define BASE_STARTUP_INIT_SELINUX_PARAM_H + +#ifdef __cplusplus +# if __cplusplus +extern "C" { +# endif // __cplusplus +#endif // __cplusplus + +# define SECON_STR_IN_CFG ("secon") +// https://github.com/xelerance/Openswan/blob/86dff2b/include/pluto/state.h#L222 +# define MAX_SECON_LEN (257) + +#ifdef __cplusplus +# if __cplusplus +} +# endif // __cplusplus +#endif // __cplusplus + +#endif // BASE_STARTUP_INIT_SELINUX_PARAM_H diff --git a/services/init/include/init_service.h b/services/init/include/init_service.h index 87713e1..6a33631 100755 --- a/services/init/include/init_service.h +++ b/services/init/include/init_service.h @@ -19,6 +19,9 @@ #include "cJSON.h" #include "init_cmds.h" #include "init_service_socket.h" +#ifdef WITH_SELINUX +# include "init_selinux_param.h" +#endif // WITH_SELINUX #include "list.h" #ifdef __cplusplus #if __cplusplus @@ -68,6 +71,9 @@ typedef struct { typedef struct { ListNode node; char name[MAX_SERVICE_NAME + 1]; +#ifdef WITH_SELINUX + char secon[MAX_SECON_LEN]; +#endif // WITH_SELINUX int pid; int crashCnt; time_t firstCrashTime; diff --git a/services/init/init_common_service.c b/services/init/init_common_service.c index 197db70..4218db6 100755 --- a/services/init/init_common_service.c +++ b/services/init/init_common_service.c @@ -37,6 +37,11 @@ #include "init_utils.h" #include "securec.h" +#ifdef WITH_SELINUX +# include "init_selinux_param.h" +# include +#endif // WITH_SELINUX + #ifndef TIOCSCTTY #define TIOCSCTTY 0x540E #endif @@ -171,6 +176,19 @@ static int WritePid(const Service *service) return SERVICE_SUCCESS; } +void SetSecon(Service * service) +{ +#ifdef WITH_SELINUX + if (*(service->secon)) { + if (setexeccon(service->secon) < 0) { + INIT_LOGE("failed to set service %s's secon (%s).", service->name, service->secon); + } else { + INIT_LOGI("service %s secon set to %s.", service->name, service->secon); + } + } +#endif // WITH_SELINUX +} + int ServiceStart(Service *service) { INIT_ERROR_CHECK(service != NULL, return SERVICE_FAILURE, "start service failed! null ptr."); @@ -208,6 +226,7 @@ int ServiceStart(Service *service) INIT_LOGE("service %s exit! write pid failed!", service->name); _exit(PROCESS_EXIT_CODE); } + SetSecon(service); ServiceExec(service); _exit(PROCESS_EXIT_CODE); } else if (pid < 0) { diff --git a/services/init/init_service_manager.c b/services/init/init_service_manager.c index be677f6..42019c8 100755 --- a/services/init/init_service_manager.c +++ b/services/init/init_service_manager.c @@ -30,6 +30,9 @@ #include "init_service_socket.h" #include "init_utils.h" #include "securec.h" +#ifdef WITH_SELINUX +# include "init_selinux_param.h" +#endif // WITH_SELINUX // All serivce processes that init will fork+exec. static ServiceSpace g_serviceSpace = { { &g_serviceSpace.services, &g_serviceSpace.services }, 0 }; @@ -398,7 +401,10 @@ static int CheckServiceKeyName(const cJSON *curService) { char *cfgServiceKeyList[] = { "name", "path", "uid", "gid", "once", "importance", "caps", "disabled", - "writepid", "critical", "socket", "console", "dynamic" + "writepid", "critical", "socket", "console", "dynamic", +#ifdef WITH_SELINUX + SECON_STR_IN_CFG, +#endif // WITH_SELINUX }; if (curService == NULL) { return SERVICE_FAILURE; @@ -432,6 +438,10 @@ static int ParseOneService(const cJSON *curItem, Service *service) } int ret = GetStringItem(curItem, "name", service->name, MAX_SERVICE_NAME); INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get service name"); +#ifdef WITH_SELINUX + ret = GetStringItem(curItem, SECON_STR_IN_CFG, service->secon, MAX_SECON_LEN); + INIT_CHECK_ONLY_ELOG(ret == 0, "GetServiceSecon %s section not found, skip", SECON_STR_IN_CFG); +#endif // WITH_SELINUX ret = GetServiceArgs(curItem, "path", MAX_PATH_ARGS_CNT, &service->pathArgs); INIT_ERROR_CHECK(ret == 0, return SERVICE_FAILURE, "Failed to get path for service %s", service->name); if ((service->pathArgs.count > 0) && IsForbidden(service->pathArgs.argv[0])) { diff --git a/services/init/standard/init.c b/services/init/standard/init.c index abd0e31..fbe1ba5 100755 --- a/services/init/standard/init.c +++ b/services/init/standard/init.c @@ -29,6 +29,9 @@ #include "init_utils.h" #include "securec.h" #include "switch_root.h" +#ifdef WITH_SELINUX +# include +#endif // WITH_SELINUX void SystemInit(void) { @@ -120,6 +123,23 @@ void SystemPrepare(void) #endif } +void SystemLoadSelinux(void) +{ +#ifdef WITH_SELINUX + // load selinux policy and context + if (load_policy() < 0) { + INIT_LOGE("main, load_policy failed."); + } else { + INIT_LOGI("main, load_policy success."); + } + if (restorecon() < 0) { + INIT_LOGE("main, restorecon failed."); + } else { + INIT_LOGI("main, restorecon success."); + } +#endif // WITH_SELINUX +} + void SystemConfig(void) { InitParamService(); @@ -141,6 +161,9 @@ void SystemConfig(void) PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init")); PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init")); PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init")); + + // load SELinux context and policy + SystemLoadSelinux(); } void SystemRun(void) diff --git a/services/init/standard/init_service.c b/services/init/standard/init_service.c index 533addb..bf10341 100755 --- a/services/init/standard/init_service.c +++ b/services/init/standard/init_service.c @@ -73,4 +73,4 @@ int ServiceExec(const Service *service) INIT_LOGE("service %s execve failed! err %d.", service->name, errno); } return SERVICE_SUCCESS; -} \ No newline at end of file +}