summaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2017-03-02 01:02:14 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2017-03-02 01:02:15 +0000
commit056eca201b093a8b3436f8020a49b1161d7c1f4c (patch)
treed6e9a08d7e59aae1f4f94a50d7ceaa94536b3051 /init
parenta02a42ecb1c2bf57cf8731d9adc6354c885f2e49 (diff)
parent16696e201b20010d7de97265224e83401861d9ad (diff)
downloadsystem_core-056eca201b093a8b3436f8020a49b1161d7c1f4c.tar.gz
system_core-056eca201b093a8b3436f8020a49b1161d7c1f4c.tar.bz2
system_core-056eca201b093a8b3436f8020a49b1161d7c1f4c.zip
Merge "Use split SELinux policy at boot, if available"
Diffstat (limited to 'init')
-rw-r--r--init/init.cpp135
1 files changed, 131 insertions, 4 deletions
diff --git a/init/init.cpp b/init/init.cpp
index ad4042617..53e7482e5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -43,6 +43,7 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <cutils/iosched_policy.h>
#include <cutils/list.h>
@@ -618,6 +619,133 @@ static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_
return 0;
}
+/*
+ * Forks, executes the provided program in the child, and waits for the completion in the parent.
+ *
+ * Returns true if the child exited with status code 0, returns false otherwise.
+ */
+static bool fork_execve_and_wait_for_completion(const char* filename, char* const argv[],
+ char* const envp[]) {
+ pid_t child_pid = fork();
+ if (child_pid == -1) {
+ PLOG(ERROR) << "Failed to fork for " << filename;
+ return false;
+ }
+
+ if (child_pid == 0) {
+ // fork succeeded -- this is executing in the child process
+ if (execve(filename, argv, envp) == -1) {
+ PLOG(ERROR) << "Failed to execve " << filename;
+ return false;
+ }
+ // Unreachable because execve will have succeeded and replaced this code
+ // with child process's code.
+ _exit(127);
+ return false;
+ } else {
+ // fork succeeded -- this is executing in the original/parent process
+ int status;
+ if (TEMP_FAILURE_RETRY(waitpid(child_pid, &status, 0)) != child_pid) {
+ PLOG(ERROR) << "Failed to wait for " << filename;
+ return false;
+ }
+
+ if (WIFEXITED(status)) {
+ int status_code = WEXITSTATUS(status);
+ if (status_code == 0) {
+ return true;
+ } else {
+ LOG(ERROR) << filename << " exited with status " << status_code;
+ }
+ } else if (WIFSIGNALED(status)) {
+ LOG(ERROR) << filename << " killed by signal " << WTERMSIG(status);
+ } else if (WIFSTOPPED(status)) {
+ LOG(ERROR) << filename << " stopped by signal " << WSTOPSIG(status);
+ } else {
+ LOG(ERROR) << "waitpid for " << filename << " returned unexpected status: " << status;
+ }
+
+ return false;
+ }
+}
+
+static constexpr const char plat_policy_cil_file[] = "/plat_sepolicy.cil";
+
+static bool selinux_is_split_policy_device() { return access(plat_policy_cil_file, R_OK) != -1; }
+
+/*
+ * Loads SELinux policy split across platform/system and non-platform/vendor files.
+ *
+ * Returns true upon success, false otherwise (failure cause is logged).
+ */
+static bool selinux_load_split_policy() {
+ // IMPLEMENTATION NOTE: Split policy consists of three CIL files:
+ // * platform -- policy needed due to logic contained in the system image,
+ // * non-platform -- policy needed due to logic contained in the vendor image,
+ // * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy
+ // with newer versions of platform policy.
+ //
+ // secilc is invoked to compile the above three policy files into a single monolithic policy
+ // file. This file is then loaded into the kernel.
+
+ LOG(INFO) << "Compiling SELinux policy";
+
+ // We store the output of the compilation on /dev because this is the most convenient tmpfs
+ // storage mount available this early in the boot sequence.
+ char compiled_sepolicy[] = "/dev/sepolicy.XXXXXX";
+ android::base::unique_fd compiled_sepolicy_fd(mkostemp(compiled_sepolicy, O_CLOEXEC));
+ if (compiled_sepolicy_fd < 0) {
+ PLOG(ERROR) << "Failed to create temporary file " << compiled_sepolicy;
+ return false;
+ }
+
+ const char* compile_args[] = {"/system/bin/secilc", plat_policy_cil_file, "-M", "true", "-c",
+ "30", // TODO: pass in SELinux policy version from build system
+ "/mapping_sepolicy.cil", "/nonplat_sepolicy.cil", "-o",
+ compiled_sepolicy,
+ // We don't care about file_contexts output by the compiler
+ "-f", "/sys/fs/selinux/null", // /dev/null is not yet available
+ nullptr};
+
+ if (!fork_execve_and_wait_for_completion(compile_args[0], (char**)compile_args, (char**)ENV)) {
+ unlink(compiled_sepolicy);
+ return false;
+ }
+ unlink(compiled_sepolicy);
+
+ LOG(INFO) << "Loading compiled SELinux policy";
+ if (selinux_android_load_policy_from_fd(compiled_sepolicy_fd, compiled_sepolicy) < 0) {
+ LOG(ERROR) << "Failed to load SELinux policy from " << compiled_sepolicy;
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Loads SELinux policy from a monolithic file.
+ *
+ * Returns true upon success, false otherwise (failure cause is logged).
+ */
+static bool selinux_load_monolithic_policy() {
+ LOG(VERBOSE) << "Loading SELinux policy from monolithic file";
+ if (selinux_android_load_policy() < 0) {
+ PLOG(ERROR) << "Failed to load monolithic SELinux policy";
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Loads SELinux policy into the kernel.
+ *
+ * Returns true upon success, false otherwise (failure cause is logged).
+ */
+static bool selinux_load_policy() {
+ return selinux_is_split_policy_device() ? selinux_load_split_policy()
+ : selinux_load_monolithic_policy();
+}
+
static void selinux_initialize(bool in_kernel_domain) {
Timer t;
@@ -628,10 +756,9 @@ static void selinux_initialize(bool in_kernel_domain) {
selinux_set_callback(SELINUX_CB_AUDIT, cb);
if (in_kernel_domain) {
- LOG(INFO) << "Loading SELinux policy...";
- if (selinux_android_load_policy() < 0) {
- PLOG(ERROR) << "failed to load policy";
- security_failure();
+ LOG(INFO) << "Loading SELinux policy";
+ if (!selinux_load_policy()) {
+ panic();
}
bool kernel_enforcing = (security_getenforce() == 1);