Merge "Error correction: Append codes to verified partitions"

This commit is contained in:
Sami Tolvanen 2015-10-19 09:49:18 +00:00 committed by Gerrit Code Review
commit 87f582611a
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))
INTERNAL_USERIMAGES_DEPS += $(BUILD_VERITY_TREE) $(APPEND2SIMG) $(VERITY_SIGNER)
ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY_FEC))
INTERNAL_USERIMAGES_DEPS += $(FEC)
endif
endif
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_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_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_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))
@ -1363,7 +1367,8 @@ OTATOOLS := $(HOST_OUT_EXECUTABLES)/minigzip \
$(HOST_OUT_EXECUTABLES)/verity_signer \
$(HOST_OUT_EXECUTABLES)/append2simg \
$(HOST_OUT_EXECUTABLES)/img2simg \
$(HOST_OUT_EXECUTABLES)/boot_signer
$(HOST_OUT_EXECUTABLES)/boot_signer \
$(HOST_OUT_EXECUTABLES)/fec
# Shared libraries.
OTATOOLS += \

View file

@ -515,6 +515,7 @@ BUILD_VERITY_TREE := $(HOST_OUT_EXECUTABLES)/build_verity_tree
BOOT_SIGNER := $(HOST_OUT_EXECUTABLES)/boot_signer
FUTILITY := prebuilts/misc/$(BUILD_OS)-$(HOST_PREBUILT_ARCH)/futility/futility
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 := $(BUILD_OUT_EXECUTABLES)/acp$(BUILD_EXECUTABLE_SUFFIX)

View file

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

View file

@ -21,6 +21,7 @@ user_variant := $(filter user userdebug,$(TARGET_BUILD_VARIANT))
ifneq (,$(user_variant))
PRODUCT_SUPPORTS_BOOT_SIGNER := true
PRODUCT_SUPPORTS_VERITY := true
PRODUCT_SUPPORTS_VERITY_FEC := true
# 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.

View file

@ -33,6 +33,7 @@ import tempfile
OPTIONS = common.OPTIONS
FIXED_SALT = "aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7"
BLOCK_SIZE = 4096
def RunCommand(cmd):
"""Echo and run the given command.
@ -48,6 +49,14 @@ def RunCommand(cmd):
print "%s" % (output.rstrip(),)
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):
cmd = "build_verity_tree -s %d"
cmd %= partition_size
@ -67,7 +76,22 @@ def GetVerityMetadataSize(partition_size):
return False, 0
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.
This information is used to size the created image appropriately.
@ -76,13 +100,43 @@ def AdjustPartitionSizeForVerity(partition_size):
Returns:
The size of the partition adjusted for verity metadata.
"""
success, verity_tree_size = GetVerityTreeSize(partition_size)
if not success:
return 0
success, verity_metadata_size = GetVerityMetadataSize(partition_size)
if not success:
return 0
return partition_size - verity_tree_size - verity_metadata_size
key = "%d %d" % (partition_size, fec_supported)
if key in AdjustPartitionSizeForVerity.results:
return AdjustPartitionSizeForVerity.results[key]
hi = partition_size
if hi % BLOCK_SIZE != 0:
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):
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,
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,
"Could not append verity tree!"):
return False
if not Append2Simg(data_image_path, verity_metadata_path,
"Could not append verity metadata!"):
return False
return True
def UnsparseImage(sparse_image_path, replace=True):
@ -154,7 +208,7 @@ def UnsparseImage(sparse_image_path, replace=True):
return False, None
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.
Args:
@ -180,6 +234,7 @@ def MakeVerityEnabledImage(out_file, prop_dict):
# get partial image paths
verity_image_path = os.path.join(tempdir_name, "verity.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
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)
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)
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
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
# verified.
if verity_supported and is_verity_partition and fs_spans_partition:
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:
return False
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))
return False
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
return False
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
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
if run_fsck and prop_dict.get("skip_fsck") != "true":
@ -416,7 +483,8 @@ def ImagePropFromGlobalDict(glob_dict, mount_point):
"skip_fsck",
"verity",
"verity_key",
"verity_signer_cmd"
"verity_signer_cmd",
"verity_fec"
)
for p in common_props:
copy_prop(p, p)