| #!/bin/sh |
| # |
| # Cryptohome service is a system daemon responsible for remote attestation |
| # and interacting with the device's TPM Chip. |
| # |
| # This script starts the following daemons: |
| # - TrouSerS daemon: TPM interaction. |
| # - CHAPS daemon: opencryptoki alternative. |
| # - Cryptohome Daemon: Remote Attestation + TPM Ussage. |
| # |
| # Cryptohome daemon depends on TrouSerS and CHAPS daemons. |
| # This script will also run the tpm-manager program before starting Cryptohome |
| # daemon, this is because tpm-manager is used to take ownership of the tpm |
| # and create the attestation enrollment credentials for the first time. |
| # |
| # Note: Cryptohome is ported from ChromeOS as a binary so it expects the ChromeOS |
| # environment. Therefore, chroot is needed to execute cryptohome. |
| # |
| |
| # Sanity check |
| [ -x /chroot/chromeos/bin/cryptohomed ] || exit 1 |
| [ -x /chroot/chromeos/bin/tcsd ] || exit 1 |
| [ -x /chroot/chromeos/bin/chapsd ] || exit 1 |
| [ -x /chroot/chromeos/bin/tpm-manager ] || exit 1 |
| |
| . /etc/utils.sh |
| |
| CONFIG_PATH=/var/config |
| SYNC_MOUNT_FLAGS="-o sync" |
| |
| # kill_if_running is used to kill an application only if it is running. |
| # using a pkill alone would return an error if the program couldn't be found. |
| # The first parameter is the binary name of the program to kill. |
| # |
| # example: kill_if_running "cryptohomed" |
| kill_if_running() { |
| echo "Stopping $1..." |
| |
| if pgrep -x $1 > /dev/null; then |
| pkill -x $1 |
| [ $? -ne 0 ] && echo "Failed to Stop $1..." && exit 1 |
| fi |
| } |
| |
| |
| # Bind chroot directories to tmpfs, as chroot may exist in a read-only |
| # filesystem. These directories are used for the DBus socket and Cryptohome |
| # libraries. |
| |
| # We need the preserve folder, but also tpm uses /mnt/stateful_partition/.tpm_owned |
| mkdir -p "$CONFIG_PATH/cryptohome/stateful_partition/unencrypted/preserve" |
| mount_once "$CONFIG_PATH/cryptohome/stateful_partition" "/chroot/chromeos/mnt/stateful_partition" |
| |
| # Home folder, for storing /home/.shadow/cryptohome.key |
| mkdir -p "$CONFIG_PATH/cryptohome/home" |
| mount_once "$CONFIG_PATH/cryptohome/home" "/chroot/chromeos/home" |
| |
| # Root home folder, for storing trousers information |
| mkdir -p "$CONFIG_PATH/cryptohome/root" |
| mount_once "$CONFIG_PATH/cryptohome/root" "/chroot/chromeos/root" |
| |
| # /var/lib stores the old .tpm_owned and opencryptoki files. Also /var/lib/tpm folder is required for trousers. |
| mkdir -p "$CONFIG_PATH/shared/lib/tpm" |
| mkdir -p "$CONFIG_PATH/shared/lib/metrics" |
| mkdir -p "$CONFIG_PATH/shared/lib/buffet" # for mount point |
| [ -e "$CONFIG_PATH/cryptohome/lib" ] || ln -sf "$CONFIG_PATH/shared/lib" "$CONFIG_PATH/cryptohome/lib" |
| mount_once "$CONFIG_PATH/shared/lib" "/chroot/chromeos/var/lib" |
| |
| # Delete metrics data. It is not used and can leave /var/config without disk space. |
| rm -f "$CONFIG_PATH/shared/lib/metrics/uma-events" |
| |
| # /etc is needed because we need to access users and groups and /etc/tcsd.conf |
| # trousers needs to check that it is running with user and group tss:tss |
| mount_once "/etc" "/chroot/chromeos/etc" |
| |
| # /dev is needed for access to /dev/tpm0, /dev/urandom, /dev/log and /dev/null |
| mount_once "/dev" "/chroot/chromeos/dev" |
| |
| # /sys is required to easily interact with the tpm via /sys/class/misc/tpm0 |
| mount_once "/sys" "/chroot/chromeos/sys" |
| |
| mount_once "/tmp/run" "/chroot/chromeos/var/run" |
| mount_once "/tmp" "/chroot/chromeos/tmp" |
| |
| # Sanity check.. DBus socket has to be present. |
| wait-until-created /chroot/chromeos/var/run/dbus/system_bus_socket |
| |
| create_new_config() { |
| FLAGS="$1" |
| IMG_PATH="$2" |
| |
| if ! rm -f ${IMG_PATH} || ! rm -f ${IMG_PATH}.key ; then |
| echo "Failed to remove old config partition files!" |
| return 1 |
| fi |
| |
| CONFIG_PART=$(find_sata_blkdev)20 |
| |
| ORIG_MOUNT_OPTS=$(grep ${CONFIG_PATH} /proc/mounts | sed -e "s/\S\+ \S\+ \S\+ \(.\+\) .\+ /\1/") |
| |
| if [ "${FLAGS}" = "${SYNC_MOUNT_FLAGS}" ]; then |
| # Remount /var/config asynchronously to speed up formatting |
| ASYNC_MOUNT_OPTS=$(echo ${ORIG_MOUNT_OPTS} | sed -e "s/,sync,/,/") |
| mount -o remount,${ASYNC_MOUNT_OPTS} ${CONFIG_PART} ${CONFIG_PATH} |
| fi |
| |
| if ! dd if=/dev/zero of=$IMG_PATH bs=1024 count=40960 ; then |
| echo "Failed to create empty config partition file!" |
| return 1 |
| fi |
| } |
| |
| format_new_config() { |
| FLAGS="$1" |
| IMG_DEVICE="$2" |
| |
| echo "Formatting encrypted config partition..." |
| mkfs.ext4 -q $IMG_DEVICE |
| MKFS_STATUS="$?" |
| |
| if [ "${FLAGS}" = "${SYNC_MOUNT_FLAGS}" ]; then |
| # Re-establish synchronous mount |
| mount -o remount,${ORIG_MOUNT_OPTS} ${CONFIG_PART} ${CONFIG_PATH} |
| fi |
| |
| if [ "${MKFS_STATUS}" != "0" ]; then |
| echo "Failed to format config partition!" |
| return 1 |
| fi |
| } |
| |
| mount_config() { |
| IMG_PATH=$CONFIG_PATH/config.img |
| IMG_DEVICE=/dev/mapper/config |
| |
| echo "Mounting encrypted config partition..." |
| |
| # Stop if /config is already mounted. |
| if mount | grep -q "on /config" ; then |
| return 0 |
| fi |
| |
| FLAGS="" |
| mount | grep ${CONFIG_PATH} | grep ,sync |
| if [ $? = "0" ]; then |
| FLAGS="${SYNC_MOUNT_FLAGS}" |
| fi |
| |
| # Create new config only if TPM was previously un-owned. |
| if [ -f "${CONFIG_PATH}/config.init" ] ; then |
| create_new_config "${FLAGS}" "${IMG_PATH}" || exit 1 |
| fi |
| |
| # cryptdev will wait for cryptohome service. |
| if ! cryptdev config $IMG_PATH ; then |
| echo "Cryptdev command failed!" |
| exit 1 |
| fi |
| |
| wait-until-created $IMG_DEVICE |
| |
| # Format new config partition. |
| if [ -f "${CONFIG_PATH}/config.init" ] ; then |
| format_new_config "${FLAGS}" "${IMG_DEVICE}" || exit 1 |
| rm -f "${CONFIG_PATH}/config.init" || exit 1 |
| fi |
| |
| if ! mount -t ext4 $FLAGS $IMG_DEVICE /config ; then |
| echo "Failed to mount encrypted config partition!" |
| exit 1 |
| fi |
| |
| # Make /config writable to non-root. |
| chown bin.sys /config |
| chmod 775 /config |
| |
| return 0 |
| } |
| |
| start() { |
| echo "Starting cryptohome services..." |
| |
| PCR0=$(chroot /chroot/chromeos /bin/tpmc pcrread 0) |
| PCR0_INIT_PATH=${CONFIG_PATH}/pcr0.init |
| |
| if [ -f ${PCR0_INIT_PATH} ]; then |
| PCR0_INIT=$(cat ${PCR0_INIT_PATH}) |
| |
| if [ x"${PCR0}" != x"${PCR0_INIT}" ]; then |
| echo "Bootmode has changed: wiping data then reboot..." |
| /bin/zap --i-really-mean-it --erase-backups |
| reboot |
| fi |
| else |
| echo -n "${PCR0}" > ${PCR0_INIT_PATH} |
| fi |
| |
| echo "starting TCSD..." |
| chroot /chroot/chromeos /bin/tcsd 2>&1 | logos tcsd |
| |
| echo "starting CHAPSD..." |
| babysit 10 chroot /chroot/chromeos /bin/chapsd 2>&1 | logos chapsd & |
| |
| chroot /chroot/chromeos /bin/tpm-manager dump_status 2>&1 | grep -q "owned: true" |
| if [ "$?" != "0" ] ; then |
| touch "${CONFIG_PATH}/config.init" || exit 1 |
| fi |
| |
| chroot /chroot/chromeos /bin/tpm-manager 2>&1 |
| [ $? -ne 0 ] && echo "Failed to run tpm-manager..." && stop && exit 1 |
| echo "tpm-manager ran successfully" |
| |
| echo "starting Cryptohomed..." |
| # babysit and logos do not work because cryptohomed does daemonize. |
| chroot /chroot/chromeos /bin/cryptohomed 2>&1 |
| |
| # Encrypted partition depends on cryptohome for encryption key. |
| mount_config 2>&1 | logos configfs |
| } |
| |
| stop() { |
| echo "Stopping cryptohome services" |
| kill_if_running "cryptohomed" |
| kill_if_running "chapsd" |
| kill_if_running "tcsd" |
| echo "Cryptohome Services stopped successfully" |
| } |
| |
| restart() { |
| stop |
| start |
| } |
| |
| case "$1" in |
| start) |
| start |
| ;; |
| stop) |
| stop |
| ;; |
| restart|reload) |
| restart |
| ;; |
| *) |
| echo "Usage: $0 {start|stop|restart}" |
| exit 1 |
| esac |
| |