Android11.0(R) MTK6771 user版本关闭 SELinux

开始我们先来跟一下 selinux 的初始化过程

system\core\init\main.cpp

java 复制代码
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif

    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

            return SubcontextMain(argc, argv, &function_map);
        }

        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    return FirstStageMain(argc, argv);
}

调用 SetupSelinux(argv),进入 selinux.cpp 中

system\core\init\selinux.cpp

java 复制代码
int SetupSelinux(char** argv) {
    SetStdioToDevNull(argv);
	...

    // Set up SELinux, loading the SELinux policy.
#ifdef MTK_LOG
    if (GetMTKLOGDISABLERATELIMIT())
        SelinuxSetupKernelLogging_split();
    else
        SelinuxSetupKernelLogging();
#else
    SelinuxSetupKernelLogging();
#endif
    SelinuxInitialize();

	....

继续调用 SelinuxInitialize()

java 复制代码
void SelinuxInitialize() {
    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(" << (is_enforcing ? "true" : "false")
                        << ") failed";
        }
    }

    if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result.ok()) {
        LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
    }

}

bool IsEnforcing() {
    if (ALLOW_PERMISSIVE_SELINUX) {
        return StatusFromCmdline() == SELINUX_ENFORCING;
    }
    return true;
}

EnforcingStatus StatusFromCmdline() {
    EnforcingStatus status = SELINUX_ENFORCING;

    ImportKernelCmdline([&](const std::string& key, const std::string& value) {
        if (key == "androidboot.selinux" && value == "permissive") {
            status = SELINUX_PERMISSIVE;
        }
    });

    return status;
}

security_getenforce() 读取 sys/fs/selinux/enforce 文件值

获取 kernel 层 selinux 默认模式,当定义了 ALLOW_PERMISSIVE_SELINUX 时,会检测是否在

cmdline 写入了 androidboot.selinux=permissive(lk 阶段写入)

kernel_enforcing 和 is_enforcing 不相等时将 is_enforcing 写入 sys/fs/selinux/enforce

在 11 User 版本中,security_setenforce(is_enforcing) 执行失败,开机直接自动进入 fastboot 模式

提示 security_setenforce(false) failed: Invalid argument

4.475989 <2>.(2)1:initinit: security_setenforce(false) failed: Invalid argument

将下面这句注释能正常开机启动,但无法成功关闭 selinux

PLOG(FATAL) << "security_setenforce(" << (is_enforcing ? "true" : "false") << ") failed";

11 eng 版本,默认烧写后 enforce 即为 Permissive,在之前的低版本 eng 中,默认 enforce 为 Enforcing

来看下 security_setenforce() 具体实现, selinux_log() 打印语句是我增加的,需要引入上面的三个头文件,

external\selinux\libselinux\src\setenforce.c

java 复制代码
#include "callbacks.h"
#include <selinux/android.h>
#include <log/log.h>

int security_setenforce(int value)
{
	int fd, ret;
	char path[PATH_MAX];
	char buf[20];
	selinux_log(SELINUX_INFO, "SELinux: security_setenforce value %d\n", value);
	selinux_log(SELINUX_INFO, "SELinux: security_setenforce selinux_mnt %s\n", selinux_mnt);
	if (!selinux_mnt) {
		errno = ENOENT;
		return -1;
	}

	snprintf(path, sizeof path, "%s/enforce", selinux_mnt);
	selinux_log(SELINUX_INFO, "SELinux: security_setenforce path %s\n", path);
	fd = open(path, O_RDWR | O_CLOEXEC);
	selinux_log(SELINUX_INFO, "SELinux: security_setenforce fd %d\n", fd);
	if (fd < 0)
		return -1;

	snprintf(buf, sizeof buf, "%d", value);
	ret = write(fd, buf, strlen(buf));
	selinux_log(SELINUX_INFO, "SELinux: security_setenforce ret %d\n", ret);
	close(fd);
	if (ret < 0)
		return -1;

	return 0;
}

hidden_def(security_setenforce)

