Error correction: Append codes to verified partitions

Append error-correcting codes to verified partitions provided that
PRODUCT_SUPPORTS_VERITY_FEC is true.

This moves verity metadata to be after the hash tree, and requires
matching changes from
  Ide48f581bbba77aed6132f77b309db71630d81ed

Bug: 21893453
Change-Id: I6945cbab99e214566a1f9d3702333f2dbbc35816
This commit is contained in:
Sami Tolvanen
2015-05-20 07:30:57 +01:00
parent 58fbd69729
commit f99b53143d
5 changed files with 94 additions and 18 deletions

View File

@@ -724,6 +724,9 @@ INTERNAL_USERIMAGES_BINARY_PATHS := $(sort $(dir $(INTERNAL_USERIMAGES_DEPS)))
ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY)) ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY))
INTERNAL_USERIMAGES_DEPS += $(BUILD_VERITY_TREE) $(APPEND2SIMG) $(VERITY_SIGNER) INTERNAL_USERIMAGES_DEPS += $(BUILD_VERITY_TREE) $(APPEND2SIMG) $(VERITY_SIGNER)
ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY_FEC))
INTERNAL_USERIMAGES_DEPS += $(FEC)
endif
endif endif
SELINUX_FC := $(TARGET_ROOT_OUT)/file_contexts.bin SELINUX_FC := $(TARGET_ROOT_OUT)/file_contexts.bin
@@ -754,6 +757,7 @@ $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_BOOT_SIGNER),$(hide) echo "
$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verity=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY)" >> $(1)) $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verity=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY)" >> $(1))
$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verity_key=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY)" >> $(1)) $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verity_key=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY)" >> $(1))
$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verity_signer_cmd=$(notdir $(VERITY_SIGNER))" >> $(1)) $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verity_signer_cmd=$(notdir $(VERITY_SIGNER))" >> $(1))
$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY_FEC),$(hide) echo "verity_fec=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY_FEC)" >> $(1))
$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION),$(hide) echo "system_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION)" >> $(1)) $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION),$(hide) echo "system_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION)" >> $(1))
$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION),$(hide) echo "vendor_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION)" >> $(1)) $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION),$(hide) echo "vendor_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION)" >> $(1))
$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT),$(hide) echo "vboot=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT)" >> $(1)) $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT),$(hide) echo "vboot=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT)" >> $(1))
@@ -1363,7 +1367,8 @@ OTATOOLS := $(HOST_OUT_EXECUTABLES)/minigzip \
$(HOST_OUT_EXECUTABLES)/verity_signer \ $(HOST_OUT_EXECUTABLES)/verity_signer \
$(HOST_OUT_EXECUTABLES)/append2simg \ $(HOST_OUT_EXECUTABLES)/append2simg \
$(HOST_OUT_EXECUTABLES)/img2simg \ $(HOST_OUT_EXECUTABLES)/img2simg \
$(HOST_OUT_EXECUTABLES)/boot_signer $(HOST_OUT_EXECUTABLES)/boot_signer \
$(HOST_OUT_EXECUTABLES)/fec
# Shared libraries. # Shared libraries.
OTATOOLS += \ OTATOOLS += \

View File

@@ -515,6 +515,7 @@ BUILD_VERITY_TREE := $(HOST_OUT_EXECUTABLES)/build_verity_tree
BOOT_SIGNER := $(HOST_OUT_EXECUTABLES)/boot_signer BOOT_SIGNER := $(HOST_OUT_EXECUTABLES)/boot_signer
FUTILITY := prebuilts/misc/$(BUILD_OS)-$(HOST_PREBUILT_ARCH)/futility/futility FUTILITY := prebuilts/misc/$(BUILD_OS)-$(HOST_PREBUILT_ARCH)/futility/futility
VBOOT_SIGNER := prebuilts/misc/scripts/vboot_signer/vboot_signer.sh VBOOT_SIGNER := prebuilts/misc/scripts/vboot_signer/vboot_signer.sh
FEC := $(HOST_OUT_EXECUTABLES)/fec
# ACP is always for the build OS, not for the host OS # ACP is always for the build OS, not for the host OS
ACP := $(BUILD_OUT_EXECUTABLES)/acp$(BUILD_EXECUTABLE_SUFFIX) ACP := $(BUILD_OUT_EXECUTABLES)/acp$(BUILD_EXECUTABLE_SUFFIX)

View File

@@ -100,6 +100,7 @@ _product_var_list := \
PRODUCT_SUPPORTS_BOOT_SIGNER \ PRODUCT_SUPPORTS_BOOT_SIGNER \
PRODUCT_SUPPORTS_VBOOT \ PRODUCT_SUPPORTS_VBOOT \
PRODUCT_SUPPORTS_VERITY \ PRODUCT_SUPPORTS_VERITY \
PRODUCT_SUPPORTS_VERITY_FEC \
PRODUCT_OEM_PROPERTIES \ PRODUCT_OEM_PROPERTIES \
PRODUCT_SYSTEM_PROPERTY_BLACKLIST \ PRODUCT_SYSTEM_PROPERTY_BLACKLIST \
PRODUCT_SYSTEM_SERVER_JARS \ PRODUCT_SYSTEM_SERVER_JARS \

