OLD | NEW |
(Empty) | |
| 1 #!/bin/sh |
| 2 # |
| 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 # |
| 7 # This script can change key (usually developer keys) and kernel config |
| 8 # of a kernels on SSD. |
| 9 |
| 10 SCRIPT_BASE="$(dirname "$0")" |
| 11 . "$SCRIPT_BASE/common.sh" |
| 12 load_shflags || exit 1 |
| 13 |
| 14 # Constants used by DEFINE_* |
| 15 VBOOT_BASE='/usr/share/vboot' |
| 16 DEFAULT_KEYS_FOLDER="$VBOOT_BASE/devkeys" |
| 17 DEFAULT_BACKUP_FOLDER='/mnt/stateful_partition/backups' |
| 18 |
| 19 # DEFINE_string name default_value description flag |
| 20 DEFINE_string image "/dev/sda" "Path to device or image file" "i" |
| 21 DEFINE_string keys "$DEFAULT_KEYS_FOLDER" "Path to folder of dev keys" "k" |
| 22 DEFINE_boolean remove_rootfs_verification \ |
| 23 $FLAGS_FALSE "Modify kernel boot config to disable rootfs verification" "" |
| 24 DEFINE_string backup_dir \ |
| 25 "$DEFAULT_BACKUP_FOLDER" "Path of directory to store kernel backups" "" |
| 26 DEFINE_boolean debug $FLAGS_FALSE "Provide debug messages" "d" |
| 27 |
| 28 # Parse command line |
| 29 FLAGS "$@" || exit 1 |
| 30 eval set -- "$FLAGS_ARGV" |
| 31 |
| 32 # Globals |
| 33 # ---------------------------------------------------------------------------- |
| 34 set -e |
| 35 |
| 36 # a log file to keep the output results of executed command |
| 37 EXEC_LOG="$(make_temp_file)" |
| 38 |
| 39 # Functions |
| 40 # ---------------------------------------------------------------------------- |
| 41 # Reports error message and exit(1) |
| 42 err_die() { |
| 43 echo "ERROR: $*" 1>&2 |
| 44 exit 1 |
| 45 } |
| 46 |
| 47 # Returns true if we're running in debug mode |
| 48 is_debug_mode() { |
| 49 [ "$FLAGS_debug" = $FLAGS_TRUE ] |
| 50 } |
| 51 |
| 52 # Prints messages (in parameters) in debug mode |
| 53 debug_msg() { |
| 54 if is_debug_mode; then |
| 55 echo "DEBUG: $*" 1>&2 |
| 56 fi |
| 57 } |
| 58 |
| 59 # Removes rootfs verification from kernel boot parameter |
| 60 remove_rootfs_verification() { |
| 61 echo "$*" | sed ' |
| 62 s|dm_verity[^ ]\+||g |
| 63 s| ro | rw | |
| 64 s|verity /dev/sd%D%P /dev/sd%D%P || |
| 65 s| root=/dev/dm-0 | root=/dev/sd%D%P | |
| 66 s|dm="[^"]\+" ||' |
| 67 } |
| 68 |
| 69 # Wrapped version of dd |
| 70 mydd() { |
| 71 # oflag=sync is safer, but since we need bs=512, syncing every block would be |
| 72 # very slow. |
| 73 dd "$@" >"$EXEC_LOG" 2>&1 || |
| 74 err_die "Failed in [dd $@], Message: $(cat "$EXEC_LOG")" |
| 75 } |
| 76 |
| 77 # Prints a more friendly name from kernel index number |
| 78 cros_kernel_name() { |
| 79 case $1 in |
| 80 2) |
| 81 echo "Kernel A" |
| 82 ;; |
| 83 4) |
| 84 echo "Kernel B" |
| 85 ;; |
| 86 *) |
| 87 err_die "unknown kernel index: $1" |
| 88 esac |
| 89 } |
| 90 |
| 91 # Resigns a kernel on SSD or image. |
| 92 resign_ssd_kernel() { |
| 93 # bs=512 is the fixed block size for dd and cgpt |
| 94 local bs=512 |
| 95 local ssd_device="$1" |
| 96 |
| 97 # reasonable size for current kernel partition |
| 98 local min_kernel_size=32000 |
| 99 local max_kernel_size=65536 |
| 100 local resigned_kernels=0 |
| 101 |
| 102 for kernel_index in 2 4; do |
| 103 local old_blob="$(make_temp_file)" |
| 104 local new_blob="$(make_temp_file)" |
| 105 local name="$(cros_kernel_name $kernel_index)" |
| 106 |
| 107 debug_msg "Probing $name information" |
| 108 local offset size |
| 109 offset="$(partoffset "$ssd_device" "$kernel_index")" || |
| 110 err_die "Failed to get partition $kernel_index offset from $ssd_device" |
| 111 size="$(partsize "$ssd_device" "$kernel_index")" || |
| 112 err_die "Failed to get partition $kernel_index size from $ssd_device" |
| 113 if [ ! $size -gt $min_kernel_size ]; then |
| 114 echo "WARNING: $name seems too small ($size), ignored." |
| 115 continue |
| 116 fi |
| 117 if [ ! $size -le $max_kernel_size ]; then |
| 118 echo "WARNING: $name seems too large ($size), ignored." |
| 119 continue |
| 120 fi |
| 121 |
| 122 debug_msg "Reading $name from partition $kernel_index" |
| 123 mydd if="$ssd_device" of="$old_blob" bs=$bs skip=$offset count=$size |
| 124 |
| 125 debug_msg "Checking if $name is valid" |
| 126 local old_kernel_config |
| 127 if ! old_kernel_config="$(dump_kernel_config "$old_blob" 2>"$EXEC_LOG")" |
| 128 then |
| 129 debug_msg "dump_kernel_config error message: $(cat "$EXEC_LOG")" |
| 130 echo "WARNING: $name: no kernel boot information, ignored." |
| 131 continue |
| 132 fi |
| 133 |
| 134 debug_msg "Decide and prepare signing parameters" |
| 135 local resign_command |
| 136 # TODO(hungte) $KERNEL_KEYBLOCK and $new_kernel_config should also be |
| 137 # quoted, but quoting inside would cause extra quote... We should find some |
| 138 # better way to do this, for example using eval. |
| 139 if [ ${FLAGS_remove_rootfs_verification} = $FLAGS_TRUE ]; then |
| 140 local new_kernel_config_file="$(make_temp_file)" |
| 141 remove_rootfs_verification "$old_kernel_config" >"$new_kernel_config_file" |
| 142 resign_command="--config $new_kernel_config_file" |
| 143 debug_msg "New kernel config: $(cat $new_kernel_config_file)" |
| 144 echo "$name: Disabled rootfs verification." |
| 145 else |
| 146 resign_command="--vblockonly --keyblock $KERNEL_KEYBLOCK" |
| 147 fi |
| 148 |
| 149 debug_msg "Re-signing $name from $old_blob to $new_blob" |
| 150 debug_msg "Using key: $KERNEL_DATAKEY, command: $resign_command" |
| 151 vbutil_kernel \ |
| 152 --repack "$new_blob" \ |
| 153 $resign_command \ |
| 154 --signprivate "$KERNEL_DATAKEY" \ |
| 155 --oldblob "$old_blob" >"$EXEC_LOG" 2>&1 || |
| 156 err_die "Failed to resign $name. Message: $(cat "$EXEC_LOG")" |
| 157 |
| 158 debug_msg "Creating new kernel image (vboot+code+config)" |
| 159 local new_kern="$(make_temp_file)" |
| 160 cp "$old_blob" "$new_kern" |
| 161 mydd if="$new_blob" of="$new_kern" conv=notrunc |
| 162 |
| 163 if is_debug_mode; then |
| 164 debug_msg "for debug purposes, check *.dbgbin" |
| 165 cp "$old_blob" old_blob.dbgbin |
| 166 cp "$new_blob" new_blob.dbgbin |
| 167 cp "$new_kern" new_kern.dbgbin |
| 168 fi |
| 169 |
| 170 debug_msg "Verifying new kernel and keys" |
| 171 vbutil_kernel \ |
| 172 --verify "$new_kern" \ |
| 173 --signpubkey "$KERNEL_PUBKEY" --verbose >"$EXEC_LOG" 2>&1 || |
| 174 err_die "Failed to verify new $name. Message: $(cat "$EXEC_LOG")" |
| 175 |
| 176 debug_msg "Backup old kernel blob" |
| 177 local backup_date_time="$(date +'%Y%m%d_%H%M%S')" |
| 178 local backup_name="$(echo "$name" | sed 's/ /_/g; s/^K/k/')" |
| 179 local backup_file_name="${backup_name}_${backup_date_time}.bin" |
| 180 local backup_file_path="$FLAGS_backup_dir/$backup_file_name" |
| 181 if mkdir -p "$FLAGS_backup_dir" && |
| 182 cp -f "$old_blob" "$backup_file_path"; then |
| 183 echo "Backup of $name is stored in: $backup_file_path" |
| 184 else |
| 185 echo "WARNING: Cannot create file in $FLAGS_backup_dir... Ignore backups." |
| 186 fi |
| 187 |
| 188 debug_msg "Writing $name to partition $kernel_index" |
| 189 mydd \ |
| 190 if="$new_kern" \ |
| 191 of="$ssd_device" \ |
| 192 seek=$offset \ |
| 193 bs=$bs \ |
| 194 count=$size \ |
| 195 conv=notrunc |
| 196 resigned_kernels=$(($resigned_kernels + 1)) |
| 197 |
| 198 # Sometimes doing "dump_kernel_config" or other I/O now (or after return to |
| 199 # shell) will get the data before modification. Not a problem now, but for |
| 200 # safety, let's try to sync more. |
| 201 sync; sync; sync |
| 202 |
| 203 echo "$name: Re-signed with developer keys successfully." |
| 204 done |
| 205 return $resigned_kernels |
| 206 } |
| 207 |
| 208 # Main |
| 209 # ---------------------------------------------------------------------------- |
| 210 main() { |
| 211 local num_signed=0 |
| 212 # Check parameters |
| 213 KERNEL_KEYBLOCK="$FLAGS_keys/kernel.keyblock" |
| 214 KERNEL_DATAKEY="$FLAGS_keys/kernel_data_key.vbprivk" |
| 215 KERNEL_PUBKEY="$FLAGS_keys/kernel_subkey.vbpubk" |
| 216 |
| 217 debug_msg "Prerequisite check" |
| 218 ensure_files_exist \ |
| 219 "$KERNEL_KEYBLOCK" \ |
| 220 "$KERNEL_DATAKEY" \ |
| 221 "$KERNEL_PUBKEY" \ |
| 222 "$FLAGS_image" || |
| 223 exit 1 |
| 224 |
| 225 resign_ssd_kernel "$FLAGS_image" || num_signed=$? |
| 226 |
| 227 debug_msg "Complete." |
| 228 if [ $num_signed -gt 0 -a $num_signed -le 2 ]; then |
| 229 # signed 1 or two kernels |
| 230 echo "Successfully re-signed $num_signed kernel(s) on device $FLAGS_image". |
| 231 else |
| 232 err_die "Failed re-signing kernels." |
| 233 fi |
| 234 } |
| 235 |
| 236 main |
OLD | NEW |