selinux_mnt 的定义在 external\selinux\libselinux\src\policy.h

java 复制代码
/* Preferred selinux mount location */
#define SELINUXMNT "/sys/fs/selinux"
#define OLDSELINUXMNT "/selinux"

/* selinuxfs mount point */
extern char *selinux_mnt;

selinux_mnt 赋值在 init.c

java 复制代码
external\selinux\libselinux\src\init.c

void set_selinuxmnt(const char *mnt)
{
	selinux_mnt = strdup(mnt);
}

external\selinux\libselinux\src\android\android_platform.c

int selinux_android_load_policy_from_fd(int fd, const char *description)
{	
    ......
	set_selinuxmnt(SELINUXMNT);

所以最终的 path = sys/fs/selinux/enforce

snprintf(path, sizeof path, "%s/enforce", selinux_mnt);

security_setenforce() 和 security_getenforce() 都是读写 path = sys/fs/selinux/enforce

当使用 adb shell setenforce 0 时,调用对应文件位于,

external\toybox\toys\android\setenforce.c

通过上面加的 log,最终还是调用到 setenforce.c

java 复制代码
#define FOR_setenforce
#include "toys.h"

void setenforce_main(void)
{
  char *new = *toys.optargs;
  int state, ret;

  if (!is_selinux_enabled()) error_exit("SELinux is disabled");
  else if (!strcmp(new, "1") || !strcasecmp(new, "enforcing")) state = 1;
  else if (!strcmp(new, "0") || !strcasecmp(new, "permissive")) state = 0;
  else error_exit("Invalid state: %s", new);

  ret = security_setenforce(state);
  if (ret == -1) perror_msg("Couldn't set enforcing status to '%s'", new);
}


adb shell setenforce 0
SELinux: security_setenforce value 0
SELinux: security_setenforce selinux_mnt /sys/fs/selinux
SELinux: security_setenforce path /sys/fs/selinux/enforce
SELinux: security_setenforce fd 3
SELinux: security_setenforce ret -1
setenforce: Couldn't set enforcing status to '0': Invalid argument

看到 eng 版本 logcat 中打印了

audit: type=1404 audit(1262304022.108:3): enforcing=0 old_enforcing=1 auid=4294967295 ses=4294967295 enabled=1 old-enabled=1 lsm=selinux res=1

搜索找到 kernel 中 kernel-4.19\security\selinux\selinuxfs.c

java 复制代码
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
				 size_t count, loff_t *ppos)

{
	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
	struct selinux_state *state = fsi->state;
	char *page = NULL;
	ssize_t length;
	int old_value, new_value;

	if (count >= PAGE_SIZE)
		return -ENOMEM;

	/* No partial writes. */
	if (*ppos != 0)
		return -EINVAL;

	page = memdup_user_nul(buf, count);
	if (IS_ERR(page))
		return PTR_ERR(page);

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;

	new_value = !!new_value;

	old_value = enforcing_enabled(state);
	if (new_value != old_value) {
		length = avc_has_perm(&selinux_state,
				      current_sid(), SECINITSID_SECURITY,
				      SECCLASS_SECURITY, SECURITY__SETENFORCE,
				      NULL);
		if (length)
			goto out;
		audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
			"enforcing=%d old_enforcing=%d auid=%u ses=%u"
			" enabled=%d old-enabled=%d lsm=selinux res=1",
			new_value, old_value,
			from_kuid(&init_user_ns, audit_get_loginuid(current)),
			audit_get_sessionid(current),
			selinux_enabled, selinux_enabled);
		enforcing_set(state, new_value);
		if (new_value)
			avc_ss_reset(state->avc, 0);
		selnl_notify_setenforce(new_value);
		selinux_status_update_setenforce(state, new_value);
		if (!new_value)
			call_lsm_notifier(LSM_POLICY_CHANGE, NULL);
	}
	length = count;
out:
	kfree(page);
	return length;
}
#else
#define sel_write_enforce NULL
#endif

可以看到 CONFIG_SECURITY_SELINUX_DEVELOP 宏决定了是否存在 sel_write_enforce 方法

