Always set a avb salt for hermetic build

When building images via `m` , build_image.py is invoked directly
without going through add_img_to_target_files. To ensure images built in
either way are identical, move uuid/salt computation to build_image.py,
so that the same uuid/salt will be used.

Bug: 281960439
Test: m installclean && m && m target-files-dir , maks sure images in
$OUT and $OUT/obj/PACKING/target_files_intermediates are identical

Change-Id: Icdab29df84f5a0ec7c080f99f9fdbdc3c9b10b90
This commit is contained in:
Kelvin Zhang
2023-06-02 16:41:19 -07:00
parent ccf0471af3
commit c819b29f46
4 changed files with 61 additions and 38 deletions

View File

@@ -68,6 +68,7 @@ import sparse_img
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from apex_utils import GetApexInfoFromTargetFiles from apex_utils import GetApexInfoFromTargetFiles
from common import ZipDelete, PARTITIONS_WITH_CARE_MAP, ExternalError, RunAndCheckOutput, IsSparseImage, MakeTempFile, ZipWrite from common import ZipDelete, PARTITIONS_WITH_CARE_MAP, ExternalError, RunAndCheckOutput, IsSparseImage, MakeTempFile, ZipWrite
from build_image import FIXED_FILE_TIMESTAMP
if sys.hexversion < 0x02070000: if sys.hexversion < 0x02070000:
print("Python 2.7 or newer is required.", file=sys.stderr) print("Python 2.7 or newer is required.", file=sys.stderr)
@@ -81,12 +82,6 @@ OPTIONS.rebuild_recovery = False
OPTIONS.replace_updated_files_list = [] OPTIONS.replace_updated_files_list = []
OPTIONS.is_signing = False OPTIONS.is_signing = False
# Use a fixed timestamp (01/01/2009 00:00:00 UTC) for files when packaging
# images. (b/24377993, b/80600931)
FIXED_FILE_TIMESTAMP = int((
datetime.datetime(2009, 1, 1, 0, 0, 0, 0, None) -
datetime.datetime.utcfromtimestamp(0)).total_seconds())
def ParseAvbFooter(img_path) -> avbtool.AvbFooter: def ParseAvbFooter(img_path) -> avbtool.AvbFooter:
with open(img_path, 'rb') as fp: with open(img_path, 'rb') as fp:
@@ -594,15 +589,6 @@ def CreateImage(input_dir, info_dict, what, output_file, block_list=None):
if block_list: if block_list:
image_props["block_list"] = block_list.name image_props["block_list"] = block_list.name
# Use repeatable ext4 FS UUID and hash_seed UUID (based on partition name and
# build fingerprint). Also use the legacy build id, because the vbmeta digest
# isn't available at this point.
build_info = common.BuildInfo(info_dict, use_legacy_id=True)
uuid_seed = what + "-" + build_info.GetPartitionFingerprint(what)
image_props["uuid"] = str(uuid.uuid5(uuid.NAMESPACE_URL, uuid_seed))
hash_seed = "hash_seed-" + uuid_seed
image_props["hash_seed"] = str(uuid.uuid5(uuid.NAMESPACE_URL, hash_seed))
build_image.BuildImage( build_image.BuildImage(
os.path.join(input_dir, what.upper()), image_props, output_file.name) os.path.join(input_dir, what.upper()), image_props, output_file.name)
@@ -1144,14 +1130,18 @@ def AddImagesToTargetFiles(filename):
item for item in vbmeta_partitions item for item in vbmeta_partitions
if item not in vbmeta_vendor.split()] if item not in vbmeta_vendor.split()]
vbmeta_partitions.append("vbmeta_vendor") vbmeta_partitions.append("vbmeta_vendor")
custom_avb_partitions = OPTIONS.info_dict.get("avb_custom_vbmeta_images_partition_list", "").strip().split() custom_avb_partitions = OPTIONS.info_dict.get(
"avb_custom_vbmeta_images_partition_list", "").strip().split()
if custom_avb_partitions: if custom_avb_partitions:
for avb_part in custom_avb_partitions: for avb_part in custom_avb_partitions:
partition_name = "vbmeta_" + avb_part partition_name = "vbmeta_" + avb_part
included_partitions = OPTIONS.info_dict.get("avb_vbmeta_{}".format(avb_part), "").strip().split() included_partitions = OPTIONS.info_dict.get(
assert included_partitions, "Custom vbmeta partition {0} missing avb_vbmeta_{0} prop".format(avb_part) "avb_vbmeta_{}".format(avb_part), "").strip().split()
assert included_partitions, "Custom vbmeta partition {0} missing avb_vbmeta_{0} prop".format(
avb_part)
banner(partition_name) banner(partition_name)
logger.info("VBMeta partition {} needs {}".format(partition_name, included_partitions)) logger.info("VBMeta partition {} needs {}".format(
partition_name, included_partitions))
partitions[partition_name] = AddVBMeta( partitions[partition_name] = AddVBMeta(
output_zip, partitions, partition_name, included_partitions) output_zip, partitions, partition_name, included_partitions)
vbmeta_partitions = [ vbmeta_partitions = [
@@ -1159,7 +1149,6 @@ def AddImagesToTargetFiles(filename):
if item not in included_partitions] if item not in included_partitions]
vbmeta_partitions.append(partition_name) vbmeta_partitions.append(partition_name)
if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true": if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true":
banner("vbmeta") banner("vbmeta")
AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions) AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)

