Update for new Android Verified Boot (AVB).

This updates the build system for the new Android Verified Boot
codebase. As this is based on Brillo Verified Boot, this change replaces
the existing BVB support.

Android Verified Boot is enabled by the BOARD_AVB_ENABLE variable

 BOARD_AVB_ENABLE := true

This will make the build system create vbmeta.img which will contain a
hash descriptor for boot.img, a hashtree descriptor for system.img, a
kernel-cmdline descriptor for setting up dm-verity for system.img and
append a hash-tree to system.img.

Additionally, the descriptors are left in boot.img and system.img so a
third party can create their own vbmeta.img file linking - using the
option --chain_partition - to these images. If this is not needed
footers can be erased using the 'avbtool erase_footer' command. It's
also harmless to just leave them in the images.

By default, the algorithm SHA256_RSA4096 is used with a test key from
the AVB source directory. This can be overriden by the
BOARD_AVB_ALGORITHM and BOARD_AVB_KEY_PATH variables to use e.g. a
4096-bit RSA key and SHA-512:

 BOARD_AVB_ALGORITHM := SHA512_RSA4096
 BOARD_AVB_KEY_PATH := /path/to/rsa_key_4096bits.pem

To prevent rollback attacks, the rollback index should be increased on a
regular basis. The rollback index can be set with the
BOARD_AVB_ROLLBACK_INDEX variable:

 BOARD_AVB_ROLLBACK_INDEX := 5

If this is not set, the rollback index defaults to 0.

The variable BOARD_AVB_MAKE_VBMETA_IMAGE_ARGS can be used to specify
additional options passed to 'avbtool make_vbmeta_image'. Typical
options to be used here include '--prop', '--prop_from_file', and
'--chain_partition'.

The variable BOARD_AVBTOOL_BOOT_ADD_HASH_FOOTER_ARGS can be used to
specify additional options passed to 'avbtool add_hash_footer' for
boot.img. Typical options to be used here include '--hash_algorithm' and
'--salt'.

The variable BOARD_AVBTOOL_SYSTEM_ADD_HASHTREE_FOOTER_ARGS can be used
to specify additional options passed to 'avbtool add_hashtree_footer'
for systems.img. Typical options to be used here include
'--hash_algorithm', '--salt', and '--block_size'.

BUG=31264226
TEST=Manually tested on edison-eng by inspecting {boot, system,
  vbmeta}.img in out/ directory as well as their counterparts in
  the IMAGES/ directory of edision-target_files-eng.zeuthen.zip

Merged-In: Ic9a61cfc65c148b12996e57f04da5432eef6b982

Change-Id: I97042655bca15e7eac899f12c5bada2f6184d307
This commit is contained in:
David Zeuthen
2016-09-15 13:43:54 -04:00
parent 52eafee87a
commit 2ce63edab7
5 changed files with 167 additions and 203 deletions

View File