接下来再来看 kernel 中 selinux 初始化设置

kernel-4.19\security\selinux\hooks.c

java 复制代码
static __init int selinux_init(void)
{
	if (!security_module_enable("selinux")) {
		selinux_enabled = 0;
		return 0;
	}

	if (!selinux_enabled) {
		pr_info("SELinux:  Disabled at boot.\n");
		return 0;
	}

	pr_info("SELinux:  Initializing. %d\n", selinux_enforcing_boot);

	memset(&selinux_state, 0, sizeof(selinux_state));
	enforcing_set(&selinux_state, selinux_enforcing_boot);
	selinux_state.checkreqprot = selinux_checkreqprot_boot;
	selinux_ss_init(&selinux_state.ss);
	selinux_avc_init(&selinux_state.avc);

	....

	if (selinux_enforcing_boot)
		pr_info("SELinux:  Starting in enforcing mode\n");
	else
		pr_info("SELinux:  Starting in permissive mode\n");

	return 0;
}

enforcing_set(&selinux_state, selinux_enforcing_boot);

selinux_enforcing_boot 默认值定义由 CONFIG_SECURITY_SELINUX_DEVELOP 决定

全局搜索到 kernel-4.19\kernel\configs\userdebug.config 中定义了 CONFIG_SECURITY_SELINUX_DEVELOP=y

由此可以解释上面说的 eng 版本默认为 permissive 0,user 版本默认为 enforce 1

但是最终搜索发现 eng 版本编译时并没有引入 userdebug.config,这就奇怪了,看 log 可以肯定的是 eng 版本中必须

定义了 CONFIG_SECURITY_SELINUX_DEVELOP,但为何找不到定义的地方???????

device\mediateksample\k62v1_64_bsp\vnd_k62v1_64_bsp.mk

java 复制代码
ifeq ($(TARGET_BUILD_VARIANT), eng)
KERNEL_DEFCONFIG ?= k62v1_64_bsp_debug_defconfig
endif
ifeq ($(TARGET_BUILD_VARIANT), user)
KERNEL_DEFCONFIG ?= k62v1_64_bsp_defconfig
endif
ifeq ($(TARGET_BUILD_VARIANT), userdebug)
KERNEL_DEFCONFIG ?= k62v1_64_bsp_defconfig userdebug.config
endif
PRELOADER_TARGET_PRODUCT ?= k62v1_64_bsp
LK_PROJECT ?= k62v1_64_bsp
TRUSTY_PROJECT ?= k62v1_64_bsp

可以看到有且仅有编译 userdebug 版本时才引入 userdebug.config,所以想要 user 版本中默认关闭 selinux,只需编译

时引入 userdebug.config。这样就定义了 CONFIG_SECURITY_SELINUX_DEVELOP

初始化时 enforcing_set(&selinux_state, selinux_enforcing_boot); 直接写入 0

kernel-4.19\security\selinux\include\security.h 中才能成功写入

java 复制代码
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
static inline bool enforcing_enabled(struct selinux_state *state)
{
	return state->enforcing;
}

static inline void enforcing_set(struct selinux_state *state, bool value)
{
	state->enforcing = value;
}
#else
static inline bool enforcing_enabled(struct selinux_state *state)
{
	return true;
}

static inline void enforcing_set(struct selinux_state *state, bool value)
{
}
#endif

最后当你在 user 版本关闭 selinux 后,烧写后重新开机系统会弹出您的设备内部出现了问题。请联系您的设备制造商了解详情 对话框

具体原因可查看这篇进行屏蔽 blog.csdn.net/qq_18059855...

Linux权限详解(chmod、600、644、666、700、711、755、777、4755、6755、7755)

8.0selinux状态获取过程

深入理解SELinux/SEAndroid

玩转Android10源码开发定制(13)修改安卓源码关闭selinux

CONFIG_SECURITY_SELINUX_DEVELOP flag

相关推荐
千里马学框架2 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone2 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc2 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo2 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077002 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone2 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen2 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone2 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui