init: support selinux

此提交使 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 <qinfd@superred.com.cn>
This commit is contained in:
Qin Fandong 2021-10-19 15:36:51 +08:00
parent 93c3e2640f
commit 55582482ab
10 changed files with 125 additions and 2 deletions

View File

@ -22,6 +22,7 @@
<licensefile></licensefile>
<policylist>
<policy name="projectPolicy" desc="">
<policyitem type="copyright" name="北京万里红科技有限公司" path=".*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
<!--policyitem type="compatibility" name="GPL-2.0+" path="abc/.*" desc="Process that runs independently, invoked by the X process."/-->
<!--policyitem type="license" name="LGPL" path="abc/.*" desc="Dynamically linked by module X"/-->
<!--policyitem type="copyright" name="xxx" path="abc/.*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc="Developed by X Company"/-->

View File

@ -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**, *
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p12738691479"><a name="p12738691479"></a><a name="p12738691479"></a>Group ID (GID) of the current service process.</p>
</td>
</tr>
<tr id="row127381591693"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p47388919793"><a name="p47388919793"></a><a name="p47388919715"></a>secon</p>
</td>
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p12738691493"><a name="p12738691493"></a><a name="p12738691493"></a>Security context of the current service process (no need to set currently).</p>
</td>
</tr>
<tr id="row188301014171116"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p183112146115"><a name="p183112146115"></a><a name="p183112146115"></a>once</p>
</td>
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p18548317195715"><a name="p18548317195715"></a><a name="p18548317195715"></a>Whether the current service process is a one-off process.</p>

View File

@ -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将系统启动分为三个阶段
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p12738691479"><a name="p12738691479"></a><a name="p12738691479"></a>当前服务进程的gid值。</p>
</td>
</tr>
<tr id="row127381591693"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p47388919793"><a name="p47388919793"></a><a name="p47388919715"></a>secon</p>
</td>
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p12738691493"><a name="p12738691493"></a><a name="p12738691493"></a>当前服务进程的安全上下文(当前不需要设置该字段)。</p>
</td>
</tr>
<tr id="row188301014171116"><td class="cellrowborder" valign="top" width="10.37%" headers="mcps1.2.3.1.1 "><p id="p183112146115"><a name="p183112146115"></a><a name="p183112146115"></a>once</p>
</td>
<td class="cellrowborder" valign="top" width="89.63%" headers="mcps1.2.3.1.2 "><p id="p18548317195715"><a name="p18548317195715"></a><a name="p18548317195715"></a>当前服务进程是否为一次性进程:</p>

View File

@ -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" ]
}

View File

@ -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

View File

@ -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;

View File

@ -37,6 +37,11 @@
#include "init_utils.h"
#include "securec.h"
#ifdef WITH_SELINUX
# include "init_selinux_param.h"
# include <selinux/selinux.h>
#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) {

View File

@ -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])) {

View File

@ -29,6 +29,9 @@
#include "init_utils.h"
#include "securec.h"
#include "switch_root.h"
#ifdef WITH_SELINUX
# include <policycoreutils.h>
#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)

View File

@ -73,4 +73,4 @@ int ServiceExec(const Service *service)
INIT_LOGE("service %s execve failed! err %d.", service->name, errno);
}
return SERVICE_SUCCESS;
}
}