From adf0d1bbfa4bc560c2106f14afa8258a11c48bf6 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 22 Apr 2015 18:39:58 -0700 Subject: [PATCH] Make init re-exec itself for its SELinux domain transition. Change-Id: I38adabe5789d671e3f7d21936071a758ec8cea8a --- 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..ed20661f3 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); + 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 a5ea60aaa..4d9c4f3f3 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