View File

@@ -23,24 +23,34 @@ Usage: build_image input_directory properties_file output_image \\
""" """
from __future__ import print_function from __future__ import print_function
import datetime
import glob import glob
import logging import logging
import os import os
import os.path import os.path
import re import re
import shlex
import shutil import shutil
import sys import sys
import uuid
import common import common
import verity_utils import verity_utils
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
OPTIONS = common.OPTIONS OPTIONS = common.OPTIONS
BLOCK_SIZE = common.BLOCK_SIZE BLOCK_SIZE = common.BLOCK_SIZE
BYTES_IN_MB = 1024 * 1024 BYTES_IN_MB = 1024 * 1024
# Use a fixed timestamp (01/01/2009 00:00:00 UTC) for files when packaging
# images. (b/24377993, b/80600931)
FIXED_FILE_TIMESTAMP = int((
datetime.datetime(2009, 1, 1, 0, 0, 0, 0, None) -
datetime.datetime.utcfromtimestamp(0)).total_seconds())
class BuildImageError(Exception): class BuildImageError(Exception):
"""An Exception raised during image building.""" """An Exception raised during image building."""
@@ -487,6 +497,20 @@ def RunErofsFsck(out_file):
raise raise
def SetUUIDIfNotExist(image_props):
# Use repeatable ext4 FS UUID and hash_seed UUID (based on partition name and
# build fingerprint). Also use the legacy build id, because the vbmeta digest
# isn't available at this point.
what = image_props["mount_point"]
fingerprint = image_props.get("fingerprint", "")
uuid_seed = what + "-" + fingerprint
logger.info("Using fingerprint %s for partition %s", fingerprint, what)
image_props["uuid"] = str(uuid.uuid5(uuid.NAMESPACE_URL, uuid_seed))
hash_seed = "hash_seed-" + uuid_seed
image_props["hash_seed"] = str(uuid.uuid5(uuid.NAMESPACE_URL, hash_seed))
def BuildImage(in_dir, prop_dict, out_file, target_out=None): 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. """Builds an image for the files under in_dir and writes it to out_file.
@@ -504,6 +528,7 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None):
BuildImageError: On build image failures. BuildImageError: On build image failures.
""" """
in_dir, fs_config = SetUpInDirAndFsConfig(in_dir, prop_dict) in_dir, fs_config = SetUpInDirAndFsConfig(in_dir, prop_dict)
SetUUIDIfNotExist(prop_dict)
build_command = [] build_command = []
fs_type = prop_dict.get("fs_type", "") fs_type = prop_dict.get("fs_type", "")
@@ -635,6 +660,19 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None):
verity_image_builder.Build(out_file) verity_image_builder.Build(out_file)
def TryParseFingerprint(glob_dict: dict):
for (key, val) in glob_dict.items():
if not key.endswith("_add_hashtree_footer_args") and not key.endswith("_add_hash_footer_args"):
continue
for arg in shlex.split(val):
m = re.match(r"^com\.android\.build\.\w+\.fingerprint:", arg)
if m is None:
continue
fingerprint = arg[len(m.group()):]
glob_dict["fingerprint"] = fingerprint
return
def ImagePropFromGlobalDict(glob_dict, mount_point): def ImagePropFromGlobalDict(glob_dict, mount_point):
"""Build an image property dictionary from the global dictionary. """Build an image property dictionary from the global dictionary.
@@ -643,7 +681,9 @@ def ImagePropFromGlobalDict(glob_dict, mount_point):
mount_point: such as "system", "data" etc. mount_point: such as "system", "data" etc.
""" """
d = {} d = {}
TryParseFingerprint(glob_dict)
d["timestamp"] = FIXED_FILE_TIMESTAMP
if "build.prop" in glob_dict: if "build.prop" in glob_dict:
timestamp = glob_dict["build.prop"].GetProp("ro.build.date.utc") timestamp = glob_dict["build.prop"].GetProp("ro.build.date.utc")
if timestamp: if timestamp:
@@ -680,6 +720,7 @@ def ImagePropFromGlobalDict(glob_dict, mount_point):
"avb_enable", "avb_enable",
"avb_avbtool", "avb_avbtool",
"use_dynamic_partition_size", "use_dynamic_partition_size",
"fingerprint",
) )
for p in common_props: for p in common_props:
copy_prop(p, p) copy_prop(p, p)
@@ -870,7 +911,6 @@ def BuildVBMeta(in_dir, glob_dict, output_path):
if item not in vbmeta_vendor.split()] if item not in vbmeta_vendor.split()]
vbmeta_partitions.append("vbmeta_vendor") vbmeta_partitions.append("vbmeta_vendor")
partitions = {part: os.path.join(in_dir, part + ".img") partitions = {part: os.path.join(in_dir, part + ".img")
for part in vbmeta_partitions} for part in vbmeta_partitions}
partitions = {part: path for (part, path) in partitions.items() if os.path.exists(path)} partitions = {part: path for (part, path) in partitions.items() if os.path.exists(path)}

View File

@@ -928,20 +928,7 @@ def LoadInfoDict(input_file, repacking=False):
input_file, partition, ramdisk_format=ramdisk_format) input_file, partition, ramdisk_format=ramdisk_format)
d["build.prop"] = d["system.build.prop"] d["build.prop"] = d["system.build.prop"]
# Set up the salt (based on fingerprint) that will be used when adding AVB
# hash / hashtree footers.
if d.get("avb_enable") == "true": if d.get("avb_enable") == "true":
build_info = BuildInfo(d, use_legacy_id=True)
for partition in PARTITIONS_WITH_BUILD_PROP:
fingerprint = build_info.GetPartitionFingerprint(partition)
if fingerprint:
d["avb_{}_salt".format(partition)] = sha256(
fingerprint.encode()).hexdigest()
# Set up the salt for partitions without build.prop
if build_info.fingerprint:
d["avb_salt"] = sha256(build_info.fingerprint.encode()).hexdigest()
# Set the vbmeta digest if exists # Set the vbmeta digest if exists
try: try:
d["vbmeta_digest"] = read_helper("META/vbmeta_digest.txt").rstrip() d["vbmeta_digest"] = read_helper("META/vbmeta_digest.txt").rstrip()

View File

@@ -31,6 +31,7 @@ import sys
import common import common
import sparse_img import sparse_img
from rangelib import RangeSet from rangelib import RangeSet
from hashlib import sha256
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -42,6 +43,7 @@ FIXED_SALT = "aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7"
MAX_VBMETA_SIZE = 64 * 1024 MAX_VBMETA_SIZE = 64 * 1024
MAX_FOOTER_SIZE = 4096 MAX_FOOTER_SIZE = 4096
class BuildVerityImageError(Exception): class BuildVerityImageError(Exception):
"""An Exception raised during verity image building.""" """An Exception raised during verity image building."""
@@ -64,6 +66,11 @@ def CreateVerityImageBuilder(prop_dict):
# partition_size could be None at this point, if using dynamic partitions. # partition_size could be None at this point, if using dynamic partitions.
if partition_size: if partition_size:
partition_size = int(partition_size) partition_size = int(partition_size)
# Set up the salt (based on fingerprint) that will be used when adding AVB
# hash / hashtree footers.
salt = prop_dict.get("avb_salt")
if salt is None:
salt = sha256(prop_dict.get("fingerprint", "").encode()).hexdigest()
# Verified Boot 2.0 # Verified Boot 2.0
if (prop_dict.get("avb_hash_enable") == "true" or if (prop_dict.get("avb_hash_enable") == "true" or
@@ -81,7 +88,7 @@ def CreateVerityImageBuilder(prop_dict):
prop_dict["avb_avbtool"], prop_dict["avb_avbtool"],
key_path, key_path,
algorithm, algorithm,
prop_dict.get("avb_salt"), salt,
prop_dict["avb_add_hash_footer_args"]) prop_dict["avb_add_hash_footer_args"])
# Image uses hashtree footer. # Image uses hashtree footer.
@@ -92,7 +99,7 @@ def CreateVerityImageBuilder(prop_dict):
prop_dict["avb_avbtool"], prop_dict["avb_avbtool"],
key_path, key_path,
algorithm, algorithm,
prop_dict.get("avb_salt"), salt,
prop_dict["avb_add_hashtree_footer_args"]) prop_dict["avb_add_hashtree_footer_args"])
return None return None