| OLD | NEW |
| 1 #!/bin/sh | 1 #!/bin/sh |
| 2 # | 2 # |
| 3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 # | 6 # |
| 7 # This script can change key (usually developer keys) and kernel config | 7 # This script can change key (usually developer keys) and kernel config |
| 8 # of a kernels on SSD. | 8 # of kernels on an disk image (usually for SSD but also works for USB). |
| 9 | 9 |
| 10 SCRIPT_BASE="$(dirname "$0")" | 10 SCRIPT_BASE="$(dirname "$0")" |
| 11 . "$SCRIPT_BASE/common_minimal.sh" | 11 . "$SCRIPT_BASE/common_minimal.sh" |
| 12 load_shflags || exit 1 | 12 load_shflags || exit 1 |
| 13 | 13 |
| 14 # Constants used by DEFINE_* | 14 # Constants used by DEFINE_* |
| 15 VBOOT_BASE='/usr/share/vboot' | 15 VBOOT_BASE='/usr/share/vboot' |
| 16 DEFAULT_KEYS_FOLDER="$VBOOT_BASE/devkeys" | 16 DEFAULT_KEYS_FOLDER="$VBOOT_BASE/devkeys" |
| 17 DEFAULT_BACKUP_FOLDER='/mnt/stateful_partition/backups' | 17 DEFAULT_BACKUP_FOLDER='/mnt/stateful_partition/backups' |
| 18 DEFAULT_PARTITIONS='2 4' | 18 DEFAULT_PARTITIONS='2 4' |
| 19 | 19 |
| 20 # TODO(hungte) or use "rootdev -s" in future | 20 # TODO(hungte) The default image selection is no longer a SSD, so the script |
| 21 DEFAULT_IMAGE="/dev/sda" | 21 # works more like "make_dev_image". We may change the file name in future. |
| 22 ROOTDEV="$(rootdev -s 2>/dev/null)" |
| 23 ROOTDEV_PARTITION="$(echo $ROOTDEV | sed -n 's/.*\([0-9][0-9]*\)$/\1/p')" |
| 24 ROOTDEV_DISK="${ROOTDEV%$ROOTDEV_PARTITION}" |
| 25 ROOTDEV_KERNEL="$((ROOTDEV_PARTITION - 1))" |
| 22 | 26 |
| 23 # DEFINE_string name default_value description flag | 27 # DEFINE_string name default_value description flag |
| 24 DEFINE_string image "$DEFAULT_IMAGE" "Path to device or image file" "i" | 28 DEFINE_string image "$ROOTDEV_DISK" "Path to device or image file" "i" |
| 25 DEFINE_string keys "$DEFAULT_KEYS_FOLDER" "Path to folder of dev keys" "k" | 29 DEFINE_string keys "$DEFAULT_KEYS_FOLDER" "Path to folder of dev keys" "k" |
| 26 DEFINE_boolean remove_rootfs_verification \ | 30 DEFINE_boolean remove_rootfs_verification \ |
| 27 $FLAGS_FALSE "Modify kernel boot config to disable rootfs verification" "" | 31 $FLAGS_FALSE "Modify kernel boot config to disable rootfs verification" "" |
| 28 DEFINE_string backup_dir \ | 32 DEFINE_string backup_dir \ |
| 29 "$DEFAULT_BACKUP_FOLDER" "Path of directory to store kernel backups" "" | 33 "$DEFAULT_BACKUP_FOLDER" "Path of directory to store kernel backups" "" |
| 30 DEFINE_string save_config "" \ | 34 DEFINE_string save_config "" \ |
| 31 "Base filename to store kernel configs to, instead of resigning." "" | 35 "Base filename to store kernel configs to, instead of resigning." "" |
| 32 DEFINE_string set_config "" \ | 36 DEFINE_string set_config "" \ |
| 33 "Base filename to load kernel configs from" "" | 37 "Base filename to load kernel configs from" "" |
| 34 DEFINE_string partitions "$DEFAULT_PARTITIONS" \ | 38 DEFINE_string partitions "" \ |
| 35 "List of partitions to examine" "" | 39 "List of partitions to examine (default: $DEFAULT_PARTITIONS)" "" |
| 36 DEFINE_boolean recovery_key "$FLAGS_FALSE" \ | 40 DEFINE_boolean recovery_key "$FLAGS_FALSE" \ |
| 37 "Use recovery key to sign image (to boot from USB" "" | 41 "Use recovery key to sign image (to boot from USB" "" |
| 38 DEFINE_boolean force "$FLAGS_FALSE" "Skip sanity checks and make the change" "f" | 42 DEFINE_boolean force "$FLAGS_FALSE" "Skip sanity checks and make the change" "f" |
| 39 | 43 |
| 40 # Parse command line | 44 # Parse command line |
| 41 FLAGS "$@" || exit 1 | 45 FLAGS "$@" || exit 1 |
| 42 ORIGINAL_PARAMS="$@" | 46 ORIGINAL_PARAMS="$@" |
| 43 eval set -- "$FLAGS_ARGV" | 47 eval set -- "$FLAGS_ARGV" |
| 48 ORIGINAL_PARTITIONS="$FLAGS_partitions" |
| 49 : ${FLAGS_partitions:=$DEFAULT_PARTITIONS} |
| 44 | 50 |
| 45 # Globals | 51 # Globals |
| 46 # ---------------------------------------------------------------------------- | 52 # ---------------------------------------------------------------------------- |
| 47 set -e | 53 set -e |
| 48 | 54 |
| 49 # a log file to keep the output results of executed command | 55 # a log file to keep the output results of executed command |
| 50 EXEC_LOG="$(make_temp_file)" | 56 EXEC_LOG="$(make_temp_file)" |
| 51 | 57 |
| 52 # Functions | 58 # Functions |
| 53 # ---------------------------------------------------------------------------- | 59 # ---------------------------------------------------------------------------- |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 echo "Kernel B" | 106 echo "Kernel B" |
| 101 ;; | 107 ;; |
| 102 6) | 108 6) |
| 103 echo "Kernel C" | 109 echo "Kernel C" |
| 104 ;; | 110 ;; |
| 105 *) | 111 *) |
| 106 echo "Partition $1" | 112 echo "Partition $1" |
| 107 esac | 113 esac |
| 108 } | 114 } |
| 109 | 115 |
| 116 find_valid_kernel_partitions() { |
| 117 local part_id |
| 118 local valid_partitions="" |
| 119 for part_id in $*; do |
| 120 local name="$(cros_kernel_name $part_id)" |
| 121 if [ -z "$(dump_kernel_config $FLAGS_image$part_id 2>"$EXEC_LOG")" ]; then |
| 122 echo "INFO: $name: no kernel boot information, ignored." >&2 |
| 123 else |
| 124 [ -z "$valid_partitions" ] && |
| 125 valid_partitions="$part_id" || |
| 126 valid_partitions="$valid_partitions $part_id" |
| 127 continue |
| 128 fi |
| 129 done |
| 130 debug_msg "find_valid_kernel_partitions: [$*] -> [$valid_partitions]" |
| 131 echo "$valid_partitions" |
| 132 } |
| 133 |
| 110 # Resigns a kernel on SSD or image. | 134 # Resigns a kernel on SSD or image. |
| 111 resign_ssd_kernel() { | 135 resign_ssd_kernel() { |
| 112 # bs=512 is the fixed block size for dd and cgpt | 136 # bs=512 is the fixed block size for dd and cgpt |
| 113 local bs=512 | 137 local bs=512 |
| 114 local ssd_device="$1" | 138 local ssd_device="$1" |
| 115 | 139 |
| 116 # reasonable size for current kernel partition | 140 # reasonable size for current kernel partition |
| 117 local min_kernel_size=32000 | 141 local min_kernel_size=32000 |
| 118 local max_kernel_size=65536 | 142 local max_kernel_size=65536 |
| 119 local resigned_kernels=0 | 143 local resigned_kernels=0 |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 debug_msg "Writing $name to partition $kernel_index" | 252 debug_msg "Writing $name to partition $kernel_index" |
| 229 mydd \ | 253 mydd \ |
| 230 if="$new_kern" \ | 254 if="$new_kern" \ |
| 231 of="$ssd_device" \ | 255 of="$ssd_device" \ |
| 232 seek=$offset \ | 256 seek=$offset \ |
| 233 bs=$bs \ | 257 bs=$bs \ |
| 234 count=$size \ | 258 count=$size \ |
| 235 conv=notrunc | 259 conv=notrunc |
| 236 resigned_kernels=$(($resigned_kernels + 1)) | 260 resigned_kernels=$(($resigned_kernels + 1)) |
| 237 | 261 |
| 238 debug_msg "Make the root filesystem writable if needed." | 262 debug_msg "Make the root file system writable if needed." |
| 239 # TODO(hungte) for safety concern, a more robust way would be to: | 263 # TODO(hungte) for safety concern, a more robust way would be to: |
| 240 # (1) change kernel config to ro | 264 # (1) change kernel config to ro |
| 241 # (2) check if we can enable rw mount | 265 # (2) check if we can enable rw mount |
| 242 # (3) change kernel config to rw | 266 # (3) change kernel config to rw |
| 243 if [ ${FLAGS_remove_rootfs_verification} = $FLAGS_TRUE ]; then | 267 if [ ${FLAGS_remove_rootfs_verification} = $FLAGS_TRUE ]; then |
| 244 local root_offset_sector=$(partoffset "$ssd_device" $rootfs_index) | 268 local root_offset_sector=$(partoffset "$ssd_device" $rootfs_index) |
| 245 local root_offset_bytes=$((root_offset_sector * 512)) | 269 local root_offset_bytes=$((root_offset_sector * 512)) |
| 246 if ! is_ext2 "$ssd_device" "$root_offset_bytes"; then | 270 if ! is_ext2 "$ssd_device" "$root_offset_bytes"; then |
| 247 debug_msg "Non-ext2 partition: $ssd_device$rootfs_index, skip." | 271 debug_msg "Non-ext2 partition: $ssd_device$rootfs_index, skip." |
| 248 elif ! rw_mount_disabled "$ssd_device" "$root_offset_bytes"; then | 272 elif ! rw_mount_disabled "$ssd_device" "$root_offset_bytes"; then |
| (...skipping 17 matching lines...) Expand all Loading... |
| 266 | 290 |
| 267 # If we saved the kernel config, exit now so we don't print an error | 291 # If we saved the kernel config, exit now so we don't print an error |
| 268 if [ -n "${FLAGS_save_config}" ]; then | 292 if [ -n "${FLAGS_save_config}" ]; then |
| 269 echo "(Kernels have not been resigned.)" | 293 echo "(Kernels have not been resigned.)" |
| 270 exit 0 | 294 exit 0 |
| 271 fi | 295 fi |
| 272 | 296 |
| 273 return $resigned_kernels | 297 return $resigned_kernels |
| 274 } | 298 } |
| 275 | 299 |
| 300 sanity_check_live_partitions() { |
| 301 debug_msg "Partition sanity check" |
| 302 if [ "$FLAGS_partitions" = "$ROOTDEV_KERNEL" ]; then |
| 303 debug_msg "only for current active partition - safe." |
| 304 return |
| 305 fi |
| 306 if [ "$ORIGINAL_PARTITIONS" != "" ]; then |
| 307 debug_msg "user has assigned partitions - provide more info." |
| 308 echo "INFO: Making change to $FLAGS_partitions on $FLAGS_image." |
| 309 return |
| 310 fi |
| 311 echo " |
| 312 ERROR: YOU ARE TRYING TO MODIFY THE LIVE SYSTEM IMAGE $FLAGS_image. |
| 313 |
| 314 The system may become unusable after that change, especially when you have |
| 315 some auto updates in progress. To make it safer, we suggest you to only |
| 316 change the partition you have booted with. To do that, re-execute this command |
| 317 as: |
| 318 |
| 319 sudo ./make_dev_ssd.sh $ORIGINAL_PARAMS --partitions $ROOTDEV_KERNEL |
| 320 |
| 321 If you are sure to modify other partition, please invoke the command again and |
| 322 explicitly assign only one target partition for each time (--partitions N ) |
| 323 " |
| 324 return $FLAGS_FALSE |
| 325 } |
| 326 |
| 327 sanity_check_live_firmware() { |
| 328 debug_msg "Firmware compatibility sanity check" |
| 329 if [ "$(crossystem mainfw_type)" = "developer" ]; then |
| 330 debug_msg "developer type firmware in active." |
| 331 return |
| 332 fi |
| 333 debug_msg "Loading firmware to check root key..." |
| 334 local bios_image="$(make_temp_file)" |
| 335 local rootkey_file="$(make_temp_file)" |
| 336 echo "INFO: checking system firmware..." |
| 337 sudo flashrom -p internal:bus=spi -i GBB -r "$bios_image" >/dev/null 2>&1 |
| 338 gbb_utility -g --rootkey="$rootkey_file" "$bios_image" >/dev/null 2>&1 |
| 339 if [ ! -s "$rootkey_file" ]; then |
| 340 debug_msg "failed to read root key from system firmware..." |
| 341 else |
| 342 # The magic 130 is counted by "od dev-rootkey" for the lines until the body |
| 343 # of key is reached. Trailing bytes (0x00 or 0xFF - both may appear, and |
| 344 # that's why we need to skip them) are started at line 131. |
| 345 # TODO(hungte) compare with rootkey in $VBOOT_BASE directly. |
| 346 local rootkey_hash="$(od "$rootkey_file" | |
| 347 head -130 | md5sum | |
| 348 sed 's/ .*$//' )" |
| 349 if [ "$rootkey_hash" = "a13642246ef93daaf75bd791446fec9b" ]; then |
| 350 debug_msg "detected DEV root key in firmware." |
| 351 return |
| 352 else |
| 353 debug_msg "non-devkey hash: $rootkey_hash" |
| 354 fi |
| 355 fi |
| 356 |
| 357 echo " |
| 358 ERROR: YOU ARE NOT USING DEVELOPER FIRMWARE, AND RUNNING THIS COMMAND MAY |
| 359 THROW YOUR CHROMEOS DEVICE INTO UN-BOOTABLE STATE. |
| 360 |
| 361 You need to either install developer firmware, or change system root key. |
| 362 |
| 363 - To install developer firmware: type command |
| 364 sudo chromeos-firmwareupdate --mode=todev |
| 365 |
| 366 - To change system rootkey: disable firmware write protection (a hardware |
| 367 switch) and then type command: |
| 368 sudo ./make_dev_firmware.sh |
| 369 |
| 370 If you are sure that you want to make such image without developer |
| 371 firmware or you've already changed system root keys, please run this |
| 372 command again with --force paramemeter: |
| 373 |
| 374 sudo ./make_dev_ssd.sh --force $ORIGINAL_PARAMS |
| 375 " |
| 376 return $FLAGS_FALSE |
| 377 } |
| 378 |
| 276 # Main | 379 # Main |
| 277 # ---------------------------------------------------------------------------- | 380 # ---------------------------------------------------------------------------- |
| 278 main() { | 381 main() { |
| 279 local num_signed=0 | 382 local num_signed=0 |
| 280 local num_given=$(echo "$FLAGS_partitions" | wc -w) | 383 local num_given=$(echo "$FLAGS_partitions" | wc -w) |
| 281 # Check parameters | 384 # Check parameters |
| 282 if [ "$FLAGS_recovery_key" = "$FLAGS_TRUE" ]; then | 385 if [ "$FLAGS_recovery_key" = "$FLAGS_TRUE" ]; then |
| 283 KERNEL_KEYBLOCK="$FLAGS_keys/recovery_kernel.keyblock" | 386 KERNEL_KEYBLOCK="$FLAGS_keys/recovery_kernel.keyblock" |
| 284 KERNEL_DATAKEY="$FLAGS_keys/recovery_kernel_data_key.vbprivk" | 387 KERNEL_DATAKEY="$FLAGS_keys/recovery_kernel_data_key.vbprivk" |
| 285 KERNEL_PUBKEY="$FLAGS_keys/recovery_key.vbpubk" | 388 KERNEL_PUBKEY="$FLAGS_keys/recovery_key.vbpubk" |
| 286 else | 389 else |
| 287 KERNEL_KEYBLOCK="$FLAGS_keys/kernel.keyblock" | 390 KERNEL_KEYBLOCK="$FLAGS_keys/kernel.keyblock" |
| 288 KERNEL_DATAKEY="$FLAGS_keys/kernel_data_key.vbprivk" | 391 KERNEL_DATAKEY="$FLAGS_keys/kernel_data_key.vbprivk" |
| 289 KERNEL_PUBKEY="$FLAGS_keys/kernel_subkey.vbpubk" | 392 KERNEL_PUBKEY="$FLAGS_keys/kernel_subkey.vbpubk" |
| 290 fi | 393 fi |
| 291 | 394 |
| 292 debug_msg "Prerequisite check" | 395 debug_msg "Prerequisite check" |
| 293 ensure_files_exist \ | 396 ensure_files_exist \ |
| 294 "$KERNEL_KEYBLOCK" \ | 397 "$KERNEL_KEYBLOCK" \ |
| 295 "$KERNEL_DATAKEY" \ | 398 "$KERNEL_DATAKEY" \ |
| 296 "$KERNEL_PUBKEY" \ | 399 "$KERNEL_PUBKEY" \ |
| 297 "$FLAGS_image" || | 400 "$FLAGS_image" || |
| 298 exit 1 | 401 exit 1 |
| 299 | 402 |
| 300 debug_msg "Firmware compatibility sanity check" | 403 # checks for running on a live system image. |
| 301 if [ "$FLAGS_force" = "$FLAGS_FALSE" ] && | 404 if [ "$FLAGS_image" = "$ROOTDEV_DISK" ]; then |
| 302 [ "$FLAGS_image" = "$DEFAULT_IMAGE" ] && | 405 debug_msg "check valid kernel partitions for live system" |
| 303 [ "$(crossystem mainfw_type)" != "developer" ]; then | 406 local valid_partitions="$(find_valid_kernel_partitions $FLAGS_partitions)" |
| 407 [ -n "$valid_partitions" ] || |
| 408 err_die "No valid kernel partitions on $FLAGS_image ($FLAGS_partitions)." |
| 409 FLAGS_partitions="$valid_partitions" |
| 304 | 410 |
| 305 # TODO(hungte) we can check if the fimware rootkey is already dev keys." | 411 # Sanity checks |
| 412 if [ "$FLAGS_force" = "$FLAGS_TRUE" ]; then |
| 306 echo " | 413 echo " |
| 307 ERROR: YOU ARE NOT USING DEVELOPER FIRMWARE, AND RUNNING THIS COMMAND MAY | 414 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
| 308 THROW YOUR CHROMEOS DEVICE INTO UNBOOTABLE STATE. | 415 ! INFO: ALL SANITY CHECKS WERE BYPASSED. YOU ARE ON YOUR OWN. ! |
| 309 | 416 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
| 310 You need to either install developer firmware, or change system rootkey. | 417 " >&2 |
| 311 | 418 local i |
| 312 - To install developer firmware: type command | 419 for i in $(seq 5 -1 1); do |
| 313 sudo chromeos-firmwareupdate --mode=todev | 420 echo -n "\rStart in $i second(s) (^C to abort)... " >&2 |
| 314 | 421 sleep 1 |
| 315 - To change system rootkey: disable firmware write protection (a hardware | 422 done |
| 316 switch) and then type command: | 423 echo "" |
| 317 sudo ./make_dev_firmware.sh | 424 elif ! sanity_check_live_firmware || |
| 318 | 425 ! sanity_check_live_partitions; then |
| 319 If you are sure that you want to make such image without developer | 426 err_die "IMAGE $FLAGS_image IS NOT MODIFIED." |
| 320 firmware or you've already changed system root keys, please run this | 427 fi |
| 321 command again with --force param: | |
| 322 | |
| 323 sudo ./make_dev_ssd.sh --force $ORIGINAL_PARAMS | |
| 324 | |
| 325 YOUR IMAGE $FLAGS_image IS NOT MODIFIED. | |
| 326 " | |
| 327 exit 1 | |
| 328 fi | 428 fi |
| 329 | 429 |
| 330 resign_ssd_kernel "$FLAGS_image" || num_signed=$? | 430 resign_ssd_kernel "$FLAGS_image" || num_signed=$? |
| 331 | 431 |
| 332 debug_msg "Complete." | 432 debug_msg "Complete." |
| 333 if [ $num_signed -gt 0 -a $num_signed -le $num_given ]; then | 433 if [ $num_signed -gt 0 -a $num_signed -le $num_given ]; then |
| 334 # signed something at least | 434 # signed something at least |
| 335 echo "Successfully re-signed $num_signed of $num_given kernel(s)" \ | 435 echo "Successfully re-signed $num_signed of $num_given kernel(s)" \ |
| 336 " on device $FLAGS_image". | 436 " on device $FLAGS_image". |
| 337 else | 437 else |
| 338 err_die "Failed re-signing kernels." | 438 err_die "Failed re-signing kernels." |
| 339 fi | 439 fi |
| 340 } | 440 } |
| 341 | 441 |
| 342 # People using this to process images may forget to add "-i", | 442 # People using this to process images may forget to add "-i", |
| 343 # so adding parameter check is safer. | 443 # so adding parameter check is safer. |
| 344 if [ "$#" -gt 0 ]; then | 444 if [ "$#" -gt 0 ]; then |
| 345 flags_help | 445 flags_help |
| 346 err_die "Unknown parameters: $@" | 446 err_die "Unknown parameters: $@" |
| 347 fi | 447 fi |
| 348 | 448 |
| 349 main | 449 main |
| OLD | NEW |