diff options
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/image_signing/ensure_amd_psp_flags.sh | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/scripts/image_signing/ensure_amd_psp_flags.sh b/scripts/image_signing/ensure_amd_psp_flags.sh new file mode 100755 index 00000000..efccb69a --- /dev/null +++ b/scripts/image_signing/ensure_amd_psp_flags.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# Copyright 2022 The ChromiumOS Authors. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Load common constants and variables. +. "$(dirname "$0")/common.sh" + +# Abort on error and uninitialized variables. +set -eu + +declare -A -r REQUIRED_BIT_MASKS=( + # Bit 58 - PSP_S0I3_RESUME_VERSTAGE - Run PSP verstage during S0i3 resume. + # Checks that FW images have not been tampered with when exiting S0i3. + [guybrush]="$((1 << 58))" + [zork]="0x0" +) + +declare -A -r FORBIDDEN_BIT_MASKS=( + [guybrush]="0x0" + [zork]="0x0" +) + +# Grunt uses an old firmware format that amdfwread cannot read. +# See b/233787191 for skyrim. +BOARD_IGNORE_LIST=(grunt skyrim) + +usage() { + echo "$0: Validate AMD PSP soft-fuse flags contained in a ChromeOS image." \ + "These flags can have security implications and control debug features." + echo "Usage $0 <board> <image>" +} + +main() { + if [[ $# -ne 2 ]]; then + usage + exit 1 + fi + + local board="$1" + local image="$2" + + # Check the ignore list. + if [[ " ${BOARD_IGNORE_LIST[*]} " == *" ${board} "* ]]; then + echo "Skipping ignore-listed board ${board}" + exit 0 + fi + + # Mount the image. + local loopdev rootfs + if [[ -d "${image}" ]]; then + rootfs="${image}" + else + rootfs="$(make_temp_dir)" + loopdev="$(loopback_partscan "${image}")" + mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}" + fi + + local firmware_bundle shellball_dir + firmware_bundle="${rootfs}/usr/sbin/chromeos-firmwareupdate" + shellball_dir="$(make_temp_dir)" + + # Get the board specific bit masks. + local required_bit_mask forbidden_bit_mask + + if [[ ! -v "REQUIRED_BIT_MASKS[${board}]" ]]; then + die "Missing PSP required bit mask set for ${board}" + fi + + if [[ ! -v "FORBIDDEN_BIT_MASKS[${board}]" ]]; then + die "Missing PSP forbidden bit mask set for ${board}" + fi + + required_bit_mask="${REQUIRED_BIT_MASKS[${board}]}" + forbidden_bit_mask="${FORBIDDEN_BIT_MASKS[${board}]}" + + # Extract our firmware. + if ! extract_firmware_bundle "${firmware_bundle}" "${shellball_dir}"; then + die "Failed to extract firmware bundle" + fi + + # Find our images and check the soft-fuse bits in each. + declare -a images + readarray -t images < <(find "${shellball_dir}" -iname 'bios-*') + + local image + for image in "${images[@]}"; do + local soft_fuse soft_fuse_output forbidden_set missing_set + if ! soft_fuse_output="$(amdfwread --soft-fuse "${image}")"; then + die "'amdfwread --soft-fuse ${image}' failed" + fi + + # Output format from amdfwread is Soft-fuse:value, where value is in hex. + soft_fuse="$(echo "${soft_fuse_output}" | \ + sed -E -n 's/Soft-fuse:(0[xX][0-9a-fA-F]+)/\1/p')" + if [[ -z "${soft_fuse}" ]]; then + die "Could not parse Soft-fuse value from output: '${soft_fuse_output}'" + fi + + forbidden_set="$((soft_fuse & forbidden_bit_mask))" + if [[ "${forbidden_set}" != 0 ]]; then + local forbidden_hex + forbidden_hex="$(printf %#x "${forbidden_set}")" + die "${image}: Forbidden AMD PSP soft-fuse bits set: ${forbidden_hex}" + fi + + missing_set="$((~soft_fuse & required_bit_mask))" + if [[ "${missing_set}" != 0 ]]; then + local missing_hex + missing_hex="$(printf %#x "${missing_set}")" + die "${image}: Required AMD PSP soft-fuse bits not set: ${missing_hex}" + fi + done +} +main "$@" |