View File

@@ -21,6 +21,7 @@ user_variant := $(filter user userdebug,$(TARGET_BUILD_VARIANT))
ifneq (,$(user_variant)) ifneq (,$(user_variant))
PRODUCT_SUPPORTS_BOOT_SIGNER := true PRODUCT_SUPPORTS_BOOT_SIGNER := true
PRODUCT_SUPPORTS_VERITY := true PRODUCT_SUPPORTS_VERITY := true
PRODUCT_SUPPORTS_VERITY_FEC := true
# The dev key is used to sign boot and recovery images, and the verity # The dev key is used to sign boot and recovery images, and the verity
# metadata table. Actual product deliverables will be re-signed by hand. # metadata table. Actual product deliverables will be re-signed by hand.

View File

@@ -33,6 +33,7 @@ import tempfile
OPTIONS = common.OPTIONS OPTIONS = common.OPTIONS
FIXED_SALT = "aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7" FIXED_SALT = "aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7"
BLOCK_SIZE = 4096
def RunCommand(cmd): def RunCommand(cmd):
"""Echo and run the given command. """Echo and run the given command.
@@ -48,6 +49,14 @@ def RunCommand(cmd):
print "%s" % (output.rstrip(),) print "%s" % (output.rstrip(),)
return (output, p.returncode) return (output, p.returncode)
def GetVerityFECSize(partition_size):
cmd = "fec -s %d" % partition_size
status, output = commands.getstatusoutput(cmd)
if status:
print output
return False, 0
return True, int(output)
def GetVerityTreeSize(partition_size): def GetVerityTreeSize(partition_size):
cmd = "build_verity_tree -s %d" cmd = "build_verity_tree -s %d"
cmd %= partition_size cmd %= partition_size
@@ -67,7 +76,22 @@ def GetVerityMetadataSize(partition_size):
return False, 0 return False, 0
return True, int(output) return True, int(output)
def AdjustPartitionSizeForVerity(partition_size): def GetVeritySize(partition_size, fec_supported):
success, verity_tree_size = GetVerityTreeSize(partition_size)
if not success:
return 0
success, verity_metadata_size = GetVerityMetadataSize(partition_size)
if not success:
return 0
verity_size = verity_tree_size + verity_metadata_size
if fec_supported:
success, fec_size = GetVerityFECSize(partition_size + verity_size)
if not success:
return 0
return verity_size + fec_size
return verity_size
def AdjustPartitionSizeForVerity(partition_size, fec_supported):
"""Modifies the provided partition size to account for the verity metadata. """Modifies the provided partition size to account for the verity metadata.
This information is used to size the created image appropriately. This information is used to size the created image appropriately.
@@ -76,13 +100,43 @@ def AdjustPartitionSizeForVerity(partition_size):
Returns: Returns:
The size of the partition adjusted for verity metadata. The size of the partition adjusted for verity metadata.
""" """
success, verity_tree_size = GetVerityTreeSize(partition_size) key = "%d %d" % (partition_size, fec_supported)
if not success: if key in AdjustPartitionSizeForVerity.results:
return 0 return AdjustPartitionSizeForVerity.results[key]
success, verity_metadata_size = GetVerityMetadataSize(partition_size)
if not success: hi = partition_size
return 0 if hi % BLOCK_SIZE != 0:
return partition_size - verity_tree_size - verity_metadata_size hi = (hi // BLOCK_SIZE) * BLOCK_SIZE
# verity tree and fec sizes depend on the partition size, which
# means this estimate is always going to be unnecessarily small
lo = partition_size - GetVeritySize(hi, fec_supported)
result = lo
# do a binary search for the optimal size
while lo < hi:
i = ((lo + hi) // (2 * BLOCK_SIZE)) * BLOCK_SIZE
size = i + GetVeritySize(i, fec_supported)
if size <= partition_size:
if result < i:
result = i
lo = i + BLOCK_SIZE
else:
hi = i
AdjustPartitionSizeForVerity.results[key] = result
return result
AdjustPartitionSizeForVerity.results = {}
def BuildVerityFEC(sparse_image_path, verity_fec_path, prop_dict):
cmd = "fec -e %s %s" % (sparse_image_path, verity_fec_path)
print cmd
status, output = commands.getstatusoutput(cmd)
if status:
print "Could not build FEC data! Error: %s" % output
return False
return True
def BuildVerityTree(sparse_image_path, verity_image_path, prop_dict): def BuildVerityTree(sparse_image_path, verity_image_path, prop_dict):
cmd = "build_verity_tree -A %s %s %s" % ( cmd = "build_verity_tree -A %s %s %s" % (
@@ -130,12 +184,12 @@ def Append2Simg(sparse_image_path, unsparse_image_path, error_message):
def BuildVerifiedImage(data_image_path, verity_image_path, def BuildVerifiedImage(data_image_path, verity_image_path,
verity_metadata_path): verity_metadata_path):
if not Append2Simg(data_image_path, verity_metadata_path,
"Could not append verity metadata!"):
return False
if not Append2Simg(data_image_path, verity_image_path, if not Append2Simg(data_image_path, verity_image_path,
"Could not append verity tree!"): "Could not append verity tree!"):
return False return False
if not Append2Simg(data_image_path, verity_metadata_path,
"Could not append verity metadata!"):
return False
return True return True
def UnsparseImage(sparse_image_path, replace=True): def UnsparseImage(sparse_image_path, replace=True):
@@ -154,7 +208,7 @@ def UnsparseImage(sparse_image_path, replace=True):
return False, None return False, None
return True, unsparse_image_path return True, unsparse_image_path
def MakeVerityEnabledImage(out_file, prop_dict): def MakeVerityEnabledImage(out_file, fec_supported, prop_dict):
"""Creates an image that is verifiable using dm-verity. """Creates an image that is verifiable using dm-verity.
Args: Args:
@@ -180,6 +234,7 @@ def MakeVerityEnabledImage(out_file, prop_dict):
# get partial image paths # get partial image paths
verity_image_path = os.path.join(tempdir_name, "verity.img") verity_image_path = os.path.join(tempdir_name, "verity.img")
verity_metadata_path = os.path.join(tempdir_name, "verity_metadata.img") verity_metadata_path = os.path.join(tempdir_name, "verity_metadata.img")
verity_fec_path = os.path.join(tempdir_name, "verity_fec.img")
# build the verity tree and get the root hash and salt # build the verity tree and get the root hash and salt
if not BuildVerityTree(out_file, verity_image_path, prop_dict): if not BuildVerityTree(out_file, verity_image_path, prop_dict):
@@ -201,6 +256,16 @@ def MakeVerityEnabledImage(out_file, prop_dict):
shutil.rmtree(tempdir_name, ignore_errors=True) shutil.rmtree(tempdir_name, ignore_errors=True)
return False return False
if fec_supported:
# build FEC for the entire partition, including metadata
if not BuildVerityFEC(out_file, verity_fec_path, prop_dict):
shutil.rmtree(tempdir_name, ignore_errors=True)
return False
if not Append2Simg(out_file, verity_fec_path, "Could not append FEC!"):
shutil.rmtree(tempdir_name, ignore_errors=True)
return False
shutil.rmtree(tempdir_name, ignore_errors=True) shutil.rmtree(tempdir_name, ignore_errors=True)
return True return True
@@ -248,12 +313,14 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None):
is_verity_partition = "verity_block_device" in prop_dict is_verity_partition = "verity_block_device" in prop_dict
verity_supported = prop_dict.get("verity") == "true" verity_supported = prop_dict.get("verity") == "true"
verity_fec_supported = prop_dict.get("verity_fec") == "true"
# Adjust the partition size to make room for the hashes if this is to be # Adjust the partition size to make room for the hashes if this is to be
# verified. # verified.
if verity_supported and is_verity_partition and fs_spans_partition: if verity_supported and is_verity_partition and fs_spans_partition:
partition_size = int(prop_dict.get("partition_size")) partition_size = int(prop_dict.get("partition_size"))
adjusted_size = AdjustPartitionSizeForVerity(partition_size,
adjusted_size = AdjustPartitionSizeForVerity(partition_size) verity_fec_supported)
if not adjusted_size: if not adjusted_size:
return False return False
prop_dict["partition_size"] = str(adjusted_size) prop_dict["partition_size"] = str(adjusted_size)
@@ -366,7 +433,7 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None):
"%d" % (mount_point, image_size, partition_size)) "%d" % (mount_point, image_size, partition_size))
return False return False
if verity_supported and is_verity_partition: if verity_supported and is_verity_partition:
if 2 * image_size - AdjustPartitionSizeForVerity(image_size) > partition_size: if 2 * image_size - AdjustPartitionSizeForVerity(image_size, verity_fec_supported) > partition_size:
print "Error: No more room on %s to fit verity data" % mount_point print "Error: No more room on %s to fit verity data" % mount_point
return False return False
prop_dict["original_partition_size"] = prop_dict["partition_size"] prop_dict["original_partition_size"] = prop_dict["partition_size"]
@@ -374,7 +441,7 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None):
# create the verified image if this is to be verified # create the verified image if this is to be verified
if verity_supported and is_verity_partition: if verity_supported and is_verity_partition:
if not MakeVerityEnabledImage(out_file, prop_dict): if not MakeVerityEnabledImage(out_file, verity_fec_supported, prop_dict):
return False return False
if run_fsck and prop_dict.get("skip_fsck") != "true": if run_fsck and prop_dict.get("skip_fsck") != "true":
@@ -416,7 +483,8 @@ def ImagePropFromGlobalDict(glob_dict, mount_point):
"skip_fsck", "skip_fsck",
"verity", "verity",
"verity_key", "verity_key",
"verity_signer_cmd" "verity_signer_cmd",
"verity_fec"
) )
for p in common_props: for p in common_props:
copy_prop(p, p) copy_prop(p, p)