summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSandro Montanari <sandrom@google.com>2022-02-10 10:01:31 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-02-10 10:01:31 +0000
commit4e270ab15ff979a92c5c7686d5ff26d9c159c8f8 (patch)
treedf8e09fcc5fde345b8e4bb9cb9181015660cfb8c
parenta3424dd0ea57444a1687df9e392ab002f8f97edb (diff)
parent249aa0fd0952e571f6e85ff766ee101ff7f0c373 (diff)
downloadapex-4e270ab15ff979a92c5c7686d5ff26d9c159c8f8.tar.gz
Merge "Copy sepolicy apex data to /metadata/sepolicy/staged" am: 249aa0fd09
Original change: https://android-review.googlesource.com/c/platform/system/apex/+/1965022 Change-Id: I4e6906a965203c1dde4f867ab9b593644c75ef44
-rw-r--r--apexd/Android.bp1
-rw-r--r--apexd/apex_constants.h3
-rw-r--r--apexd/apexd.cpp89
-rw-r--r--apexd/apexd.h2
-rw-r--r--apexd/apexd_test.cpp38
5 files changed, 127 insertions, 6 deletions
diff --git a/apexd/Android.bp b/apexd/Android.bp
index 8d6cd8fb..d5149c0f 100644
--- a/apexd/Android.bp
+++ b/apexd/Android.bp
@@ -466,6 +466,7 @@ cc_test {
":com.android.apex.compressed.v1_original",
":com.android.apex.compressed.v2",
":com.android.apex.compressed.v2_original",
+ ":com.android.sepolicy",
":gen_manifest_mismatch_compressed_apex_v2",
"apexd_testdata/com.android.apex.test_package.avbpubkey",
"apexd_testdata/com.android.apex.compressed.avbpubkey",
diff --git a/apexd/apex_constants.h b/apexd/apex_constants.h
index 5f141577..edb51c38 100644
--- a/apexd/apex_constants.h
+++ b/apexd/apex_constants.h
@@ -75,6 +75,9 @@ static constexpr const char* kVmPayloadMetadataPartitionProp =
"apexd.payload_metadata.path";
static constexpr const std::chrono::seconds kBlockApexWaitTime(10);
+static constexpr const char* kMetadataSepolicyStagedDir =
+ "/metadata/sepolicy/staged";
+
// Banned APEX names
static const std::unordered_set<std::string> kBannedApexName = {
kApexSharedLibsSubDir, // To avoid conflicts with predefined
diff --git a/apexd/apexd.cpp b/apexd/apexd.cpp
index fd7f9fd8..8cb0f07f 100644
--- a/apexd/apexd.cpp
+++ b/apexd/apexd.cpp
@@ -721,6 +721,86 @@ Result<void> Unmount(const MountedApexData& data, bool deferred) {
namespace {
+// TODO(b/218672709): get the ro.build.version.sdk version of the device.
+const auto kSepolicyLevel = std::to_string(__ANDROID_API_T__);
+const auto kVersionedSepolicyZip = "SEPolicy-" + kSepolicyLevel + ".zip";
+const auto kVersionedSepolicySig = "SEPolicy-" + kSepolicyLevel + ".zip.sig";
+const auto kVersionedSepolicyFsv =
+ "SEPolicy-" + kSepolicyLevel + ".zip.fsv_sig";
+
+const auto kSepolicyZip = "SEPolicy.zip";
+const auto kSepolicySig = "SEPolicy.zip.sig";
+const auto kSepolicyFsv = "SEPolicy.zip.fsv_sig";
+
+Result<void> CopySepolicyToMetadata(const std::string& mount_point) {
+ LOG(DEBUG) << "Copying SEPolicy files to /metadata/sepolicy/staged.";
+ const auto policy_dir = mount_point + "/etc";
+
+ // Find SEPolicy zip and signature files.
+ std::optional<std::string> sepolicy_zip;
+ std::optional<std::string> sepolicy_sig;
+ std::optional<std::string> sepolicy_fsv;
+ auto status =
+ WalkDir(policy_dir, [&sepolicy_zip, &sepolicy_sig, &sepolicy_fsv](
+ const std::filesystem::directory_entry& entry) {
+ if (!entry.is_regular_file()) {
+ return;
+ }
+ const auto& path = entry.path().string();
+ if (base::EndsWith(path, kVersionedSepolicyZip)) {
+ sepolicy_zip = path;
+ } else if (base::EndsWith(path, kVersionedSepolicySig)) {
+ sepolicy_sig = path;
+ } else if (base::EndsWith(path, kVersionedSepolicyFsv)) {
+ sepolicy_fsv = path;
+ }
+ });
+ if (!status.ok()) {
+ return status.error();
+ }
+ if (sepolicy_zip->empty() || sepolicy_sig->empty() || sepolicy_fsv->empty()) {
+ return Error() << "SEPolicy files not found.";
+ }
+ LOG(INFO) << "SEPolicy files found.";
+
+ // Set up staging directory.
+ std::error_code ec;
+ const auto staged_dir =
+ std::string(gConfig->metadata_sepolicy_staged_dir) + "/";
+ status = CreateDirIfNeeded(staged_dir, 0755);
+ if (!status.ok()) {
+ return status.error();
+ }
+
+ // Clean up after myself.
+ auto scope_guard = android::base::make_scope_guard([&staged_dir]() {
+ std::error_code ec;
+ std::filesystem::remove_all(staged_dir, ec);
+ if (ec) {
+ LOG(WARNING) << "Failed to clear " << staged_dir << ": " << ec.message();
+ }
+ });
+
+ // Copy files to staged folder.
+ std::map<std::string, std::string> from_to = {
+ {*sepolicy_zip, staged_dir + kSepolicyZip},
+ {*sepolicy_sig, staged_dir + kSepolicySig},
+ {*sepolicy_fsv, staged_dir + kSepolicyFsv}};
+ for (const auto& [from, to] : from_to) {
+ std::filesystem::copy_file(
+ from, to, std::filesystem::copy_options::overwrite_existing, ec);
+ if (ec) {
+ return Error() << "Failed to copy " << from << " to " << to << ": "
+ << ec.message();
+ }
+ }
+
+ // TODO(b/218672709): if the kernel supports fs-verity, apply it after copy.
+
+ scope_guard.Disable();
+ return {};
+}
+
template <typename VerifyFn>
Result<void> RunVerifyFnInsideTempMount(const ApexFile& apex,
const VerifyFn& verify_fn,
@@ -828,10 +908,13 @@ Result<void> VerifyPackageStagedInstall(const ApexFile& apex_file) {
return verify_package_boot_status;
}
- constexpr const auto kSuccessFn = [](const std::string& /*mount_point*/) {
+ const auto validate_fn = [&apex_file](const std::string& mount_point) {
+ if (apex_file.GetManifest().name() == "com.android.sepolicy.apex") {
+ return CopySepolicyToMetadata(mount_point);
+ }
return Result<void>{};
};
- return RunVerifyFnInsideTempMount(apex_file, kSuccessFn, false);
+ return RunVerifyFnInsideTempMount(apex_file, validate_fn, false);
}
template <typename VerifyApexFn>
@@ -1591,6 +1674,7 @@ Result<ApexFile> GetActivePackage(const std::string& packageName) {
* Returns without error only if session was successfully aborted.
**/
Result<void> AbortStagedSession(int session_id) {
+ // TODO(b/218672709): Delete staged SEPolicy file if the session is aborted.
auto session = ApexSession::GetSession(session_id);
if (!session.ok()) {
return Error() << "No session found with id " << session_id;
@@ -2857,6 +2941,7 @@ void OnStart() {
const auto& all_apex = instance.AllApexFilesByName();
// There can be multiple APEX packages with package name X. Determine which
// one to activate.
+ // TODO(b/218672709): skip activation of sepolicy APEX during boot.
auto activation_list = SelectApexForActivation(all_apex, instance);
// Process compressed APEX, if any
diff --git a/apexd/apexd.h b/apexd/apexd.h
index d08c9ac0..cdcc193a 100644
--- a/apexd/apexd.h
+++ b/apexd/apexd.h
@@ -48,6 +48,7 @@ struct ApexdConfig {
const char* ota_reserved_dir;
const char* apex_hash_tree_dir;
const char* staged_session_dir;
+ const char* metadata_sepolicy_staged_dir;
// Overrides the path to the "metadata" partition which is by default
// /dev/block/by-name/payload-metadata It should be a path pointing the first
// partition of the VM payload disk. So, realpath() of this path is checked if
@@ -65,6 +66,7 @@ static const ApexdConfig kDefaultConfig = {
kOtaReservedDir,
kApexHashTreeDir,
kStagedSessionsDir,
+ kMetadataSepolicyStagedDir,
kVmPayloadMetadataPartitionProp,
"u:object_r:staging_data_file",
};
diff --git a/apexd/apexd_test.cpp b/apexd/apexd_test.cpp
index a101bbb8..784a9397 100644
--- a/apexd/apexd_test.cpp
+++ b/apexd/apexd_test.cpp
@@ -139,13 +139,19 @@ class ApexdUnitTest : public ::testing::Test {
ota_reserved_dir_ = StringPrintf("%s/ota-reserved", td_.path);
hash_tree_dir_ = StringPrintf("%s/apex-hash-tree", td_.path);
staged_session_dir_ = StringPrintf("%s/staged-session-dir", td_.path);
+ metadata_sepolicy_dir_ = StringPrintf("%s/metadata-sepolicy-dir", td_.path);
vm_payload_disk_ = StringPrintf("%s/vm-payload", td_.path);
- config_ = {kTestApexdStatusSysprop, {built_in_dir_},
- data_dir_.c_str(), decompression_dir_.c_str(),
- ota_reserved_dir_.c_str(), hash_tree_dir_.c_str(),
- staged_session_dir_.c_str(), kTestVmPayloadMetadataPartitionProp,
+ config_ = {kTestApexdStatusSysprop,
+ {built_in_dir_},
+ data_dir_.c_str(),
+ decompression_dir_.c_str(),
+ ota_reserved_dir_.c_str(),
+ hash_tree_dir_.c_str(),
+ staged_session_dir_.c_str(),
+ metadata_sepolicy_dir_.c_str(),
+ kTestVmPayloadMetadataPartitionProp,
kTestActiveApexSelinuxCtx};
}
@@ -158,6 +164,7 @@ class ApexdUnitTest : public ::testing::Test {
return StringPrintf("%s/session_%d", staged_session_dir_.c_str(),
session_id);
}
+ const std::string& GetMetadataSepolicyDir() { return metadata_sepolicy_dir_; }
std::string GetRootDigest(const ApexFile& apex) {
if (apex.IsCompressed()) {
@@ -240,6 +247,7 @@ class ApexdUnitTest : public ::testing::Test {
ASSERT_EQ(mkdir(ota_reserved_dir_.c_str(), 0755), 0);
ASSERT_EQ(mkdir(hash_tree_dir_.c_str(), 0755), 0);
ASSERT_EQ(mkdir(staged_session_dir_.c_str(), 0755), 0);
+ ASSERT_EQ(mkdir(metadata_sepolicy_dir_.c_str(), 0755), 0);
DeleteDirContent(ApexSession::GetSessionsDir());
}
@@ -276,6 +284,7 @@ class ApexdUnitTest : public ::testing::Test {
std::string vm_payload_disk_;
std::string vm_payload_metadata_path_;
std::string staged_session_dir_;
+ std::string metadata_sepolicy_dir_;
ApexdConfig config_;
std::vector<loop::LoopbackDeviceUniqueFd> loop_devices_; // to be cleaned up
};
@@ -4269,6 +4278,27 @@ TEST_F(ApexdMountTest, AddBlockApexFailsWithCompressedDuplicate) {
"duplicate of com.android.apex.compressed found"))));
}
+TEST_F(ApexdMountTest, CopySepolicyToMetadata) {
+ std::string file_path = AddPreInstalledApex("com.android.sepolicy.apex");
+ ASSERT_THAT(
+ ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}),
+ Ok());
+ ASSERT_THAT(ActivatePackage(file_path), Ok());
+ UnmountOnTearDown(file_path);
+ ASSERT_THAT(CreateStagedSession("com.android.sepolicy.apex", 666), Ok());
+
+ ASSERT_THAT(
+ SubmitStagedSession(666, {}, /* has_rollback_enabled= */ false,
+ /* is_rollback= */ false, /* rollback_id= */ -1),
+ Ok());
+
+ auto metadata_dir = GetMetadataSepolicyDir();
+ ASSERT_THAT(PathExists(metadata_dir + "/SEPolicy.zip"), HasValue(true));
+ ASSERT_THAT(PathExists(metadata_dir + "/SEPolicy.zip.sig"), HasValue(true));
+ ASSERT_THAT(PathExists(metadata_dir + "/SEPolicy.zip.fsv_sig"),
+ HasValue(true));
+}
+
class ApexActivationFailureTests : public ApexdMountTest {};
TEST_F(ApexActivationFailureTests, BuildFingerprintDifferent) {