| |
| # shellcheck shell=bash |
| |
| SWTPM=swtpm |
| SWTPM_EXE=${SWTPM_EXE:-${ROOT}/src/swtpm/${SWTPM}} |
| SWTPM_IOCTL=${SWTPM_IOCTL:-${ROOT}/src/swtpm_ioctl/swtpm_ioctl} |
| SWTPM_BIOS=${SWTPM_BIOS:-${ROOT}/src/swtpm_bios/swtpm_bios} |
| SWTPM_SETUP=${SWTPM_SETUP:-${ROOT}/src/swtpm_setup/swtpm_setup} |
| SWTPM_CERT=${SWTPM_CERT:-${ROOT}/src/swtpm_cert/swtpm_cert} |
| ECHO=$(type -P echo) |
| |
| case "$(uname -s)" in |
| Darwin) |
| CERTTOOL=gnutls-certtool;; |
| *) |
| CERTTOOL=certtool;; |
| esac |
| export CERTTOOL |
| |
| # Note: Do not use file descriptors above 127 due to OpenBSD. |
| |
| # Kill a process quietly |
| # @1: signal, e.g. -9 |
| # @2: pid |
| function kill_quiet() |
| { |
| local sig="$1" |
| local pid="$2" |
| |
| bash -c "kill $sig $pid &>/dev/null" |
| return $? |
| } |
| |
| # Wait for a regular file to appear and for it to have > 0 bytes |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_for_file() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -f "${filename}" ] && [ "$(get_filesize "${filename}")" != 0 ] && { |
| return 1 |
| } |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a regular file to disappear |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_file_gone() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -f "${filename}" ] || return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a process with given PID to be gone |
| # |
| # @1: pid |
| # @2: timeout in seconds |
| function wait_process_gone() |
| { |
| local pid="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| kill_quiet -0 "${pid}" || return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a chardev to appear |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_for_chardev() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -c "${filename}" ] && return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a chardev to disappear |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_chardev_gone() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -c "${filename}" ] || return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a socket file to appear |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_for_socketfile() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -S "${filename}" ] && return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a socket file to disappear |
| # |
| # @1: filename |
| # @2: timeout in seconds |
| function wait_socketfile_gone() |
| { |
| local filename="$1" |
| local timeout="$2" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| [ -S "${filename}" ] || return 1 |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a server socket to appear |
| # |
| # @1: port |
| # @2: host |
| # @3: timeout in seconds |
| function wait_for_serversocket() |
| { |
| local port="$1" |
| local host="$2" |
| local timeout="$3" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| if (exec 127<>"/dev/tcp/${host}/${port}") &>/dev/null; then |
| return 1 |
| fi |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a server socket to disappear |
| # |
| # @1: port |
| # @2: host |
| # @3: timeout in seconds |
| function wait_serversocket_gone() |
| { |
| local port="$1" |
| local host="$2" |
| local timeout="$3" |
| |
| local loops=$((timeout * 10)) loop |
| |
| for ((loop=0; loop<loops; loop++)); do |
| if ! (exec 127<>"/dev/tcp/${host}/${port}") &>/dev/null; then |
| return 1 |
| fi |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a TCP port to open for listening |
| # @1: port |
| # @2: id of process to open port |
| # @3: timeout in seconds |
| function wait_port_open() |
| { |
| local port=$1 |
| local pid=$2 |
| local timeout=$3 |
| |
| local loops=$((timeout * 10)) loop |
| local NETSTAT |
| |
| NETSTAT=$(type -P netstat) |
| |
| for ((loop = 0; loop < loops; loop++)); do |
| if [ -n "$NETSTAT" ]; then |
| if netstat -naptl 2>/dev/null | |
| grep "LISTEN" | |
| grep " $pid/" | |
| grep -q ":$port "; then |
| return 1 |
| fi |
| else |
| if ss -nptl | \ |
| grep ",pid=${pid}," | \ |
| grep -q ":$port "; then |
| return 1 |
| fi |
| fi |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Wait for a TCP listening port to close |
| # @1: port |
| # @2: id of process to close port |
| # @3: timeout in seconds |
| function wait_port_closed() |
| { |
| local port=$1 |
| local pid=$2 |
| local timeout=$3 |
| |
| local loops=$((timeout * 10)) loop NETSTAT |
| |
| NETSTAT=$(type -P netstat) |
| |
| for ((loop = 0; loop < loops; loop++)); do |
| if [ -n "$NETSTAT" ]; then |
| if ! netstat -naptl 2>/dev/null | \ |
| grep "LISTEN" | \ |
| grep " $pid/" | \ |
| grep -q ":$port "; then |
| return 1 |
| fi |
| else |
| if ! ss -nptl | \ |
| grep ",pid=${pid}," | \ |
| grep -q ":$port "; then |
| return 1 |
| fi |
| fi |
| sleep 0.1 |
| done |
| return 0 |
| } |
| |
| # Run the swtpm_ioctl command |
| # |
| # @param1: type of interface |
| function run_swtpm_ioctl() |
| { |
| local iface=$1; shift |
| |
| case "${iface}" in |
| cuse) |
| [ -z "${SWTPM_DEV_NAME}" ] && { |
| echo "SWTPM_DEV_NAME not defined" |
| exit 1 |
| } |
| ${SWTPM_IOCTL} "$@" "${SWTPM_DEV_NAME}" |
| return $? |
| ;; |
| socket+socket|unix+socket) |
| [ -z "${SWTPM_SERVER_NAME}" ] && { |
| echo "SWTPM_SERVER_NAME not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_SERVER_PORT}" ] && { |
| echo "SWTPM_SERVER_PORT not defined" |
| exit 1 |
| } |
| ${SWTPM_IOCTL} \ |
| --tcp "${SWTPM_SERVER_NAME}:${SWTPM_CTRL_PORT}" \ |
| "$@" |
| return $? |
| ;; |
| socket+unix|unix+unix) |
| [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && { |
| echo "SWTPM_CTRL_UNIX_PATH not defined" |
| exit 1 |
| } |
| ${SWTPM_IOCTL} \ |
| --unix "${SWTPM_CTRL_UNIX_PATH}" \ |
| "$@" |
| return $? |
| ;; |
| esac |
| } |
| |
| # Start the swtpm in the background |
| # |
| # @param1: type of interface |
| # @param2.. : parameters to pass to 'swtpm' |
| function run_swtpm() |
| { |
| local iface=$1; shift |
| local swtpm_server_disconnect="" |
| |
| echo "==== Starting swtpm with interfaces ${iface} ====" |
| if [ -z "${SWTPM_SERVER_NO_DISCONNECT}" ]; then |
| swtpm_server_disconnect=",disconnect" |
| fi |
| |
| case "${iface}" in |
| cuse) |
| [ -z "${SWTPM_DEV_NAME}" ] && { |
| echo "SWTPM_DEV_NAME not defined" |
| exit 1 |
| } |
| |
| if wait_chardev_gone "${SWTPM_DEV_NAME}" 2; then |
| echo "${SWTPM_DEV_NAME} is still there and may be used." |
| exit 1 |
| fi |
| |
| ${SWTPM_EXE} cuse "$@" \ |
| ${SWTPM_TEST_SECCOMP_OPT:+${SWTPM_TEST_SECCOMP_OPT}} \ |
| -n "${SWTPM_DEV_NAME##*/}" |
| rc=$? |
| if [ $rc -ne 0 ]; then |
| echo "Could not run ${SWTPM_EXE} using ${iface}" |
| exit 1 |
| fi |
| if wait_for_chardev "${SWTPM_DEV_NAME}" 2; then |
| echo "$SWTPM_DEV_NAME did not appear" |
| exit 1 |
| fi |
| |
| SWTPM_PID=$(ps aux | |
| grep "cuse" | |
| grep -E " ${SWTPM_DEV_NAME##*/}\$" | |
| grep -v grep | |
| gawk '{print $2}') |
| return $? |
| ;; |
| socket+socket) |
| [ -z "${SWTPM_SERVER_PORT}" ] && { |
| echo "SWTPM_SERVER_PORT not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_CTRL_PORT}" ] && { |
| echo "SWTPM_CTRL_PORT not defined" |
| exit 1 |
| } |
| |
| if wait_serversocket_gone "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then |
| echo "Port ${SWTPM_SERVER_PORT} is still used" |
| exit 1 |
| fi |
| if wait_serversocket_gone "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then |
| echo "Port ${SWTPM_CTRL_PORT} is still used" |
| exit 1 |
| fi |
| |
| ${SWTPM_EXE} socket "$@" \ |
| ${SWTPM_TEST_SECCOMP_OPT:+${SWTPM_TEST_SECCOMP_OPT}} \ |
| --server "type=tcp,port=${SWTPM_SERVER_PORT}${swtpm_server_disconnect}" \ |
| --ctrl "type=tcp,port=${SWTPM_CTRL_PORT}" & |
| rc=$? |
| if [ $rc -ne 0 ]; then |
| echo "Could not run ${SWTPM_EXE} using ${iface}" |
| exit 1 |
| fi |
| SWTPM_PID=$! |
| if wait_for_serversocket "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then |
| echo "Server did not open port ${SWTPM_SERVER_PORT}" |
| kill -9 "${SWTPM_PID}" |
| exit 1 |
| fi |
| if wait_for_serversocket "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then |
| echo "Server did not open port ${SWTPM_CTRL_PORT}" |
| kill -9 "${SWTPM_PID}" |
| exit 1 |
| fi |
| return 0 |
| ;; |
| socket+unix) |
| [ -z "${SWTPM_SERVER_PORT}" ] && { |
| echo "SWTPM_SERVER_PORT not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && { |
| echo "SWTPM_CTRL_UNIX_PATH not defined" |
| exit 1 |
| } |
| |
| if wait_serversocket_gone "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then |
| echo "Port ${SWTPM_SERVER_PORT} is still used" |
| exit 1 |
| fi |
| if wait_socketfile_gone "${SWTPM_CTRL_UNIX_PATH}" 2; then |
| echo "Unix socket ${SWTPM_CTRL_UNIX_PATH} is still there" |
| exit 1 |
| fi |
| |
| ${SWTPM_EXE} socket "$@" \ |
| ${SWTPM_TEST_SECCOMP_OPT:+${SWTPM_TEST_SECCOMP_OPT}} \ |
| --server "type=tcp,port=${SWTPM_SERVER_PORT}${swtpm_server_disconnect}" \ |
| --ctrl "type=unixio,path=${SWTPM_CTRL_UNIX_PATH}" & |
| rc=$? |
| if [ $rc -ne 0 ]; then |
| echo "Could not run ${SWTPM_EXE} using ${iface}" |
| exit 1 |
| fi |
| [ $rc -ne 0 ] && return $rc |
| SWTPM_PID=$! |
| if wait_for_serversocket "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then |
| echo "Server did not open port ${SWTPM_SERVER_PORT}" |
| kill -9 "${SWTPM_PID}" |
| exit 1 |
| fi |
| if wait_for_socketfile "${SWTPM_CTRL_UNIX_PATH}" 1; then |
| echo "Server did not create UnixIO socket ${SWTPM_CTRL_UNIX_PATH}" |
| kill -9 "${SWTPM_PID}" |
| exit 1 |
| fi |
| return 0 |
| ;; |
| unix+socket) |
| [ -z "${SWTPM_CMD_UNIX_PATH}" ] && { |
| echo "SWTPM_CMD_UNIX_PATH not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_CTRL_PORT}" ] && { |
| echo "SWTPM_CTRL_PORT not defined" |
| exit 1 |
| } |
| |
| if wait_socketfile_gone "${SWTPM_CMD_UNIX_PATH}" 2; then |
| echo "Unix socket ${SWTPM_CMD_UNIX_PATH} is still there" |
| exit 1 |
| fi |
| if wait_serversocket_gone "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then |
| echo "Port ${SWTPM_CTRL_PORT} is still used" |
| exit 1 |
| fi |
| |
| ${SWTPM_EXE} socket "$@" \ |
| ${SWTPM_TEST_SECCOMP_OPT:+${SWTPM_TEST_SECCOMP_OPT}} \ |
| --server "type=unixio,path=${SWTPM_CMD_UNIX_PATH}" \ |
| --ctrl "type=tcp,port=${SWTPM_CTRL_PORT}" & |
| rc=$? |
| if [ $rc -ne 0 ]; then |
| echo "Could not run ${SWTPM_EXE} using ${iface}" |
| exit 1 |
| fi |
| SWTPM_PID=$! |
| if wait_for_socketfile "${SWTPM_CMD_UNIX_PATH}" 2; then |
| echo "Server did not create UnixIO socket ${SWTPM_CMD_UNIX_PATH}" |
| kill -9 "${SWTPM_PID}" |
| exit 1 |
| fi |
| if wait_for_serversocket "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then |
| echo "Server did not open port ${SWTPM_CTRL_PORT}" |
| kill -9 "${SWTPM_PID}" |
| exit 1 |
| fi |
| return 0 |
| ;; |
| unix+unix) |
| [ -z "${SWTPM_CMD_UNIX_PATH}" ] && { |
| echo "SWTPM_CMD_UNIX_PATH not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && { |
| echo "SWTPM_CTRL_UNIX_PATH not defined" |
| exit 1 |
| } |
| |
| if wait_socketfile_gone "${SWTPM_CMD_UNIX_PATH}" 2; then |
| echo "Unix socket ${SWTPM_CMD_UNIX_PATH} is still there" |
| exit 1 |
| fi |
| if wait_socketfile_gone "${SWTPM_CTRL_UNIX_PATH}" 2; then |
| echo "Unix socket ${SWTPM_CTRL_UNIX_PATH} is still there" |
| exit 1 |
| fi |
| |
| ${SWTPM_EXE} socket "$@" \ |
| ${SWTPM_TEST_SECCOMP_OPT:+${SWTPM_TEST_SECCOMP_OPT}} \ |
| --server "type=unixio,path=${SWTPM_CMD_UNIX_PATH}" \ |
| --ctrl "type=unixio,path=${SWTPM_CTRL_UNIX_PATH}" & |
| rc=$? |
| if [ $rc -ne 0 ]; then |
| echo "Could not run ${SWTPM_EXE} using ${iface}" |
| exit 1 |
| fi |
| SWTPM_PID=$! |
| if wait_for_socketfile "${SWTPM_CMD_UNIX_PATH}" 2; then |
| echo "Server did not create UnixIO socket ${SWTPM_CMD_UNIX_PATH}" |
| kill -9 "${SWTPM_PID}" |
| exit 1 |
| fi |
| if wait_for_socketfile "${SWTPM_CTRL_UNIX_PATH}" 1; then |
| echo "Server did not create UnixIO socket ${SWTPM_CTRL_UNIX_PATH}" |
| kill -9 "${SWTPM_PID}" |
| exit 1 |
| fi |
| return 0 |
| ;; |
| esac |
| } |
| |
| # Open the command channel/device on fd 100 |
| # |
| # @param1: type of interface |
| # @param2: must be '100' |
| function swtpm_open_cmddev() |
| { |
| local iface=$1; shift |
| |
| [ "$1" != "100" ] && { |
| echo "swtpm_opendev: Filedescriptor must be 100" |
| exit 1 |
| } |
| |
| case "${iface}" in |
| cuse) |
| [ -z "${SWTPM_DEV_NAME}" ] && { |
| echo "SWTPM_DEV_NAME not defined" |
| exit 1 |
| } |
| exec 100>&- |
| exec 100<>"${SWTPM_DEV_NAME}" |
| return $? |
| ;; |
| socket+socket|socket+unix) |
| [ -z "${SWTPM_SERVER_NAME}" ] && { |
| echo "SWTPM_SERVER_NAME not defined" |
| exit 1 |
| } |
| [ -z "${SWTPM_SERVER_PORT}" ] && { |
| echo "SWTPM_SERVER_PORT not defined" |
| exit 1 |
| } |
| # Must first close on OS/X |
| exec 100>&- |
| exec 100<>"/dev/tcp/${SWTPM_SERVER_NAME}/${SWTPM_SERVER_PORT}" |
| return $? |
| ;; |
| unix+socket|unix+unix) |
| ;; |
| *) |
| echo "swtpm_opendev: unsupported interface $iface" |
| exit 1 |
| esac |
| } |
| |
| # Transmit a command on fd 100 |
| # |
| # @param1: type of interface |
| function swtpm_cmd_tx() |
| { |
| local iface=$1 |
| local cmd_path |
| |
| cmd_path=$(mktemp) |
| |
| swtpm_open_cmddev "${iface}" 100 |
| |
| case "${iface}" in |
| cuse) |
| echo -en "$2" > "${cmd_path}" |
| cat "${cmd_path}" >&100 |
| cat <&100 | \ |
| od -t x1 -A n | \ |
| tr -s ' ' | \ |
| tr -d '\n' | \ |
| sed 's/ $//g' |
| ;; |
| socket+socket|socket+unix) |
| echo -en "$2" > "${cmd_path}" |
| cat "${cmd_path}" >&100 |
| cat <&100 | od -t x1 -A n | \ |
| tr -s ' ' | \ |
| tr -d '\n' | \ |
| sed 's/ $//g' |
| ;; |
| unix+socket|unix+unix) |
| echo -en "$2" > "${cmd_path}" |
| socat -x -t50 \ |
| "FILE:${cmd_path},rdonly" \ |
| "UNIX-CLIENT:${SWTPM_CMD_UNIX_PATH}" 2>&1 | \ |
| sed -n '/^ /p' | \ |
| tail -n1 |
| ;; |
| *) |
| echo "swtpm_opendev: unsupported interface $iface" |
| rm -f "${cmd_path}" |
| exit 1 |
| esac |
| |
| rm -f "${cmd_path}" |
| } |
| |
| # Transmit a control command on fd 101 |
| # |
| # @param1: type of interface |
| function swtpm_ctrl_tx() |
| { |
| local iface=$1 |
| |
| local ctrl_path |
| |
| case "${iface}" in |
| socket+socket|unix+socket) |
| $ECHO -en "$2" >&101 |
| cat <&101 | od -t x1 -A n -w128 |
| ;; |
| socket+unix|unix+unix) |
| ctrl_path=$(mktemp) |
| echo -en "$2" > "${ctrl_path}" |
| socat -x -t50 \ |
| "FILE:${ctrl_path},rdonly" \ |
| "UNIX-CLIENT:${SWTPM_CTRL_UNIX_PATH}" 2>&1 | \ |
| sed -n '/^ /p' | \ |
| tail -n1 |
| rm -f "${ctrl_path}" |
| ;; |
| *) |
| echo "swtpm_opendev: unsupported interface $iface" |
| exit 1 |
| esac |
| } |
| |
| |
| # Run swtpm_bios |
| # |
| # @param1: type of interface |
| # @param2 ...: parameters to pass to swtpm_bios |
| function run_swtpm_bios() |
| { |
| local iface=$1 |
| |
| shift |
| |
| case "${iface}" in |
| cuse) |
| [ -z "${SWTPM_DEV_NAME}" ] && { |
| echo "SWTPM_DEV_NAME not defined" |
| exit 1 |
| } |
| ${SWTPM_BIOS} --tpm-device "${SWTPM_DEV_NAME}" "$@" |
| return $? |
| ;; |
| unix+unix|unix+socket) |
| [ -z "${SWTPM_CMD_UNIX_PATH}" ] && { |
| echo "SWTPM_CMD_UNIX_PATH not defined" |
| exit 1 |
| } |
| ${SWTPM_BIOS} --unix "${SWTPM_CMD_UNIX_PATH}" "$@" |
| return $? |
| ;; |
| socket+unix|socket+socket) |
| [ -z "${SWTPM_SERVER_PORT}" ] && { |
| echo "SWTPM_SERVER_PORT not defined" |
| exit 1 |
| } |
| ${SWTPM_BIOS} --tcp "${SWTPM_SERVER_NAME}:${SWTPM_SERVER_PORT}" "$@" |
| return $? |
| ;; |
| *) |
| echo "run_swtpm_bios: unsupported interface $iface" |
| exit 1 |
| esac |
| } |
| |
| # Get the size of a file in bytes |
| # |
| # @1: filename |
| function get_filesize() |
| { |
| if [[ "$(uname -s)" =~ (Linux|CYGWIN_NT-) ]]; then |
| stat -c%s "$1" |
| else |
| # OpenBSD |
| stat -f%z "$1" |
| fi |
| } |
| |
| # Get the file mode bits in octal format |
| # |
| # @1: filename |
| function get_filemode() |
| { |
| if [[ "$(uname -s)" =~ (Linux|CYGWIN_NT-) ]]; then |
| stat -c%a "$1" |
| else |
| # BSDs |
| stat -f%Lp "$1" |
| fi |
| } |
| |
| # Get the file owner uid and gid |
| # |
| # @1: filename |
| function get_fileowner() |
| { |
| if [[ "$(uname -s)" =~ (Linux|CYGWIN_NT-) ]]; then |
| stat -c"%u %g" "$1" |
| else |
| # BSDs |
| stat -f"%u %g" "$1" |
| fi |
| } |
| |
| # Get the file owner user name and group name |
| # |
| # @1: filename |
| function get_fileowner_names() |
| { |
| if [[ "$(uname -s)" =~ (Linux|CYGWIN_NT-) ]]; then |
| stat -c"%U %G" "$1" |
| else |
| # BSDs |
| stat -f"%Su %Sg" "$1" |
| fi |
| } |
| |
| # Get the SHA1 of a file |
| # |
| # @1: filename |
| function get_sha1_file() |
| { |
| if ! [ -r "$1" ]; then |
| echo "[file $1 does not exist]" |
| return |
| fi |
| case "$(uname -s)" in |
| Linux|CYGWIN*) |
| sha1sum "$1" | cut -f1 -d" " |
| ;; |
| Darwin) |
| shasum "$1" | cut -f1 -d" " |
| ;; |
| *) |
| # OpenBSD |
| sha1 "$1" | cut -d "=" -f2 | tr -d " " |
| esac |
| } |
| |
| # Display process that have the same name |
| # |
| # @1: process name to match |
| function display_processes_by_name() |
| { |
| local name="$1" |
| |
| if false; then |
| ps aux | grep "${name}" | grep -v grep |
| fi |
| } |
| |
| # Check whether seccomp support is compiled in |
| # |
| # @1: path to swtpm |
| # |
| # Returns 0 if seccomp is supported, 1 otherwise |
| function has_seccomp_support() |
| { |
| local swtpm_exe="$1" |
| |
| local tmp |
| |
| tmp=$(${swtpm_exe} socket --help | grep -E "\--seccomp") |
| [ -n "${tmp}" ] && return 0 |
| return 1 |
| } |
| |
| # Check whether the given process runs with the given seccomp |
| # profile type IF the given swtpm executable has seccomp support |
| # |
| # @1: Path to swtpm executable from which process was started |
| # @2: The process ID |
| # @3: The expected seccomp profile type |
| function check_seccomp_profile() |
| { |
| local swtpm_exe="$1" |
| local swtpm_pid="$2" |
| local profile="$3" |
| |
| local tmp |
| |
| if ! has_seccomp_support "${swtpm_exe}"; then |
| return 0 |
| fi |
| if [ -n "${SWTPM_TEST_SECCOMP_OPT}" ]; then |
| return 0 |
| fi |
| |
| tmp=$(grep -E "^Seccomp" /proc/self/status | |
| cut -d":" -f2 | |
| tr -d '\t') |
| if [ "${tmp}" != "0" ]; then |
| echo "check_seccomp_profile: skipping check since test env." \ |
| "runs with in a seccomp profile overriding --seccomp" |
| return 0 |
| fi |
| |
| tmp=$(grep -E "^Seccomp" "/proc/${swtpm_pid}/status" | |
| cut -d":" -f2 | |
| tr -d '\t') |
| if [ "${tmp}" != "${profile}" ]; then |
| echo "Process ${swtpm_pid} has wrong seccomp profile type" |
| echo "Expected: ${profile}" |
| echo "Actual : ${tmp}" |
| return 1 |
| fi |
| return 0 |
| } |
| |
| # Validate the content of the pid file |
| # @1: Expected PID |
| # @2: pid file filename |
| function validate_pidfile() |
| { |
| local pid="$1" |
| local pidfile="$2" |
| |
| local rpid |
| |
| rpid="$(cat "$pidfile")" |
| |
| if [ -z "$rpid" ]; then |
| sleep 0.1 |
| rpid="$(cat "$pidfile")" |
| fi |
| |
| if [ "$pid" != "$rpid" ]; then |
| echo "Error: pid file contains unexpected PID value." |
| echo "expected: $pid" |
| echo "actual : $(cat "${pidfile}")" |
| exit 1 |
| fi |
| } |
| |
| # Check whether swtpm can use a TPM 1.2 |
| function skip_test_no_tpm12() |
| { |
| local swtpm_exe="$1" |
| |
| local res |
| |
| res=$(${swtpm_exe} socket --print-capabilities | grep '"tpm-1.2"') |
| if [ -z "${res}" ]; then |
| echo "${swtpm_exe} does not provide a TPM 1.2" |
| exit 77 |
| fi |
| } |
| |
| # Check whether swtpm can use a TPM 2.0 |
| function skip_test_no_tpm20() |
| { |
| local swtpm_exe="$1" |
| |
| local res |
| |
| res=$(${swtpm_exe} socket --print-capabilities | grep '"tpm-2.0"') |
| if [ -z "${res}" ]; then |
| echo "${swtpm_exe} does not provide a TPM 2.0" |
| exit 77 |
| fi |
| } |
| |
| # Test whether swtpm has a chardev interface; Returns 0 if true, 1 otherwise |
| function test_swtpm_has_chardev() |
| { |
| local swtpm_exe="$1" |
| |
| local res |
| |
| res=$(${swtpm_exe} chardev --help 2>&1 | |
| grep "Unsupported TPM interface") |
| if [ -z "${res}" ]; then |
| return 0 |
| fi |
| return 1 |
| } |
| |
| # Skip test if swtpm does not support chardev interface |
| function skip_test_no_chardev() |
| { |
| local swtpm_exe="$1" |
| |
| if ! test_swtpm_has_chardev "${swtpm_exe}"; then |
| echo "${swtpm_exe} does not support chardev interface" |
| exit 77 |
| fi |
| } |
| |
| # Check whether swtpm links with ASAN |
| function skip_test_linked_with_asan() |
| { |
| local swtpm_exe="$1" |
| |
| local act_exe |
| |
| if [[ "$(uname -s)" =~ Linux ]]; then |
| if ! file "${swtpm_exe}" | grep -q ELF; then |
| act_exe="$(dirname "${swtpm_exe}")"/.libs/"$(basename "${swtpm_exe}")" |
| else |
| act_exe="${swtpm_exe}" |
| fi |
| if nm "${act_exe}" | grep -q "__asan_"; then |
| echo "${act_exe} is built with ASAN" |
| exit 77 |
| fi |
| fi |
| } |
| |
| # Have swtpm lock or re-lock the storage. Neither locking nor re-locking |
| # may produce an error |
| # |
| # @param1: reason like 'lock' or 're-lock' |
| function swtpm_lock_storage() |
| { |
| local reason="$1" |
| |
| if ! run_swtpm_ioctl "${SWTPM_INTERFACE}" --lock-storage 0; then |
| echo "Error: 'swtpm_ioctl --lock-storage' to ${reason} storage failed" |
| exit 1 |
| fi |
| } |
| |
| # Check that swtpm has no lock on the directory backend storage |
| function check_swtpm_no_storage_lock() |
| { |
| local pid="$1" |
| |
| if [ -d "/proc/${pid}/fd" ]; then |
| # shellcheck disable=SC2010 |
| if ls -l "/proc/${pid}/fd" | grep -q -E "\.lock\$"; then |
| echo "Error: swtpm must not have storage locked" |
| ls -l "/proc/${pid}/fd" |
| exit 1 |
| fi |
| elif [ -n "$(type -P lsof)" ]; then |
| if lsof -p "${pid}" | grep -q -e "\.lock\$"; then |
| echo "Error: swtpm must not have storage locked" |
| lsof -p "${pid}" |
| exit 1 |
| fi |
| else |
| echo "Missing procfs directory and lsof tool to determine open files." |
| exit 1 |
| fi |
| } |
| |
| # Check that swtpm has a lock on the directory backend storage |
| function check_swtpm_storage_locked() |
| { |
| local pid="$1" |
| |
| if [ -d "/proc/${pid}/fd" ]; then |
| # shellcheck disable=SC2010 |
| if ! ls -l "/proc/${pid}/fd" | grep -q -E "\.lock\$"; then |
| echo "Error: swtpm must have storage locked" |
| ls -l "/proc/${pid}/fd" |
| exit 1 |
| fi |
| elif [ -n "$(type -P lsof)" ]; then |
| if ! lsof -p "${pid}" | grep -q -e "\.lock\$"; then |
| echo "Error: swtpm must have storage locked" |
| lsof -p "${pid}" |
| exit 1 |
| fi |
| else |
| echo "Missing procfs directory and lsof tool to determine open files." |
| exit 1 |
| fi |
| } |