installd: implement measureFsverityRootHash
Test: Observed to ioctl, will soon integrate with the actual ioctl
Bug: 30972906
Change-Id: I30729abbdc540093d2b33d0451a29c5bbf0fb83d
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 1627756..bc91285 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -18,6 +18,7 @@
#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+#include <algorithm>
#include <errno.h>
#include <fstream>
#include <fts.h>
@@ -90,6 +91,7 @@
// fsverity assumes the page size is always 4096. If not, the feature can not be
// enabled.
static constexpr int kVerityPageSize = 4096;
+static constexpr size_t kSha256Size = 32;
static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
// NOTE: keep in sync with Installer
@@ -2357,6 +2359,14 @@
__u64 flags;
};
+struct fsverity_root_hash {
+ short root_hash_algorithm;
+ short flags;
+ __u8 reserved[4];
+ __u8 root_hash[64];
+};
+
+#define FS_IOC_MEASURE_FSVERITY _IOW('f', 2733, struct fsverity_root_hash)
#define FS_IOC_SET_FSVERITY _IOW('f', 2734, struct fsverity_set)
#define FSVERITY_FLAG_ENABLED 0x0001
@@ -2423,6 +2433,36 @@
return ok();
}
+binder::Status InstalldNativeService::assertFsverityRootHashMatches(const std::string& filePath,
+ const std::vector<uint8_t>& expectedHash) {
+ ENFORCE_UID(AID_SYSTEM);
+ if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) {
+ return ok();
+ }
+ // TODO: also check fsverity support in the current file system if compiled with DEBUG.
+ if (expectedHash.size() != kSha256Size) {
+ return error("verity hash size should be " + std::to_string(kSha256Size) + " but is " +
+ std::to_string(expectedHash.size()));
+ }
+
+ // TODO(71871109): Validate filePath.
+ ::android::base::unique_fd fd(open(filePath.c_str(), O_RDONLY));
+ if (fd.get() < 0) {
+ return error("Failed to open " + filePath + ": " + strerror(errno));
+ }
+
+ struct fsverity_root_hash config;
+ memset(&config, 0, sizeof(config));
+ config.root_hash_algorithm = 0; // SHA256
+ memcpy(config.root_hash, expectedHash.data(), std::min(sizeof(config.root_hash), kSha256Size));
+ if (ioctl(fd.get(), FS_IOC_MEASURE_FSVERITY, &config) < 0) {
+ // This includes an expected failure case with no FSVerity setup. It normally happens when
+ // the apk does not contains the Merkle tree root hash.
+ return error("Failed to measure fsverity on " + filePath + ": " + strerror(errno));
+ }
+ return ok(); // hashes match
+}
+
binder::Status InstalldNativeService::reconcileSecondaryDexFile(
const std::string& dexPath, const std::string& packageName, int32_t uid,
const std::vector<std::string>& isas, const std::unique_ptr<std::string>& volumeUuid,
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index cef62cd..887a2fc 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -120,6 +120,8 @@
const std::unique_ptr<std::string>& outputPath);
binder::Status installApkVerity(const std::string& filePath,
const ::android::base::unique_fd& verityInput);
+ binder::Status assertFsverityRootHashMatches(const std::string& filePath,
+ const std::vector<uint8_t>& expectedHash);
binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
const std::string& packageName, int32_t uid, const std::vector<std::string>& isa,
const std::unique_ptr<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index c819e98..3725fc0 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -82,6 +82,7 @@
void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
@nullable @utf8InCpp String outputPath);
void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput);
+ void assertFsverityRootHashMatches(@utf8InCpp String filePath, in byte[] expectedHash);
boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid,