2 * ptm - CUSE based TPM PassThrough Multiplexer for QEMU.
4 * (c) Copyright IBM Corporation 2014, 2015.
6 * This program instantiates one /dev/vtpm* device, and
7 * calls libtpms to handle requests
9 * The following code was derived from
10 * http://fuse.sourceforge.net/doxygen/cusexmp_8c.html
12 * It's original header states:
14 * CUSE example: Character device in Userspace
15 * Copyright (C) 2008-2009 SUSE Linux Products GmbH
16 * Copyright (C) 2008-2009 Tejun Heo <tj@kernel.org>
17 * This program can be distributed under the terms of the GNU GPL.
18 * See the file COPYING.
21 * Authors: David Safford safford@us.ibm.com
22 * Stefan Berger stefanb@us.ibm.com
27 * Note: It's possible for multiple process to open access to
28 * the same character device. Concurrency problems may arise
29 * if those processes all write() to the device and then try
30 * to pick up the results. Proper usage of the device is to
31 * have one process (QEMU) use ioctl, read and write and have
32 * other processes (libvirt, etc.) only use ioctl.
34 #define FUSE_USE_VERSION 29
44 #include <sys/types.h>
48 #include <arpa/inet.h>
50 #include <libtpms/tpm_library.h>
51 #include <libtpms/tpm_tis.h>
52 #include <libtpms/tpm_error.h>
53 #include <libtpms/tpm_memory.h>
54 #include <libtpms/tpm_nvfilename.h>
56 #include "cuse_lowlevel.h"
58 #include "tpm_ioctl.h"
60 #include "swtpm_nvfile.h"
69 #define TPM_REQ_MAX 4096
70 static unsigned char *ptm_request
, *ptm_response
;
71 static uint32_t ptm_req_len
, ptm_res_len
, ptm_res_tot
;
72 static TPM_MODIFIER_INDICATOR locality
;
73 static int tpm_running
;
74 static int thread_busy
;
75 static GThreadPool
*pool
;
76 static struct passwd
*passwd
;
78 #if GLIB_MAJOR_VERSION >= 2
79 # if GLIB_MINOR_VERSION >= 32
81 GCond thread_busy_signal
;
82 GMutex thread_busy_lock
;
84 # define THREAD_BUSY_SIGNAL &thread_busy_signal
85 # define THREAD_BUSY_LOCK &thread_busy_lock
86 # define FILE_OPS_LOCK &file_ops_lock
90 GCond
*thread_busy_signal
;
91 GMutex
*thread_busy_lock
;
92 GMutex
*file_ops_lock
;
93 # define THREAD_BUSY_SIGNAL thread_busy_signal
94 # define THREAD_BUSY_LOCK thread_busy_lock
95 # define FILE_OPS_LOCK file_ops_lock
100 #error Unsupport glib version
123 struct thread_message
{
128 #define min(a,b) ((a) < (b) ? (a) : (b))
134 TPM_BOOL is_encrypted
;
137 typedef struct stateblob_desc
{
140 TPM_BOOL is_encrypted
;
142 uint32_t data_length
;
145 typedef enum tx_state_type
{
146 TX_STATE_RW_COMMAND
= 1,
147 TX_STATE_SET_STATE_BLOB
= 2,
148 TX_STATE_GET_STATE_BLOB
= 3,
151 typedef struct transfer_state
{
153 /* while in TX_STATE_GET/SET_STATEBLOB */
155 TPM_BOOL blob_is_encrypted
;
156 /* while in TX_STATE_GET */
160 /* function prototypes */
163 ptm_set_stateblob_append(uint32_t blobtype
,
164 const unsigned char *data
, uint32_t length
,
165 bool is_encrypted
, bool is_last
);
168 cached_stateblob_get(uint32_t offset
,
169 unsigned char **bufptr
, size_t *length
);
172 static const char *usage
=
173 "usage: %s [options]\n"
175 "The following options are supported:\n"
177 "-n NAME|--name=NAME : device name (mandatory)\n"
178 "-M MAJ|--maj=MAJ : device major number\n"
179 "-m MIN|--min=MIN : device minor number\n"
180 "--key file=<path>[,mode=aes-cbc][,format=hex|binary][,remove=[true|false]]\n"
181 " : use an AES key for the encryption of the TPM's state\n"
182 " files; use the given mode for the block encryption;\n"
183 " the key is to be provided as a hex string or in binary\n"
184 " format; the keyfile can be automatically removed using\n"
185 " the remove parameter\n"
186 "--key pwdfile=<path>[,mode=aes-cbc][,remove=[true|false]]\n"
187 " : provide a passphrase in a file; the AES key will be\n"
188 " derived from this passphrase\n"
189 "--migration-key file=<path>,[,mode=aes-cbc][,format=hex|binary][,remove=[true|false]]\n"
190 " : use an AES key for the encryption of the TPM's state\n"
191 " when it is retrieved from the TPM via ioctls;\n"
192 " Setting this key ensures that the TPM's state will always\n"
193 " be encrypted when migrated\n"
194 "--migration-key pwdfile=<path>[,mode=aes-cbc][,remove=[true|false]]\n"
195 " : provide a passphrase in a file; the AES key will be\n"
196 " derived from this passphrase\n"
197 "--log file=<path>|fd=<filedescriptor>\n"
198 " : write the TPM's log into the given file rather than\n"
199 " to the console; provide '-' for path to avoid logging\n"
200 "-h|--help : display this help screen and terminate\n"
202 "Make sure that TPM_PATH environment variable points to directory\n"
203 "where TPM's NV storage file is kept\n"
206 const static unsigned char TPM_Resp_FatalError
[] = {
207 0x00, 0xC4, /* TPM Response */
208 0x00, 0x00, 0x00, 0x0A, /* length (10) */
209 0x00, 0x00, 0x00, 0x09 /* TPM_FAIL */
212 const static unsigned char TPM_ResetEstablishmentBit
[] = {
213 0x00, 0xC1, /* TPM Request */
214 0x00, 0x00, 0x00, 0x0A, /* length (10) */
215 0x40, 0x00, 0x00, 0x0B /* TPM_ORD_ResetEstablishmentBit */
218 typedef struct TPM_Response_Header
{
222 } __attribute__ ((packed
)) TPM_Response_Header
;
225 ptm_io_getlocality(TPM_MODIFIER_INDICATOR
*loc
, uint32_t tpmnum
)
231 static struct libtpms_callbacks cbs
= {
232 .sizeOfStruct
= sizeof(struct libtpms_callbacks
),
233 .tpm_nvram_init
= SWTPM_NVRAM_Init
,
234 .tpm_nvram_loaddata
= SWTPM_NVRAM_LoadData
,
235 .tpm_nvram_storedata
= SWTPM_NVRAM_StoreData
,
236 .tpm_nvram_deletename
= SWTPM_NVRAM_DeleteName
,
237 .tpm_io_getlocality
= ptm_io_getlocality
,
240 static struct thread_message msg
;
242 static transfer_state tx_state
;
244 /* worker_thread_wait_done
246 * Wait while the TPM worker thread is busy
248 static void worker_thread_wait_done(void)
250 g_mutex_lock(THREAD_BUSY_LOCK
);
251 while (thread_busy
) {
252 #if GLIB_MINOR_VERSION >= 32
253 gint64 end_time
= g_get_monotonic_time() +
254 1 * G_TIME_SPAN_SECOND
;
255 g_cond_wait_until(THREAD_BUSY_SIGNAL
,
261 * seems like occasionally the g_cond_signal did not wake up
262 * the sleeping task; so we poll [TIS Test in BIOS]
265 abs_time
.tv_usec
= 0;
266 g_cond_timed_wait(THREAD_BUSY_SIGNAL
,
271 g_mutex_unlock(THREAD_BUSY_LOCK
);
274 /* worker_thread_mark_busy
276 * Mark the worker thread as busy; call this with the lock held
278 static void worker_thread_mark_busy(void)
280 g_mutex_lock(THREAD_BUSY_LOCK
);
282 g_mutex_unlock(THREAD_BUSY_LOCK
);
285 /* work_tread_mark_done
287 * Mark the worker thread as done and wake
288 * up the waiting thread
290 static void worker_thread_mark_done(void)
292 g_mutex_lock(THREAD_BUSY_LOCK
);
294 g_cond_signal(THREAD_BUSY_SIGNAL
);
295 g_mutex_unlock(THREAD_BUSY_LOCK
);
298 /* worker_thread_is_busy
300 * Determine whether the worker thread is busy
302 static int worker_thread_is_busy()
307 static void worker_thread(gpointer data
, gpointer user_data
)
309 struct thread_message
*msg
= (struct thread_message
*)data
;
312 case MESSAGE_TPM_CMD
:
313 TPMLIB_Process(&ptm_response
, &ptm_res_len
, &ptm_res_tot
,
314 ptm_request
, ptm_req_len
);
320 /* results are ready */
321 worker_thread_mark_done();
326 * finish the worker thread
328 static void worker_thread_end()
331 worker_thread_wait_done();
332 g_thread_pool_free(pool
, TRUE
, TRUE
);
337 /* _TPM_IO_TpmEstablished_Reset
339 * Reset the TPM Established bit
342 _TPM_IO_TpmEstablished_Reset(fuse_req_t req
,
343 TPM_MODIFIER_INDICATOR locty
)
345 TPM_RESULT res
= TPM_FAIL
;
346 TPM_Response_Header
*tpmrh
;
347 TPM_MODIFIER_INDICATOR orig_locality
= locality
;
351 ptm_req_len
= sizeof(TPM_ResetEstablishmentBit
);
352 memcpy(ptm_request
, TPM_ResetEstablishmentBit
, ptm_req_len
);
353 msg
.type
= MESSAGE_TPM_CMD
;
356 worker_thread_mark_busy();
358 g_thread_pool_push(pool
, &msg
, NULL
);
360 worker_thread_wait_done();
362 if (ptm_res_len
>= sizeof(TPM_Response_Header
)) {
363 tpmrh
= (TPM_Response_Header
*)ptm_response
;
364 res
= ntohl(tpmrh
->returnCode
);
367 locality
= orig_locality
;
372 static int tpm_start(uint32_t flags
)
375 char * tpmdir
= NULL
;
377 /* temporary - the backend script lacks the perms to do this */
378 if (tpmdir
== NULL
) {
379 tpmdir
= getenv("TPM_PATH");
381 logprintf(STDOUT_FILENO
,
382 "Error: TPM_PATH is not set\n");
386 dir
= opendir(tpmdir
);
390 if (mkdir(tpmdir
, 0775)) {
391 logprintf(STDERR_FILENO
,
392 "Error: Could not open TPM_PATH dir\n");
397 pool
= g_thread_pool_new(worker_thread
,
403 logprintf(STDERR_FILENO
,
404 "Error: Could not create the thread pool.\n");
408 if (TPMLIB_RegisterCallbacks(&cbs
) != TPM_SUCCESS
) {
409 logprintf(STDERR_FILENO
,
410 "Error: Could not register the callbacks.\n");
414 if (TPMLIB_MainInit() != TPM_SUCCESS
) {
415 logprintf(STDERR_FILENO
,
416 "Error: Could not start the CUSE TPM.\n");
420 if (flags
& PTM_INIT_FLAG_DELETE_VOLATILE
) {
421 uint32_t tpm_number
= 0;
422 char *name
= TPM_VOLATILESTATE_NAME
;
423 if (SWTPM_NVRAM_DeleteName(tpm_number
,
425 FALSE
) != TPM_SUCCESS
) {
426 logprintf(STDERR_FILENO
,
427 "Error: Could not delete the volatile "
428 "state of the TPM.\n");
429 goto error_terminate
;
434 ptm_request
= malloc(4096);
436 logprintf(STDERR_FILENO
,
437 "Error: Could not allocate memory for request buffer.\n");
438 goto error_terminate
;
441 logprintf(STDOUT_FILENO
,
442 "CUSE TPM successfully initialized.\n");
447 g_thread_pool_free(pool
, TRUE
, TRUE
);
456 * convert the blobtype integer into a string that libtpms
459 static const char *ptm_get_blobname(uint32_t blobtype
)
462 case PTM_BLOB_TYPE_PERMANENT
:
463 return TPM_PERMANENT_ALL_NAME
;
464 case PTM_BLOB_TYPE_VOLATILE
:
465 return TPM_VOLATILESTATE_NAME
;
466 case PTM_BLOB_TYPE_SAVESTATE
:
467 return TPM_SAVESTATE_NAME
;
473 static void ptm_open(fuse_req_t req
, struct fuse_file_info
*fi
)
475 tx_state
.state
= TX_STATE_RW_COMMAND
;
477 fuse_reply_open(req
, fi
);
480 /* ptm_write_fatal_error_response
482 * Write a fatal error response
484 static void ptm_write_fatal_error_response(void)
486 if (ptm_response
== NULL
||
487 ptm_res_tot
< sizeof(TPM_Resp_FatalError
)) {
488 ptm_res_tot
= sizeof(TPM_Resp_FatalError
);
489 TPM_Realloc(&ptm_response
, ptm_res_tot
);
492 ptm_res_len
= sizeof(TPM_Resp_FatalError
);
495 sizeof(TPM_Resp_FatalError
));
499 static void ptm_read_cmd(fuse_req_t req
, size_t size
)
504 /* wait until results are ready */
505 worker_thread_wait_done();
510 if (ptm_res_len
> size
) {
517 fuse_reply_buf(req
, (const char *)ptm_response
, len
);
521 * ptm_read_stateblob: get a stateblob via the read() interface
522 * @req: the fuse_req_t
523 * @size: the number of bytes to read
525 * The internal offset into the buffer is advanced by the number
526 * of bytes that were copied.
528 static void ptm_read_stateblob(fuse_req_t req
, size_t size
)
530 unsigned char *bufptr
= NULL
;
534 if (cached_stateblob_get(tx_state
.offset
, &bufptr
, &numbytes
) < 0) {
535 fuse_reply_err(req
, EIO
);
536 tx_state
.state
= TX_STATE_RW_COMMAND
;
538 tocopy
= MIN(size
, numbytes
);
539 tx_state
.offset
+= tocopy
;
541 fuse_reply_buf(req
, (char *)bufptr
, tocopy
);
542 /* last transfer indicated by less bytes available than requested */
543 if (numbytes
< size
) {
544 tx_state
.state
= TX_STATE_RW_COMMAND
;
549 static void ptm_read(fuse_req_t req
, size_t size
, off_t off
,
550 struct fuse_file_info
*fi
)
552 switch (tx_state
.state
) {
553 case TX_STATE_RW_COMMAND
:
554 ptm_read_cmd(req
, size
);
556 case TX_STATE_SET_STATE_BLOB
:
557 fuse_reply_err(req
, EIO
);
558 tx_state
.state
= TX_STATE_RW_COMMAND
;
560 case TX_STATE_GET_STATE_BLOB
:
561 ptm_read_stateblob(req
, size
);
566 static void ptm_write_cmd(fuse_req_t req
, const char *buf
, size_t size
)
571 /* prevent other threads from writing or doing ioctls */
572 g_mutex_lock(FILE_OPS_LOCK
);
575 /* ensure that we only ever work on one TPM command */
576 if (worker_thread_is_busy()) {
577 fuse_reply_err(req
, EBUSY
);
581 /* have command processed by thread pool */
582 if (ptm_req_len
> TPM_REQ_MAX
)
583 ptm_req_len
= TPM_REQ_MAX
;
585 memcpy(ptm_request
, buf
, ptm_req_len
);
586 msg
.type
= MESSAGE_TPM_CMD
;
589 worker_thread_mark_busy();
591 g_thread_pool_push(pool
, &msg
, NULL
);
593 fuse_reply_write(req
, ptm_req_len
);
595 /* TPM not initialized; return error */
596 ptm_write_fatal_error_response();
597 fuse_reply_write(req
, ptm_req_len
);
601 g_mutex_unlock(FILE_OPS_LOCK
);
607 * ptm_write_stateblob: Write the state blob using the write() interface
609 * @req: the fuse_req_t
610 * @buf: the buffer with the data
611 * @size: the number of bytes in the buffer
613 * The data are appended to an existing buffer that was created with the
616 static void ptm_write_stateblob(fuse_req_t req
, const char *buf
, size_t size
)
620 res
= ptm_set_stateblob_append(tx_state
.blobtype
,
621 (unsigned char *)buf
, size
,
622 tx_state
.blob_is_encrypted
,
625 tx_state
.state
= TX_STATE_RW_COMMAND
;
626 fuse_reply_err(req
, EIO
);
628 fuse_reply_write(req
, size
);
633 * ptm_write: low-level write() interface; calls approriate function depending
634 * on what is being transferred using the write()
636 static void ptm_write(fuse_req_t req
, const char *buf
, size_t size
,
637 off_t off
, struct fuse_file_info
*fi
)
639 switch (tx_state
.state
) {
640 case TX_STATE_RW_COMMAND
:
641 ptm_write_cmd(req
, buf
, size
);
643 case TX_STATE_GET_STATE_BLOB
:
644 fuse_reply_err(req
, EIO
);
645 tx_state
.state
= TX_STATE_RW_COMMAND
;
647 case TX_STATE_SET_STATE_BLOB
:
648 ptm_write_stateblob(req
, buf
, size
);
653 static stateblob_desc cached_stateblob
;
656 cached_stateblob_is_loaded(uint32_t blobtype
, TPM_BOOL decrypt
)
658 return (cached_stateblob
.data
!= NULL
) &&
659 (cached_stateblob
.blobtype
== blobtype
) &&
660 (cached_stateblob
.decrypt
== decrypt
);
664 * cached_stateblob_free: Free any previously loaded state blob
667 cached_stateblob_free(void)
669 TPM_Free(cached_stateblob
.data
);
670 cached_stateblob
.data
= NULL
;
671 cached_stateblob
.data_length
= 0;
675 * cached_stateblob_get_bloblength: get the total length of the cached blob
678 cached_stateblob_get_bloblength(void)
680 return cached_stateblob
.data_length
;
684 * cached_statblob_get: get stateblob data without copying them
686 * @offset: at which offset to get the data
687 * @bufptr: pointer to a buffer pointer used to return buffer start
688 * @length: pointer used to return number of available bytes in returned buffer
691 cached_stateblob_get(uint32_t offset
,
692 unsigned char **bufptr
, size_t *length
)
694 if (cached_stateblob
.data
== NULL
||
695 offset
> cached_stateblob
.data_length
)
698 *bufptr
= &cached_stateblob
.data
[offset
];
699 *length
= cached_stateblob
.data_length
- offset
;
705 * cached_stateblob_load: load a state blob into the cache
707 * blobtype: the type of blob
708 * decrypt: whether the blob is to be decrypted
711 cached_stateblob_load(uint32_t blobtype
, TPM_BOOL decrypt
)
714 const char *blobname
= ptm_get_blobname(blobtype
);
715 uint32_t tpm_number
= 0;
718 return TPM_BAD_PARAMETER
;
720 cached_stateblob_free();
722 if (blobtype
== PTM_BLOB_TYPE_VOLATILE
)
723 res
= SWTPM_NVRAM_Store_Volatile();
726 res
= SWTPM_NVRAM_GetStateBlob(&cached_stateblob
.data
,
727 &cached_stateblob
.data_length
,
728 tpm_number
, blobname
, decrypt
,
729 &cached_stateblob
.is_encrypted
);
731 /* make sure the volatile state file is gone */
732 if (blobtype
== PTM_BLOB_TYPE_VOLATILE
)
733 SWTPM_NVRAM_DeleteName(tpm_number
, blobname
, FALSE
);
736 cached_stateblob
.blobtype
= blobtype
;
737 cached_stateblob
.decrypt
= decrypt
;
744 * cached_state_blob_copy: copy the cached state blob to a destination buffer
746 * dest: destination buffer
747 * destlen: size of the buffer
748 * srcoffset: offset to copy from
749 * copied: variable to return the number of copied bytes
750 * is_encrypted: variable to return whether the blob is encrypted
753 cached_stateblob_copy(void *dest
, size_t destlen
, uint32_t srcoffset
,
754 uint32_t *copied
, TPM_BOOL
*is_encrypted
)
760 if (cached_stateblob
.data
!= NULL
&& cached_stateblob
.data_length
> 0) {
762 if (srcoffset
< cached_stateblob
.data_length
) {
763 *copied
= min(cached_stateblob
.data_length
- srcoffset
, destlen
);
765 memcpy(dest
, &cached_stateblob
.data
[srcoffset
], *copied
);
767 *is_encrypted
= cached_stateblob
.is_encrypted
;
777 * ptm_get_stateblob_part: get part of a state blob
780 ptm_get_stateblob_part(uint32_t blobtype
,
781 unsigned char *buffer
, size_t buffer_size
,
782 uint32_t offset
, uint32_t *copied
,
783 TPM_BOOL decrypt
, TPM_BOOL
*is_encrypted
)
787 if (!cached_stateblob_is_loaded(blobtype
, decrypt
)) {
788 res
= cached_stateblob_load(blobtype
, decrypt
);
792 cached_stateblob_copy(buffer
, buffer_size
,
793 offset
, copied
, is_encrypted
);
800 * ptm_get_stateblob: Get the state blob from the TPM using ioctl()
803 ptm_get_stateblob(fuse_req_t req
, ptm_getstate
*pgs
)
806 uint32_t blobtype
= pgs
->u
.req
.type
;
808 ((pgs
->u
.req
.state_flags
& PTM_STATE_FLAG_DECRYPTED
) != 0);
809 TPM_BOOL is_encrypted
= FALSE
;
811 uint32_t offset
= pgs
->u
.req
.offset
;
814 res
= ptm_get_stateblob_part(blobtype
,
815 pgs
->u
.resp
.data
, sizeof(pgs
->u
.resp
.data
),
816 pgs
->u
.req
.offset
, &copied
,
817 decrypt
, &is_encrypted
);
819 totlength
= cached_stateblob_get_bloblength();
821 pgs
->u
.resp
.state_flags
= 0;
823 pgs
->u
.resp
.state_flags
|= PTM_STATE_FLAG_ENCRYPTED
;
825 pgs
->u
.resp
.length
= copied
;
826 pgs
->u
.resp
.totlength
= totlength
;
827 pgs
->u
.resp
.tpm_result
= res
;
830 if (offset
+ copied
< totlength
) {
831 /* last byte was not copied */
832 tx_state
.state
= TX_STATE_GET_STATE_BLOB
;
833 tx_state
.blobtype
= pgs
->u
.req
.type
;
834 tx_state
.blob_is_encrypted
= is_encrypted
;
835 tx_state
.offset
= copied
;
837 /* last byte was copied */
838 tx_state
.state
= TX_STATE_RW_COMMAND
;
842 tx_state
.state
= TX_STATE_RW_COMMAND
;
845 fuse_reply_ioctl(req
, 0, pgs
, sizeof(pgs
->u
.resp
));
849 * ptm_set_stateblob_append: Append a piece of TPM state blob and transfer to TPM
851 * blobtype: the type of blob
852 * data: the data to append
853 * length: length of the data
854 * is_encrypted: whether the blob is encrypted
855 * is_last: whether this is the last part of the TPM state blob; if it is, the TPM
856 * state blob will then be transferred to the TPM
859 ptm_set_stateblob_append(uint32_t blobtype
,
860 const unsigned char *data
, uint32_t length
,
861 bool is_encrypted
, bool is_last
)
863 const char *blobname
;
865 static struct stateblob stateblob
;
867 if (stateblob
.type
!= blobtype
) {
869 TPM_Free(stateblob
.data
);
870 stateblob
.data
= NULL
;
871 stateblob
.length
= 0;
872 stateblob
.type
= blobtype
;
873 stateblob
.is_encrypted
= is_encrypted
;
876 * on the first call for a new state blob we allow 0 bytes to be written
877 * this allows the user to transfer via write()
884 res
= TPM_Realloc(&stateblob
.data
, stateblob
.length
+ length
);
887 TPM_Free(stateblob
.data
);
888 stateblob
.data
= NULL
;
889 stateblob
.length
= 0;
895 memcpy(&stateblob
.data
[stateblob
.length
], data
, length
);
896 stateblob
.length
+= length
;
899 /* full packet -- expecting more data */
902 blobname
= ptm_get_blobname(blobtype
);
905 res
= SWTPM_NVRAM_SetStateBlob(stateblob
.data
,
907 stateblob
.is_encrypted
,
911 res
= TPM_BAD_PARAMETER
;
914 TPM_Free(stateblob
.data
);
915 stateblob
.data
= NULL
;
916 stateblob
.length
= 0;
919 /* transfer of blob is complete */
920 tx_state
.state
= TX_STATE_RW_COMMAND
;
926 ptm_set_stateblob(fuse_req_t req
, ptm_setstate
*pss
)
929 TPM_BOOL is_encrypted
=
930 ((pss
->u
.req
.state_flags
& PTM_STATE_FLAG_ENCRYPTED
) != 0);
931 bool is_last
= (sizeof(pss
->u
.req
.data
) != pss
->u
.req
.length
);
933 if (pss
->u
.req
.length
> sizeof(pss
->u
.req
.data
)) {
934 res
= TPM_BAD_PARAMETER
;
938 /* transfer of blob initiated */
939 tx_state
.state
= TX_STATE_SET_STATE_BLOB
;
940 tx_state
.blobtype
= pss
->u
.req
.type
;
941 tx_state
.blob_is_encrypted
= is_encrypted
;
944 res
= ptm_set_stateblob_append(pss
->u
.req
.type
,
951 tx_state
.state
= TX_STATE_RW_COMMAND
;
954 pss
->u
.resp
.tpm_result
= res
;
956 fuse_reply_ioctl(req
, 0, pss
, sizeof(*pss
));
960 * ptm_ioctl : ioctl execution
962 * req: the fuse_req_t used to send response with
963 * cmd: the ioctl request code
964 * arg: the pointer the application used for calling the ioctl (3rd param)
966 * flags: some flags provided by fuse
967 * in_buf: the copy of the input buffer
968 * in_bufsz: size of the input buffer; provided by fuse and has size of
970 * out_bufsz: size of the output buffer; provided by fuse and has size of
973 static void ptm_ioctl(fuse_req_t req
, int cmd
, void *arg
,
974 struct fuse_file_info
*fi
, unsigned flags
,
975 const void *in_buf
, size_t in_bufsz
, size_t out_bufsz
)
978 bool exit_prg
= FALSE
;
981 if (flags
& FUSE_IOCTL_COMPAT
) {
982 fuse_reply_err(req
, ENOSYS
);
986 /* some commands have to wait until the worker thread is done */
988 case PTM_GET_CAPABILITY
:
989 case PTM_SET_LOCALITY
:
990 case PTM_CANCEL_TPM_CMD
:
992 /* no need to wait */
996 case PTM_GET_TPMESTABLISHED
:
997 case PTM_RESET_TPMESTABLISHED
:
1001 case PTM_STORE_VOLATILE
:
1002 case PTM_GET_STATEBLOB
:
1003 case PTM_SET_STATEBLOB
:
1005 worker_thread_wait_done();
1009 /* prevent other threads from writing or doing ioctls */
1010 g_mutex_lock(FILE_OPS_LOCK
);
1013 case PTM_GET_CAPABILITY
:
1014 if (out_bufsz
!= sizeof(ptm_cap
)) {
1015 struct iovec iov
= { arg
, sizeof(uint8_t) };
1016 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1019 ptm_caps
= PTM_CAP_INIT
| PTM_CAP_SHUTDOWN
1020 | PTM_CAP_GET_TPMESTABLISHED
1021 | PTM_CAP_SET_LOCALITY
1023 | PTM_CAP_CANCEL_TPM_CMD
1024 | PTM_CAP_STORE_VOLATILE
1025 | PTM_CAP_RESET_TPMESTABLISHED
1026 | PTM_CAP_GET_STATEBLOB
1027 | PTM_CAP_SET_STATEBLOB
1029 | PTM_CAP_GET_CONFIG
;
1030 fuse_reply_ioctl(req
, 0, &ptm_caps
, sizeof(ptm_caps
));
1035 if (in_bufsz
!= sizeof(ptm_init
)) {
1036 struct iovec iov
= { arg
, sizeof(uint8_t) };
1037 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1039 init_p
= (ptm_init
*)in_buf
;
1041 worker_thread_end();
1046 if ((res
= tpm_start(init_p
->u
.req
.init_flags
))) {
1047 logprintf(STDERR_FILENO
,
1048 "Error: Could not initialize the TPM.\n");
1052 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1057 worker_thread_end();
1064 TPM_Free(ptm_response
);
1065 ptm_response
= NULL
;
1067 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1072 worker_thread_end();
1077 TPM_Free(ptm_response
);
1078 ptm_response
= NULL
;
1080 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1085 case PTM_GET_TPMESTABLISHED
:
1087 goto error_not_running
;
1089 if (out_bufsz
!= sizeof(ptm_est
)) {
1090 struct iovec iov
= { arg
, sizeof(uint8_t) };
1091 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1094 te
.u
.resp
.tpm_result
= TPM_IO_TpmEstablished_Get(&te
.u
.resp
.bit
);
1095 fuse_reply_ioctl(req
, 0, &te
, sizeof(te
));
1099 case PTM_RESET_TPMESTABLISHED
:
1101 goto error_not_running
;
1103 if (in_bufsz
!= sizeof(ptm_reset_est
)) {
1104 struct iovec iov
= { arg
, sizeof(uint32_t) };
1105 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1107 ptm_reset_est
*re
= (ptm_reset_est
*)in_buf
;
1108 if (re
->u
.req
.loc
> 4) {
1109 res
= TPM_BAD_LOCALITY
;
1111 res
= _TPM_IO_TpmEstablished_Reset(req
, re
->u
.req
.loc
);
1112 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1117 case PTM_SET_LOCALITY
:
1118 if (in_bufsz
!= sizeof(ptm_loc
)) {
1119 struct iovec iov
= { arg
, sizeof(uint32_t) };
1120 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1122 ptm_loc
*l
= (ptm_loc
*)in_buf
;
1123 if (l
->u
.req
.loc
> 4) {
1124 res
= TPM_BAD_LOCALITY
;
1127 locality
= l
->u
.req
.loc
;
1129 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1133 case PTM_HASH_START
:
1135 goto error_not_running
;
1137 res
= TPM_IO_Hash_Start();
1138 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1143 goto error_not_running
;
1145 if (in_bufsz
!= sizeof(ptm_hdata
)) {
1146 struct iovec iov
= { arg
, sizeof(uint32_t) };
1147 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1149 ptm_hdata
*data
= (ptm_hdata
*)in_buf
;
1150 if (data
->u
.req
.length
<= sizeof(data
->u
.req
.data
)) {
1151 res
= TPM_IO_Hash_Data(data
->u
.req
.data
,
1152 data
->u
.req
.length
);
1156 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1162 goto error_not_running
;
1164 res
= TPM_IO_Hash_End();
1165 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1168 case PTM_CANCEL_TPM_CMD
:
1170 goto error_not_running
;
1172 /* for cancellation to work, the TPM would have to
1173 * execute in another thread that polls on a cancel
1177 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1180 case PTM_STORE_VOLATILE
:
1182 goto error_not_running
;
1184 res
= SWTPM_NVRAM_Store_Volatile();
1185 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1187 cached_stateblob_free();
1190 case PTM_GET_STATEBLOB
:
1192 goto error_not_running
;
1194 if (in_bufsz
!= sizeof(ptm_getstate
)) {
1195 struct iovec iov
= { arg
, sizeof(uint32_t) };
1196 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1198 ptm_get_stateblob(req
, (ptm_getstate
*)in_buf
);
1202 case PTM_SET_STATEBLOB
:
1206 /* tpm state dir must be set */
1209 if (in_bufsz
!= sizeof(ptm_setstate
)) {
1210 struct iovec iov
= { arg
, sizeof(uint32_t) };
1211 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1213 ptm_set_stateblob(req
, (ptm_setstate
*)in_buf
);
1217 case PTM_GET_CONFIG
:
1218 if (out_bufsz
!= sizeof(ptm_getconfig
)) {
1219 struct iovec iov
= { arg
, sizeof(uint32_t) };
1220 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1223 pgs
.u
.resp
.tpm_result
= 0;
1224 pgs
.u
.resp
.flags
= 0;
1225 if (SWTPM_NVRAM_Has_FileKey())
1226 pgs
.u
.resp
.flags
|= PTM_CONFIG_FLAG_FILE_KEY
;
1227 if (SWTPM_NVRAM_Has_MigrationKey())
1228 pgs
.u
.resp
.flags
|= PTM_CONFIG_FLAG_MIGRATION_KEY
;
1229 fuse_reply_ioctl(req
, 0, &pgs
, sizeof(pgs
));
1234 fuse_reply_err(req
, EINVAL
);
1238 g_mutex_unlock(FILE_OPS_LOCK
);
1241 logprintf(STDOUT_FILENO
,
1242 "CUSE TPM is shutting down.\n");
1250 res
= TPM_BAD_ORDINAL
;
1251 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1256 static void ptm_init_done(void *userdata
)
1258 /* at this point the entry in /dev/ is available */
1259 if (pidfile_write(getpid()) < 0) {
1264 if (initgroups(passwd
->pw_name
, passwd
->pw_gid
) < 0) {
1265 logprintf(STDERR_FILENO
,
1266 "Error: initgroups(%s, %d) failed.\n",
1267 passwd
->pw_name
, passwd
->pw_gid
);
1270 if (setgid(passwd
->pw_gid
) < 0) {
1271 logprintf(STDERR_FILENO
,
1272 "Error: setgid(%d) failed.\n",
1276 if (setuid(passwd
->pw_uid
) < 0) {
1277 logprintf(STDERR_FILENO
,
1278 "Error: setuid(%d) failed.\n",
1285 static const struct cuse_lowlevel_ops ptm_clop
= {
1290 .init_done
= ptm_init_done
,
1293 #define PTM_OPT(t, p) { t, offsetof(struct ptm_param, p), 1 }
1295 static const struct fuse_opt ptm_opts
[] = {
1296 PTM_OPT("-M %u", major
),
1297 PTM_OPT("--maj=%u", major
),
1298 PTM_OPT("-m %u", minor
),
1299 PTM_OPT("--min=%u", minor
),
1300 PTM_OPT("-n %s", dev_name
),
1301 PTM_OPT("--name=%s", dev_name
),
1302 PTM_OPT("-r %s", runas
),
1303 PTM_OPT("--runas=%s", runas
),
1304 PTM_OPT("--log %s", logging
),
1305 PTM_OPT("--key %s", keydata
),
1306 PTM_OPT("--migration-key %s", migkeydata
),
1307 PTM_OPT("--pid %s", piddata
),
1308 FUSE_OPT_KEY("-h", 0),
1309 FUSE_OPT_KEY("--help", 0),
1310 FUSE_OPT_KEY("-v", 1),
1311 FUSE_OPT_KEY("--version", 1),
1315 static int ptm_process_arg(void *data
, const char *arg
, int key
,
1316 struct fuse_args
*outargs
)
1318 struct ptm_param
*param
= data
;
1323 fprintf(stdout
, usage
, param
->prgname
);
1324 return fuse_opt_add_arg(outargs
, "-ho");
1327 fprintf(stdout
, "TPM emulator CUSE interface version %d.%d.%d, "
1328 "Copyright (c) 2014 IBM Corp.\n",
1339 int main(int argc
, char **argv
)
1341 struct fuse_args args
= FUSE_ARGS_INIT(argc
, argv
);
1342 struct ptm_param param
= {
1353 char dev_name
[128] = "DEVNAME=";
1354 const char *dev_info_argv
[] = { dev_name
};
1355 struct cuse_info ci
;
1358 if ((ret
= fuse_opt_parse(&args
, ¶m
, ptm_opts
, ptm_process_arg
))) {
1359 fprintf(stderr
, "Error: Could not parse option\n");
1363 if (!param
.is_help
) {
1364 if (!param
.dev_name
) {
1365 fprintf(stderr
, "Error: device name missing\n");
1368 strncat(dev_name
, param
.dev_name
, sizeof(dev_name
) - 9);
1373 if (handle_log_options(param
.logging
) < 0 ||
1374 handle_key_options(param
.keydata
) < 0 ||
1375 handle_migration_key_options(param
.migkeydata
) < 0 ||
1376 handle_pid_options(param
.piddata
) < 0)
1380 fprintf(stderr
, "Error: Unable to setuid root. uid = %d, "
1381 "euid = %d, gid = %d\n", getuid(), geteuid(), getgid());
1386 if (!(passwd
= getpwnam(param
.runas
))) {
1387 fprintf(stderr
, "User '%s' does not exist\n",
1393 memset(&ci
, 0, sizeof(ci
));
1394 ci
.dev_major
= param
.major
;
1395 ci
.dev_minor
= param
.minor
;
1396 ci
.dev_info_argc
= 1;
1397 ci
.dev_info_argv
= dev_info_argv
;
1399 #if GLIB_MINOR_VERSION >= 32
1400 g_mutex_init(THREAD_BUSY_LOCK
);
1401 g_cond_init(THREAD_BUSY_SIGNAL
);
1402 g_mutex_init(FILE_OPS_LOCK
);
1404 g_thread_init(NULL
);
1405 THREAD_BUSY_LOCK
= g_mutex_new();
1406 THREAD_BUSY_SIGNAL
= g_cond_new();
1407 FILE_OPS_LOCK
= g_mutex_new();
1410 return cuse_lowlevel_main(args
.argc
, args
.argv
, &ci
, &ptm_clop
,