Use precompiled sepolicy when available
NOTE: This change affects only devices which use SELinux kernel policy split over system and vendor directories/partitions. Prior to this change, init compiled sepolicy from *.cil files on every boot, thus slowing boot down by about 400 ms. This change enables init to skip the step compilation and thus avoid spending the 400 ms. The skipping occurs only if the device's vendor partition includes an acceptable precompiled policy file. If no acceptable policy is found, the compilation step takes place same as before. Because such devices support updating system and vendor partitions independently of each other, the vendor partition's precompiled policy is only used if it was compiled against the system partition's policy. The exact mechanism is that both partitions include a file containing the SHA-256 digest of the system partition's policy (plat_sepolicy.cil) and the precompiled policy is considered usable only if the two digests are identical. Test: Device with monolithic policy boots up just fine Test: Device with split policy and with matching precompiled policy boots up just fine and getprop ro.boottime.init.selinux returns a number below 100 ms. No "Compiling SELinux policy" message in dmesg. Test: Device with split policy and with non-matching precompiled policy boots up just fine and getpropr ro.boottime.init.selinux returns a number above 400 ms. There is a "Compiling SELinux policy" message in dmesg. The non-matching policy was obtained by adding an allow rule to system/sepolicy, building a new system image using make systemimage and then flashing it onto the device. Bug: 31363362 Change-Id: Ic2e81a83051689b5cd5ef1299ba6aaa1b1df1bdc
This commit is contained in:
parent
5811a434fc
commit
2d19aeb13a
|
@ -119,7 +119,14 @@ LOCAL_REQUIRED_MODULES += \
|
|||
mapping_sepolicy.cil \
|
||||
nonplat_sepolicy.cil \
|
||||
plat_sepolicy.cil \
|
||||
plat_sepolicy.cil.sha256 \
|
||||
secilc
|
||||
|
||||
# Include precompiled policy, unless told otherwise
|
||||
ifneq ($(PRODUCT_PRECOMPILED_SEPOLICY),false)
|
||||
LOCAL_REQUIRED_MODULES += precompiled_sepolicy precompiled_sepolicy.plat.sha256
|
||||
endif
|
||||
|
||||
else
|
||||
# Use monolithic SELinux policy
|
||||
LOCAL_REQUIRED_MODULES += sepolicy
|
||||
|
|
|
@ -715,6 +715,44 @@ static bool fork_execve_and_wait_for_completion(const char* filename, char* cons
|
|||
}
|
||||
}
|
||||
|
||||
static bool read_first_line(const char* file, std::string* line) {
|
||||
line->clear();
|
||||
|
||||
std::string contents;
|
||||
if (!android::base::ReadFileToString(file, &contents, true /* follow symlinks */)) {
|
||||
return false;
|
||||
}
|
||||
std::istringstream in(contents);
|
||||
std::getline(in, *line);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool selinux_find_precompiled_split_policy(std::string* file) {
|
||||
file->clear();
|
||||
|
||||
static constexpr const char precompiled_sepolicy[] = "/vendor/etc/selinux/precompiled_sepolicy";
|
||||
if (access(precompiled_sepolicy, R_OK) == -1) {
|
||||
return false;
|
||||
}
|
||||
std::string actual_plat_id;
|
||||
if (!read_first_line("/system/etc/selinux/plat_sepolicy.cil.sha256", &actual_plat_id)) {
|
||||
PLOG(INFO) << "Failed to read /system/etc/selinux/plat_sepolicy.cil.sha256";
|
||||
return false;
|
||||
}
|
||||
std::string precompiled_plat_id;
|
||||
if (!read_first_line("/vendor/etc/selinux/precompiled_sepolicy.plat.sha256",
|
||||
&precompiled_plat_id)) {
|
||||
PLOG(INFO) << "Failed to read /vendor/etc/selinux/precompiled_sepolicy.plat.sha256";
|
||||
return false;
|
||||
}
|
||||
if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*file = precompiled_sepolicy;
|
||||
return true;
|
||||
}
|
||||
|
||||
static constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil";
|
||||
|
||||
static bool selinux_is_split_policy_device() { return access(plat_policy_cil_file, R_OK) != -1; }
|
||||
|
@ -734,6 +772,22 @@ static bool selinux_load_split_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.
|
||||
|
||||
// Load precompiled policy from vendor image, if a matching policy is found there. The policy
|
||||
// must match the platform policy on the system image.
|
||||
std::string precompiled_sepolicy_file;
|
||||
if (selinux_find_precompiled_split_policy(&precompiled_sepolicy_file)) {
|
||||
android::base::unique_fd fd(
|
||||
open(precompiled_sepolicy_file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
|
||||
if (fd != -1) {
|
||||
if (selinux_android_load_policy_from_fd(fd, precompiled_sepolicy_file.c_str()) < 0) {
|
||||
LOG(ERROR) << "Failed to load SELinux policy from " << precompiled_sepolicy_file;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// No suitable precompiled policy could be loaded
|
||||
|
||||
LOG(INFO) << "Compiling SELinux policy";
|
||||
|
||||
// We store the output of the compilation on /dev because this is the most convenient tmpfs
|
||||
|
|
Loading…
Reference in New Issue