swtpm_cuse: Support parial reads (issue #376)

This patch adds support for partial reads to the CUSE swtpm.

We introduce a ptm_read_offset variable that holds the offset where to read
from next. It is reset every time a command has been processed as part of a
write() so that subsequent read()s start reading from offset 0. It is
advanced by the number of bytes that were read.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Stefan Berger 2020-12-29 18:27:26 -05:00 committed by Stefan Berger
parent e753128b27
commit 024073c5cc
3 changed files with 172 additions and 11 deletions

View File

@ -91,6 +91,9 @@ static unsigned char *ptm_request;
/* buffer containing the TPM response */
static unsigned char *ptm_response;
/* offset from where to read from; reset when ptm_response is set */
static size_t ptm_read_offset;
/* the sizes of the data in the buffers */
static uint32_t ptm_req_len, ptm_res_len, ptm_res_tot;
@ -401,6 +404,7 @@ static void worker_thread(gpointer data, gpointer user_data)
case MESSAGE_TPM_CMD:
TPMLIB_Process(&ptm_response, &ptm_res_len, &ptm_res_tot,
ptm_request, ptm_req_len);
ptm_read_offset = 0;
break;
case MESSAGE_IOCTL:
break;
@ -489,6 +493,7 @@ static void ptm_write_fatal_error_response(TPMLIB_TPMVersion l_tpmversion)
&ptm_res_len,
&ptm_res_tot,
l_tpmversion);
ptm_read_offset = 0;
}
/*
@ -506,9 +511,11 @@ static int ptm_send_startup(uint16_t startupType, TPMLIB_TPMVersion l_tpmversion
startupType,
tpmversion,
command, max_command_length);
if (command_length > 0)
if (command_length > 0) {
rc = TPMLIB_Process(&ptm_response, &ptm_res_len, &ptm_res_tot,
(unsigned char *)command, command_length);
ptm_read_offset = 0;
}
if (rc || command_length == 0) {
if (rc) {
@ -530,23 +537,22 @@ static int ptm_send_startup(uint16_t startupType, TPMLIB_TPMVersion l_tpmversion
*/
static void ptm_read_result(fuse_req_t req, size_t size)
{
int len;
size_t len = 0;
if (tpm_running) {
/* wait until results are ready */
worker_thread_wait_done();
}
len = ptm_res_len;
if (ptm_res_len > size) {
len = size;
ptm_res_len -= size;
} else {
ptm_res_len = 0;
if (ptm_read_offset < ptm_res_len) {
len = ptm_res_len - ptm_read_offset;
if (size < len)
len = size;
}
fuse_reply_buf(req, (const char *)ptm_response, len);
fuse_reply_buf(req, (const char *)&ptm_response[ptm_read_offset], len);
ptm_read_offset += len;
}
/*
@ -871,8 +877,10 @@ static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size,
tpmlib_process(&ptm_response, &ptm_res_len, &ptm_res_tot,
(unsigned char *)buf, ptm_req_len,
locality_flags, &locality, tpmversion);
if (ptm_res_len)
if (ptm_res_len) {
ptm_read_offset = 0;
goto skip_process;
}
if (tpmlib_is_request_cancelable(l_tpmversion,
(const unsigned char*)buf,
@ -889,6 +897,7 @@ static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size,
/* direct processing */
TPMLIB_Process(&ptm_response, &ptm_res_len, &ptm_res_tot,
(unsigned char *)buf, ptm_req_len);
ptm_read_offset = 0;
}
} else {
/* TPM not initialized; return error */

View File

@ -56,6 +56,7 @@ TESTS += \
test_tpm2_hashing2 \
test_tpm2_hashing3 \
test_tpm2_migration_key \
test_tpm2_partial_reads \
test_tpm2_print_capabilities \
test_tpm2_resume_volatile \
test_tpm2_savestate \

151
tests/test_tpm2_partial_reads Executable file
View File

@ -0,0 +1,151 @@
#!/usr/bin/env bash
# For the license, see the LICENSE file in the root directory.
# set -x
cd $(dirname "$0")
ROOT=${abs_top_builddir:-$(pwd)/..}
export SWTPM_INTERFACE=cuse
VTPM_NAME="vtpm-test-tpm2-partial-reads"
SWTPM_DEV_NAME="/dev/${VTPM_NAME}"
export TPM_PATH=$(mktemp -d)
CMD_PATH="${TPM_PATH}/cmd"
function cleanup()
{
pid=${SWTPM_PID}
if [ -n "$pid" ]; then
kill_quiet -9 $pid
fi
rm -rf $TPM_PATH
}
function swtpm_read_n_bytes_fd100()
{
dd bs=1 count=$1 if=/proc/self/fd/100 2>/dev/null | \
od -t x1 -A n | \
tr -s ' ' | \
tr -d '\n' | \
sed 's/ $//g'
}
trap "cleanup" EXIT
[ "${SWTPM_INTERFACE}" == "cuse" ] && source test_cuse
source common
run_swtpm ${SWTPM_INTERFACE} --tpm2
kill_quiet -0 ${SWTPM_PID}
if [ $? -ne 0 ]; then
echo "Error: ${SWTPM_INTERFACE} TPM did not start."
exit 1
fi
# Init the TPM
run_swtpm_ioctl ${SWTPM_INTERFACE} -i
if [ $? -ne 0 ]; then
echo "Error: Could not initialize the ${SWTPM_INTERFACE} TPM."
exit 1
fi
kill_quiet -0 ${SWTPM_PID} 2>/dev/null
if [ $? -ne 0 ]; then
echo "Error: ${SWTPM_INTERFACE} TPM not running anymore after INIT."
exit 1
fi
# Prepare the TPM2_Startup
echo -en '\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00' > "${CMD_PATH}"
swtpm_open_cmddev ${SWTPM_INTERFACE} 100
# Startup the TPM2
cat "${CMD_PATH}" >&100
# Read 4 and then 6 bytes of the response
res1=$(swtpm_read_n_bytes_fd100 4)
exp1=' 80 01 00 00'
if [ "$res1" != "$exp1" ]; then
echo "1st Startup: Unexpected 1st response part"
echo "Expected: $exp1"
echo "Actual : $res1"
exit 1
fi
res2=$(swtpm_read_n_bytes_fd100 6)
exp2=' 00 0a 00 00 00 00'
if [ "$res2" != "$exp2" ]; then
echo "1st Startup: Unexpected 2nd response part"
echo "Expected: $exp2"
echo "Actual : $res2"
exit 1
fi
# Startup the TPM2 again (will fail, but that's ok)
cat "${CMD_PATH}" >&100
# Read 4 and then only 4 bytes of the response
res1=$(swtpm_read_n_bytes_fd100 4)
exp1=' 80 01 00 00'
if [ "$res1" != "$exp1" ]; then
echo "2nd Startup: Unexpected 1st response part"
echo "Expected: $exp1"
echo "Actual : $res1"
exit 1
fi
res2=$(swtpm_read_n_bytes_fd100 4)
exp2=' 00 0a 00 00'
if [ "$res2" != "$exp2" ]; then
echo "2nd Startup: Unexpected 2nd part"
echo "Expected: $exp2"
echo "Actual : $res2"
exit 1
fi
# Startup the TPM2 again (will fail, but that's ok)
cat "${CMD_PATH}" >&100
# Read 4 and then 6 bytes of the response
res1=$(swtpm_read_n_bytes_fd100 4)
exp1=' 80 01 00 00'
if [ "$res1" != "$exp1" ]; then
echo "3rd Startup: Unexpected 1st response part"
echo "Expected: $exp1"
echo "Actual : $res1"
exit 1
fi
res2=$(swtpm_read_n_bytes_fd100 6)
exp2=' 00 0a 00 00 01 00'
if [ "$res2" != "$exp2" ]; then
echo "3rd Startup: Unexpected 2nd part"
echo "Expected: $exp2"
echo "Actual : $res2"
exit 1
fi
run_swtpm_ioctl ${SWTPM_INTERFACE} -s
if [ $? -ne 0 ]; then
echo "Error: Could not shut down the ${SWTPM_INTERFACE} TPM."
exit 1
fi
if wait_process_gone ${SWTPM_PID} 4; then
echo "Error: ${SWTPM_INTERFACE} TPM should not be running anymore."
exit 1
fi
if [ ! -e $STATE_FILE ]; then
echo "Error: TPM state file $STATE_FILE does not exist."
exit 1
fi
echo "OK"
exit 0