Index: scripts/image_signing/make_dev_ssd.sh |
diff --git a/scripts/image_signing/make_dev_ssd.sh b/scripts/image_signing/make_dev_ssd.sh |
new file mode 100755 |
index 0000000000000000000000000000000000000000..a5a961d69b786c55530f7ac53206e643f4668682 |
--- /dev/null |
+++ b/scripts/image_signing/make_dev_ssd.sh |
@@ -0,0 +1,236 @@ |
+#!/bin/sh |
+# |
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+# |
+# This script can change key (usually developer keys) and kernel config |
+# of a kernels on SSD. |
+ |
+SCRIPT_BASE="$(dirname "$0")" |
+. "$SCRIPT_BASE/common.sh" |
+load_shflags || exit 1 |
+ |
+# Constants used by DEFINE_* |
+VBOOT_BASE='/usr/share/vboot' |
+DEFAULT_KEYS_FOLDER="$VBOOT_BASE/devkeys" |
+DEFAULT_BACKUP_FOLDER='/mnt/stateful_partition/backups' |
+ |
+# DEFINE_string name default_value description flag |
+DEFINE_string image "/dev/sda" "Path to device or image file" "i" |
+DEFINE_string keys "$DEFAULT_KEYS_FOLDER" "Path to folder of dev keys" "k" |
+DEFINE_boolean remove_rootfs_verification \ |
+ $FLAGS_FALSE "Modify kernel boot config to disable rootfs verification" "" |
+DEFINE_string backup_dir \ |
+ "$DEFAULT_BACKUP_FOLDER" "Path of directory to store kernel backups" "" |
+DEFINE_boolean debug $FLAGS_FALSE "Provide debug messages" "d" |
+ |
+# Parse command line |
+FLAGS "$@" || exit 1 |
+eval set -- "$FLAGS_ARGV" |
+ |
+# Globals |
+# ---------------------------------------------------------------------------- |
+set -e |
+ |
+# a log file to keep the output results of executed command |
+EXEC_LOG="$(make_temp_file)" |
+ |
+# Functions |
+# ---------------------------------------------------------------------------- |
+# Reports error message and exit(1) |
+err_die() { |
+ echo "ERROR: $*" 1>&2 |
+ exit 1 |
+} |
+ |
+# Returns true if we're running in debug mode |
+is_debug_mode() { |
+ [ "$FLAGS_debug" = $FLAGS_TRUE ] |
+} |
+ |
+# Prints messages (in parameters) in debug mode |
+debug_msg() { |
+ if is_debug_mode; then |
+ echo "DEBUG: $*" 1>&2 |
+ fi |
+} |
+ |
+# Removes rootfs verification from kernel boot parameter |
+remove_rootfs_verification() { |
+ echo "$*" | sed ' |
+ s|dm_verity[^ ]\+||g |
+ s| ro | rw | |
+ s|verity /dev/sd%D%P /dev/sd%D%P || |
+ s| root=/dev/dm-0 | root=/dev/sd%D%P | |
+ s|dm="[^"]\+" ||' |
+} |
+ |
+# Wrapped version of dd |
+mydd() { |
+ # oflag=sync is safer, but since we need bs=512, syncing every block would be |
+ # very slow. |
+ dd "$@" >"$EXEC_LOG" 2>&1 || |
+ err_die "Failed in [dd $@], Message: $(cat "$EXEC_LOG")" |
+} |
+ |
+# Prints a more friendly name from kernel index number |
+cros_kernel_name() { |
+ case $1 in |
+ 2) |
+ echo "Kernel A" |
+ ;; |
+ 4) |
+ echo "Kernel B" |
+ ;; |
+ *) |
+ err_die "unknown kernel index: $1" |
+ esac |
+} |
+ |
+# Resigns a kernel on SSD or image. |
+resign_ssd_kernel() { |
+ # bs=512 is the fixed block size for dd and cgpt |
+ local bs=512 |
+ local ssd_device="$1" |
+ |
+ # reasonable size for current kernel partition |
+ local min_kernel_size=32000 |
+ local max_kernel_size=65536 |
+ local resigned_kernels=0 |
+ |
+ for kernel_index in 2 4; do |
+ local old_blob="$(make_temp_file)" |
+ local new_blob="$(make_temp_file)" |
+ local name="$(cros_kernel_name $kernel_index)" |
+ |
+ debug_msg "Probing $name information" |
+ local offset size |
+ offset="$(partoffset "$ssd_device" "$kernel_index")" || |
+ err_die "Failed to get partition $kernel_index offset from $ssd_device" |
+ size="$(partsize "$ssd_device" "$kernel_index")" || |
+ err_die "Failed to get partition $kernel_index size from $ssd_device" |
+ if [ ! $size -gt $min_kernel_size ]; then |
+ echo "WARNING: $name seems too small ($size), ignored." |
+ continue |
+ fi |
+ if [ ! $size -le $max_kernel_size ]; then |
+ echo "WARNING: $name seems too large ($size), ignored." |
+ continue |
+ fi |
+ |
+ debug_msg "Reading $name from partition $kernel_index" |
+ mydd if="$ssd_device" of="$old_blob" bs=$bs skip=$offset count=$size |
+ |
+ debug_msg "Checking if $name is valid" |
+ local old_kernel_config |
+ if ! old_kernel_config="$(dump_kernel_config "$old_blob" 2>"$EXEC_LOG")" |
+ then |
+ debug_msg "dump_kernel_config error message: $(cat "$EXEC_LOG")" |
+ echo "WARNING: $name: no kernel boot information, ignored." |
+ continue |
+ fi |
+ |
+ debug_msg "Decide and prepare signing parameters" |
+ local resign_command |
+ # TODO(hungte) $KERNEL_KEYBLOCK and $new_kernel_config should also be |
+ # quoted, but quoting inside would cause extra quote... We should find some |
+ # better way to do this, for example using eval. |
+ if [ ${FLAGS_remove_rootfs_verification} = $FLAGS_TRUE ]; then |
+ local new_kernel_config_file="$(make_temp_file)" |
+ remove_rootfs_verification "$old_kernel_config" >"$new_kernel_config_file" |
+ resign_command="--config $new_kernel_config_file" |
+ debug_msg "New kernel config: $(cat $new_kernel_config_file)" |
+ echo "$name: Disabled rootfs verification." |
+ else |
+ resign_command="--vblockonly --keyblock $KERNEL_KEYBLOCK" |
+ fi |
+ |
+ debug_msg "Re-signing $name from $old_blob to $new_blob" |
+ debug_msg "Using key: $KERNEL_DATAKEY, command: $resign_command" |
+ vbutil_kernel \ |
+ --repack "$new_blob" \ |
+ $resign_command \ |
+ --signprivate "$KERNEL_DATAKEY" \ |
+ --oldblob "$old_blob" >"$EXEC_LOG" 2>&1 || |
+ err_die "Failed to resign $name. Message: $(cat "$EXEC_LOG")" |
+ |
+ debug_msg "Creating new kernel image (vboot+code+config)" |
+ local new_kern="$(make_temp_file)" |
+ cp "$old_blob" "$new_kern" |
+ mydd if="$new_blob" of="$new_kern" conv=notrunc |
+ |
+ if is_debug_mode; then |
+ debug_msg "for debug purposes, check *.dbgbin" |
+ cp "$old_blob" old_blob.dbgbin |
+ cp "$new_blob" new_blob.dbgbin |
+ cp "$new_kern" new_kern.dbgbin |
+ fi |
+ |
+ debug_msg "Verifying new kernel and keys" |
+ vbutil_kernel \ |
+ --verify "$new_kern" \ |
+ --signpubkey "$KERNEL_PUBKEY" --verbose >"$EXEC_LOG" 2>&1 || |
+ err_die "Failed to verify new $name. Message: $(cat "$EXEC_LOG")" |
+ |
+ debug_msg "Backup old kernel blob" |
+ local backup_date_time="$(date +'%Y%m%d_%H%M%S')" |
+ local backup_name="$(echo "$name" | sed 's/ /_/g; s/^K/k/')" |
+ local backup_file_name="${backup_name}_${backup_date_time}.bin" |
+ local backup_file_path="$FLAGS_backup_dir/$backup_file_name" |
+ if mkdir -p "$FLAGS_backup_dir" && |
+ cp -f "$old_blob" "$backup_file_path"; then |
+ echo "Backup of $name is stored in: $backup_file_path" |
+ else |
+ echo "WARNING: Cannot create file in $FLAGS_backup_dir... Ignore backups." |
+ fi |
+ |
+ debug_msg "Writing $name to partition $kernel_index" |
+ mydd \ |
+ if="$new_kern" \ |
+ of="$ssd_device" \ |
+ seek=$offset \ |
+ bs=$bs \ |
+ count=$size \ |
+ conv=notrunc |
+ resigned_kernels=$(($resigned_kernels + 1)) |
+ |
+ # Sometimes doing "dump_kernel_config" or other I/O now (or after return to |
+ # shell) will get the data before modification. Not a problem now, but for |
+ # safety, let's try to sync more. |
+ sync; sync; sync |
+ |
+ echo "$name: Re-signed with developer keys successfully." |
+ done |
+ return $resigned_kernels |
+} |
+ |
+# Main |
+# ---------------------------------------------------------------------------- |
+main() { |
+ local num_signed=0 |
+ # Check parameters |
+ KERNEL_KEYBLOCK="$FLAGS_keys/kernel.keyblock" |
+ KERNEL_DATAKEY="$FLAGS_keys/kernel_data_key.vbprivk" |
+ KERNEL_PUBKEY="$FLAGS_keys/kernel_subkey.vbpubk" |
+ |
+ debug_msg "Prerequisite check" |
+ ensure_files_exist \ |
+ "$KERNEL_KEYBLOCK" \ |
+ "$KERNEL_DATAKEY" \ |
+ "$KERNEL_PUBKEY" \ |
+ "$FLAGS_image" || |
+ exit 1 |
+ |
+ resign_ssd_kernel "$FLAGS_image" || num_signed=$? |
+ |
+ debug_msg "Complete." |
+ if [ $num_signed -gt 0 -a $num_signed -le 2 ]; then |
+ # signed 1 or two kernels |
+ echo "Successfully re-signed $num_signed kernel(s) on device $FLAGS_image". |
+ else |
+ err_die "Failed re-signing kernels." |
+ fi |
+} |
+ |
+main |