blob: eea6d96f4a911f31c90b2dfb1a33f838d288fb32 [file] [log] [blame]
#!/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