From 804e74728e6315ae914029db27c13056cb037cba Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Sun, 20 Dec 2015 20:54:03 -0500 Subject: [PATCH] swtpm: add CMD_SHUTDOWN to control channel Extend the control channel with CMD_SHUTDOWN to shut down the TPM. Signed-off-by: Stefan Berger --- include/swtpm/tpm_ioctl.h | 1 + src/swtpm/ctrlchannel.c | 51 +++++++++++++++++++++++++++------- src/swtpm/ctrlchannel.h | 5 +++- src/swtpm/swtpm.c | 5 ++-- src/swtpm/swtpm_chardev.c | 14 ++++++---- tests/test_ctrlchannel | 58 +++++++++++++++++++++++++++++++++++++-- 6 files changed, 114 insertions(+), 20 deletions(-) diff --git a/include/swtpm/tpm_ioctl.h b/include/swtpm/tpm_ioctl.h index d6652d4..1aa9b94 100644 --- a/include/swtpm/tpm_ioctl.h +++ b/include/swtpm/tpm_ioctl.h @@ -218,6 +218,7 @@ enum { enum { CMD_GET_CAPABILITY = 1, CMD_INIT, + CMD_SHUTDOWN, }; #endif /* _TPM_IOCTL_H */ diff --git a/src/swtpm/ctrlchannel.c b/src/swtpm/ctrlchannel.c index ff17e14..1d14aa6 100644 --- a/src/swtpm/ctrlchannel.c +++ b/src/swtpm/ctrlchannel.c @@ -1,3 +1,4 @@ +#include /* * ctrlchannel.c -- control channel implementation * @@ -45,6 +46,7 @@ #include #include +#include #include "ctrlchannel.h" #include "logging.h" @@ -77,7 +79,8 @@ int ctrlchannel_get_fd(struct ctrlchannel *cc) } int ctrlchannel_process_fd(int fd, - struct libtpms_callbacks *cbs) + struct libtpms_callbacks *cbs, + bool *terminate) { struct input { uint32_t cmd; @@ -88,9 +91,10 @@ int ctrlchannel_process_fd(int fd, } output; ssize_t n; ptm_init *init_p; - ptm_cap *ptm_caps; - TPM_RESULT *res_p; + ptm_cap *ptm_caps = (ptm_cap *)&output.body; + ptm_res *res_p = (ptm_res *)&output.body; size_t out_len = 0; + TPM_RESULT res; if (fd < 0) return -1; @@ -99,6 +103,10 @@ int ctrlchannel_process_fd(int fd, if (n < 0) { goto err_socket; } + if (n == 0) { + /* remote socket closed */ + goto err_socket; + } if ((size_t)n < sizeof(input.cmd)) { goto err_bad_input; } @@ -107,8 +115,9 @@ int ctrlchannel_process_fd(int fd, switch (be32toh(input.cmd)) { case CMD_GET_CAPABILITY: - ptm_caps = (ptm_cap *)&output.body; - *ptm_caps = htobe64(PTM_CAP_INIT); + *ptm_caps = htobe64( + PTM_CAP_INIT | + PTM_CAP_SHUTDOWN); out_len = sizeof(*ptm_caps); break; @@ -118,24 +127,41 @@ int ctrlchannel_process_fd(int fd, goto err_bad_input; } else { init_p = (ptm_init *)input.body; - res_p = (TPM_RESULT *)output.body; - out_len = sizeof(*res_p); + out_len = sizeof(ptm_res); TPMLIB_Terminate(); - *res_p = tpmlib_start(cbs, be32toh(init_p->u.req.init_flags)); - if (*res_p) { + res = tpmlib_start(cbs, be32toh(init_p->u.req.init_flags)); + if (res) { logprintf(STDERR_FILENO, "Error: Could not initialize the TPM\n"); } + *res_p = htobe32(res); + } + break; + + case CMD_SHUTDOWN: + if (n != 0) { + goto err_bad_input; + } else { + out_len = sizeof(ptm_res); + + TPMLIB_Terminate(); + + *res_p = htobe32(TPM_SUCCESS); + + *terminate = true; } break; default: logprintf(STDERR_FILENO, "Error: Unknown command\n"); + out_len = sizeof(ptm_res); + *res_p = htobe32(TPM_BAD_ORDINAL); } +send_resp: n = write(fd, output.body, out_len); if (n < 0) { logprintf(STDERR_FILENO, @@ -145,9 +171,14 @@ int ctrlchannel_process_fd(int fd, "Error: Could not send complete response\n"); } -err_bad_input: return fd; +err_bad_input: + out_len = sizeof(ptm_res); + *res_p = htobe32(TPM_BAD_PARAMETER); + + goto send_resp; + err_socket: close(fd); diff --git a/src/swtpm/ctrlchannel.h b/src/swtpm/ctrlchannel.h index 450727d..be59808 100644 --- a/src/swtpm/ctrlchannel.h +++ b/src/swtpm/ctrlchannel.h @@ -38,12 +38,15 @@ #ifndef _SWTPM_CTRLCHANNEL_H_ #define _SWTPM_CTRLCHANNEL_H_ +#include + struct ctrlchannel; struct libtpms_callbacks; struct ctrlchannel *ctrlchannel_new(int fd); int ctrlchannel_get_fd(struct ctrlchannel *cc); int ctrlchannel_process_fd(int fd, - struct libtpms_callbacks *cbs); + struct libtpms_callbacks *cbs, + bool *terminate); #endif /* _SWTPM_CTRLCHANNEL_H_ */ diff --git a/src/swtpm/swtpm.c b/src/swtpm/swtpm.c index 4aca470..943ad2f 100644 --- a/src/swtpm/swtpm.c +++ b/src/swtpm/swtpm.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -63,7 +64,7 @@ /* local variables */ static int notify_fd[2] = {-1, -1}; -static TPM_BOOL terminate; +static bool terminate; static struct libtpms_callbacks callbacks = { .sizeOfStruct = sizeof(struct libtpms_callbacks), @@ -92,7 +93,7 @@ static void sigterm_handler(int sig __attribute__((unused))) logprintf(STDERR_FILENO, "Error: sigterm notification failed: %s\n", strerror(errno)); } - terminate = TRUE; + terminate = true; } static void usage(FILE *file, const char *prgname, const char *iface) diff --git a/src/swtpm/swtpm_chardev.c b/src/swtpm/swtpm_chardev.c index ff4ce35..41ccf1b 100644 --- a/src/swtpm/swtpm_chardev.c +++ b/src/swtpm/swtpm_chardev.c @@ -65,7 +65,7 @@ /* local variables */ static int notify_fd[2] = {-1, -1}; -static TPM_BOOL terminate; +static bool terminate; static struct libtpms_callbacks callbacks = { .sizeOfStruct = sizeof(struct libtpms_callbacks), @@ -94,7 +94,7 @@ static void sigterm_handler(int sig __attribute__((unused))) logprintf(STDERR_FILENO, "Error: sigterm notification failed: %s\n", strerror(errno)); } - terminate = TRUE; + terminate = true; } static void usage(FILE *file, const char *prgname, const char *iface) @@ -391,15 +391,19 @@ static int mainLoop(struct mainLoopParams *mlp) } if ((pollfds[0].revents & POLLHUP)) { - terminate = 1; + terminate = true; break; } if (pollfds[2].revents & POLLIN) ctrlclntfd = accept(ctrlfd, NULL, 0); - if (pollfds[3].revents & POLLIN) - ctrlclntfd = ctrlchannel_process_fd(ctrlclntfd, &callbacks); + if (pollfds[3].revents & POLLIN) { + ctrlclntfd = ctrlchannel_process_fd(ctrlclntfd, &callbacks, + &terminate); + if (terminate) + break; + } if (pollfds[3].revents & POLLHUP) { if (ctrlclntfd >= 0) diff --git a/tests/test_ctrlchannel b/tests/test_ctrlchannel index cb9baaa..db653f1 100755 --- a/tests/test_ctrlchannel +++ b/tests/test_ctrlchannel @@ -26,7 +26,7 @@ function cleanup() # use a pseudo terminal exec 100<>/dev/ptmx -$SWTPM_EXE chardev --fd 100 --tpmstate dir=$TPMDIR --pid file=$PID_FILE --ctrl type=unixio,path=$SOCK_PATH &>/dev/null & +$SWTPM_EXE chardev --fd 100 --tpmstate dir=$TPMDIR --pid file=$PID_FILE --ctrl type=unixio,path=$SOCK_PATH & sleep 0.5 if [ ! -r $PID_FILE ]; then @@ -43,7 +43,7 @@ socat -x FILE:$CMD_PATH,rdonly UNIX-CONNECT:$SOCK_PATH 2>&1 | \ sed -n '/^ /p' | \ tail -n1 > $RESP_PATH res="$(cat $RESP_PATH)" -exp=" 00 00 00 00 00 00 00 01" +exp=" 00 00 00 00 00 00 00 03" if [ "$res" != "$exp" ]; then echo "Error: Unexpected response from CMD_GET_CAPABILITY:" echo " actual : $res" @@ -51,6 +51,60 @@ if [ "$res" != "$exp" ]; then exit 1 fi +# Send TPM_Init to the TPM: CMD_INIT = 0x00 00 00 02 + flags +echo -en '\x00\x00\x00\x02\x00\x00\x00\x00' > $CMD_PATH +socat -x FILE:$CMD_PATH,rdonly UNIX-CONNECT:$SOCK_PATH 2>&1 | \ + sed -n '/^ /p' | \ + tail -n1 > $RESP_PATH +res="$(cat $RESP_PATH)" +exp=" 00 00 00 00" +if [ "$res" != "$exp" ]; then + echo "Error: Unexpected response from CMD_INIT:" + echo " actual : $res" + echo " expected: $exp" + exit 1 +fi + +# Send unknown command to the TPM +echo -en '\x00\x00\xff\xff' > $CMD_PATH +socat -x FILE:$CMD_PATH,rdonly UNIX-CONNECT:$SOCK_PATH 2>&1 | \ + sed -n '/^ /p' | \ + tail -n1 > $RESP_PATH +res="$(cat $RESP_PATH)" +exp=" 00 00 00 0a" +if [ "$res" != "$exp" ]; then + echo "Error: Unexpected response from sending unsupported command:" + echo " actual : $res" + echo " expected: $exp" + exit 1 +fi + +# Send shutdown command to the TPM: CMD_SHUTDOWN = 00 00 00 03 +echo -en '\x00\x00\x00\x03' > $CMD_PATH +socat -x FILE:$CMD_PATH,rdonly UNIX-CONNECT:$SOCK_PATH 2>&1 | \ + sed -n '/^ /p' | \ + tail -n1 > $RESP_PATH +res="$(cat $RESP_PATH)" +exp=" 00 00 00 00" +if [ "$res" != "$exp" ]; then + echo "Error: Unexpected response from CMD_SHUTDOWN:" + echo " actual : $res" + echo " expected: $exp" + exit 1 +fi + +sleep 0.2 +kill -0 $PID 2>/dev/null +if [ $? -eq 0 ]; then + echo "Error: TPM should not be running anymore." + exit 1 +fi + +if [ -f $PID_FILE ]; then + echo "Error: TPM should have removed the PID file." + exit 1 +fi + echo "OK" exit 0 -- 2.39.2