diff --git a/init/Android.bp b/init/Android.bp index d4852d648..4c25ad7b7 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -174,7 +174,6 @@ libinit_cc_defaults { "libprotobuf-cpp-lite", "libpropertyinfoserializer", "libpropertyinfoparser", - "libsigningutils", "libsnapshot_cow", "libsnapshot_init", "libxml2", @@ -183,7 +182,6 @@ libinit_cc_defaults { ], shared_libs: [ "libbase", - "libcrypto", "libcutils", "libdl", "libext4_utils", @@ -199,7 +197,6 @@ libinit_cc_defaults { "libselinux", "libunwindstack", "libutils", - "libziparchive", ], header_libs: ["bionic_libc_platform_headers"], bootstrap: true, diff --git a/init/property_service.cpp b/init/property_service.cpp index f5de17d82..2064fae8f 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -1247,9 +1247,6 @@ void CreateSerializedPropertyInfo() { // Don't check for failure here, since we don't always have all of these partitions. // E.g. In case of recovery, the vendor partition will not have mounted and we // still need the system / platform properties to function. - if (access("/dev/selinux/apex_property_contexts", R_OK) != -1) { - LoadPropertyInfoFromFile("/dev/selinux/apex_property_contexts", &property_infos); - } if (access("/system_ext/etc/selinux/system_ext_property_contexts", R_OK) != -1) { LoadPropertyInfoFromFile("/system_ext/etc/selinux/system_ext_property_contexts", &property_infos); @@ -1273,7 +1270,6 @@ void CreateSerializedPropertyInfo() { LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos); LoadPropertyInfoFromFile("/product_property_contexts", &property_infos); LoadPropertyInfoFromFile("/odm_property_contexts", &property_infos); - LoadPropertyInfoFromFile("/dev/selinux/apex_property_contexts", &property_infos); } auto serialized_contexts = std::string(); diff --git a/init/selinux.cpp b/init/selinux.cpp index ac102eb4e..9095b854e 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -26,29 +26,26 @@ // The monolithic policy variant is for legacy non-treble devices that contain a single SEPolicy // file located at /sepolicy and is directly loaded into the kernel SELinux subsystem. -// The split policy is for supporting treble devices and updateable apexes. It splits the SEPolicy -// across files on /system/etc/selinux (the 'plat' portion of the policy), /vendor/etc/selinux -// (the 'vendor' portion of the policy), /system_ext/etc/selinux, /product/etc/selinux, -// /odm/etc/selinux, and /dev/selinux (the apex portion of policy). This is necessary to allow -// images to be updated independently of the vendor image, while maintaining contributions from -// multiple partitions in the SEPolicy. This is especially important for VTS testing, where the -// SEPolicy on the Google System Image may not be identical to the system image shipped on a -// vendor's device. +// The split policy is for supporting treble devices. It splits the SEPolicy across files on +// /system/etc/selinux (the 'plat' portion of the policy) and /vendor/etc/selinux (the 'vendor' +// portion of the policy). This is necessary to allow the system image to be updated independently +// of the vendor image, while maintaining contributions from both partitions in the SEPolicy. This +// is especially important for VTS testing, where the SEPolicy on the Google System Image may not be +// identical to the system image shipped on a vendor's device. // The split SEPolicy is loaded as described below: // 1) There is a precompiled SEPolicy located at either /vendor/etc/selinux/precompiled_sepolicy or // /odm/etc/selinux/precompiled_sepolicy if odm parition is present. Stored along with this file -// are the sha256 hashes of the parts of the SEPolicy on /system, /system_ext, /product, and apex -// that were used to compile this precompiled policy. The system partition contains a similar -// sha256 of the parts of the SEPolicy that it currently contains. Symmetrically, system_ext, -// product, and apex contain sha256 hashes of their SEPolicy. Init loads this +// are the sha256 hashes of the parts of the SEPolicy on /system, /system_ext and /product that +// were used to compile this precompiled policy. The system partition contains a similar sha256 +// of the parts of the SEPolicy that it currently contains. Symmetrically, system_ext and +// product paritition contain sha256 hashes of their SEPolicy. The init loads this // precompiled_sepolicy directly if and only if the hashes along with the precompiled SEPolicy on -// /vendor or /odm match the hashes for system, system_ext, product, and apex SEPolicy, -// respectively. -// 2) If these hashes do not match, then either /system or /system_ext /product, or apex (or some of -// them) have been updated out of sync with /vendor (or /odm if it is present) and the init needs -// to compile the SEPolicy. /system contains the SEPolicy compiler, secilc, and it is used by -// the OpenSplitPolicy() function below to compile the SEPolicy to a temp directory and load it. +// /vendor or /odm match the hashes for system, system_ext and product SEPolicy, respectively. +// 2) If these hashes do not match, then either /system or /system_ext or /product (or some of them) +// have been updated out of sync with /vendor (or /odm if it is present) and the init needs to +// compile the SEPolicy. /system contains the SEPolicy compiler, secilc, and it is used by the +// OpenSplitPolicy() function below to compile the SEPolicy to a temp directory and load it. // That function contains even more documentation with the specific implementation details of how // the SEPolicy is compiled if needed. @@ -61,15 +58,12 @@ #include #include #include -#include -#include #include #include #include #include #include -#include #include #include #include @@ -77,7 +71,6 @@ #include #include #include -#include #include "block_dev_initializer.h" #include "debug_ramdisk.h" @@ -245,7 +238,6 @@ Result FindPrecompiledSplitPolicy() { precompiled_sepolicy + ".system_ext_sepolicy_and_mapping.sha256"}, {"/product/etc/selinux/product_sepolicy_and_mapping.sha256", precompiled_sepolicy + ".product_sepolicy_and_mapping.sha256"}, - {"/dev/selinux/apex_sepolicy.sha256", precompiled_sepolicy + ".apex_sepolicy.sha256"}, }; for (const auto& [actual_id_path, precompiled_id_path] : sepolicy_hashes) { @@ -324,7 +316,7 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { // * vendor -- 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. - // * (optional) policy needed due to logic on product, system_ext, odm, or apex. + // * (optional) policy needed due to logic on product, system_ext, or odm images. // secilc is invoked to compile the above three policy files into a single monolithic policy // file. This file is then loaded into the kernel. @@ -420,12 +412,6 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { if (access(odm_policy_cil_file.c_str(), F_OK) == -1) { odm_policy_cil_file.clear(); } - - // apex_sepolicy.cil is default but optional. - std::string apex_policy_cil_file("/dev/selinux/apex_sepolicy.cil"); - if (access(apex_policy_cil_file.c_str(), F_OK) == -1) { - apex_policy_cil_file.clear(); - } const std::string version_as_string = std::to_string(SEPOLICY_VERSION); // clang-format off @@ -468,9 +454,6 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { if (!odm_policy_cil_file.empty()) { compile_args.push_back(odm_policy_cil_file.c_str()); } - if (!apex_policy_cil_file.empty()) { - compile_args.push_back(apex_policy_cil_file.c_str()); - } compile_args.push_back(nullptr); if (!ForkExecveAndWaitForCompletion(compile_args[0], (char**)compile_args.data())) { @@ -497,194 +480,6 @@ bool OpenMonolithicPolicy(PolicyFile* policy_file) { return true; } -constexpr const char* kSigningCertRelease = - "/system/etc/selinux/com.android.sepolicy.cert-release.der"; -const std::string kSepolicyApexMetadataDir = "/metadata/sepolicy/"; -const std::string kSepolicyApexSystemDir = "/system/etc/selinux/apex/"; -const std::string kSepolicyZip = "SEPolicy.zip"; -const std::string kSepolicySignature = "SEPolicy.zip.sig"; - -const std::string kTmpfsDir = "/dev/selinux/"; - -// Files that are deleted after policy is compiled/loaded. -const std::vector kApexSepolicyTmp{"apex_sepolicy.cil", "apex_sepolicy.sha256"}; -// Files that need to persist because they are used by userspace processes. -const std::vector kApexSepolicy{"apex_file_contexts", "apex_property_contexts", - "apex_service_contexts", "apex_seapp_contexts", - "apex_test"}; - -Result CreateTmpfsDir() { - mode_t mode = 0744; - struct stat stat_data; - if (stat(kTmpfsDir.c_str(), &stat_data) != 0) { - if (errno != ENOENT) { - return ErrnoError() << "Could not stat " << kTmpfsDir; - } - if (mkdir(kTmpfsDir.c_str(), mode) != 0) { - return ErrnoError() << "Could not mkdir " << kTmpfsDir; - } - } else { - if (!S_ISDIR(stat_data.st_mode)) { - return Error() << kTmpfsDir << " exists and is not a directory."; - } - LOG(WARNING) << "Directory " << kTmpfsDir << " already exists"; - } - - // Need to manually call chmod because mkdir will create a folder with - // permissions mode & ~umask. - if (chmod(kTmpfsDir.c_str(), mode) != 0) { - return ErrnoError() << "Could not chmod " << kTmpfsDir; - } - - return {}; -} - -Result PutFileInTmpfs(ZipArchiveHandle archive, const std::string& fileName) { - ZipEntry entry; - std::string dstPath = kTmpfsDir + fileName; - - int ret = FindEntry(archive, fileName, &entry); - if (ret != 0) { - // All files are optional. If a file doesn't exist, return without error. - return {}; - } - - unique_fd fd(TEMP_FAILURE_RETRY( - open(dstPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRUSR | S_IWUSR))); - if (fd == -1) { - return ErrnoError() << "Failed to open " << dstPath; - } - - ret = ExtractEntryToFile(archive, &entry, fd.get()); - if (ret != 0) { - return Error() << "Failed to extract entry \"" << fileName << "\" (" - << entry.uncompressed_length << " bytes) to \"" << dstPath - << "\": " << ErrorCodeString(ret); - } - - return {}; -} - -Result GetPolicyFromApex(const std::string& dir) { - LOG(INFO) << "Loading APEX Sepolicy from " << dir + kSepolicyZip; - unique_fd fd(open((dir + kSepolicyZip).c_str(), O_RDONLY | O_BINARY | O_CLOEXEC)); - if (fd < 0) { - return ErrnoError() << "Failed to open package " << dir + kSepolicyZip; - } - - ZipArchiveHandle handle; - int ret = OpenArchiveFd(fd.get(), (dir + kSepolicyZip).c_str(), &handle, - /*assume_ownership=*/false); - if (ret < 0) { - return Error() << "Failed to open package " << dir + kSepolicyZip << ": " - << ErrorCodeString(ret); - } - - auto handle_guard = android::base::make_scope_guard([&handle] { CloseArchive(handle); }); - - auto create = CreateTmpfsDir(); - if (!create.ok()) { - return create.error(); - } - - for (const auto& file : kApexSepolicy) { - auto extract = PutFileInTmpfs(handle, file); - if (!extract.ok()) { - return extract.error(); - } - } - for (const auto& file : kApexSepolicyTmp) { - auto extract = PutFileInTmpfs(handle, file); - if (!extract.ok()) { - return extract.error(); - } - } - return {}; -} - -Result SepolicyCheckSignature(const std::string& dir) { - std::string signature; - if (!android::base::ReadFileToString(dir + kSepolicySignature, &signature)) { - return ErrnoError() << "Failed to read " << kSepolicySignature; - } - - std::fstream sepolicyZip(dir + kSepolicyZip, std::ios::in | std::ios::binary); - if (!sepolicyZip) { - return Error() << "Failed to open " << kSepolicyZip; - } - sepolicyZip.seekg(0); - std::string sepolicyStr((std::istreambuf_iterator(sepolicyZip)), - std::istreambuf_iterator()); - - auto releaseKey = extractPublicKeyFromX509(kSigningCertRelease); - if (!releaseKey.ok()) { - return releaseKey.error(); - } - - return verifySignature(sepolicyStr, signature, *releaseKey); -} - -Result SepolicyVerify(const std::string& dir) { - auto sepolicySignature = SepolicyCheckSignature(dir); - if (!sepolicySignature.ok()) { - return Error() << "Apex SEPolicy failed signature check"; - } - return {}; -} - -void CleanupApexSepolicy() { - for (const auto& file : kApexSepolicyTmp) { - std::string path = kTmpfsDir + file; - unlink(path.c_str()); - } -} - -// Updatable sepolicy is shipped within an zip within an APEX. Because -// it needs to be available before Apexes are mounted, apexd copies -// the zip from the APEX and stores it in /metadata/sepolicy. If there is -// no updatable sepolicy in /metadata/sepolicy, then the updatable policy is -// loaded from /system/etc/selinux/apex. Init performs the following -// steps on boot: -// -// 1. Validates the zip by checking its signature against a public key that is -// stored in /system/etc/selinux. -// 2. Extracts files from zip and stores them in /dev/selinux. -// 3. Checks if the apex_sepolicy.sha256 matches the sha256 of precompiled_sepolicy. -// if so, the precompiled sepolicy is used. Otherwise, an on-device compile of the policy -// is used. This is the same flow as on-device compilation of policy for Treble. -// 4. Cleans up files in /dev/selinux which are no longer needed. -// 5. Restorecons the remaining files in /dev/selinux. -// 6. Sets selinux into enforcing mode and continues normal booting. -// -void PrepareApexSepolicy() { - // If apex sepolicy zip exists in /metadata/sepolicy, use that, otherwise use version on - // /system. If neither exists, do nothing. - std::string dir; - if (access((kSepolicyApexMetadataDir + kSepolicyZip).c_str(), F_OK) == 0) { - dir = kSepolicyApexMetadataDir; - } else if (access((kSepolicyApexSystemDir + kSepolicyZip).c_str(), F_OK) == 0) { - dir = kSepolicyApexSystemDir; - } else { - LOG(INFO) << "APEX Sepolicy not found"; - return; - } - - auto sepolicyVerify = SepolicyVerify(dir); - if (!sepolicyVerify.ok()) { - LOG(INFO) << "Error: " << sepolicyVerify.error(); - // If signature verification fails, fall back to version on /system. - // This file doesn't need to be verified because it lives on the system partition which - // is signed and protected by verified boot. - dir = kSepolicyApexSystemDir; - } - - auto apex = GetPolicyFromApex(dir); - if (!apex.ok()) { - // TODO(b/199914227) Make failure fatal. For now continue booting with non-apex sepolicy. - LOG(ERROR) << apex.error(); - } -} - void ReadPolicy(std::string* policy) { PolicyFile policy_file; @@ -961,12 +756,9 @@ void LoadSelinuxPolicyAndroid() { LOG(INFO) << "Opening SELinux policy"; - PrepareApexSepolicy(); - // Read the policy before potentially killing snapuserd. std::string policy; ReadPolicy(&policy); - CleanupApexSepolicy(); auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded(); if (snapuserd_helper) { @@ -982,13 +774,6 @@ void LoadSelinuxPolicyAndroid() { snapuserd_helper->FinishTransition(); snapuserd_helper = nullptr; } - - // This restorecon is intentionally done before SelinuxSetEnforcement because the permissions - // needed to transition files from tmpfs to *_contexts_file context should not be granted to - // any process after selinux is set into enforcing mode. - if (selinux_android_restorecon("/dev/selinux/", SELINUX_ANDROID_RESTORECON_RECURSE) == -1) { - PLOG(FATAL) << "restorecon failed of /dev/selinux failed"; - } } int SetupSelinux(char** argv) {