Add fsverity digest manifest
fsverity digest manifest stores a map from files to fsverity digests. The manifest is installed as a serialized protobuf file, to a signed apk system/etc/security/fsverity/BuildManifest.apk. Bug: 193113311 Test: build with PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA := true Change-Id: I55fc10400206b8ce0d5f198faea08fe3930b362c
This commit is contained in:
parent
9cda397948
commit
f69346e0a8
4 changed files with 97 additions and 19 deletions
|
@ -526,6 +526,16 @@ $(foreach kmd,$(BOARD_KERNEL_MODULE_DIRS), \
|
|||
$(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-recovery-as-boot-load,$(kmd))),\
|
||||
$(eval ALL_DEFAULT_INSTALLED_MODULES += $(call build-image-kernel-modules-dir,GENERIC_RAMDISK,$(TARGET_RAMDISK_OUT),,modules.load,,$(kmd)))))
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# FSVerity metadata generation
|
||||
ifeq ($(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA),true)
|
||||
|
||||
FSVERITY_APK_KEY_PATH := $(DEFAULT_SYSTEM_DEV_CERTIFICATE)
|
||||
FSVERITY_APK_OUT := system/etc/security/fsverity/BuildManifest.apk
|
||||
FSVERITY_APK_MANIFEST_PATH := system/security/fsverity/AndroidManifest.xml
|
||||
|
||||
endif # PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Cert-to-package mapping. Used by the post-build signing tools.
|
||||
# Use a macro to add newline to each echo command
|
||||
|
@ -575,6 +585,8 @@ $(APKCERTS_FILE):
|
|||
$(if $(PACKAGES.$(p).EXTERNAL_KEY),\
|
||||
$(call _apkcerts_write_line,$(PACKAGES.$(p).STEM),EXTERNAL,,$(PACKAGES.$(p).COMPRESSED),$(PACKAGES.$(p).PARTITION),$@),\
|
||||
$(call _apkcerts_write_line,$(PACKAGES.$(p).STEM),$(PACKAGES.$(p).CERTIFICATE),$(PACKAGES.$(p).PRIVATE_KEY),$(PACKAGES.$(p).COMPRESSED),$(PACKAGES.$(p).PARTITION),$@))))
|
||||
$(if $(filter true,$(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA)),\
|
||||
$(call _apkcerts_write_line,$(notdir $(basename $(FSVERITY_APK_OUT))),$(FSVERITY_APK_KEY_PATH).x509.pem,$(FSVERITY_APK_KEY_PATH).pk8,,system,$@))
|
||||
# In case value of PACKAGES is empty.
|
||||
$(hide) touch $@
|
||||
|
||||
|
@ -1674,6 +1686,9 @@ $(if $(filter $(2),system),\
|
|||
$(if $(PRODUCT_SYSTEM_HEADROOM),$(hide) echo "system_headroom=$(PRODUCT_SYSTEM_HEADROOM)" >> $(1))
|
||||
$(if $(filter true,$(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA)),$(hide) echo "fsverity=$(HOST_OUT_EXECUTABLES)/fsverity" >> $(1))
|
||||
$(if $(filter true,$(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA)),$(hide) echo "fsverity_generate_metadata=true" >> $(1))
|
||||
$(if $(filter true,$(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA)),$(hide) echo "fsverity_apk_key=$(FSVERITY_APK_KEY_PATH)" >> $(1))
|
||||
$(if $(filter true,$(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA)),$(hide) echo "fsverity_apk_manifest=$(FSVERITY_APK_MANIFEST_PATH)" >> $(1))
|
||||
$(if $(filter true,$(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA)),$(hide) echo "fsverity_apk_out=$(FSVERITY_APK_OUT)" >> $(1))
|
||||
$(call add-common-ro-flags-to-image-props,system,$(1))
|
||||
)
|
||||
$(if $(filter $(2),system_other),\
|
||||
|
@ -2776,7 +2791,8 @@ ifeq ($(BOARD_AVB_ENABLE),true)
|
|||
$(BUILT_SYSTEMIMAGE): $(BOARD_AVB_SYSTEM_KEY_PATH)
|
||||
endif
|
||||
ifeq ($(PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA),true)
|
||||
$(BUILT_SYSTEMIMAGE): $(HOST_OUT_EXECUTABLES)/fsverity
|
||||
$(BUILT_SYSTEMIMAGE): $(HOST_OUT_EXECUTABLES)/fsverity $(HOST_OUT_EXECUTABLES)/aapt2 \
|
||||
$(FSVERITY_APK_MANIFEST_PATH) $(FSVERITY_APK_KEY_PATH).x509.pem $(FSVERITY_APK_KEY_PATH).pk8
|
||||
endif
|
||||
$(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE)
|
||||
$(call build-systemimage-target,$@)
|
||||
|
|
|
@ -265,8 +265,8 @@ python_library_host {
|
|||
srcs: [
|
||||
"fsverity_metadata_generator.py",
|
||||
],
|
||||
required: [
|
||||
"fsverity",
|
||||
libs: [
|
||||
"fsverity_digests_proto_python",
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ import sys
|
|||
import common
|
||||
import verity_utils
|
||||
|
||||
from fsverity_digests_pb2 import FSVerityDigests
|
||||
from fsverity_metadata_generator import FSVerityMetadataGenerator
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -450,6 +451,68 @@ def BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config):
|
|||
|
||||
return mkfs_output
|
||||
|
||||
def GenerateFSVerityMetadata(in_dir, fsverity_path, apk_key_path, apk_manifest_path, apk_out_path):
|
||||
"""Generates fsverity metadata files.
|
||||
|
||||
By setting PRODUCT_SYSTEM_FSVERITY_GENERATE_METADATA := true, fsverity
|
||||
metadata files will be generated. For the input files, see `patterns` below.
|
||||
|
||||
One metadata file per one input file will be generated with the suffix
|
||||
.fsv_meta. e.g. system/framework/foo.jar -> system/framework/foo.jar.fsv_meta
|
||||
Also a mapping file containing fsverity digests will be generated to
|
||||
system/etc/security/fsverity/BuildManifest.apk.
|
||||
|
||||
Args:
|
||||
in_dir: temporary working directory (same as BuildImage)
|
||||
fsverity_path: path to host tool fsverity
|
||||
apk_key_path: path to key (e.g. build/make/target/product/security/platform)
|
||||
apk_manifest_path: path to AndroidManifest.xml for APK
|
||||
apk_out_path: path to the output APK
|
||||
|
||||
Returns:
|
||||
None. The files are generated directly under in_dir.
|
||||
"""
|
||||
|
||||
patterns = [
|
||||
"system/framework/*.jar",
|
||||
"system/framework/oat/*/*.oat",
|
||||
"system/framework/oat/*/*.vdex",
|
||||
"system/framework/oat/*/*.art",
|
||||
"system/etc/boot-image.prof",
|
||||
"system/etc/dirty-image-objects",
|
||||
]
|
||||
files = []
|
||||
for pattern in patterns:
|
||||
files += glob.glob(os.path.join(in_dir, pattern))
|
||||
files = sorted(set(files))
|
||||
|
||||
generator = FSVerityMetadataGenerator(fsverity_path)
|
||||
generator.set_hash_alg("sha256")
|
||||
|
||||
digests = FSVerityDigests()
|
||||
for f in files:
|
||||
generator.generate(f)
|
||||
# f is a full path for now; make it relative so it starts with {mount_point}/
|
||||
digest = digests.digests[os.path.relpath(f, in_dir)]
|
||||
digest.digest = generator.digest(f)
|
||||
digest.hash_alg = "sha256"
|
||||
|
||||
temp_dir = common.MakeTempDir()
|
||||
|
||||
os.mkdir(os.path.join(temp_dir, "assets"))
|
||||
metadata_path = os.path.join(temp_dir, "assets", "build_manifest")
|
||||
with open(metadata_path, "wb") as f:
|
||||
f.write(digests.SerializeToString())
|
||||
|
||||
apk_path = os.path.join(in_dir, apk_out_path)
|
||||
|
||||
common.RunAndCheckOutput(["aapt2", "link",
|
||||
"-A", os.path.join(temp_dir, "assets"),
|
||||
"-o", apk_path,
|
||||
"--manifest", apk_manifest_path])
|
||||
common.RunAndCheckOutput(["apksigner", "sign", "--in", apk_path,
|
||||
"--cert", apk_key_path + ".x509.pem",
|
||||
"--key", apk_key_path + ".pk8"])
|
||||
|
||||
def BuildImage(in_dir, prop_dict, out_file, target_out=None):
|
||||
"""Builds an image for the files under in_dir and writes it to out_file.
|
||||
|
@ -479,22 +542,11 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None):
|
|||
fs_spans_partition = False
|
||||
|
||||
if "fsverity_generate_metadata" in prop_dict:
|
||||
patterns = [
|
||||
"system/framework/*.jar",
|
||||
"system/framework/oat/*/*.oat",
|
||||
"system/framework/oat/*/*.vdex",
|
||||
"system/framework/oat/*/*.art",
|
||||
"system/etc/boot-image.prof",
|
||||
"system/etc/dirty-image-objects",
|
||||
]
|
||||
files = []
|
||||
for pattern in patterns:
|
||||
files += glob.glob(os.path.join(in_dir, pattern))
|
||||
files = sorted(set(files))
|
||||
|
||||
generator = FSVerityMetadataGenerator(prop_dict["fsverity"])
|
||||
for f in files:
|
||||
generator.generate(f)
|
||||
GenerateFSVerityMetadata(in_dir,
|
||||
fsverity_path=prop_dict["fsverity"],
|
||||
apk_key_path=prop_dict["fsverity_apk_key"],
|
||||
apk_manifest_path=prop_dict["fsverity_apk_manifest"],
|
||||
apk_out_path=prop_dict["fsverity_apk_out"])
|
||||
|
||||
# Get a builder for creating an image that's to be verified by Verified Boot,
|
||||
# or None if not applicable.
|
||||
|
@ -747,6 +799,9 @@ def ImagePropFromGlobalDict(glob_dict, mount_point):
|
|||
copy_prop("root_fs_config", "root_fs_config")
|
||||
copy_prop("fsverity", "fsverity")
|
||||
copy_prop("fsverity_generate_metadata", "fsverity_generate_metadata")
|
||||
copy_prop("fsverity_apk_key","fsverity_apk_key")
|
||||
copy_prop("fsverity_apk_manifest","fsverity_apk_manifest")
|
||||
copy_prop("fsverity_apk_out","fsverity_apk_out")
|
||||
elif mount_point == "data":
|
||||
# Copy the generic fs type first, override with specific one if available.
|
||||
copy_prop("flash_logical_block_size", "flash_logical_block_size")
|
||||
|
|
|
@ -94,6 +94,13 @@ class FSVerityMetadataGenerator:
|
|||
f.seek(offset + header_len)
|
||||
return f.read(size)
|
||||
|
||||
def digest(self, input_file):
|
||||
cmd = [self._fsverity_path, 'digest', input_file]
|
||||
cmd.extend(['--compact'])
|
||||
cmd.extend(['--hash-alg', self._hash_alg])
|
||||
out = subprocess.check_output(cmd, universal_newlines=True).strip()
|
||||
return bytes(bytearray.fromhex(out))
|
||||
|
||||
def generate(self, input_file, output_file=None):
|
||||
if self._signature != 'none':
|
||||
if not self._key:
|
||||
|
|
Loading…
Reference in a new issue