Advertisement
Guest User

Chrome Recovery Script

a guest
Jan 11th, 2017
939
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 21.29 KB | None | 0 0
  1. # Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. #
  5. # This consists of functions sourced by the /init script and used
  6. # exclusively for recovery images.  Note that this code uses the
  7. # busybox shell (not bash, not dash).
  8.  
  9. # Include disk information.
  10. . /usr/sbin/write_gpt.sh
  11.  
  12. # Starting kernel rollback version.
  13. KERNEL_VER_MIN=0x10001
  14. # TPM NVRAM index where the rollback kernel version is stored.
  15. KERNEL_VER_TPM_NV_SPACE=0x1008
  16. # TPM NVRAM index for the lockbox.
  17. LOCKBOX_TPM_NV_SPACE=0x20000004
  18. # Where chromeos-install will store any related hardware diagnostics data.
  19. LOG_HARDWARE_DIAGNOSTICS=hardware_diagnostics.log
  20.  
  21.  
  22. # Installation Target.
  23. #  DST_DEV_BASE: A device path for concatenate partition number.
  24. #                Sample: /dev/mmcblk0p /dev/sda
  25. #                Usage: "${DST_DEV_BASE}${PART_NUM}"
  26. #  DST: A device path for the block device itself (similar to rootdev -d).
  27. #                Sample: /dev/mmcblk0 /dev/sda
  28. DST_DEV_BASE=
  29. DST=
  30.  
  31.  
  32. # Error codes used as return code by functions to indicate installation
  33. # should be aborted for the corresponding reason.
  34.  
  35. # Indicates a failure validating the kernel.
  36. ERR_INVALID_INSTALL_KERNEL=2
  37.  
  38. # The image failed validation on a device with block_devmode=1.
  39. ERR_DEV_MODE_BLOCKED=3
  40.  
  41.  
  42. # Check whether the device owner has configured the device to block
  43. # developer mode.  Note that the check works regardless of whether the
  44. # device is currently booted in developer mode or not.
  45. #
  46. # This check is used to enforce the block_devmode flag.  The regular boot
  47. # path checks the flag in chromeos_startup, which resides in the root.
  48. # Hence, only official kernels and roots that are guaranteed to perform the
  49. # check can be allowed to be installed - otherwise developer mode blocking
  50. # is easily circumvented by installing an unofficial kernel or root that
  51. # doesn't perform the block_devmode check.
  52. is_developer_mode_blocked() {
  53.   # The device should refuse operation in developer mode if the device
  54.   # owner has flipped the block_devmode flag to 1.  We still block
  55.   # even if firmware write protection is disabled, because removing a
  56.   # screw is simpler than hooking up a different disk or using a
  57.   # dediprog to reprogram the flash directly.
  58.   crossystem block_devmode?1
  59. }
  60.  
  61. # Verifies the recovery root by reading all blocks of the dm-verity
  62. # block device.  Return code indicates whether verification succeeded.
  63. verify_recovery_root() {
  64.   local usb_base=$(basename "$USB_DEV")
  65.   local size=$(( 512 * $(cat /sys/block/$usb_base/size) ))
  66.  
  67.   # Ensure the verified rootfs is fully intact or fail with no USB_DEV.
  68.   # REAL_USB_DEV is left intact.
  69.   #
  70.   # Correctness wins over speed for this.  Correctness also wins
  71.   # over readability.  :-(
  72.   #
  73.   # High level summary:  The 'pv -n' command copies bytes from stdin
  74.   # to stdout, and periodically prints *to stderr* the amount read
  75.   # as a percentage of the size in the '-s' option.  The pipeline
  76.   # redirects the stderr from 'pv' into stdin of 'progress_bar'.
  77.   # This usage is covered in the pv(1) man page, which rightly warns
  78.   # that "it may cause the programmer to overheat."
  79.   (
  80.     # The 'set -x' output goes to stderr, which would become input
  81.     # to 'progress_bar', below.  Turn it off in a subshell so as not
  82.     # to affect the main process.
  83.     set +x
  84.     (
  85.       (
  86.         # This 'dd' is the actual validation.  We must capture the
  87.         # exit code in order to figure out whether it passed or not.
  88.         dd if="$USB_DEV" bs=$((16 * 1024 * 1024)) 2>/dev/null
  89.         echo $? >/tmp/verification_status
  90.       ) | pv -n -s $size >/dev/null
  91.     ) 2>&1 | ( set -x ; progress_bar ) >$LOG_DIR/progress.log 2>&1
  92.   )
  93.   if [ "$(cat /tmp/verification_status)" != "0" ]; then
  94.     dlog "Included root filesystem could not be verified."
  95.     return 1
  96.   fi
  97.   return 0
  98. }
  99.  
  100. # Checks that we have a valid recovery root before handing it off to the
  101. # installer.
  102. validate_recovery_root() {
  103.   # Allow test recovery roots that are unverified unless developer mode
  104.   # is blocked by the device owner.
  105.   if [ "$USB_DEV" != "/dev/dm-0" ] || is_unofficial_root; then
  106.     is_developer_mode_blocked && return $ERR_DEV_MODE_BLOCKED
  107.     return 0
  108.   fi
  109.  
  110.   # Perform a full device mapper root validation to avoid any unexpected
  111.   # failures during postinst.  It also allows us to detect if the root
  112.   # is intentionally mismatched - such as during Chromium OS recovery
  113.   # with a Chrome OS recovery kernel.
  114.   verify_recovery_root && return 0
  115.  
  116.   # Verification failed. Only proceed in developer mode.
  117.   is_developer_mode || return 1
  118.  
  119.   # If developer mode is blocked, don't allow an unverified root.
  120.   is_developer_mode_blocked && return $ERR_DEV_MODE_BLOCKED
  121.  
  122.   # The root we just mounted looked like an official recovery image, but
  123.   # it didn't pass validation.  Try to fall back to installing a
  124.   # developer image.
  125.   umount "${USB_MNT}"
  126.   dmsetup remove "$DM_NAME"  # Free up the real root for use.
  127.   USB_DEV=
  128.  
  129.   find_developer_root || return 1
  130.   get_stateful_dev || return 1
  131.  
  132.   message developer_image
  133.  
  134.   return 0
  135. }
  136.  
  137. get_dst() {
  138.   load_base_vars
  139.   DST="$(get_fixed_dst_drive)"
  140.   if [ -z "${DST}" ]; then
  141.     dlog "SSD for installation not specified"
  142.     return 1
  143.   fi
  144.   if [ "${DST%[0-9]}" = "${DST}" ]; then
  145.     # ex, sda => sda1, sdb1
  146.     DST_DEV_BASE="${DST}"
  147.   else
  148.     # ex, mmcblk0 => mmcblk0p1
  149.     DST_DEV_BASE="${DST}p"
  150.   fi
  151.   local src_dev_base="${REAL_USB_DEV%[0-9]*}"
  152.   if [ "${src_dev_base}" = "${DST_DEV_BASE}" ]; then
  153.     dlog "Cannot find SSD for installation."
  154.     return 1
  155.   fi
  156.   SRC_DEV_BASE="${src_dev_base}"
  157. }
  158.  
  159. # Checks whether a given key block is also a valid key block used to
  160. # sign a kernel currently installed on the destination block device.
  161. check_install_kernel_key_match() {
  162.   dlogf "Searching the system disk for a matching kernel key . . ."
  163.   if ! cgpt find -t kernel -M "$1" "$DST"; then
  164.     dlog " failed."
  165.     return 1
  166.   fi
  167.   dlog " found."
  168.  
  169.   dlogf "Validating matching signature(s) . . ."
  170.   # If we found a keyblock, at the right offset, make sure it actually signed
  171.   # the subsequent payload.
  172.   local kdev=
  173.   for kdev in $(cgpt find -t kernel -M "$1" "${DST}"); do
  174.     dlogf " ."
  175.     verify_kernel_signature "$kdev" "/tmp/kern.keyblock" || continue
  176.     dlog " done."
  177.     return 0
  178.   done
  179.  
  180.   dlog " failed."
  181.   return 1
  182. }
  183.  
  184. # Get the kernel version by directly reading the TPM NVRAM spaces.
  185. # Needed when crossystem doesn't work (e.g. Mario systems).
  186. get_kernelver_from_tpmc () {
  187.   set -- $(tpmc read $KERNEL_VER_TPM_NV_SPACE 9)
  188.   # Example output:
  189.   #
  190.   # 1 4c 57 52 47 1 0 1 0
  191.   #
  192.   # The first 5 bytes of the output are a canary value and can be
  193.   # ignored. The full kernel version is stored as a 32-bit integer
  194.   # in little endian format.
  195.   echo "$(( $9 << 24 | $8 << 16 | $7 << 8 | $6 ))"
  196. }
  197.  
  198. verify_kernel_signature() {
  199.   local kern_dev="$1"
  200.   local keyblock="$2"
  201.  
  202.   if ! dd if="$kern_dev" of="/tmp/kern.bin"; then
  203.     return 1
  204.   fi
  205.  
  206.   # Validates the signature and outputs a keyblock.
  207.   if ! vbutil_kernel --verify "/tmp/kern.bin" \
  208.                      --keyblock "$keyblock"; then
  209.     return 1
  210.   fi
  211.   return 0
  212. }
  213.  
  214. verify_kernel_version() {
  215.   local kern_dev="$1"
  216.   local minversion="$KERNEL_VER_MIN"
  217.  
  218.   if ! dd if="$kern_dev" of="/tmp/kern.bin"; then
  219.     return 1
  220.   fi
  221.  
  222.   # Get the currently set TPM NVRAM rollback versions.
  223.   minversion=$(crossystem tpm_kernver || get_kernelver_from_tpmc)
  224.   dlog "Rollback version stored in the TPM: $minversion"
  225.  
  226.   # Validate the signature and rollback versions.
  227.   if ! vbutil_kernel --verify "/tmp/kern.bin" --minversion "$minversion"; then
  228.     return 1
  229.   fi
  230.   return 0
  231. }
  232.  
  233. verify_install_kernel() {
  234.   # TODO(wad) check signatures from stateful on kern b using the
  235.   #           root of trust instead of using a baked in cmdline.
  236.   if [ "$REAL_KERN_B_HASH" != "$KERN_ARG_KERN_B_HASH" ]; then
  237.     # Assertion: we have to be in developer mode; this was verified in the
  238.     # course of the general init process.
  239.     is_developer_mode || return 1
  240.  
  241.     # Only allow verified kernels when developer mode blocking is on.
  242.     is_developer_mode_blocked && return $ERR_DEV_MODE_BLOCKED
  243.  
  244.     message developer_image
  245.  
  246.     # Extract the kernel so that vbutil_kernel will happily consume it.
  247.     dlog "Checking the install kernel for a valid developer signature . . ."
  248.     verify_kernel_signature "$KERN_B_DEV" "/tmp/kern_b.keyblock" || return 1
  249.     check_install_kernel_key_match /tmp/kern_b.keyblock || message key_change
  250.     return 0
  251.   fi
  252.  
  253.   # Looks like we have an official recovery image. Check for version rollback.
  254.   dlog "Checking the install kernel for valid versions and signature . . ."
  255.   if ! verify_kernel_version "$KERN_B_DEV"; then
  256.     # Rollback version check failure is fatal if we are not in developer mode.
  257.     is_developer_mode || return $ERR_INVALID_INSTALL_KERNEL
  258.  
  259.     # Don't allow version downgrades when developer mode blocking is on.
  260.     is_developer_mode_blocked && return $ERR_DEV_MODE_BLOCKED
  261.  
  262.     message warn_invalid_install_kernel
  263.   fi
  264.  
  265.   return 0
  266. }
  267.  
  268. setup_install_mounts() {
  269.   mount -t tmpfs -o mode=1777 none "${USB_MNT}/tmp" || return 1
  270.   mount -t tmpfs -o mode=0755 run "${USB_MNT}/run" || return 1
  271.   mkdir -p -m 0755 "${USB_MNT}/run/lock" || return 1
  272.  
  273.   dlog "Re-binding $BASE_MOUNTS for $NEWROOT_MNT"
  274.   for mnt in $BASE_MOUNTS; do
  275.     # $mnt is a full path (leading '/'), so no '/' joiner
  276.     mkdir -p "$NEWROOT_MNT$mnt"
  277.     mount -n -o bind "$mnt" "$NEWROOT_MNT$mnt" || return 1
  278.   done
  279.   dlog "Done."
  280.   return 0
  281. }
  282.  
  283. cleanup_install_mounts() {
  284.   dlog "Unmounting $BASE_MOUNTS in $NEWROOT_MNT"
  285.   for mnt in $BASE_MOUNTS; do
  286.     # $mnt is a full path (leading '/'), so no '/' joiner
  287.     umount "$NEWROOT_MNT$mnt"
  288.   done
  289.   dlog "Done."
  290.   umount "${USB_MNT}/run"
  291.   umount "${USB_MNT}/tmp"
  292.   return 0
  293. }
  294.  
  295. call_image_recovery_script() {
  296.   setup_install_mounts || return 1
  297.  
  298.   dlog "Installing software; this will take some time."
  299.   dlog "See the debug log on VT3 for the full output."
  300.  
  301.   # Prevent accidentally loading modules from the usb mount
  302.   echo 1 >/proc/sys/kernel/modules_disabled
  303.  
  304.   chroot "${USB_MNT}" /usr/sbin/chromeos-recovery "$1"
  305.   local install_status=$?
  306.   if [  $install_status -ne 0 ]; then
  307.     dlog "WARNING!!! Installation of software failed. Displaying hw diagnostics"
  308.     local diagnostics_file="${USB_MNT}/tmp/$LOG_HARDWARE_DIAGNOSTICS"
  309.     if [ -f "$diagnostics_file" ]; then
  310.       cp "$diagnostics_file" "$LOG_DIR"
  311.       dlog \
  312. "============================ HARDWARE DIAGNOSTICS =========================="
  313.       dlog $(cat "$diagnostics_file")
  314.       dlog "See recovery log for more information."
  315.       dlog \
  316. "============================================================================"
  317.       dlog
  318.     else
  319.       dlog "Missing hardware diagnostics."
  320.     fi
  321.   fi
  322.  
  323.   # No error check here:  Clean up doesn't need to be successful.
  324.   cleanup_install_mounts
  325.  
  326.   return $install_status
  327. }
  328.  
  329. clobber_lockbox_space() {
  330.   # Clobber the lockbox space, by defining a new space at the same index.
  331.   # Protection flags and size of the new space don't matter, as it will get
  332.   # recreated again by cryptohome.
  333.   local ppwrite_permission=0x1
  334.   local temporary_lockbox_size=1
  335.   tpmc def $LOCKBOX_TPM_NV_SPACE $temporary_lockbox_size $ppwrite_permission
  336. }
  337.  
  338. clear_tpm() {
  339.   dlogf "Resetting security device . . ."
  340.   # TODO(wad) should we fail on this?
  341.   tpmc ppon || dlog "tpmc ppon error: $?"
  342.   tpmc clear || dlog "tpmc clear error: $?"
  343.   tpmc enable || dlog "tpmc enable error: $?"
  344.   tpmc activate || dlog "tpmc activate error: $?"
  345.   clobber_lockbox_space || dlog "error clobbering lockbox space: $?"
  346.   tpmc pplock || dlog "tpmc pplock error: $?"
  347.   dlog " done."
  348.   return 0
  349. }
  350.  
  351. verify_rw_vpd() {
  352.   local tmpfile="$(mktemp ${TMPDIR:-/tmp}/rw_vpd.XXXXXX)"
  353.   local rc=0
  354.  
  355.   dlog "Verifying RW_VPD"
  356.  
  357.   # First method: Check if RW VPD entries have been populated in sysfs by the
  358.   # kernel. If so, assume everything is good. Otherwise fall back to using
  359.   # flashrom and vpd utilities (slower).
  360.   ls -1A "/sys/firmware/vpd/rw" | grep -q .
  361.   if [ $? -eq 0 ]; then
  362.     dlog "Found RW VPD in sysfs."
  363.     return 0
  364.   fi
  365.  
  366.   # Test if RW_VPD region exists on system by attempting to read it
  367.   # using flashrom.
  368.   flashrom -p host -i RW_VPD:${tmpfile} -r
  369.   if [ $? -ne 0 ]; then
  370.     dlog "RW_VPD does not exist on this system, skipping."
  371.     return 0
  372.   else
  373.     rm -f "${tmpfile}"
  374.   fi
  375.  
  376.   # vpd utility exit codes defined in vpd/include/lib/lib_vpd.h:
  377.   # 0:  VPD_OK
  378.   # 9:  VPD_ERR_NOT_FOUND, meaning VPD was not found.
  379.   # 10: VPD_ERR_OVERFLOW, meaning VPD is likely corrupt.
  380.   # 11: VPD_ERR_INVALID, meaning VPD is corrupt.
  381.   #
  382.   # All others will be treated as generic failures.
  383.   vpd -i RW_VPD -l
  384.   rc=$?
  385.   case $rc in
  386.     0)
  387.       dlog "Successfully read VPD from RW_VPD."
  388.       return 0
  389.       ;;
  390.     9)
  391.       dlog "VPD not found in RW_VPD."
  392.       ;;
  393.     10)
  394.       dlog "Overflow detected in VPD. May be corrupted."
  395.       ;;
  396.     11)
  397.       dlog "VPD found in RW_VPD, but is corrupted."
  398.       ;;
  399.     *)
  400.       dlog "Unspecified error when reading VPD from RW_VPD: $rc"
  401.       return 1
  402.   esac
  403.  
  404.   # From here, erase the RW_VPD region and re-initialize. If erase fails then
  405.   # try initializing anyway and hope it works well enough.
  406.   dlog "Erasing RW_VPD region and re-initializing the VPD."
  407.  
  408.   flashrom -p host -i RW_VPD -E
  409.   if [ $? -ne 0 ]; then
  410.     dlog "Failed to erase RW_VPD region, continuing anyway."
  411.   fi
  412.  
  413.   vpd -i RW_VPD -O
  414.   rc=$?
  415.   if [ $rc -ne 0 ]; then
  416.     dlog "Error re-formatting VPD region: $rc"
  417.     return 1
  418.   fi
  419.  
  420.   return 0
  421. }
  422.  
  423. recover_system() {
  424.   local source=$(strip_partition "$REAL_USB_DEV")
  425.   dlog "Beginning system recovery from $source"
  426.  
  427.   # If we're not running a developer script then we're either
  428.   # installing a developer image or an official one. If we're
  429.   # in normal recovery mode, then we require that the KERN-B
  430.   # on the recovery image matches the hash on the command line.
  431.   # In developer mode, we will just check the keys.
  432.   verify_install_kernel || return $?
  433.  
  434.   # Only clear on full installs. Shim scripts can call tpmc if they
  435.   # like.  Only bGlobalLock will be in place in advance.
  436.   clear_tpm || return 1
  437.  
  438.   # Check if RW_VPD is valid and reinitialize if not. This is intended to
  439.   # ensure certain functionality such as re-enrollment works. Refer to
  440.   # crbug.com/660121 for details.
  441.   verify_rw_vpd || dlog "Could not verify or re-format RW_VPD"
  442.  
  443.   message recovery_start
  444.  
  445.   call_image_recovery_script "$source" || return 1
  446.  
  447.   return 0
  448. }
  449.  
  450. # Return the path to the node under /sys/block associated with
  451. # the USB stick.  The existence of that path is used to test whether
  452. # the user has removed the stick and we can reboot.
  453. #
  454. # For certain non-interactive test cases, the stateful partition on
  455. # the USB stick may be flagged to request that we bypass the
  456. # interactive removal of the USB stick.  If we detect that
  457. # condition, we signal it by returning an empty string instead
  458. # of a path.
  459. get_usb_node_dir() {
  460.   local usb_node_dir=/sys/block/$(strip_partition "${REAL_USB_DEV##*/}")
  461.   if [ "$INTERACTIVE_COMPLETE" = false ]; then
  462.     usb_node_dir=""
  463.   elif mount -n -o sync,rw "${REAL_USB_DEV%[0-9]*}1" /tmp; then
  464.     if [ -f /tmp/non_interactive ]; then
  465.       usb_node_dir=""
  466.     fi
  467.     umount /tmp
  468.   fi
  469.   echo "$usb_node_dir"
  470. }
  471.  
  472. get_usb_debugging_flag() {
  473.   local decrypt=""
  474.   if get_stateful_dev && mount -n -o sync,ro "${STATE_DEV}" /tmp; then
  475.     if [ -f /tmp/decrypt_stateful ]; then
  476.       decrypt=$(cat /tmp/decrypt_stateful)
  477.     fi
  478.     umount /tmp
  479.   fi
  480.   echo "$decrypt"
  481. }
  482.  
  483. maybe_get_debugging_logs() {
  484.   local state=$(get_usb_debugging_flag)
  485.   if [ -z "$state" ]; then
  486.     return 0
  487.   fi
  488.   log "Stateful recovery requested."
  489.  
  490.   dlog "Attempting to find the destination stateful . . ."
  491.   get_dst || return 0
  492.  
  493.   log "Please wait (this may take up to 2 and a half minutes). . ."
  494.   sleep 150  # Five minutes in half.
  495.   if ! mount -n -o sync,rw "${DST_DEV_BASE}1" "${STATEFUL_MNT}"; then
  496.     log "Unable to perform stateful recovery."
  497.     dlog "mount failed for ${DST_DEV_BASE}1"
  498.     sleep 1d
  499.     reboot -f
  500.   fi
  501.  
  502.   local flagfile="${STATEFUL_MNT}/decrypt_stateful"
  503.   local decrypted_dir="${STATEFUL_MNT}/decrypted"
  504.   local tarball_dir="/tmp/recovery"
  505.   local tarball="${tarball_dir}/extracted.tgz"
  506.   # Check if the files exist already or if recovery needs to be requested.
  507.   if [ -f "$flagfile" ] && [ ! -d "$decrypted_dir" ]; then
  508.     log "Prior recovery request incomplete. Starting over . . ."
  509.   fi
  510.   if [ -f "$flagfile" ] && [ -d "$decrypted_dir" ]; then
  511.     log "Prior recovery request exists. Attempting to extract files."
  512.     if ! mount -n -o sync,rw "${STATE_DEV}" /tmp 2>"${TTY_LOG}"; then
  513.       log "Failed to mount recovery stateful partition."
  514.       on_error
  515.     fi
  516.     mkdir -p "$tarball_dir" || on_error
  517.     log "Copying files . . ."
  518.     # Due to the tty redirection that this script runs under, without the
  519.     # explicit stdin and stdout redirects, tar will fail with "Broken pipe".
  520.     if ! tar -czf "${tarball}" -C "${STATEFUL_MNT}" \
  521.          --exclude './decrypt_stateful' \
  522.          --exclude './encrypted*' \
  523.          --exclude './home/.shadow/*/*' \
  524.          --exclude './dev_image' \
  525.          . >"${TTY_LOG}" 2>"${TTY_LOG}" </dev/null ; then
  526.       log "Extraction failed. See debug log for more details."
  527.       crossystem recovery_request=1
  528.       umount /tmp
  529.       umount "${STATEFUL_MNT}"
  530.       on_error
  531.     fi
  532.     log "Removing the request file and old data . . ."
  533.     rm -f "${flagfile}"
  534.     rm -rf "${decrypted_dir}"
  535.     umount /tmp
  536.     umount "${STATEFUL_MNT}"
  537.     log "Operation complete, you can now remove your recovery media."
  538.     log "The requested data can be found in the /recovery folder."
  539.     sleep 1d
  540.     reboot -f
  541.   fi
  542.  
  543.   log "Stateful recovery requires authentication."
  544.   log "Your username and salted password will be temporarily written to the"
  545.   log "device for the duration of this recovery process. Once finished,"
  546.   log "please be sure to change your password as a precautionary measure."
  547.  
  548.   local username
  549.   read -p Username: username <"${TTY_CONSOLE}" 2>"${TTY_CONSOLE}"
  550.  
  551.   if [ -n "${username}" ]; then
  552.     local password
  553.     read -p Password: -s password <"${TTY_CONSOLE}" 2>"${TTY_CONSOLE}"
  554.     # Force a newline for sane output after silent input.
  555.     echo "" >"${TTY_CONSOLE}"
  556.  
  557.     local saltfile="${STATEFUL_MNT}"/home/.shadow/salt
  558.     if [ ! -f "${saltfile}" ]; then
  559.       log "Target has no system salt file. Giving up."
  560.       sleep 1d
  561.       reboot -f
  562.     fi
  563.  
  564.     local salt=$(hexdump -v -e '/1 "%02x"' <"$saltfile")
  565.     local passkey=$(echo -n "${salt}${password}" | sha256sum | cut -c-32)
  566.  
  567.     log "Installing v2 request file . . ."
  568.     cat > "${flagfile}" <<EOM
  569. 2
  570. $username
  571. $passkey
  572. EOM
  573.   else
  574.     log "Installing v1 request file . . ."
  575.     echo -n "1" > "${flagfile}"
  576.   fi
  577.   umount "${STATEFUL_MNT}"
  578.  
  579.   log "Stateful recovery initiation completed."
  580.   log "In 60 seconds, the system will reboot to the local OS."
  581.   log "Once the files are prepared, it will return back to recovery mode."
  582.   log "Please use this same recovery media."
  583.   sleep 60
  584.   reboot -f  # Back to the system!
  585.   return 1
  586. }
  587.  
  588. # Shows the appropriate error screen for the specified error code and
  589. # stops further action, i.e. doesn't return.
  590. handle_error() {
  591.   case "$1" in
  592.     $ERR_DEV_MODE_BLOCKED)
  593.       message block_developer_mode
  594.       ;;
  595.     $ERR_INVALID_INSTALL_KERNEL)
  596.       message invalid_install_kernel
  597.       ;;
  598.     *)
  599.       # Show the generic error screen by default.
  600.       on_error
  601.       ;;
  602.   esac
  603. }
  604.  
  605. recovery_install() {
  606.   NEWROOT_MNT="${USB_MNT}"
  607.  
  608.   # Always lock the TPM.  If a NVRAM reset is ever needed, we can change it.
  609.   lock_tpm || on_error
  610.  
  611.   # Check if we're really doing debugging log extraction.
  612.   maybe_get_debugging_logs || return 1
  613.  
  614.   # Check if we have a verified recovery root.
  615.   validate_recovery_root || handle_error $?
  616.  
  617.   get_dst || on_error
  618.  
  619.   recover_system || handle_error $?
  620.  
  621.   stop_log_file
  622.   # Save the recovery log to the target on success and the USB.
  623.   save_log_files "${DST_DEV_BASE}"1 ext4
  624.   save_log_files "${SRC_DEV_BASE}"12 vfat
  625.   save_log_files "${SRC_DEV_BASE}"1 ext4
  626.  
  627.   # This assignment depends on the stateful partition on the USB
  628.   # stick, so we must do it before unmount_usb and the
  629.   # "recovery_complete" message, because the user could remove the
  630.   # USB stick from that moment forward.
  631.   local usb_node_dir=$(get_usb_node_dir)
  632.  
  633.   unmount_usb
  634.   message recovery_complete
  635.  
  636.   if [ -n "$usb_node_dir" ]; then
  637.     # Default (interactive) case; wait till the user removes the USB
  638.     # stick.
  639.     while [ -d "$usb_node_dir" ]; do
  640.       sleep 1
  641.     done
  642.   elif [ $(cat /sys/devices/virtual/tty/tty0/active) != tty1 ]; then
  643.     # Special (non-interactive) test case, and the user is watching
  644.     # VT2 or VT3.  Stay up a long time to allow for debugging.
  645.     dlog "Recovery is complete!  The system will remain up to allow"
  646.     dlog "you to examine VT screen contents.  You must manually"
  647.     dlog "power off when you're done."
  648.     sleep 1d
  649.   else
  650.     # Special (non-interactive) test case; reboot after a nominal
  651.     # pause to allow a human to observe the screen.
  652.     sleep 10
  653.   fi
  654.  
  655.   reboot -f
  656.   exit 0
  657. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement