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


目录
相关文章
|
1月前
|
Android开发
Android 11 添加Service服务SELinux问题
Android 11 添加Service服务SELinux问题
88 1
|
1月前
|
编解码 Android开发
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)1
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)
91 1
|
1月前
|
Android开发
Android Service Call /dev/xxx SELinux
Android Service Call /dev/xxx SELinux
29 1
|
1月前
|
编解码 开发工具 Android开发
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)2
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)2
62 2
|
1月前
|
存储 算法 Android开发
AVB校验微观版本:android avb(Android Verified Boot)验证
AVB校验微观版本:android avb(Android Verified Boot)验证
433 0
|
1月前
|
Shell 开发工具 Android开发
android 修改kernel编译版本信息
android 修改kernel编译版本信息
25 0
|
1月前
|
Shell Android开发
android Selinux 之 platform
android Selinux 之 platform
16 0
|
1月前
|
编解码 缓存 安全
Android SELinux 参数语法介绍及基础分析
Android SELinux 参数语法介绍及基础分析
28 0
|
1月前
|
存储 Android开发
Android 高版本 packageManager.getPackageArchiveInfo 总是返回null
Android 高版本 packageManager.getPackageArchiveInfo 总是返回null
25 1
|
1月前
|
编解码 监控 API
Android HAL深入探索(6): HIDL 添加SELinux 完整调试过程
Android HAL深入探索(6): HIDL 添加SELinux 完整调试过程
193 0