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:init]init: 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

相关推荐
sunly_3 小时前
Flutter:启动屏逻辑处理02:启动页
android·javascript·flutter
Sgq丶4 小时前
Android Studio 配置 proto
android·ide·android studio
_小马快跑_7 小时前
ConstraintLayout 中的ImageFilterView探索:处理图片圆角、亮度、饱和度、图片重叠等
android
IT-sec8 小时前
jquery-picture-cut 任意文件上传(CVE-2018-9208)
android·前端·javascript·安全·web安全·网络安全·jquery
xiaoduyyy9 小时前
【Android】RecyclerView回收复用机制
android
林北芒大果9 小时前
【Flutter】搭建Flutter开发环境,安卓开发
android·flutter
m0_7482302111 小时前
MySQL 数据库连接池爆满问题排查与解决
android·数据库·mysql
SunshineBrother11 小时前
Flutter求职、面试20+面试官总结:Dart篇
android·前端·flutter
鸿儒51712 小时前
利用adb工具安装卸载安卓平板(手机)软件
android·adb·智能手机
软件聚导航14 小时前
uniapp 安卓和ios震动方法,支持息屏和后台震动,ios和安卓均通过测试
android·ios·uni-app