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

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

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

system\core\init\main.cpp

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

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()

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


#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

/* Preferred selinux mount location */
#define SELINUXMNT "/sys/fs/selinux"
#define OLDSELINUXMNT "/selinux"
/* selinuxfs mount point */
extern char *selinux_mnt;

selinux_mnt 赋值在 init.c

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

#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


#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

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

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 中才能成功写入

#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 后,烧写后重新开机系统会弹出您的设备内部出现了问题。请联系您的设备制造商了解详情 对话框


具体原因可查看这篇进行屏蔽 https://blog.csdn.net/qq_18059855/article/details/108409157


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


8.0selinux状态获取过程


深入理解SELinux/SEAndroid


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


CONFIG_SECURITY_SELINUX_DEVELOP flag


目录
相关文章
|
24天前
|
Java API 开发工具
Android cmdline-tools版本与最小JDK的关系
总的来说,Android的命令行工具和JDK之间的关系就像是一场舞会,两者需要彼此配合,才能共同创造出美妙的舞蹈。如果选择了不合适的舞伴(即不兼容的版本),可能会导致舞蹈中的步伐混乱,甚至无法完成舞蹈。而即使选择了合适的舞伴,也需要考虑舞伴的舞蹈技巧(即性能和稳定性),才能确保舞蹈的完美表现。因此,选择合适的Android命令行工具和JDK版本,是每一个Android开发者都需要面对的重要决定。
54 13
|
3月前
|
移动开发 安全 Java
Android历史版本与APK文件结构
通过以上内容,您可以全面了解Android的历史版本及其主要特性,同时掌握APK文件的结构和各部分的作用。这些知识对于理解Android应用的开发和发布过程非常重要,也有助于在实际开发中进行高效的应用管理和优化。希望这些内容对您的学习和工作有所帮助。
355 83
|
1月前
|
安全 搜索推荐 Android开发
Android系统SELinux安全机制详解
如此看来,SELinux对于大家来说,就像那位不眠不休,严阵以待的港口管理员,守护我们安卓系统的平安,维护这片海港的和谐生态。SELinux就这样,默默无闻,却卫士如山,给予Android系统一份厚重的安全保障。
95 18
|
6月前
|
人工智能 搜索推荐 物联网
Android系统版本演进与未来展望####
本文深入探讨了Android操作系统从诞生至今的发展历程,详细阐述了其关键版本迭代带来的创新特性、用户体验提升及对全球移动生态系统的影响。通过对Android历史版本的回顾与分析,本文旨在揭示其成功背后的驱动力,并展望未来Android可能的发展趋势与面临的挑战,为读者呈现一个既全面又具深度的技术视角。 ####
|
2月前
|
安全 开发工具 Android开发
【Android Git】Git版本回退方式
在实际操作中,选择合适的版本回退方式,可以有效地管理代码版本,提高开发效率和代码质量。
149 26
|
3月前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
252 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
9月前
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
345 1
|
9月前
|
Shell Serverless
makefile 函数全解
makefile 函数全解
758 0
makefile 函数全解
|
9月前
|
编解码 安全 Ubuntu
Android Selinux 问题处理笔记
这篇文章是关于处理Android系统中SELinux权限问题的笔记,介绍了如何通过分析SELinux拒绝的日志、修改SELinux策略文件,并重新编译部署来解决权限问题,同时提供了一些SELinux的背景知识和实用工具。
432 0
|
9月前
|
Java 开发工具 Android开发
Android Studio利用Build.gradle导入Git commit ID、Git Branch、User等版本信息
本文介绍了在Android Studio项目中通过修改`build.gradle`脚本来自动获取并添加Git的commit ID、branch名称和用户信息到BuildConfig类中,从而实现在编译时将这些版本信息加入到APK中的方法。
246 0