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

Extend an existing test case to ensure that a 2nd swtpm process terminates with an error related to not being able to get a lock on the storage's lockfile. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
1069 lines
22 KiB
Plaintext
1069 lines
22 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'
|
|
#
|
|
# If SWTPM_RUN_SWTPM_WONT_START is set then a start failure is expected
|
|
# and exit will not be called.
|
|
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
|
|
if [ -z "${SWTPM_RUN_SWTPM_WONT_START}" ]; then
|
|
echo "Could not run ${SWTPM_EXE} using ${iface}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
if wait_for_chardev "${SWTPM_DEV_NAME}" 2; then
|
|
if [ -z "${SWTPM_RUN_SWTPM_WONT_START}" ]; then
|
|
echo "$SWTPM_DEV_NAME did not appear"
|
|
exit 1
|
|
fi
|
|
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
|
|
# Due to '&' above, an error means SWTPM_EXE is bad
|
|
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
|
|
if [ -z "${SWTPM_RUN_SWTPM_WONT_START}" ]; then
|
|
echo "Server did not open port ${SWTPM_SERVER_PORT}"
|
|
kill -9 "${SWTPM_PID}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
if wait_for_serversocket "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then
|
|
if [ -z "${SWTPM_RUN_SWTPM_WONT_START}" ]; then
|
|
echo "Server did not open port ${SWTPM_CTRL_PORT}"
|
|
kill -9 "${SWTPM_PID}"
|
|
exit 1
|
|
fi
|
|
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
|
|
# Due to '&' above, an error means SWTPM_EXE is bad
|
|
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
|
|
if [ -z "${SWTPM_RUN_SWTPM_WONT_START}" ]; then
|
|
echo "Server did not open port ${SWTPM_SERVER_PORT}"
|
|
kill -9 "${SWTPM_PID}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
if wait_for_socketfile "${SWTPM_CTRL_UNIX_PATH}" 1; then
|
|
if [ -z "${SWTPM_RUN_SWTPM_WONT_START}" ]; then
|
|
echo "Server did not create UnixIO socket ${SWTPM_CTRL_UNIX_PATH}"
|
|
kill -9 "${SWTPM_PID}"
|
|
exit 1
|
|
fi
|
|
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
|
|
# Due to '&' above, an error means SWTPM_EXE is bad
|
|
echo "Could not run ${SWTPM_EXE} using ${iface}"
|
|
exit 1
|
|
fi
|
|
SWTPM_PID=$!
|
|
if wait_for_socketfile "${SWTPM_CMD_UNIX_PATH}" 2; then
|
|
if [ -z "${SWTPM_RUN_SWTPM_WONT_START}" ]; then
|
|
echo "Server did not create UnixIO socket ${SWTPM_CMD_UNIX_PATH}"
|
|
kill -9 "${SWTPM_PID}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
if wait_for_serversocket "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then
|
|
if [ -z "${SWTPM_RUN_SWTPM_WONT_START}" ]; then
|
|
echo "Server did not open port ${SWTPM_CTRL_PORT}"
|
|
kill -9 "${SWTPM_PID}"
|
|
exit 1
|
|
fi
|
|
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
|
|
# Due to '&' above, an error means SWTPM_EXE is bad
|
|
echo "Could not run ${SWTPM_EXE} using ${iface}"
|
|
exit 1
|
|
fi
|
|
SWTPM_PID=$!
|
|
if wait_for_socketfile "${SWTPM_CMD_UNIX_PATH}" 2; then
|
|
if [ -z "${SWTPM_RUN_SWTPM_WONT_START}" ]; then
|
|
echo "Server did not create UnixIO socket ${SWTPM_CMD_UNIX_PATH}"
|
|
kill -9 "${SWTPM_PID}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
if wait_for_socketfile "${SWTPM_CTRL_UNIX_PATH}" 1; then
|
|
if [ -z "${SWTPM_RUN_SWTPM_WONT_START}" ]; then
|
|
echo "Server did not create UnixIO socket ${SWTPM_CTRL_UNIX_PATH}"
|
|
kill -9 "${SWTPM_PID}"
|
|
exit 1
|
|
fi
|
|
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}'
|
|
}
|