直接配置init进程的Android.bp文件和uboot配置的值最佳,Android.bp下面-DALLOW_PERMISSIVE_SELINUX=0则是关闭,=1则是打开;bootloader/uboot-repo/bl33/board/公司名/configs/对应芯片的配置头文件.h,"EnableSelinux=enforcing\0"\是打开,"EnableSelinux=permissive\0"\则是关闭。偷懒则是直接修改selinux.cpp下面的isEnforcing函数。
下面是分析。
先看init初始化selinux的代码。security_getenforce是读取uboot设置的selinux模式,isEnforcing则是读取init Android.mk/Android.bp配置的selinux模式
void SelinuxInitialize() {
Timer t;
LOG(INFO) << "Loading SELinux policy";
if (!LoadPolicy()) {
LOG(FATAL) << "Unable to load SELinux policy";
}
bool kernel_enforcing = (security_getenforce() == 1);
bool is_enforcing = IsEnforcing();
if (kernel_enforcing != is_enforcing) {
if (security_setenforce(is_enforcing)) {
PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
}
}
if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result) {
LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
}
// init's first stage can't set properties, so pass the time to the second stage.
setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
}
isEnforcing里面。ALLOW_PERMISSIVE_SELINUX来自于Android.bp定义的"-DALLOW_PERMISSIVE_SELINUX=0",然后在下面debuggable打开即非user版本则会将其设置为1,即permissvie模式。
system/core/init/selinux.cpp
这里能看到判断系统师傅打开selinux的逻辑。
1.init Android.bp配置-DALLOW_PERMISSIVE_SELINUX=1
2.StatusFromCmdline是读取/proc/cmdline uboot设置的键值对,其中"EnableSelinux=permissive\0"\
bool IsEnforcing() {
if (ALLOW_PERMISSIVE_SELINUX) {
return StatusFromCmdline() == SELINUX_ENFORCING;
}
return true;
}
cflags: [
"-DLOG_UEVENTS=0",
"-Wall",
"-Wextra",
"-Wno-unused-parameter",
"-Werror",
"-DALLOW_LOCAL_PROP_OVERRIDE=0",
"-DALLOW_PERMISSIVE_SELINUX=0",
"-DREBOOT_BOOTLOADER_ON_PANIC=0",
"-DWORLD_WRITABLE_KMSG=0",
"-DDUMP_ON_UMOUNT_FAILURE=0",
"-DSHUTDOWN_ZERO_TIMEOUT=0",
],
product_variables: {
debuggable: {
cppflags: [
"-UALLOW_LOCAL_PROP_OVERRIDE",
"-DALLOW_LOCAL_PROP_OVERRIDE=1",
"-UALLOW_PERMISSIVE_SELINUX",
"-DALLOW_PERMISSIVE_SELINUX=1",
"-UREBOOT_BOOTLOADER_ON_PANIC",
"-DREBOOT_BOOTLOADER_ON_PANIC=1",
"-UWORLD_WRITABLE_KMSG",
"-DWORLD_WRITABLE_KMSG=1",
"-UDUMP_ON_UMOUNT_FAILURE",
"-DDUMP_ON_UMOUNT_FAILURE=1",
],
},
eng: {
cppflags: [
"-USHUTDOWN_ZERO_TIMEOUT",
"-DSHUTDOWN_ZERO_TIMEOUT=1",
],
},
uml: {
cppflags: ["-DUSER_MODE_LINUX"],
},
},
而security_getenforce函数实现在./external/selinux/libselinux/src/getenforce.c里面,具体是读取系统节点"sys/fs/selinux/enforce",默认是打开的。
int security_getenforce(void)
{
int fd, ret, enforce = 0;
char path[PATH_MAX];
char buf[20];
if (!selinux_mnt) {
errno = ENOENT;
return -1;
}
snprintf(path, sizeof path, "%s/enforce", selinux_mnt);
fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return -1;
memset(buf, 0, sizeof buf);
ret = read(fd, buf, sizeof buf - 1);
close(fd);
if (ret < 0)
return -1;
if (sscanf(buf, "%d", &enforce) != 1)
return -1;
return !!enforce;
}
然后如果二者不一致,则将init进程配置的值赋值到kernel对应的节点里面。
external/selinux/libselinux/src/setenforce.c
int security_setenforce(int value)
{
int fd, ret;
char path[PATH_MAX];
char buf[20];
if (!selinux_mnt) {
errno = ENOENT;
return -1;
}
snprintf(path, sizeof path, "%s/enforce", selinux_mnt);
fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0)
return -1;
snprintf(buf, sizeof buf, "%d", value);
ret = write(fd, buf, strlen(buf));
close(fd);
if (ret < 0)
return -1;
return 0;
}