@@ -384,6 +384,16 @@ def DumpInfoDict(d):
print "%-25s = (%s) %s" % (k, type(v).__name__, v)
def AppendAVBSigningArgs(cmd):
"""Append signing arguments for avbtool."""
keypath = OPTIONS.info_dict.get("board_avb_key_path", None)
algorithm = OPTIONS.info_dict.get("board_avb_algorithm", None)
if not keypath or not algorithm:
algorithm = "SHA256_RSA4096"
keypath = "external/avb/test/data/testkey_rsa4096.pem"
cmd.extend(["--key", keypath, "--algorithm", algorithm])
def _BuildBootableImage(sourcedir, fs_config_file, info_dict=None,
has_ramdisk=False):
"""Build a bootable image from the specified sourcedir.
@@ -503,111 +513,20 @@ def _BuildBootableImage(sourcedir, fs_config_file, info_dict=None,
img_unsigned.close()
img_keyblock.close()
img.seek(os.SEEK_SET, 0)
data = img.read()
if has_ramdisk:
ramdisk_img.close()
img.close()
return data
def _BuildBvbBootableImage(sourcedir, fs_config_file, system_img_path,
info_dict=None, has_ramdisk=False):
"""Build a bootable image compatible with Brillo Verified Boot from the
specified sourcedir.
Take a kernel, cmdline, system image path, and optionally a ramdisk
directory from the input (in 'sourcedir'), and turn them into a boot
image. Return the image data, or None if sourcedir does not appear
to contains files for building the requested image.
"""
def make_ramdisk():
ramdisk_img = tempfile.NamedTemporaryFile()
if os.access(fs_config_file, os.F_OK):
cmd = ["mkbootfs", "-f", fs_config_file,
os.path.join(sourcedir, "RAMDISK")]
else:
cmd = ["mkbootfs", os.path.join(sourcedir, "RAMDISK")]
p1 = Run(cmd, stdout=subprocess.PIPE)
p2 = Run(["minigzip"], stdin=p1.stdout, stdout=ramdisk_img.file.fileno())
p2.wait()
p1.wait()
assert p1.returncode == 0, "mkbootfs of %s ramdisk failed" % (sourcedir,)
assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (sourcedir,)
return ramdisk_img
if not os.access(os.path.join(sourcedir, "kernel"), os.F_OK):
return None
if has_ramdisk and not os.access(os.path.join(sourcedir, "RAMDISK"), os.F_OK):
return None
if info_dict is None:
info_dict = OPTIONS.info_dict
img = tempfile.NamedTemporaryFile()
if has_ramdisk:
ramdisk_img = make_ramdisk()
# use BVBTOOL from environ, or "bvbtool" if empty or not set
bvbtool = os.getenv('BVBTOOL') or "bvbtool"
# First, create boot.img.
cmd = [bvbtool, "make_boot_image"]
fn = os.path.join(sourcedir, "cmdline")
if os.access(fn, os.F_OK):
cmd.append("--kernel_cmdline")
cmd.append(open(fn).read().rstrip("\n"))
cmd.extend(["--kernel", os.path.join(sourcedir, "kernel")])
if has_ramdisk:
cmd.extend(["--initrd", ramdisk_img.name])
cmd.extend(["--rootfs_with_hashes", system_img_path])
args = info_dict.get("board_bvb_make_boot_image_args", None)
if args and args.strip():
cmd.extend(shlex.split(args))
rollback_index = info_dict.get("board_bvb_rollback_index", None)
if rollback_index and rollback_index.strip():
cmd.extend(["--rollback_index", rollback_index.strip()])
cmd.extend(["--output", img.name])
p = Run(cmd, stdout=subprocess.PIPE)
p.communicate()
assert p.returncode == 0, "bvbtool make_boot_image of %s image failed" % (
os.path.basename(sourcedir),)
# Then, sign boot.img.
cmd = [bvbtool, "sign_boot_image", "--image", img.name]
algorithm = info_dict.get("board_bvb_algorithm", None)
key_path = info_dict.get("board_bvb_key_path", None)
if algorithm and algorithm.strip() and key_path and key_path.strip():
cmd.extend(["--algorithm", algorithm, "--key", key_path])
else:
cmd.extend(["--algorithm", "SHA256_RSA4096"])
cmd.extend(["--key", "external/bvb/test/testkey_rsa4096.pem"])
args = info_dict.get("board_bvb_sign_boot_image_args", None)
if args and args.strip():
cmd.extend(shlex.split(args))
p = Run(cmd, stdout=subprocess.PIPE)
p.communicate()
assert p.returncode == 0, "bvbtool sign_boot_image of %s image failed" % (
os.path.basename(sourcedir),)
# AVB: if enabled, calculate and add hash to boot.img.
if OPTIONS.info_dict.get("board_avb_enable", None) == "true":
avbtool = os.getenv('AVBTOOL') or "avbtool"
part_size = OPTIONS.info_dict.get("boot_size", None)
cmd = [avbtool, "add_hash_footer", "--image", img.name,
"--partition_size", str(part_size), "--partition_name", "boot"]
AppendAVBSigningArgs(cmd)
args = OPTIONS.info_dict.get("board_avb_boot_add_hash_footer_args", None)
if args and args.strip():
cmd.extend(shlex.split(args))
p = Run(cmd, stdout=subprocess.PIPE)
p.communicate()
assert p.returncode == 0, "avbtool add_hash_footer of %s failed" % (
os.path.basename(OPTIONS.input_tmp))
img.seek(os.SEEK_SET, 0)
data = img.read()
@@ -650,14 +569,9 @@ def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir,
info_dict.get("recovery_as_boot") == "true")
fs_config = "META/" + tree_subdir.lower() + "_filesystem_config.txt"
if info_dict.get("board_bvb_enable", None) == "true":
data = _BuildBvbBootableImage(os.path.join(unpack_dir, tree_subdir),
os.path.join(unpack_dir, fs_config),
system_img_path, info_dict, has_ramdisk)
else:
data = _BuildBootableImage(os.path.join(unpack_dir, tree_subdir),
os.path.join(unpack_dir, fs_config),
info_dict, has_ramdisk)
data = _BuildBootableImage(os.path.join(unpack_dir, tree_subdir),
os.path.join(unpack_dir, fs_config),
info_dict, has_ramdisk)
if data:
return File(name, data)
return None