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>
57 #include <fuse/cuse_lowlevel.h>
61 #include <libtpms/tpm_library.h>
62 #include <libtpms/tpm_tis.h>
63 #include <libtpms/tpm_error.h>
64 #include <libtpms/tpm_memory.h>
65 #include <libtpms/tpm_nvfilename.h>
72 #include "tpm_ioctl.h"
73 #include "swtpm_nvfile.h"
77 #include "threadpool.h"
79 /* maximum size of request buffer */
80 #define TPM_REQ_MAX 4096
82 /* buffer containing the TPM request */
83 static unsigned char *ptm_request
;
85 /* buffer containing the TPM response */
86 static unsigned char *ptm_response
;
88 /* the sizes of the data in the buffers */
89 static uint32_t ptm_req_len
, ptm_res_len
, ptm_res_tot
;
91 /* locality applied to TPM commands */
92 static TPM_MODIFIER_INDICATOR locality
;
94 /* whether the TPM is running (TPM_Init was received) */
95 static bool tpm_running
;
97 #if GLIB_MAJOR_VERSION >= 2
98 # if GLIB_MINOR_VERSION >= 32
100 GMutex file_ops_lock
;
101 # define FILE_OPS_LOCK &file_ops_lock
105 GMutex
*file_ops_lock
;
106 # define FILE_OPS_LOCK file_ops_lock
111 #error Unsupport glib version
124 /* single message to send to the worker thread */
125 static struct thread_message msg
;
127 #define min(a,b) ((a) < (b) ? (a) : (b))
133 TPM_BOOL is_encrypted
;
136 typedef struct stateblob_desc
{
139 TPM_BOOL is_encrypted
;
141 uint32_t data_length
;
144 typedef enum tx_state_type
{
145 TX_STATE_RW_COMMAND
= 1,
146 TX_STATE_SET_STATE_BLOB
= 2,
147 TX_STATE_GET_STATE_BLOB
= 3,
150 typedef struct transfer_state
{
152 /* while in TX_STATE_GET/SET_STATEBLOB */
154 TPM_BOOL blob_is_encrypted
;
155 /* while in TX_STATE_GET */
159 typedef struct TPM_Response_Header
{
163 } __attribute__ ((packed
)) TPM_Response_Header
;
165 /*********************************** data *************************************/
167 static const char *usage
=
168 "usage: %s %s [options]\n"
170 "The following options are supported:\n"
172 "-n NAME|--name=NAME : device name (mandatory)\n"
173 "-M MAJ|--maj=MAJ : device major number\n"
174 "-m MIN|--min=MIN : device minor number\n"
175 "--key file=<path>[,mode=aes-cbc][,format=hex|binary][,remove=[true|false]]\n"
176 " : use an AES key for the encryption of the TPM's state\n"
177 " files; use the given mode for the block encryption;\n"
178 " the key is to be provided as a hex string or in binary\n"
179 " format; the keyfile can be automatically removed using\n"
180 " the remove parameter\n"
181 "--key pwdfile=<path>[,mode=aes-cbc][,remove=[true|false]]\n"
182 " : provide a passphrase in a file; the AES key will be\n"
183 " derived from this passphrase\n"
184 "--migration-key file=<path>[,mode=aes-cbc][,format=hex|binary][,remove=[true|false]]\n"
185 " : use an AES key for the encryption of the TPM's state\n"
186 " when it is retrieved from the TPM via ioctls;\n"
187 " Setting this key ensures that the TPM's state will always\n"
188 " be encrypted when migrated\n"
189 "--migration-key pwdfile=<path>[,mode=aes-cbc][,remove=[true|false]]\n"
190 " : provide a passphrase in a file; the AES key will be\n"
191 " derived from this passphrase\n"
192 "--log file=<path>|fd=<filedescriptor>\n"
193 " : write the TPM's log into the given file rather than\n"
194 " to the console; provide '-' for path to avoid logging\n"
195 "--pid file=<path> : write the process ID into the given file\n"
196 "--tpmstate dir=<dir>\n"
197 " : set the directory where the TPM's state will be written\n"
198 " into; the TPM_PATH environment variable can be used\n"
200 "-r|--runas <user> : after creating the CUSE device, change to the given\n"
203 "-h|--help : display this help screen and terminate\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 */
219 ptm_io_getlocality(TPM_MODIFIER_INDICATOR
*loc
, uint32_t tpmnum
)
225 static struct libtpms_callbacks cbs
= {
226 .sizeOfStruct
= sizeof(struct libtpms_callbacks
),
227 .tpm_nvram_init
= SWTPM_NVRAM_Init
,
228 .tpm_nvram_loaddata
= SWTPM_NVRAM_LoadData
,
229 .tpm_nvram_storedata
= SWTPM_NVRAM_StoreData
,
230 .tpm_nvram_deletename
= SWTPM_NVRAM_DeleteName
,
231 .tpm_io_getlocality
= ptm_io_getlocality
,
234 /* the current state the transfer interface is in */
235 static transfer_state tx_state
;
238 * convert the blobtype integer into a string that libtpms
241 static const char *ptm_get_blobname(uint32_t blobtype
)
244 case PTM_BLOB_TYPE_PERMANENT
:
245 return TPM_PERMANENT_ALL_NAME
;
246 case PTM_BLOB_TYPE_VOLATILE
:
247 return TPM_VOLATILESTATE_NAME
;
248 case PTM_BLOB_TYPE_SAVESTATE
:
249 return TPM_SAVESTATE_NAME
;
255 /************************* cached stateblob *********************************/
257 static stateblob_desc cached_stateblob
;
260 * cached_stateblob_is_loaded: is the stateblob with the given properties
261 * the one in the cache?
263 static bool cached_stateblob_is_loaded(uint32_t blobtype
,
266 return (cached_stateblob
.data
!= NULL
) &&
267 (cached_stateblob
.blobtype
== blobtype
) &&
268 (cached_stateblob
.decrypt
== decrypt
);
272 * cached_stateblob_free: Free any previously loaded state blob
274 static void cached_stateblob_free(void)
276 TPM_Free(cached_stateblob
.data
);
277 cached_stateblob
.data
= NULL
;
278 cached_stateblob
.data_length
= 0;
282 * cached_stateblob_get_bloblength: get the total length of the cached blob
284 static uint32_t cached_stateblob_get_bloblength(void)
286 return cached_stateblob
.data_length
;
290 * cached_statblob_get: get stateblob data without copying them
292 * @offset: at which offset to get the data
293 * @bufptr: pointer to a buffer pointer used to return buffer start
294 * @length: pointer used to return number of available bytes in returned buffer
296 static int cached_stateblob_get(uint32_t offset
,
297 unsigned char **bufptr
, size_t *length
)
299 if (cached_stateblob
.data
== NULL
||
300 offset
> cached_stateblob
.data_length
)
303 *bufptr
= &cached_stateblob
.data
[offset
];
304 *length
= cached_stateblob
.data_length
- offset
;
310 * cached_stateblob_load: load a state blob into the cache
312 * blobtype: the type of blob
313 * decrypt: whether the blob is to be decrypted
315 static TPM_RESULT
cached_stateblob_load(uint32_t blobtype
, TPM_BOOL decrypt
)
318 const char *blobname
= ptm_get_blobname(blobtype
);
319 uint32_t tpm_number
= 0;
322 return TPM_BAD_PARAMETER
;
324 cached_stateblob_free();
326 if (blobtype
== PTM_BLOB_TYPE_VOLATILE
)
327 res
= SWTPM_NVRAM_Store_Volatile();
330 res
= SWTPM_NVRAM_GetStateBlob(&cached_stateblob
.data
,
331 &cached_stateblob
.data_length
,
332 tpm_number
, blobname
, decrypt
,
333 &cached_stateblob
.is_encrypted
);
335 /* make sure the volatile state file is gone */
336 if (blobtype
== PTM_BLOB_TYPE_VOLATILE
)
337 SWTPM_NVRAM_DeleteName(tpm_number
, blobname
, FALSE
);
340 cached_stateblob
.blobtype
= blobtype
;
341 cached_stateblob
.decrypt
= decrypt
;
348 * cached_state_blob_copy: copy the cached state blob to a destination buffer
350 * dest: destination buffer
351 * destlen: size of the buffer
352 * srcoffset: offset to copy from
353 * copied: variable to return the number of copied bytes
354 * is_encrypted: variable to return whether the blob is encrypted
356 static int cached_stateblob_copy(void *dest
, size_t destlen
,
357 uint32_t srcoffset
, uint32_t *copied
,
358 TPM_BOOL
*is_encrypted
)
364 if (cached_stateblob
.data
!= NULL
&& cached_stateblob
.data_length
> 0) {
366 if (srcoffset
< cached_stateblob
.data_length
) {
367 *copied
= min(cached_stateblob
.data_length
- srcoffset
, destlen
);
369 memcpy(dest
, &cached_stateblob
.data
[srcoffset
], *copied
);
371 *is_encrypted
= cached_stateblob
.is_encrypted
;
380 /************************* worker thread ************************************/
383 * worker_thread: the worker thread
385 static void worker_thread(gpointer data
, gpointer user_data
)
387 struct thread_message
*msg
= (struct thread_message
*)data
;
390 case MESSAGE_TPM_CMD
:
391 TPMLIB_Process(&ptm_response
, &ptm_res_len
, &ptm_res_tot
,
392 ptm_request
, ptm_req_len
);
398 /* results are ready */
399 worker_thread_mark_done();
402 /***************************** utility functions ****************************/
404 /* _TPM_IO_TpmEstablished_Reset
406 * Reset the TPM Established bit by creating a TPM_ResetEstablishmentBit
407 * command and sending it to the TPM; we temporarily switch the locality
408 * to the one provded to this call. We wait until the TPM has processed
411 static TPM_RESULT
_TPM_IO_TpmEstablished_Reset(fuse_req_t req
,
412 TPM_MODIFIER_INDICATOR locty
)
414 TPM_RESULT res
= TPM_FAIL
;
415 TPM_Response_Header
*tpmrh
;
416 TPM_MODIFIER_INDICATOR orig_locality
= locality
;
420 ptm_req_len
= sizeof(TPM_ResetEstablishmentBit
);
421 memcpy(ptm_request
, TPM_ResetEstablishmentBit
, ptm_req_len
);
423 msg
.type
= MESSAGE_TPM_CMD
;
425 worker_thread_mark_busy();
427 g_thread_pool_push(pool
, &msg
, NULL
);
429 worker_thread_wait_done();
431 if (ptm_res_len
>= sizeof(TPM_Response_Header
)) {
432 tpmrh
= (TPM_Response_Header
*)ptm_response
;
433 res
= ntohl(tpmrh
->returnCode
);
436 locality
= orig_locality
;
442 * tpm_start: Start the TPM
444 * Check whether the TPM's state directory exists and if it does
445 * not exists, try to creat it. Start the thread pool, initilize
446 * libtpms and allocate a global TPM request buffer.
448 * @flags: libtpms init flags
450 static int tpm_start(uint32_t flags
)
453 const char *tpmdir
= tpmstate_get_dir();
455 dir
= opendir(tpmdir
);
459 if (mkdir(tpmdir
, 0775)) {
460 logprintf(STDERR_FILENO
,
461 "Error: Could not open tpmstate dir %s\n",
467 pool
= g_thread_pool_new(worker_thread
,
473 logprintf(STDERR_FILENO
,
474 "Error: Could not create the thread pool.\n");
479 ptm_request
= malloc(4096);
481 logprintf(STDERR_FILENO
,
482 "Error: Could not allocate memory for request buffer.\n");
486 if (tpmlib_start(&cbs
, flags
) != TPM_SUCCESS
)
489 logprintf(STDOUT_FILENO
,
490 "CUSE TPM successfully initialized.\n");
495 g_thread_pool_free(pool
, TRUE
, TRUE
);
502 * ptm_write_fatal_error_response: Write fatal error response
504 * Write a fatal error response into the global ptm_response buffer.
506 static void ptm_write_fatal_error_response(void)
508 if (ptm_response
== NULL
||
509 ptm_res_tot
< sizeof(TPM_Resp_FatalError
)) {
510 ptm_res_tot
= sizeof(TPM_Resp_FatalError
);
511 TPM_Realloc(&ptm_response
, ptm_res_tot
);
514 ptm_res_len
= sizeof(TPM_Resp_FatalError
);
517 sizeof(TPM_Resp_FatalError
));
521 /************************************ read() support ***************************/
524 * ptm_read_result: Return the TPM response packet
526 * @req: the fuse_req_t
527 * @size: the max. number of bytes to return to the requester
529 static void ptm_read_result(fuse_req_t req
, size_t size
)
534 /* wait until results are ready */
535 worker_thread_wait_done();
540 if (ptm_res_len
> size
) {
547 fuse_reply_buf(req
, (const char *)ptm_response
, len
);
551 * ptm_read_stateblob: get a TPM stateblob via the read() interface
553 * @req: the fuse_req_t
554 * @size: the number of bytes to read
556 * The internal offset into the buffer is advanced by the number
557 * of bytes that were copied. We switch back to command read/write
558 * mode if an error occurred or once all bytes were read.
560 static void ptm_read_stateblob(fuse_req_t req
, size_t size
)
562 unsigned char *bufptr
= NULL
;
566 if (cached_stateblob_get(tx_state
.offset
, &bufptr
, &numbytes
) < 0) {
567 fuse_reply_err(req
, EIO
);
568 tx_state
.state
= TX_STATE_RW_COMMAND
;
570 tocopy
= MIN(size
, numbytes
);
571 tx_state
.offset
+= tocopy
;
573 fuse_reply_buf(req
, (char *)bufptr
, tocopy
);
574 /* last transfer indicated by less bytes available than requested */
575 if (numbytes
< size
) {
576 tx_state
.state
= TX_STATE_RW_COMMAND
;
582 * ptm_read: interface to POSIX read()
585 * @size: number of bytes to read
586 * @off: offset (not used)
587 * @fi: fuse_file_info (not used)
589 * Depending on the current state of the transfer interface (read/write)
590 * return either the results of TPM commands or a data of a TPM state blob.
592 static void ptm_read(fuse_req_t req
, size_t size
, off_t off
,
593 struct fuse_file_info
*fi
)
595 switch (tx_state
.state
) {
596 case TX_STATE_RW_COMMAND
:
597 ptm_read_result(req
, size
);
599 case TX_STATE_SET_STATE_BLOB
:
600 fuse_reply_err(req
, EIO
);
601 tx_state
.state
= TX_STATE_RW_COMMAND
;
603 case TX_STATE_GET_STATE_BLOB
:
604 ptm_read_stateblob(req
, size
);
609 /*************************read/write stateblob support ***********************/
612 * ptm_set_stateblob_append: Append a piece of TPM state blob and transfer to TPM
614 * blobtype: the type of blob
615 * data: the data to append
616 * length: length of the data
617 * is_encrypted: whether the blob is encrypted
618 * is_last: whether this is the last part of the TPM state blob; if it is, the TPM
619 * state blob will then be transferred to the TPM
622 ptm_set_stateblob_append(uint32_t blobtype
,
623 const unsigned char *data
, uint32_t length
,
624 bool is_encrypted
, bool is_last
)
626 const char *blobname
;
628 static struct stateblob stateblob
;
630 if (stateblob
.type
!= blobtype
) {
631 /* new blob; clear old data */
632 TPM_Free(stateblob
.data
);
633 stateblob
.data
= NULL
;
634 stateblob
.length
= 0;
635 stateblob
.type
= blobtype
;
636 stateblob
.is_encrypted
= is_encrypted
;
639 * on the first call for a new state blob we allow 0 bytes to be written
640 * this allows the user to transfer via write()
647 res
= TPM_Realloc(&stateblob
.data
, stateblob
.length
+ length
);
650 TPM_Free(stateblob
.data
);
651 stateblob
.data
= NULL
;
652 stateblob
.length
= 0;
658 memcpy(&stateblob
.data
[stateblob
.length
], data
, length
);
659 stateblob
.length
+= length
;
662 /* full packet -- expecting more data */
665 blobname
= ptm_get_blobname(blobtype
);
668 res
= SWTPM_NVRAM_SetStateBlob(stateblob
.data
,
670 stateblob
.is_encrypted
,
674 res
= TPM_BAD_PARAMETER
;
677 TPM_Free(stateblob
.data
);
678 stateblob
.data
= NULL
;
679 stateblob
.length
= 0;
682 /* transfer of blob is complete */
683 tx_state
.state
= TX_STATE_RW_COMMAND
;
689 * ptm_set_stateblob: set part of a TPM state blob
692 * pss: ptm_setstate provided via ioctl()
695 ptm_set_stateblob(fuse_req_t req
, ptm_setstate
*pss
)
698 TPM_BOOL is_encrypted
=
699 ((pss
->u
.req
.state_flags
& PTM_STATE_FLAG_ENCRYPTED
) != 0);
700 bool is_last
= (sizeof(pss
->u
.req
.data
) != pss
->u
.req
.length
);
702 if (pss
->u
.req
.length
> sizeof(pss
->u
.req
.data
)) {
703 res
= TPM_BAD_PARAMETER
;
707 /* transfer of blob initiated */
708 tx_state
.state
= TX_STATE_SET_STATE_BLOB
;
709 tx_state
.blobtype
= pss
->u
.req
.type
;
710 tx_state
.blob_is_encrypted
= is_encrypted
;
713 res
= ptm_set_stateblob_append(pss
->u
.req
.type
,
720 tx_state
.state
= TX_STATE_RW_COMMAND
;
723 pss
->u
.resp
.tpm_result
= res
;
725 fuse_reply_ioctl(req
, 0, pss
, sizeof(*pss
));
729 * ptm_get_stateblob_part: get part of a state blob
731 * @blobtype: the type of blob to get
732 * @buffer: the buffer this function will write the blob into
733 * @buffer_size: the size of the buffer
734 * @offset: the offset into the state blob
735 * @copied: pointer to int to indicate the number of bytes that were copied
736 * @is_encryped: returns whether the state blob is encrypted
739 ptm_get_stateblob_part(uint32_t blobtype
,
740 unsigned char *buffer
, size_t buffer_size
,
741 uint32_t offset
, uint32_t *copied
,
742 TPM_BOOL decrypt
, TPM_BOOL
*is_encrypted
)
746 if (!cached_stateblob_is_loaded(blobtype
, decrypt
)) {
747 res
= cached_stateblob_load(blobtype
, decrypt
);
751 cached_stateblob_copy(buffer
, buffer_size
,
752 offset
, copied
, is_encrypted
);
759 * ptm_get_stateblob: Get the state blob from the TPM using ioctl()
762 ptm_get_stateblob(fuse_req_t req
, ptm_getstate
*pgs
)
765 uint32_t blobtype
= pgs
->u
.req
.type
;
767 ((pgs
->u
.req
.state_flags
& PTM_STATE_FLAG_DECRYPTED
) != 0);
768 TPM_BOOL is_encrypted
= FALSE
;
770 uint32_t offset
= pgs
->u
.req
.offset
;
773 res
= ptm_get_stateblob_part(blobtype
,
774 pgs
->u
.resp
.data
, sizeof(pgs
->u
.resp
.data
),
775 pgs
->u
.req
.offset
, &copied
,
776 decrypt
, &is_encrypted
);
778 totlength
= cached_stateblob_get_bloblength();
780 pgs
->u
.resp
.state_flags
= 0;
782 pgs
->u
.resp
.state_flags
|= PTM_STATE_FLAG_ENCRYPTED
;
784 pgs
->u
.resp
.length
= copied
;
785 pgs
->u
.resp
.totlength
= totlength
;
786 pgs
->u
.resp
.tpm_result
= res
;
789 if (offset
+ copied
< totlength
) {
790 /* last byte was not copied */
791 tx_state
.state
= TX_STATE_GET_STATE_BLOB
;
792 tx_state
.blobtype
= pgs
->u
.req
.type
;
793 tx_state
.blob_is_encrypted
= is_encrypted
;
794 tx_state
.offset
= copied
;
796 /* last byte was copied */
797 tx_state
.state
= TX_STATE_RW_COMMAND
;
801 tx_state
.state
= TX_STATE_RW_COMMAND
;
804 fuse_reply_ioctl(req
, 0, pgs
, sizeof(pgs
->u
.resp
));
807 /*********************************** write() support *************************/
810 * ptm_write_stateblob: Write the state blob using the write() interface
812 * @req: the fuse_req_t
813 * @buf: the buffer with the data
814 * @size: the number of bytes in the buffer
816 * The data are appended to an existing buffer that was created with the
819 static void ptm_write_stateblob(fuse_req_t req
, const char *buf
, size_t size
)
823 res
= ptm_set_stateblob_append(tx_state
.blobtype
,
824 (unsigned char *)buf
, size
,
825 tx_state
.blob_is_encrypted
,
828 tx_state
.state
= TX_STATE_RW_COMMAND
;
829 fuse_reply_err(req
, EIO
);
831 fuse_reply_write(req
, size
);
836 * ptm_write_cmd: User writing a TPM command
839 * buf: the buffer containing the TPM command
840 * size: the size of the buffer
842 static void ptm_write_cmd(fuse_req_t req
, const char *buf
, size_t size
)
847 /* prevent other threads from writing or doing ioctls */
848 g_mutex_lock(FILE_OPS_LOCK
);
851 /* ensure that we only ever work on one TPM command */
852 if (worker_thread_is_busy()) {
853 fuse_reply_err(req
, EBUSY
);
857 /* have command processed by thread pool */
858 if (ptm_req_len
> TPM_REQ_MAX
)
859 ptm_req_len
= TPM_REQ_MAX
;
861 memcpy(ptm_request
, buf
, ptm_req_len
);
863 msg
.type
= MESSAGE_TPM_CMD
;
865 worker_thread_mark_busy();
867 g_thread_pool_push(pool
, &msg
, NULL
);
869 /* TPM not initialized; return error */
870 ptm_write_fatal_error_response();
873 fuse_reply_write(req
, ptm_req_len
);
876 g_mutex_unlock(FILE_OPS_LOCK
);
882 * ptm_write: low-level write() interface; calls approriate function depending
883 * on what is being transferred using the write()
885 static void ptm_write(fuse_req_t req
, const char *buf
, size_t size
,
886 off_t off
, struct fuse_file_info
*fi
)
888 switch (tx_state
.state
) {
889 case TX_STATE_RW_COMMAND
:
890 ptm_write_cmd(req
, buf
, size
);
892 case TX_STATE_GET_STATE_BLOB
:
893 fuse_reply_err(req
, EIO
);
894 tx_state
.state
= TX_STATE_RW_COMMAND
;
896 case TX_STATE_SET_STATE_BLOB
:
897 ptm_write_stateblob(req
, buf
, size
);
903 * ptm_open: interface to POSIX open()
905 static void ptm_open(fuse_req_t req
, struct fuse_file_info
*fi
)
907 tx_state
.state
= TX_STATE_RW_COMMAND
;
909 fuse_reply_open(req
, fi
);
913 * ptm_ioctl : ioctl execution
915 * req: the fuse_req_t used to send response with
916 * cmd: the ioctl request code
917 * arg: the pointer the application used for calling the ioctl (3rd param)
919 * flags: some flags provided by fuse
920 * in_buf: the copy of the input buffer
921 * in_bufsz: size of the input buffer; provided by fuse and has size of
923 * out_bufsz: size of the output buffer; provided by fuse and has size of
926 static void ptm_ioctl(fuse_req_t req
, int cmd
, void *arg
,
927 struct fuse_file_info
*fi
, unsigned flags
,
928 const void *in_buf
, size_t in_bufsz
, size_t out_bufsz
)
930 TPM_RESULT res
= TPM_FAIL
;
931 bool exit_prg
= FALSE
;
934 if (flags
& FUSE_IOCTL_COMPAT
) {
935 fuse_reply_err(req
, ENOSYS
);
939 /* some commands have to wait until the worker thread is done */
941 case PTM_GET_CAPABILITY
:
942 case PTM_SET_LOCALITY
:
943 case PTM_CANCEL_TPM_CMD
:
945 /* no need to wait */
949 case PTM_GET_TPMESTABLISHED
:
950 case PTM_RESET_TPMESTABLISHED
:
954 case PTM_STORE_VOLATILE
:
955 case PTM_GET_STATEBLOB
:
956 case PTM_SET_STATEBLOB
:
958 worker_thread_wait_done();
962 /* prevent other threads from writing or doing ioctls */
963 g_mutex_lock(FILE_OPS_LOCK
);
966 case PTM_GET_CAPABILITY
:
967 if (out_bufsz
!= sizeof(ptm_cap
)) {
968 struct iovec iov
= { arg
, sizeof(uint8_t) };
969 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
972 ptm_caps
= PTM_CAP_INIT
| PTM_CAP_SHUTDOWN
973 | PTM_CAP_GET_TPMESTABLISHED
974 | PTM_CAP_SET_LOCALITY
976 | PTM_CAP_CANCEL_TPM_CMD
977 | PTM_CAP_STORE_VOLATILE
978 | PTM_CAP_RESET_TPMESTABLISHED
979 | PTM_CAP_GET_STATEBLOB
980 | PTM_CAP_SET_STATEBLOB
982 | PTM_CAP_GET_CONFIG
;
983 fuse_reply_ioctl(req
, 0, &ptm_caps
, sizeof(ptm_caps
));
988 if (in_bufsz
!= sizeof(ptm_init
)) {
989 struct iovec iov
= { arg
, sizeof(uint8_t) };
990 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
992 init_p
= (ptm_init
*)in_buf
;
999 if (tpm_start(init_p
->u
.req
.init_flags
) < 0) {
1001 logprintf(STDERR_FILENO
,
1002 "Error: Could not initialize the TPM.\n");
1007 init_p
->u
.resp
.tpm_result
= res
;
1008 fuse_reply_ioctl(req
, 0, init_p
, sizeof(*init_p
));
1013 worker_thread_end();
1018 tpm_running
= false;
1020 TPM_Free(ptm_response
);
1021 ptm_response
= NULL
;
1023 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1028 worker_thread_end();
1033 TPM_Free(ptm_response
);
1034 ptm_response
= NULL
;
1036 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1041 case PTM_GET_TPMESTABLISHED
:
1043 goto error_not_running
;
1045 if (out_bufsz
!= sizeof(ptm_est
)) {
1046 struct iovec iov
= { arg
, sizeof(uint8_t) };
1047 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1050 te
.u
.resp
.tpm_result
= TPM_IO_TpmEstablished_Get(&te
.u
.resp
.bit
);
1051 fuse_reply_ioctl(req
, 0, &te
, sizeof(te
));
1055 case PTM_RESET_TPMESTABLISHED
:
1057 goto error_not_running
;
1059 if (in_bufsz
!= sizeof(ptm_reset_est
)) {
1060 struct iovec iov
= { arg
, sizeof(uint32_t) };
1061 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1063 ptm_reset_est
*re
= (ptm_reset_est
*)in_buf
;
1064 if (re
->u
.req
.loc
> 4) {
1065 res
= TPM_BAD_LOCALITY
;
1067 res
= _TPM_IO_TpmEstablished_Reset(req
, re
->u
.req
.loc
);
1068 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1073 case PTM_SET_LOCALITY
:
1074 if (in_bufsz
!= sizeof(ptm_loc
)) {
1075 struct iovec iov
= { arg
, sizeof(uint32_t) };
1076 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1078 ptm_loc
*l
= (ptm_loc
*)in_buf
;
1079 if (l
->u
.req
.loc
> 4) {
1080 res
= TPM_BAD_LOCALITY
;
1083 locality
= l
->u
.req
.loc
;
1085 l
->u
.resp
.tpm_result
= res
;
1086 fuse_reply_ioctl(req
, 0, l
, sizeof(*l
));
1090 case PTM_HASH_START
:
1092 goto error_not_running
;
1094 res
= TPM_IO_Hash_Start();
1095 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1100 goto error_not_running
;
1102 if (in_bufsz
!= sizeof(ptm_hdata
)) {
1103 struct iovec iov
= { arg
, sizeof(uint32_t) };
1104 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1106 ptm_hdata
*data
= (ptm_hdata
*)in_buf
;
1107 if (data
->u
.req
.length
<= sizeof(data
->u
.req
.data
)) {
1108 res
= TPM_IO_Hash_Data(data
->u
.req
.data
,
1109 data
->u
.req
.length
);
1113 data
->u
.resp
.tpm_result
= res
;
1114 fuse_reply_ioctl(req
, 0, data
, sizeof(*data
));
1120 goto error_not_running
;
1122 res
= TPM_IO_Hash_End();
1123 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1126 case PTM_CANCEL_TPM_CMD
:
1128 goto error_not_running
;
1130 /* for cancellation to work, the TPM would have to
1131 * execute in another thread that polls on a cancel
1135 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1138 case PTM_STORE_VOLATILE
:
1140 goto error_not_running
;
1142 res
= SWTPM_NVRAM_Store_Volatile();
1143 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1145 cached_stateblob_free();
1148 case PTM_GET_STATEBLOB
:
1150 goto error_not_running
;
1152 if (in_bufsz
!= sizeof(ptm_getstate
)) {
1153 struct iovec iov
= { arg
, sizeof(uint32_t) };
1154 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1156 ptm_get_stateblob(req
, (ptm_getstate
*)in_buf
);
1160 case PTM_SET_STATEBLOB
:
1164 /* tpm state dir must be set */
1167 if (in_bufsz
!= sizeof(ptm_setstate
)) {
1168 struct iovec iov
= { arg
, sizeof(uint32_t) };
1169 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1171 ptm_set_stateblob(req
, (ptm_setstate
*)in_buf
);
1175 case PTM_GET_CONFIG
:
1176 if (out_bufsz
!= sizeof(ptm_getconfig
)) {
1177 struct iovec iov
= { arg
, sizeof(uint32_t) };
1178 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1181 pgs
.u
.resp
.tpm_result
= 0;
1182 pgs
.u
.resp
.flags
= 0;
1183 if (SWTPM_NVRAM_Has_FileKey())
1184 pgs
.u
.resp
.flags
|= PTM_CONFIG_FLAG_FILE_KEY
;
1185 if (SWTPM_NVRAM_Has_MigrationKey())
1186 pgs
.u
.resp
.flags
|= PTM_CONFIG_FLAG_MIGRATION_KEY
;
1187 fuse_reply_ioctl(req
, 0, &pgs
, sizeof(pgs
));
1192 fuse_reply_err(req
, EINVAL
);
1196 g_mutex_unlock(FILE_OPS_LOCK
);
1199 logprintf(STDOUT_FILENO
, "CUSE TPM is shutting down.\n");
1209 res
= TPM_BAD_ORDINAL
;
1210 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1215 static void ptm_init_done(void *userdata
)
1217 struct cuse_param
*param
= userdata
;
1220 /* at this point the entry in /dev/ is available */
1221 if (pidfile_write(getpid()) < 0) {
1226 ret
= change_process_owner(param
->runas
);
1232 static const struct cuse_lowlevel_ops clops
= {
1237 .init_done
= ptm_init_done
,
1240 #ifndef HAVE_SWTPM_CUSE_MAIN
1241 int main(int argc
, char **argv
)
1243 const char *prgname
= argv
[0];
1244 const char *iface
= "";
1246 int swtpm_cuse_main(int argc
, char **argv
, const char *prgname
, const char *iface
)
1249 int opt
, longindex
= 0;
1250 static struct option longopts
[] = {
1251 {"maj" , required_argument
, 0, 'M'},
1252 {"min" , required_argument
, 0, 'm'},
1253 {"name" , required_argument
, 0, 'n'},
1254 {"runas" , required_argument
, 0, 'r'},
1255 {"log" , required_argument
, 0, 'l'},
1256 {"key" , required_argument
, 0, 'k'},
1257 {"migration-key" , required_argument
, 0, 'K'},
1258 {"pid" , required_argument
, 0, 'p'},
1259 {"tpmstate" , required_argument
, 0, 's'},
1260 {"help" , no_argument
, 0, 'h'},
1261 {"version" , no_argument
, 0, 'v'},
1264 struct cuse_info cinfo
;
1265 struct cuse_param param
;
1266 const char *devname
= NULL
;
1267 char *cinfo_argv
[1];
1269 struct passwd
*passwd
;
1272 char path
[PATH_MAX
];
1274 memset(&cinfo
, 0, sizeof(cinfo
));
1275 memset(¶m
, 0, sizeof(param
));
1278 opt
= getopt_long(argc
, argv
, "M:m:n:r:hv", longopts
, &longindex
);
1284 case 'M': /* major */
1285 if (sscanf(optarg
, "%u", &num
) != 1) {
1286 fprintf(stderr
, "Could not parse major number\n");
1290 fprintf(stderr
, "Major number outside valid range [0 - 65535]\n");
1293 cinfo
.dev_major
= num
;
1295 case 'm': /* minor */
1296 if (sscanf(optarg
, "%u", &num
) != 1) {
1297 fprintf(stderr
, "Could not parse major number\n");
1300 if (num
< 0 || num
> 65535) {
1301 fprintf(stderr
, "Major number outside valid range [0 - 65535]\n");
1304 cinfo
.dev_minor
= num
;
1306 case 'n': /* name */
1307 if (!cinfo
.dev_info_argc
) {
1308 cinfo_argv
[0] = calloc(1, strlen("DEVNAME=") + strlen(optarg
) + 1);
1309 if (!cinfo_argv
[0]) {
1310 fprintf(stderr
, "Out of memory\n");
1315 strcpy(cinfo_argv
[0], "DEVNAME=");
1316 strcat(cinfo_argv
[0], optarg
);
1318 cinfo
.dev_info_argc
= 1;
1319 cinfo
.dev_info_argv
= (const char **)cinfo_argv
;
1322 case 'r': /* runas */
1323 param
.runas
= optarg
;
1326 param
.logging
= optarg
;
1329 param
.keydata
= optarg
;
1331 case 'K': /* migration-key */
1332 param
.migkeydata
= optarg
;
1335 param
.piddata
= optarg
;
1337 case 's': /* tpmstate */
1338 param
.tpmstatedata
= optarg
;
1340 case 'h': /* help */
1341 fprintf(stdout
, usage
, prgname
, iface
);
1343 case 'v': /* version */
1344 fprintf(stdout
, "TPM emulator CUSE interface version %d.%d.%d, "
1345 "Copyright (c) 2014-2015 IBM Corp.\n",
1353 if (!cinfo
.dev_info_argv
) {
1354 fprintf(stderr
, "Error: device name missing\n");
1358 if (handle_log_options(param
.logging
) < 0 ||
1359 handle_key_options(param
.keydata
) < 0 ||
1360 handle_migration_key_options(param
.migkeydata
) < 0 ||
1361 handle_pid_options(param
.piddata
) < 0 ||
1362 handle_tpmstate_options(param
.tpmstatedata
) < 0)
1366 fprintf(stderr
, "Error: Unable to setuid root. uid = %d, "
1367 "euid = %d, gid = %d\n", getuid(), geteuid(), getgid());
1372 if (!(passwd
= getpwnam(param
.runas
))) {
1373 fprintf(stderr
, "User '%s' does not exist\n",
1379 tpmdir
= tpmstate_get_dir();
1380 if (tpmdir
== NULL
) {
1382 "Error: No TPM state directory is defined; TPM_PATH is not set\n");
1386 n
= snprintf(path
, sizeof(path
), "/dev/%s", devname
);
1389 "Error: Could not create device file name\n");
1392 if (n
>= (int)sizeof(path
)) {
1394 "Error: Buffer too small to create device file name\n");
1398 tpmfd
= open(path
, O_RDWR
);
1402 "Error: A device '%s' already exists.\n",
1407 worker_thread_init();
1409 #if GLIB_MINOR_VERSION >= 32
1410 g_mutex_init(FILE_OPS_LOCK
);
1412 FILE_OPS_LOCK
= g_mutex_new();
1415 return cuse_lowlevel_main(1, argv
, &cinfo
, &clops
, ¶m
);