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 #include 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...](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fqq_18059855%2Farticle%2Fdetails%2F108409157 "https://blog.csdn.net/qq_18059855/article/details/108409157") [Linux权限详解(chmod、600、644、666、700、711、755、777、4755、6755、7755)](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fu013197629%2Farticle%2Fdetails%2F73608613 "https://blog.csdn.net/u013197629/article/details/73608613") [8.0selinux状态获取过程](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fmike8825%2Farticle%2Fdetails%2F90733610 "https://blog.csdn.net/mike8825/article/details/90733610") [深入理解SELinux/SEAndroid](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2FFybon%2Farticle%2Fdetails%2F37812695 "https://blog.csdn.net/Fybon/article/details/37812695") [玩转Android10源码开发定制(13)修改安卓源码关闭selinux](https://link.juejin.cn?target=https%3A%2F%2Fmp.weixin.qq.com%2Fs%2FUAPwYIMRFyDyPkvMfjNXCg "https://mp.weixin.qq.com/s/UAPwYIMRFyDyPkvMfjNXCg") [CONFIG_SECURITY_SELINUX_DEVELOP flag](https://link.juejin.cn?target=https%3A%2F%2Fwww.spinics.net%2Flists%2Fselinux%2Fmsg16412.html "https://www.spinics.net/lists/selinux/msg16412.html")

相关推荐
还鮟2 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡4 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi004 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil5 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你6 小时前
Android View的绘制原理详解
android
移动开发者1号8 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号8 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best13 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk14 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭18 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin