1 /********************************************************************************/
4 /* IBM Thomas J. Watson Research Center */
6 /* (c) Copyright IBM Corporation 2014-2015. */
8 /* All rights reserved. */
10 /* Redistribution and use in source and binary forms, with or without */
11 /* modification, are permitted provided that the following conditions are */
14 /* Redistributions of source code must retain the above copyright notice, */
15 /* this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in the */
19 /* documentation and/or other materials provided with the distribution. */
21 /* Neither the names of the IBM Corporation nor the names of its */
22 /* contributors may be used to endorse or promote products derived from */
23 /* this software without specific prior written permission. */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
28 /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
31 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
32 /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
33 /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
34 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
35 /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /********************************************************************************/
40 * Eric Richter, erichte@us.ibm.com
41 * Stefan Berger, stefanb@us.ibm.com
42 * David Safford, safford@us.ibm.com
54 #include <arpa/inet.h>
56 #include <fuse/cuse_lowlevel.h>
60 #include <libtpms/tpm_library.h>
61 #include <libtpms/tpm_tis.h>
62 #include <libtpms/tpm_error.h>
63 #include <libtpms/tpm_memory.h>
64 #include <libtpms/tpm_nvfilename.h>
71 #include "tpm_ioctl.h"
72 #include "swtpm_nvfile.h"
75 /* maximum size of request buffer */
76 #define TPM_REQ_MAX 4096
78 /* buffer containing the TPM request */
79 static unsigned char *ptm_request
;
81 /* buffer containing the TPM response */
82 static unsigned char *ptm_response
;
84 /* the sizes of the data in the buffers */
85 static uint32_t ptm_req_len
, ptm_res_len
, ptm_res_tot
;
87 /* locality applied to TPM commands */
88 static TPM_MODIFIER_INDICATOR locality
;
90 /* whether the TPM is running (TPM_Init was received) */
91 static bool tpm_running
;
93 /* whether the worker thread is busy processing a command */
94 static bool thread_busy
;
96 /* thread pool with one single TPM thread */
97 static GThreadPool
*pool
;
99 #if GLIB_MAJOR_VERSION >= 2
100 # if GLIB_MINOR_VERSION >= 32
102 GCond thread_busy_signal
;
103 GMutex thread_busy_lock
;
104 GMutex file_ops_lock
;
105 # define THREAD_BUSY_SIGNAL &thread_busy_signal
106 # define THREAD_BUSY_LOCK &thread_busy_lock
107 # define FILE_OPS_LOCK &file_ops_lock
111 GCond
*thread_busy_signal
;
112 GMutex
*thread_busy_lock
;
113 GMutex
*file_ops_lock
;
114 # define THREAD_BUSY_SIGNAL thread_busy_signal
115 # define THREAD_BUSY_LOCK thread_busy_lock
116 # define FILE_OPS_LOCK file_ops_lock
121 #error Unsupport glib version
139 /* the message we are sending to the thread in the pool */
140 struct thread_message
{
145 #define min(a,b) ((a) < (b) ? (a) : (b))
151 TPM_BOOL is_encrypted
;
154 typedef struct stateblob_desc
{
157 TPM_BOOL is_encrypted
;
159 uint32_t data_length
;
162 typedef enum tx_state_type
{
163 TX_STATE_RW_COMMAND
= 1,
164 TX_STATE_SET_STATE_BLOB
= 2,
165 TX_STATE_GET_STATE_BLOB
= 3,
168 typedef struct transfer_state
{
170 /* while in TX_STATE_GET/SET_STATEBLOB */
172 TPM_BOOL blob_is_encrypted
;
173 /* while in TX_STATE_GET */
177 typedef struct TPM_Response_Header
{
181 } __attribute__ ((packed
)) TPM_Response_Header
;
183 /*********************************** data *************************************/
185 static const char *usage
=
186 "usage: %s [options]\n"
188 "The following options are supported:\n"
190 "-n NAME|--name=NAME : device name (mandatory)\n"
191 "-M MAJ|--maj=MAJ : device major number\n"
192 "-m MIN|--min=MIN : device minor number\n"
193 "--key file=<path>[,mode=aes-cbc][,format=hex|binary][,remove=[true|false]]\n"
194 " : use an AES key for the encryption of the TPM's state\n"
195 " files; use the given mode for the block encryption;\n"
196 " the key is to be provided as a hex string or in binary\n"
197 " format; the keyfile can be automatically removed using\n"
198 " the remove parameter\n"
199 "--key pwdfile=<path>[,mode=aes-cbc][,remove=[true|false]]\n"
200 " : provide a passphrase in a file; the AES key will be\n"
201 " derived from this passphrase\n"
202 "--migration-key file=<path>,[,mode=aes-cbc][,format=hex|binary][,remove=[true|false]]\n"
203 " : use an AES key for the encryption of the TPM's state\n"
204 " when it is retrieved from the TPM via ioctls;\n"
205 " Setting this key ensures that the TPM's state will always\n"
206 " be encrypted when migrated\n"
207 "--migration-key pwdfile=<path>[,mode=aes-cbc][,remove=[true|false]]\n"
208 " : provide a passphrase in a file; the AES key will be\n"
209 " derived from this passphrase\n"
210 "--log file=<path>|fd=<filedescriptor>\n"
211 " : write the TPM's log into the given file rather than\n"
212 " to the console; provide '-' for path to avoid logging\n"
213 "--pid file=<path> : write the process ID into the given file\n"
214 "--tpmstate dir=<dir>\n"
215 " : set the directory where the TPM's state will be written\n"
216 " into; the TPM_PATH environment variable can be used\n"
219 "-h|--help : display this help screen and terminate\n"
222 const static unsigned char TPM_Resp_FatalError
[] = {
223 0x00, 0xC4, /* TPM Response */
224 0x00, 0x00, 0x00, 0x0A, /* length (10) */
225 0x00, 0x00, 0x00, 0x09 /* TPM_FAIL */
228 const static unsigned char TPM_ResetEstablishmentBit
[] = {
229 0x00, 0xC1, /* TPM Request */
230 0x00, 0x00, 0x00, 0x0A, /* length (10) */
231 0x40, 0x00, 0x00, 0x0B /* TPM_ORD_ResetEstablishmentBit */
235 ptm_io_getlocality(TPM_MODIFIER_INDICATOR
*loc
, uint32_t tpmnum
)
241 static struct libtpms_callbacks cbs
= {
242 .sizeOfStruct
= sizeof(struct libtpms_callbacks
),
243 .tpm_nvram_init
= SWTPM_NVRAM_Init
,
244 .tpm_nvram_loaddata
= SWTPM_NVRAM_LoadData
,
245 .tpm_nvram_storedata
= SWTPM_NVRAM_StoreData
,
246 .tpm_nvram_deletename
= SWTPM_NVRAM_DeleteName
,
247 .tpm_io_getlocality
= ptm_io_getlocality
,
250 /* single message to send to the worker thread */
251 static struct thread_message msg
;
253 /* the current state the transfer interface is in */
254 static transfer_state tx_state
;
257 * convert the blobtype integer into a string that libtpms
260 static const char *ptm_get_blobname(uint32_t blobtype
)
263 case PTM_BLOB_TYPE_PERMANENT
:
264 return TPM_PERMANENT_ALL_NAME
;
265 case PTM_BLOB_TYPE_VOLATILE
:
266 return TPM_VOLATILESTATE_NAME
;
267 case PTM_BLOB_TYPE_SAVESTATE
:
268 return TPM_SAVESTATE_NAME
;
274 /************************* cached stateblob *********************************/
276 static stateblob_desc cached_stateblob
;
279 * cached_stateblob_is_loaded: is the stateblob with the given properties
280 * the one in the cache?
282 static bool cached_stateblob_is_loaded(uint32_t blobtype
,
285 return (cached_stateblob
.data
!= NULL
) &&
286 (cached_stateblob
.blobtype
== blobtype
) &&
287 (cached_stateblob
.decrypt
== decrypt
);
291 * cached_stateblob_free: Free any previously loaded state blob
293 static void cached_stateblob_free(void)
295 TPM_Free(cached_stateblob
.data
);
296 cached_stateblob
.data
= NULL
;
297 cached_stateblob
.data_length
= 0;
301 * cached_stateblob_get_bloblength: get the total length of the cached blob
303 static uint32_t cached_stateblob_get_bloblength(void)
305 return cached_stateblob
.data_length
;
309 * cached_statblob_get: get stateblob data without copying them
311 * @offset: at which offset to get the data
312 * @bufptr: pointer to a buffer pointer used to return buffer start
313 * @length: pointer used to return number of available bytes in returned buffer
315 static int cached_stateblob_get(uint32_t offset
,
316 unsigned char **bufptr
, size_t *length
)
318 if (cached_stateblob
.data
== NULL
||
319 offset
> cached_stateblob
.data_length
)
322 *bufptr
= &cached_stateblob
.data
[offset
];
323 *length
= cached_stateblob
.data_length
- offset
;
329 * cached_stateblob_load: load a state blob into the cache
331 * blobtype: the type of blob
332 * decrypt: whether the blob is to be decrypted
334 static TPM_RESULT
cached_stateblob_load(uint32_t blobtype
, TPM_BOOL decrypt
)
337 const char *blobname
= ptm_get_blobname(blobtype
);
338 uint32_t tpm_number
= 0;
341 return TPM_BAD_PARAMETER
;
343 cached_stateblob_free();
345 if (blobtype
== PTM_BLOB_TYPE_VOLATILE
)
346 res
= SWTPM_NVRAM_Store_Volatile();
349 res
= SWTPM_NVRAM_GetStateBlob(&cached_stateblob
.data
,
350 &cached_stateblob
.data_length
,
351 tpm_number
, blobname
, decrypt
,
352 &cached_stateblob
.is_encrypted
);
354 /* make sure the volatile state file is gone */
355 if (blobtype
== PTM_BLOB_TYPE_VOLATILE
)
356 SWTPM_NVRAM_DeleteName(tpm_number
, blobname
, FALSE
);
359 cached_stateblob
.blobtype
= blobtype
;
360 cached_stateblob
.decrypt
= decrypt
;
367 * cached_state_blob_copy: copy the cached state blob to a destination buffer
369 * dest: destination buffer
370 * destlen: size of the buffer
371 * srcoffset: offset to copy from
372 * copied: variable to return the number of copied bytes
373 * is_encrypted: variable to return whether the blob is encrypted
375 static int cached_stateblob_copy(void *dest
, size_t destlen
,
376 uint32_t srcoffset
, uint32_t *copied
,
377 TPM_BOOL
*is_encrypted
)
383 if (cached_stateblob
.data
!= NULL
&& cached_stateblob
.data_length
> 0) {
385 if (srcoffset
< cached_stateblob
.data_length
) {
386 *copied
= min(cached_stateblob
.data_length
- srcoffset
, destlen
);
388 memcpy(dest
, &cached_stateblob
.data
[srcoffset
], *copied
);
390 *is_encrypted
= cached_stateblob
.is_encrypted
;
400 /************************* worker thread ************************************/
403 * worker_thread_wait_done: wait until the worker thread is done
405 static void worker_thread_wait_done(void)
407 g_mutex_lock(THREAD_BUSY_LOCK
);
408 while (thread_busy
) {
409 #if GLIB_MINOR_VERSION >= 32
410 gint64 end_time
= g_get_monotonic_time() +
411 1 * G_TIME_SPAN_SECOND
;
412 g_cond_wait_until(THREAD_BUSY_SIGNAL
,
418 * seems like occasionally the g_cond_signal did not wake up
419 * the sleeping task; so we poll [TIS Test in BIOS]
422 abs_time
.tv_usec
= 0;
423 g_cond_timed_wait(THREAD_BUSY_SIGNAL
,
428 g_mutex_unlock(THREAD_BUSY_LOCK
);
432 * worker_thread_mark_busy: mark the workder thread as busy
434 static void worker_thread_mark_busy(void)
436 g_mutex_lock(THREAD_BUSY_LOCK
);
438 g_mutex_unlock(THREAD_BUSY_LOCK
);
442 * work_tread_mark_done: mark the worker thread as having completed
444 * Mark the worker thread as done and wake up the waiting thread.
446 static void worker_thread_mark_done(void)
448 g_mutex_lock(THREAD_BUSY_LOCK
);
450 g_cond_signal(THREAD_BUSY_SIGNAL
);
451 g_mutex_unlock(THREAD_BUSY_LOCK
);
455 * worker_thread_is_busy: is the worker thread busy?
457 * Determine whether the worker thread is busy.
459 static int worker_thread_is_busy()
465 * worker_thread: the worker thread
467 static void worker_thread(gpointer data
, gpointer user_data
)
469 struct thread_message
*msg
= (struct thread_message
*)data
;
472 case MESSAGE_TPM_CMD
:
473 TPMLIB_Process(&ptm_response
, &ptm_res_len
, &ptm_res_tot
,
474 ptm_request
, ptm_req_len
);
480 /* results are ready */
481 worker_thread_mark_done();
485 * worker_thread_end: cleanup once worker thread is all done
487 static void worker_thread_end()
490 worker_thread_wait_done();
491 g_thread_pool_free(pool
, TRUE
, TRUE
);
496 /***************************** utility functions ****************************/
498 /* _TPM_IO_TpmEstablished_Reset
500 * Reset the TPM Established bit by creating a TPM_ResetEstablishmentBit
501 * command and sending it to the TPM; we temporarily switch the locality
502 * to the one provded to this call. We wait until the TPM has processed
505 static TPM_RESULT
_TPM_IO_TpmEstablished_Reset(fuse_req_t req
,
506 TPM_MODIFIER_INDICATOR locty
)
508 TPM_RESULT res
= TPM_FAIL
;
509 TPM_Response_Header
*tpmrh
;
510 TPM_MODIFIER_INDICATOR orig_locality
= locality
;
514 ptm_req_len
= sizeof(TPM_ResetEstablishmentBit
);
515 memcpy(ptm_request
, TPM_ResetEstablishmentBit
, ptm_req_len
);
517 msg
.type
= MESSAGE_TPM_CMD
;
520 worker_thread_mark_busy();
522 g_thread_pool_push(pool
, &msg
, NULL
);
524 worker_thread_wait_done();
526 if (ptm_res_len
>= sizeof(TPM_Response_Header
)) {
527 tpmrh
= (TPM_Response_Header
*)ptm_response
;
528 res
= ntohl(tpmrh
->returnCode
);
531 locality
= orig_locality
;
537 * tpm_start: Start the TPM
539 * Check whether the TPM's state directory exists and if it does
540 * not exists, try to creat it. Start the thread pool, initilize
541 * libtpms and allocate a global TPM request buffer.
543 * @flags: libtpms init flags
545 static int tpm_start(uint32_t flags
)
548 const char *tpmdir
= tpmstate_get_dir();
550 dir
= opendir(tpmdir
);
554 if (mkdir(tpmdir
, 0775)) {
555 logprintf(STDERR_FILENO
,
556 "Error: Could not open tpmstate dir %s\n",
562 pool
= g_thread_pool_new(worker_thread
,
568 logprintf(STDERR_FILENO
,
569 "Error: Could not create the thread pool.\n");
574 ptm_request
= malloc(4096);
576 logprintf(STDERR_FILENO
,
577 "Error: Could not allocate memory for request buffer.\n");
581 if (tpmlib_start(&cbs
, flags
) != TPM_SUCCESS
)
584 logprintf(STDOUT_FILENO
,
585 "CUSE TPM successfully initialized.\n");
590 g_thread_pool_free(pool
, TRUE
, TRUE
);
597 * ptm_write_fatal_error_response: Write fatal error response
599 * Write a fatal error response into the global ptm_response buffer.
601 static void ptm_write_fatal_error_response(void)
603 if (ptm_response
== NULL
||
604 ptm_res_tot
< sizeof(TPM_Resp_FatalError
)) {
605 ptm_res_tot
= sizeof(TPM_Resp_FatalError
);
606 TPM_Realloc(&ptm_response
, ptm_res_tot
);
609 ptm_res_len
= sizeof(TPM_Resp_FatalError
);
612 sizeof(TPM_Resp_FatalError
));
616 /************************************ read() support ***************************/
619 * ptm_read_result: Return the TPM response packet
621 * @req: the fuse_req_t
622 * @size: the max. number of bytes to return to the requester
624 static void ptm_read_result(fuse_req_t req
, size_t size
)
629 /* wait until results are ready */
630 worker_thread_wait_done();
635 if (ptm_res_len
> size
) {
642 fuse_reply_buf(req
, (const char *)ptm_response
, len
);
646 * ptm_read_stateblob: get a TPM stateblob via the read() interface
648 * @req: the fuse_req_t
649 * @size: the number of bytes to read
651 * The internal offset into the buffer is advanced by the number
652 * of bytes that were copied. We switch back to command read/write
653 * mode if an error occurred or once all bytes were read.
655 static void ptm_read_stateblob(fuse_req_t req
, size_t size
)
657 unsigned char *bufptr
= NULL
;
661 if (cached_stateblob_get(tx_state
.offset
, &bufptr
, &numbytes
) < 0) {
662 fuse_reply_err(req
, EIO
);
663 tx_state
.state
= TX_STATE_RW_COMMAND
;
665 tocopy
= MIN(size
, numbytes
);
666 tx_state
.offset
+= tocopy
;
668 fuse_reply_buf(req
, (char *)bufptr
, tocopy
);
669 /* last transfer indicated by less bytes available than requested */
670 if (numbytes
< size
) {
671 tx_state
.state
= TX_STATE_RW_COMMAND
;
677 * ptm_read: interface to POSIX read()
680 * @size: number of bytes to read
681 * @off: offset (not used)
682 * @fi: fuse_file_info (not used)
684 * Depending on the current state of the transfer interface (read/write)
685 * return either the results of TPM commands or a data of a TPM state blob.
687 static void ptm_read(fuse_req_t req
, size_t size
, off_t off
,
688 struct fuse_file_info
*fi
)
690 switch (tx_state
.state
) {
691 case TX_STATE_RW_COMMAND
:
692 ptm_read_result(req
, size
);
694 case TX_STATE_SET_STATE_BLOB
:
695 fuse_reply_err(req
, EIO
);
696 tx_state
.state
= TX_STATE_RW_COMMAND
;
698 case TX_STATE_GET_STATE_BLOB
:
699 ptm_read_stateblob(req
, size
);
704 /*************************read/write stateblob support ***********************/
707 * ptm_set_stateblob_append: Append a piece of TPM state blob and transfer to TPM
709 * blobtype: the type of blob
710 * data: the data to append
711 * length: length of the data
712 * is_encrypted: whether the blob is encrypted
713 * is_last: whether this is the last part of the TPM state blob; if it is, the TPM
714 * state blob will then be transferred to the TPM
717 ptm_set_stateblob_append(uint32_t blobtype
,
718 const unsigned char *data
, uint32_t length
,
719 bool is_encrypted
, bool is_last
)
721 const char *blobname
;
723 static struct stateblob stateblob
;
725 if (stateblob
.type
!= blobtype
) {
726 /* new blob; clear old data */
727 TPM_Free(stateblob
.data
);
728 stateblob
.data
= NULL
;
729 stateblob
.length
= 0;
730 stateblob
.type
= blobtype
;
731 stateblob
.is_encrypted
= is_encrypted
;
734 * on the first call for a new state blob we allow 0 bytes to be written
735 * this allows the user to transfer via write()
742 res
= TPM_Realloc(&stateblob
.data
, stateblob
.length
+ length
);
745 TPM_Free(stateblob
.data
);
746 stateblob
.data
= NULL
;
747 stateblob
.length
= 0;
753 memcpy(&stateblob
.data
[stateblob
.length
], data
, length
);
754 stateblob
.length
+= length
;
757 /* full packet -- expecting more data */
760 blobname
= ptm_get_blobname(blobtype
);
763 res
= SWTPM_NVRAM_SetStateBlob(stateblob
.data
,
765 stateblob
.is_encrypted
,
769 res
= TPM_BAD_PARAMETER
;
772 TPM_Free(stateblob
.data
);
773 stateblob
.data
= NULL
;
774 stateblob
.length
= 0;
777 /* transfer of blob is complete */
778 tx_state
.state
= TX_STATE_RW_COMMAND
;
784 * ptm_set_stateblob: set part of a TPM state blob
787 * pss: ptm_setstate provided via ioctl()
790 ptm_set_stateblob(fuse_req_t req
, ptm_setstate
*pss
)
793 TPM_BOOL is_encrypted
=
794 ((pss
->u
.req
.state_flags
& PTM_STATE_FLAG_ENCRYPTED
) != 0);
795 bool is_last
= (sizeof(pss
->u
.req
.data
) != pss
->u
.req
.length
);
797 if (pss
->u
.req
.length
> sizeof(pss
->u
.req
.data
)) {
798 res
= TPM_BAD_PARAMETER
;
802 /* transfer of blob initiated */
803 tx_state
.state
= TX_STATE_SET_STATE_BLOB
;
804 tx_state
.blobtype
= pss
->u
.req
.type
;
805 tx_state
.blob_is_encrypted
= is_encrypted
;
808 res
= ptm_set_stateblob_append(pss
->u
.req
.type
,
815 tx_state
.state
= TX_STATE_RW_COMMAND
;
818 pss
->u
.resp
.tpm_result
= res
;
820 fuse_reply_ioctl(req
, 0, pss
, sizeof(*pss
));
824 * ptm_get_stateblob_part: get part of a state blob
826 * @blobtype: the type of blob to get
827 * @buffer: the buffer this function will write the blob into
828 * @buffer_size: the size of the buffer
829 * @offset: the offset into the state blob
830 * @copied: pointer to int to indicate the number of bytes that were copied
831 * @is_encryped: returns whether the state blob is encrypted
834 ptm_get_stateblob_part(uint32_t blobtype
,
835 unsigned char *buffer
, size_t buffer_size
,
836 uint32_t offset
, uint32_t *copied
,
837 TPM_BOOL decrypt
, TPM_BOOL
*is_encrypted
)
841 if (!cached_stateblob_is_loaded(blobtype
, decrypt
)) {
842 res
= cached_stateblob_load(blobtype
, decrypt
);
846 cached_stateblob_copy(buffer
, buffer_size
,
847 offset
, copied
, is_encrypted
);
854 * ptm_get_stateblob: Get the state blob from the TPM using ioctl()
857 ptm_get_stateblob(fuse_req_t req
, ptm_getstate
*pgs
)
860 uint32_t blobtype
= pgs
->u
.req
.type
;
862 ((pgs
->u
.req
.state_flags
& PTM_STATE_FLAG_DECRYPTED
) != 0);
863 TPM_BOOL is_encrypted
= FALSE
;
865 uint32_t offset
= pgs
->u
.req
.offset
;
868 res
= ptm_get_stateblob_part(blobtype
,
869 pgs
->u
.resp
.data
, sizeof(pgs
->u
.resp
.data
),
870 pgs
->u
.req
.offset
, &copied
,
871 decrypt
, &is_encrypted
);
873 totlength
= cached_stateblob_get_bloblength();
875 pgs
->u
.resp
.state_flags
= 0;
877 pgs
->u
.resp
.state_flags
|= PTM_STATE_FLAG_ENCRYPTED
;
879 pgs
->u
.resp
.length
= copied
;
880 pgs
->u
.resp
.totlength
= totlength
;
881 pgs
->u
.resp
.tpm_result
= res
;
884 if (offset
+ copied
< totlength
) {
885 /* last byte was not copied */
886 tx_state
.state
= TX_STATE_GET_STATE_BLOB
;
887 tx_state
.blobtype
= pgs
->u
.req
.type
;
888 tx_state
.blob_is_encrypted
= is_encrypted
;
889 tx_state
.offset
= copied
;
891 /* last byte was copied */
892 tx_state
.state
= TX_STATE_RW_COMMAND
;
896 tx_state
.state
= TX_STATE_RW_COMMAND
;
899 fuse_reply_ioctl(req
, 0, pgs
, sizeof(pgs
->u
.resp
));
902 /*********************************** write() support *************************/
905 * ptm_write_stateblob: Write the state blob using the write() interface
907 * @req: the fuse_req_t
908 * @buf: the buffer with the data
909 * @size: the number of bytes in the buffer
911 * The data are appended to an existing buffer that was created with the
914 static void ptm_write_stateblob(fuse_req_t req
, const char *buf
, size_t size
)
918 res
= ptm_set_stateblob_append(tx_state
.blobtype
,
919 (unsigned char *)buf
, size
,
920 tx_state
.blob_is_encrypted
,
923 tx_state
.state
= TX_STATE_RW_COMMAND
;
924 fuse_reply_err(req
, EIO
);
926 fuse_reply_write(req
, size
);
931 * ptm_write_cmd: User writing a TPM command
934 * buf: the buffer containing the TPM command
935 * size: the size of the buffer
937 static void ptm_write_cmd(fuse_req_t req
, const char *buf
, size_t size
)
942 /* prevent other threads from writing or doing ioctls */
943 g_mutex_lock(FILE_OPS_LOCK
);
946 /* ensure that we only ever work on one TPM command */
947 if (worker_thread_is_busy()) {
948 fuse_reply_err(req
, EBUSY
);
952 /* have command processed by thread pool */
953 if (ptm_req_len
> TPM_REQ_MAX
)
954 ptm_req_len
= TPM_REQ_MAX
;
956 memcpy(ptm_request
, buf
, ptm_req_len
);
958 msg
.type
= MESSAGE_TPM_CMD
;
961 worker_thread_mark_busy();
963 g_thread_pool_push(pool
, &msg
, NULL
);
965 /* TPM not initialized; return error */
966 ptm_write_fatal_error_response();
969 fuse_reply_write(req
, ptm_req_len
);
972 g_mutex_unlock(FILE_OPS_LOCK
);
978 * ptm_write: low-level write() interface; calls approriate function depending
979 * on what is being transferred using the write()
981 static void ptm_write(fuse_req_t req
, const char *buf
, size_t size
,
982 off_t off
, struct fuse_file_info
*fi
)
984 switch (tx_state
.state
) {
985 case TX_STATE_RW_COMMAND
:
986 ptm_write_cmd(req
, buf
, size
);
988 case TX_STATE_GET_STATE_BLOB
:
989 fuse_reply_err(req
, EIO
);
990 tx_state
.state
= TX_STATE_RW_COMMAND
;
992 case TX_STATE_SET_STATE_BLOB
:
993 ptm_write_stateblob(req
, buf
, size
);
999 * ptm_open: interface to POSIX open()
1001 static void ptm_open(fuse_req_t req
, struct fuse_file_info
*fi
)
1003 tx_state
.state
= TX_STATE_RW_COMMAND
;
1005 fuse_reply_open(req
, fi
);
1009 * ptm_ioctl : ioctl execution
1011 * req: the fuse_req_t used to send response with
1012 * cmd: the ioctl request code
1013 * arg: the pointer the application used for calling the ioctl (3rd param)
1015 * flags: some flags provided by fuse
1016 * in_buf: the copy of the input buffer
1017 * in_bufsz: size of the input buffer; provided by fuse and has size of
1019 * out_bufsz: size of the output buffer; provided by fuse and has size of
1022 static void ptm_ioctl(fuse_req_t req
, int cmd
, void *arg
,
1023 struct fuse_file_info
*fi
, unsigned flags
,
1024 const void *in_buf
, size_t in_bufsz
, size_t out_bufsz
)
1027 bool exit_prg
= FALSE
;
1030 if (flags
& FUSE_IOCTL_COMPAT
) {
1031 fuse_reply_err(req
, ENOSYS
);
1035 /* some commands have to wait until the worker thread is done */
1037 case PTM_GET_CAPABILITY
:
1038 case PTM_SET_LOCALITY
:
1039 case PTM_CANCEL_TPM_CMD
:
1040 case PTM_GET_CONFIG
:
1041 /* no need to wait */
1045 case PTM_GET_TPMESTABLISHED
:
1046 case PTM_RESET_TPMESTABLISHED
:
1047 case PTM_HASH_START
:
1050 case PTM_STORE_VOLATILE
:
1051 case PTM_GET_STATEBLOB
:
1052 case PTM_SET_STATEBLOB
:
1054 worker_thread_wait_done();
1058 /* prevent other threads from writing or doing ioctls */
1059 g_mutex_lock(FILE_OPS_LOCK
);
1062 case PTM_GET_CAPABILITY
:
1063 if (out_bufsz
!= sizeof(ptm_cap
)) {
1064 struct iovec iov
= { arg
, sizeof(uint8_t) };
1065 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1068 ptm_caps
= PTM_CAP_INIT
| PTM_CAP_SHUTDOWN
1069 | PTM_CAP_GET_TPMESTABLISHED
1070 | PTM_CAP_SET_LOCALITY
1072 | PTM_CAP_CANCEL_TPM_CMD
1073 | PTM_CAP_STORE_VOLATILE
1074 | PTM_CAP_RESET_TPMESTABLISHED
1075 | PTM_CAP_GET_STATEBLOB
1076 | PTM_CAP_SET_STATEBLOB
1078 | PTM_CAP_GET_CONFIG
;
1079 fuse_reply_ioctl(req
, 0, &ptm_caps
, sizeof(ptm_caps
));
1084 if (in_bufsz
!= sizeof(ptm_init
)) {
1085 struct iovec iov
= { arg
, sizeof(uint8_t) };
1086 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1088 init_p
= (ptm_init
*)in_buf
;
1090 worker_thread_end();
1094 tpm_running
= false;
1095 if (tpm_start(init_p
->u
.req
.init_flags
) < 0) {
1097 logprintf(STDERR_FILENO
,
1098 "Error: Could not initialize the TPM.\n");
1102 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1107 worker_thread_end();
1112 tpm_running
= false;
1114 TPM_Free(ptm_response
);
1115 ptm_response
= NULL
;
1117 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1122 worker_thread_end();
1127 TPM_Free(ptm_response
);
1128 ptm_response
= NULL
;
1130 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1135 case PTM_GET_TPMESTABLISHED
:
1137 goto error_not_running
;
1139 if (out_bufsz
!= sizeof(ptm_est
)) {
1140 struct iovec iov
= { arg
, sizeof(uint8_t) };
1141 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1144 te
.u
.resp
.tpm_result
= TPM_IO_TpmEstablished_Get(&te
.u
.resp
.bit
);
1145 fuse_reply_ioctl(req
, 0, &te
, sizeof(te
));
1149 case PTM_RESET_TPMESTABLISHED
:
1151 goto error_not_running
;
1153 if (in_bufsz
!= sizeof(ptm_reset_est
)) {
1154 struct iovec iov
= { arg
, sizeof(uint32_t) };
1155 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1157 ptm_reset_est
*re
= (ptm_reset_est
*)in_buf
;
1158 if (re
->u
.req
.loc
> 4) {
1159 res
= TPM_BAD_LOCALITY
;
1161 res
= _TPM_IO_TpmEstablished_Reset(req
, re
->u
.req
.loc
);
1162 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1167 case PTM_SET_LOCALITY
:
1168 if (in_bufsz
!= sizeof(ptm_loc
)) {
1169 struct iovec iov
= { arg
, sizeof(uint32_t) };
1170 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1172 ptm_loc
*l
= (ptm_loc
*)in_buf
;
1173 if (l
->u
.req
.loc
> 4) {
1174 res
= TPM_BAD_LOCALITY
;
1177 locality
= l
->u
.req
.loc
;
1179 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1183 case PTM_HASH_START
:
1185 goto error_not_running
;
1187 res
= TPM_IO_Hash_Start();
1188 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1193 goto error_not_running
;
1195 if (in_bufsz
!= sizeof(ptm_hdata
)) {
1196 struct iovec iov
= { arg
, sizeof(uint32_t) };
1197 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1199 ptm_hdata
*data
= (ptm_hdata
*)in_buf
;
1200 if (data
->u
.req
.length
<= sizeof(data
->u
.req
.data
)) {
1201 res
= TPM_IO_Hash_Data(data
->u
.req
.data
,
1202 data
->u
.req
.length
);
1206 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1212 goto error_not_running
;
1214 res
= TPM_IO_Hash_End();
1215 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1218 case PTM_CANCEL_TPM_CMD
:
1220 goto error_not_running
;
1222 /* for cancellation to work, the TPM would have to
1223 * execute in another thread that polls on a cancel
1227 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1230 case PTM_STORE_VOLATILE
:
1232 goto error_not_running
;
1234 res
= SWTPM_NVRAM_Store_Volatile();
1235 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1237 cached_stateblob_free();
1240 case PTM_GET_STATEBLOB
:
1242 goto error_not_running
;
1244 if (in_bufsz
!= sizeof(ptm_getstate
)) {
1245 struct iovec iov
= { arg
, sizeof(uint32_t) };
1246 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1248 ptm_get_stateblob(req
, (ptm_getstate
*)in_buf
);
1252 case PTM_SET_STATEBLOB
:
1256 /* tpm state dir must be set */
1259 if (in_bufsz
!= sizeof(ptm_setstate
)) {
1260 struct iovec iov
= { arg
, sizeof(uint32_t) };
1261 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1263 ptm_set_stateblob(req
, (ptm_setstate
*)in_buf
);
1267 case PTM_GET_CONFIG
:
1268 if (out_bufsz
!= sizeof(ptm_getconfig
)) {
1269 struct iovec iov
= { arg
, sizeof(uint32_t) };
1270 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1273 pgs
.u
.resp
.tpm_result
= 0;
1274 pgs
.u
.resp
.flags
= 0;
1275 if (SWTPM_NVRAM_Has_FileKey())
1276 pgs
.u
.resp
.flags
|= PTM_CONFIG_FLAG_FILE_KEY
;
1277 if (SWTPM_NVRAM_Has_MigrationKey())
1278 pgs
.u
.resp
.flags
|= PTM_CONFIG_FLAG_MIGRATION_KEY
;
1279 fuse_reply_ioctl(req
, 0, &pgs
, sizeof(pgs
));
1284 fuse_reply_err(req
, EINVAL
);
1288 g_mutex_unlock(FILE_OPS_LOCK
);
1291 logprintf(STDOUT_FILENO
, "CUSE TPM is shutting down.\n");
1301 res
= TPM_BAD_ORDINAL
;
1302 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1307 static void ptm_init_done(void *userdata
)
1309 struct cuse_param
*param
= userdata
;
1310 struct passwd
*passwd
= NULL
;
1312 /* at this point the entry in /dev/ is available */
1313 if (pidfile_write(getpid()) < 0) {
1318 passwd
= getpwnam(param
->runas
);
1320 logprintf(STDERR_FILENO
,
1321 "Error: User '%s' does not exist.\n",
1325 if (initgroups(passwd
->pw_name
, passwd
->pw_gid
) < 0) {
1326 logprintf(STDERR_FILENO
,
1327 "Error: initgroups(%s, %d) failed.\n",
1328 passwd
->pw_name
, passwd
->pw_gid
);
1331 if (setgid(passwd
->pw_gid
) < 0) {
1332 logprintf(STDERR_FILENO
,
1333 "Error: setgid(%d) failed.\n",
1337 if (setuid(passwd
->pw_uid
) < 0) {
1338 logprintf(STDERR_FILENO
,
1339 "Error: setuid(%d) failed.\n",
1346 static const struct cuse_lowlevel_ops clops
= {
1351 .init_done
= ptm_init_done
,
1354 int main(int argc
, char **argv
)
1356 int opt
, longindex
= 0;
1357 static struct option longopts
[] = {
1358 {"maj" , required_argument
, 0, 'M'},
1359 {"min" , required_argument
, 0, 'm'},
1360 {"name" , required_argument
, 0, 'n'},
1361 {"runas" , required_argument
, 0, 'r'},
1362 {"log" , required_argument
, 0, 'l'},
1363 {"key" , required_argument
, 0, 'k'},
1364 {"migration-key" , required_argument
, 0, 'K'},
1365 {"pid" , required_argument
, 0, 'p'},
1366 {"tpmstate" , required_argument
, 0, 's'},
1367 {"help" , no_argument
, 0, 'h'},
1368 {"version" , no_argument
, 0, 'v'},
1371 struct cuse_info cinfo
;
1372 struct cuse_param param
;
1373 const char *devname
= NULL
;
1374 char *cinfo_argv
[1];
1376 struct passwd
*passwd
;
1379 char path
[PATH_MAX
];
1381 memset(&cinfo
, 0, sizeof(cinfo
));
1382 memset(¶m
, 0, sizeof(param
));
1385 opt
= getopt_long(argc
, argv
, "M:m:n:r:hv", longopts
, &longindex
);
1391 case 'M': /* major */
1392 if (sscanf(optarg
, "%u", &num
) != 1) {
1393 fprintf(stderr
, "Could not parse major number\n");
1396 if (num
< 0 || num
> 65535) {
1397 fprintf(stderr
, "Major number outside valid range [0 - 65535]\n");
1400 cinfo
.dev_major
= num
;
1402 case 'm': /* minor */
1403 if (sscanf(optarg
, "%u", &num
) != 1) {
1404 fprintf(stderr
, "Could not parse major number\n");
1407 if (num
< 0 || num
> 65535) {
1408 fprintf(stderr
, "Major number outside valid range [0 - 65535]\n");
1411 cinfo
.dev_minor
= num
;
1413 case 'n': /* name */
1414 if (!cinfo
.dev_info_argc
) {
1415 cinfo_argv
[0] = calloc(1, strlen("DEVNAME=") + strlen(optarg
) + 1);
1416 if (!cinfo_argv
[0]) {
1417 fprintf(stderr
, "Out of memory\n");
1422 strcpy(cinfo_argv
[0], "DEVNAME=");
1423 strcat(cinfo_argv
[0], optarg
);
1425 cinfo
.dev_info_argc
= 1;
1426 cinfo
.dev_info_argv
= (const char **)cinfo_argv
;
1429 case 'r': /* runas */
1430 param
.runas
= optarg
;
1433 param
.logging
= optarg
;
1436 param
.keydata
= optarg
;
1438 case 'K': /* migration-key */
1439 param
.migkeydata
= optarg
;
1442 param
.piddata
= optarg
;
1444 case 's': /* tpmstate */
1445 param
.tpmstatedata
= optarg
;
1447 case 'h': /* help */
1448 fprintf(stdout
, usage
, argv
[0]);
1450 case 'v': /* version */
1451 fprintf(stdout
, "TPM emulator CUSE interface version %d.%d.%d, "
1452 "Copyright (c) 2014-2015 IBM Corp.\n",
1460 if (!cinfo
.dev_info_argv
) {
1461 fprintf(stderr
, "Error: device name missing\n");
1465 if (handle_log_options(param
.logging
) < 0 ||
1466 handle_key_options(param
.keydata
) < 0 ||
1467 handle_migration_key_options(param
.migkeydata
) < 0 ||
1468 handle_pid_options(param
.piddata
) < 0 ||
1469 handle_tpmstate_options(param
.tpmstatedata
) < 0)
1473 fprintf(stderr
, "Error: Unable to setuid root. uid = %d, "
1474 "euid = %d, gid = %d\n", getuid(), geteuid(), getgid());
1479 if (!(passwd
= getpwnam(param
.runas
))) {
1480 fprintf(stderr
, "User '%s' does not exist\n",
1486 tpmdir
= tpmstate_get_dir();
1487 if (tpmdir
== NULL
) {
1489 "Error: No TPM state directory is defined; TPM_PATH is not set\n");
1493 n
= snprintf(path
, sizeof(path
), "/dev/%s", devname
);
1496 "Error: Could not create device file name\n");
1499 if (n
>= (int)sizeof(path
)) {
1501 "Error: Buffer too small to create device file name\n");
1505 tpmfd
= open(path
, O_RDWR
);
1509 "Error: A device '%s' already exists.\n",
1514 #if GLIB_MINOR_VERSION >= 32
1515 g_mutex_init(THREAD_BUSY_LOCK
);
1516 g_cond_init(THREAD_BUSY_SIGNAL
);
1517 g_mutex_init(FILE_OPS_LOCK
);
1519 g_thread_init(NULL
);
1520 THREAD_BUSY_LOCK
= g_mutex_new();
1521 THREAD_BUSY_SIGNAL
= g_cond_new();
1522 FILE_OPS_LOCK
= g_mutex_new();
1525 return cuse_lowlevel_main(1, argv
, &cinfo
, &clops
, ¶m
);