mirror of
https://github.com/stefanberger/swtpm.git
synced 2025-08-22 19:04:35 +00:00

Extend an existing test case with the backup option for the directory backend. Check correct behavior by trying to start swtpm with missing state decryption key and ensure that file renamings are handled as expected. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
1042 lines
21 KiB
Plaintext
1042 lines
21 KiB
Plaintext
|
|
# shellcheck shell=bash
|
|
|
|
SWTPM_TEST_UNINSTALLED=1
|
|
|
|
if [ -n "${SWTPM_TEST_UNINSTALLED}" ]; then
|
|
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}
|
|
SWTPM_LOCALCA=${SWTPM_LOCALCA:-${ROOT}/src/swtpm_localca/swtpm_localca}
|
|
SWTPM_SETUP_CONF="${ROOT}/samples/swtpm_setup.conf"
|
|
else
|
|
SWTPM_EXE=${SWTPM_EXE:-$(type -P swtpm)}
|
|
SWTPM_IOCTL=${SWTPM_IOCTL:-$(type -P swtpm_ioctl)}
|
|
SWTPM_BIOS=${SWTPM_BIOS:-$(type -P swtpm_bios)}
|
|
SWTPM_SETUP=${SWTPM_SETUP:-$(type -P swtpm_setup)}
|
|
SWTPM_CERT=${SWTPM_CERT:-$(type -P swtpm_cert)}
|
|
SWTPM_LOCALCA=${SWTPM_LOCALCA:-$(type -P swtpm_localca)}
|
|
SWTPM_SETUP_CONF="$(dirname "$0")/swtpm_setup.conf"
|
|
fi
|
|
|
|
# SC2034 unused
|
|
export SWTPM_SETUP_CONF
|
|
|
|
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-|GNU) ]]; 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-|GNU) ]]; 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-|GNU) ]]; 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 1
|
|
fi
|
|
case "$(uname -s)" in
|
|
Linux|CYGWIN*|GNU)
|
|
sha1sum "$1" | cut -f1 -d" "
|
|
;;
|
|
Darwin)
|
|
shasum "$1" | cut -f1 -d" "
|
|
;;
|
|
*)
|
|
# OpenBSD
|
|
sha1 "$1" | cut -d "=" -f2 | tr -d " "
|
|
esac
|
|
return $?
|
|
}
|
|
|
|
# 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
|
|
}
|
|
|
|
# Get the name of the distro; only a few distros are supported for specific tests
|
|
function get_distro_name()
|
|
{
|
|
if [ -r /etc/redhat-release ]; then
|
|
if grep -qE "^Red Hat Enterprise" /etc/redhat-release; then
|
|
echo "RHEL"
|
|
elif grep -qE "^CentOS Stream release" /etc/redhat-release; then
|
|
echo "CentOS"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function get_rhel_version()
|
|
{
|
|
sed -n 's/Red Hat Enterprise Linux release \([^ ]*\) .*/\1/p' /etc/redhat-release |
|
|
gawk '{split($0,a,"."); print a[1]*100 + a[2]}'
|
|
}
|
|
|
|
function get_centos_version()
|
|
{
|
|
sed -n 's/CentOS Stream release \([0-9]*\).*/\1/p' /etc/redhat-release |
|
|
gawk '{print $0*100}'
|
|
}
|