From f65730e620dde083133b8c1ab61c0d07b4dd8c2f Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 24 Apr 2015 18:38:17 +0000 Subject: [PATCH] Revert "Revert "Make init re-exec itself for its SELinux domain transition."" This reverts commit 4217374611ada50f33aee544f015f6f9dfbf7ced. It turns out that the kernel passes any unrecognized arguments on to init, and (at least) N6 and N9 have such arguments. My lazy check of argc was thus insufficient to recognize what stage of init we were in, so we'd skip to stage 2 and not set up SELinux. And apparently you can get a very long way with SELinux off... We'll fix that in a later change. Bug: 19702273 Change-Id: I43b3fb722fed35dd217cb529cbcac9a29aff4e4b --- init/init.cpp | 61 +++++++++++++++++++++++++++++++++++++------------ rootdir/init.rc | 7 ------ 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index b1d65dbc0..661ee2f3f 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -940,7 +940,13 @@ static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_ return 0; } -static void selinux_initialize() { +static void security_failure() { + ERROR("Security failure; rebooting into recovery mode...\n"); + android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); + while (true) { pause(); } // never reached +} + +static void selinux_initialize(bool in_kernel_domain) { Timer t; selinux_callback cb; @@ -953,19 +959,27 @@ static void selinux_initialize() { return; } - INFO("Loading SELinux policy...\n"); - if (selinux_android_load_policy() < 0) { - ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n"); - android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); - while (1) { pause(); } // never reached + if (in_kernel_domain) { + if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) { + ERROR("couldn't write to /sys/fs/selinux/checkreqprot: %s\n", + strerror(errno)); + security_failure(); + } + + INFO("Loading SELinux policy...\n"); + if (selinux_android_load_policy() < 0) { + ERROR("failed to load policy: %s\n", strerror(errno)); + security_failure(); + } + + bool is_enforcing = selinux_is_enforcing(); + security_setenforce(is_enforcing); + + NOTICE("(Initializing SELinux %s took %.2fs.)\n", + is_enforcing ? "enforcing" : "non-enforcing", t.duration()); + } else { + selinux_init_all_handles(); } - - selinux_init_all_handles(); - bool is_enforcing = selinux_is_enforcing(); - INFO("SELinux: security_setenforce(%d)\n", is_enforcing); - security_setenforce(is_enforcing); - - NOTICE("(Initializing SELinux took %.2fs.)\n", t.duration()); } int main(int argc, char** argv) { @@ -1006,7 +1020,8 @@ int main(int argc, char** argv) { klog_init(); klog_set_level(KLOG_NOTICE_LEVEL); - NOTICE("init started!\n"); + bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0); + NOTICE("init%s started!\n", is_first_stage ? "" : " second stage"); property_init(); @@ -1019,7 +1034,23 @@ int main(int argc, char** argv) { // used by init as well as the current required properties. export_kernel_boot_props(); - selinux_initialize(); + // Set up SELinux, including loading the SELinux policy if we're in the kernel domain. + selinux_initialize(is_first_stage); + + // If we're in the kernel domain, re-exec init to transition to the init domain now + // that the SELinux policy has been loaded. + if (is_first_stage) { + if (restorecon("/init") == -1) { + ERROR("restorecon failed: %s\n", strerror(errno)); + security_failure(); + } + char* path = argv[0]; + char* args[] = { path, const_cast("--second-stage"), nullptr }; + if (execv(path, args) == -1) { + ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno)); + security_failure(); + } + } // These directories were necessarily created before initial policy load // and therefore need their security context restored to the proper value. diff --git a/rootdir/init.rc b/rootdir/init.rc index d3c562f20..c00c590aa 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -14,13 +14,6 @@ on early-init # Set init and its forked children's oom_adj. write /proc/1/oom_score_adj -1000 - # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls. - write /sys/fs/selinux/checkreqprot 0 - - # Set the security context for the init process. - # This should occur before anything else (e.g. ueventd) is started. - setcon u:r:init:s0 - # Set the security context of /adb_keys if present. restorecon /adb_keys