diff --git a/include/swtpm/tpm_ioctl.h b/include/swtpm/tpm_ioctl.h index bad8601..d6196d4 100644 --- a/include/swtpm/tpm_ioctl.h +++ b/include/swtpm/tpm_ioctl.h @@ -191,6 +191,30 @@ struct ptm_setbuffersize { } u; }; +#define PTM_GETINFO_SIZE (3 * 1024) +/* + * PTM_GET_INFO: Get info about the TPM implementation (from libtpms) + * + * This request allows to indirectly call TPMLIB_GetInfo(flags) and + * retrieve information from libtpms. + * Only one transaction is currently necessary for returning results + * to a client. Therefore, totlength and length will be the same if + * offset is 0. + */ +struct ptm_getinfo { + union { + struct { + uint64_t flags; + uint32_t offset; /* offset from where to read */ + } req; /* request */ + struct { + ptm_res tpm_result; + uint32_t totlength; + uint32_t length; + char buffer[PTM_GETINFO_SIZE]; + } resp; /* response */ + } u; +}; typedef uint64_t ptm_cap; typedef struct ptm_est ptm_est; @@ -202,6 +226,7 @@ typedef struct ptm_getstate ptm_getstate; typedef struct ptm_setstate ptm_setstate; typedef struct ptm_getconfig ptm_getconfig; typedef struct ptm_setbuffersize ptm_setbuffersize; +typedef struct ptm_getinfo ptm_getinfo; /* capability flags returned by PTM_GET_CAPABILITY */ #define PTM_CAP_INIT (1) @@ -218,6 +243,7 @@ typedef struct ptm_setbuffersize ptm_setbuffersize; #define PTM_CAP_GET_CONFIG (1 << 11) #define PTM_CAP_SET_DATAFD (1 << 12) #define PTM_CAP_SET_BUFFERSIZE (1 << 13) +#define PTM_CAP_GET_INFO (1 << 14) enum { PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap), @@ -237,6 +263,7 @@ enum { PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig), PTM_SET_DATAFD = _IOR('P', 15, ptm_res), PTM_SET_BUFFERSIZE = _IOWR('P', 16, ptm_setbuffersize), + PTM_GET_INFO = _IOWR('P', 17, ptm_getinfo), }; /* @@ -267,6 +294,7 @@ enum { CMD_GET_CONFIG, /* 0x0f */ CMD_SET_DATAFD, /* 0x10 */ CMD_SET_BUFFERSIZE, /* 0x11 */ + CMD_GET_INFO, /* 0x12 */ }; #endif /* _TPM_IOCTL_H */ diff --git a/src/swtpm/ctrlchannel.c b/src/swtpm/ctrlchannel.c index 7b9aeb4..1303fb3 100644 --- a/src/swtpm/ctrlchannel.c +++ b/src/swtpm/ctrlchannel.c @@ -475,11 +475,16 @@ int ctrlchannel_process_fd(int fd, ptm_setstate *pss; ptm_loc *pl; ptm_setbuffersize *psbs; + ptm_getinfo *pgi; size_t out_len = 0; TPM_RESULT res; uint32_t remain; uint32_t buffersize, maxsize, minsize; + uint64_t info_flags; + uint32_t offset; + char *info_data = NULL; + size_t length; if (fd < 0) return -1; @@ -515,7 +520,8 @@ int ctrlchannel_process_fd(int fd, #ifndef __CYGWIN__ PTM_CAP_SET_DATAFD | #endif - PTM_CAP_SET_BUFFERSIZE + PTM_CAP_SET_BUFFERSIZE | + PTM_CAP_GET_INFO ); out_len = sizeof(*ptm_caps); @@ -795,6 +801,37 @@ int ctrlchannel_process_fd(int fd, break; + case CMD_GET_INFO: + pgi = (ptm_getinfo *)input.body; + if (n < (ssize_t)sizeof(pgi->u.req)) /* rw */ + goto err_bad_input; + + info_flags = be64toh(pgi->u.req.flags); + + info_data = TPMLIB_GetInfo(info_flags); + if (!info_data) + goto err_memory; + + offset = be32toh(pgi->u.req.offset); + if (offset >= strlen(info_data)) { + free(info_data); + goto err_bad_input; + } + + length = min(strlen(info_data) + 1 - offset, + sizeof(pgi->u.resp.buffer)); + + pgi = (ptm_getinfo *)&output.body; + pgi->u.resp.tpm_result = htobe32(0); + pgi->u.resp.totlength = htobe32(strlen(info_data) + 1); + pgi->u.resp.length = htobe32(length); + strncpy(pgi->u.resp.buffer, &info_data[offset], length); + free(info_data); + + out_len = offsetof(ptm_getinfo, u.resp.buffer) + length; + + break; + default: logprintf(STDERR_FILENO, "Error: Unknown command: 0x%08x\n", be32toh(input.cmd)); @@ -840,6 +877,12 @@ err_io: goto send_resp; +err_memory: + *res_p = htobe32(TPM_SIZE); + out_len = sizeof(ptm_res); + + goto send_resp; + err_socket: close(fd); diff --git a/src/swtpm/cuse_tpm.c b/src/swtpm/cuse_tpm.c index 967c6d5..e8e79b2 100644 --- a/src/swtpm/cuse_tpm.c +++ b/src/swtpm/cuse_tpm.c @@ -1209,6 +1209,39 @@ static void ptm_ioctl(fuse_req_t req, int cmd, void *arg, } break; + case PTM_GET_INFO: + if (out_bufsz != sizeof(ptm_getinfo)) { + struct iovec iov = { arg, sizeof(uint32_t) }; + fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0); + } else { + ptm_getinfo *in_pgi = (ptm_getinfo *)in_buf; + ptm_getinfo out_pgi; + char *info_data; + uint32_t length, offset; + + info_data = TPMLIB_GetInfo(in_pgi->u.req.flags); + if (!info_data) + goto error_memory; + + offset = in_pgi->u.req.offset; + if (offset >= strlen(info_data)) { + free(info_data); + goto error_bad_input; + } + + length = min(strlen(info_data) + 1 - offset, + sizeof(out_pgi.u.resp.buffer)); + + out_pgi.u.resp.tpm_result = 0; + out_pgi.u.resp.totlength = strlen(info_data) + 1; + out_pgi.u.resp.length = length; + strncpy(out_pgi.u.resp.buffer, &info_data[offset], length); + free(info_data); + + fuse_reply_ioctl(req, 0, &out_pgi, sizeof(out_pgi)); + } + break; + default: fuse_reply_err(req, EINVAL); } @@ -1225,11 +1258,23 @@ cleanup: return; +error_bad_input: + res = TPM_BAD_PARAMETER; + fuse_reply_ioctl(req, 0, &res, sizeof(res)); + + goto cleanup; + error_running: error_not_running: res = TPM_BAD_ORDINAL; fuse_reply_ioctl(req, 0, &res, sizeof(res)); + goto cleanup; + +error_memory: + res = TPM_SIZE; + fuse_reply_ioctl(req, 0, &res, sizeof(res)); + goto cleanup; } diff --git a/tests/test_clientfds.py b/tests/test_clientfds.py index 7dbbfce..289da09 100755 --- a/tests/test_clientfds.py +++ b/tests/test_clientfds.py @@ -64,7 +64,7 @@ def test_get_caps(): # test get capabilities # CMD_GET_CAPABILITY = 0x00 00 00 01 cmd_get_caps = bytearray([0x00, 0x00, 0x00, 0x01]) - expected_caps = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff]) + expected_caps = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff]) def toString(arr): return ' '.join('{:02x}'.format(x) for x in arr) diff --git a/tests/test_ctrlchannel b/tests/test_ctrlchannel index b0a2d88..41328ec 100755 --- a/tests/test_ctrlchannel +++ b/tests/test_ctrlchannel @@ -58,9 +58,9 @@ PID="$(cat $PID_FILE)" # Get the capability bits: CMD_GET_CAPABILITY = 0x00 00 00 01 res="$(swtpm_ctrl_tx ${SWTPM_INTERFACE} '\x00\x00\x00\x01')" if [[ "$(uname -s)" =~ (Linux|OpenBSD) ]]; then - exp=" 00 00 00 00 00 00 3f ff" + exp=" 00 00 00 00 00 00 7f ff" else - exp=" 00 00 00 00 00 00 2f ff" + exp=" 00 00 00 00 00 00 6f ff" fi if [ "$res" != "$exp" ]; then echo "Error: Unexpected response from CMD_GET_CAPABILITY:" @@ -173,9 +173,9 @@ swtpm_open_cmddev ${SWTPM_INTERFACE} 100 # Get the capability bits: CMD_GET_CAPABILITY = 0x00 00 00 01 res="$(swtpm_ctrl_tx ${SWTPM_INTERFACE} '\x00\x00\x00\x01')" if [[ "$(uname -s)" =~ (Linux|OpenBSD) ]]; then - exp=" 00 00 00 00 00 00 3f ff" + exp=" 00 00 00 00 00 00 7f ff" else - exp=" 00 00 00 00 00 00 2f ff" + exp=" 00 00 00 00 00 00 6f ff" fi if [ "$res" != "$exp" ]; then echo "Error: Socket TPM: Unexpected response from CMD_GET_CAPABILITY:" diff --git a/tests/test_ctrlchannel4 b/tests/test_ctrlchannel4 index 65fa6d3..ffbcde7 100755 --- a/tests/test_ctrlchannel4 +++ b/tests/test_ctrlchannel4 @@ -45,7 +45,7 @@ PID="$(cat $PID_FILE)" # Get the capability bits: CMD_GET_CAPABILITY = 0x00 00 00 01 res="$(swtpm_ctrl_tx ${SWTPM_INTERFACE} '\x00\x00\x00\x01')" -exp=" 00 00 00 00 00 00 3f ff" +exp=" 00 00 00 00 00 00 7f ff" if [ "$res" != "$exp" ]; then echo "Error: Unexpected response from CMD_GET_CAPABILITY:" echo " actual : $res"