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>
72 #include "tpm_ioctl.h"
73 #include "swtpm_nvfile.h"
77 #include "threadpool.h"
78 #include "seccomp_profile.h"
80 #include "capabilities.h"
82 /* maximum size of request buffer */
83 #define TPM_REQ_MAX 4096
85 /* version of the TPM (1.2 or 2) */
86 static TPMLIB_TPMVersion tpmversion
;
88 /* buffer containing the TPM request */
89 static unsigned char *ptm_request
;
91 /* buffer containing the TPM response */
92 static unsigned char *ptm_response
;
94 /* the sizes of the data in the buffers */
95 static uint32_t ptm_req_len
, ptm_res_len
, ptm_res_tot
;
97 /* locality applied to TPM commands */
98 static TPM_MODIFIER_INDICATOR locality
;
100 /* whether the TPM is running (TPM_Init was received) */
101 static bool tpm_running
;
103 /* flags on how to handle locality */
104 static uint32_t locality_flags
;
106 /* the fuse_session that we will signal an exit to to exit the prg. */
107 static struct fuse_session
*ptm_fuse_session
;
109 #if GLIB_MAJOR_VERSION >= 2
110 # if GLIB_MINOR_VERSION >= 32
112 GMutex file_ops_lock
;
113 # define FILE_OPS_LOCK &file_ops_lock
117 GMutex
*file_ops_lock
;
118 # define FILE_OPS_LOCK file_ops_lock
123 #error Unsupport glib version
136 unsigned int seccomp_action
;
139 /* single message to send to the worker thread */
140 static struct thread_message msg
;
146 TPM_BOOL is_encrypted
;
149 typedef struct stateblob_desc
{
152 TPM_BOOL is_encrypted
;
154 uint32_t data_length
;
157 typedef enum tx_state_type
{
158 TX_STATE_RW_COMMAND
= 1,
159 TX_STATE_SET_STATE_BLOB
= 2,
160 TX_STATE_GET_STATE_BLOB
= 3,
163 typedef struct transfer_state
{
165 /* while in TX_STATE_GET/SET_STATEBLOB */
167 TPM_BOOL blob_is_encrypted
;
168 /* while in TX_STATE_GET */
172 typedef struct TPM_Response_Header
{
176 } __attribute__ ((packed
)) TPM_Response_Header
;
178 /*********************************** data *************************************/
180 static const char *usage
=
181 "usage: %s %s [options]\n"
183 "The following options are supported:\n"
185 "-n NAME|--name=NAME : device name (mandatory)\n"
186 "-M MAJ|--maj=MAJ : device major number\n"
187 "-m MIN|--min=MIN : device minor number\n"
188 "--key file=<path>|fd=<fd>[,mode=aes-cbc|aes-256-cbc][,format=hex|binary][,remove=[true|false]]\n"
189 " : use an AES key for the encryption of the TPM's state\n"
190 " files; use the given mode for the block encryption;\n"
191 " the key is to be provided as a hex string or in binary\n"
192 " format; the keyfile can be automatically removed using\n"
193 " the remove parameter\n"
194 "--key pwdfile=<path>|pwdfd=<fd>[,mode=aes-cbc|aes-256-cbc][,remove=[true|false]][,kdf=sha512|pbkdf2]\n"
195 " : provide a passphrase in a file; the AES key will be\n"
196 " derived from this passphrase; default kdf is PBKDF2\n"
197 "--locality [reject-locality-4][,allow-set-locality]\n"
198 " : reject-locality-4: reject any command in locality 4\n"
199 " allow-set-locality: accept SetLocality command\n"
200 "--migration-key file=<path>|fd=<fd>[,mode=aes-cbc|aes-256-cbc][,format=hex|binary][,remove=[true|false]]\n"
201 " : use an AES key for the encryption of the TPM's state\n"
202 " when it is retrieved from the TPM via ioctls;\n"
203 " Setting this key ensures that the TPM's state will always\n"
204 " be encrypted when migrated\n"
205 "--migration-key pwdfile=<path>|pwdfd=<fd>[,mode=aes-cbc|aes-256-cbc][,remove=[true|false]][,kdf=sha512|pbkdf2]\n"
206 " : provide a passphrase in a file; the AES key will be\n"
207 " derived from this passphrase; default kdf is PBKDF2\n"
208 "--log file=<path>|fd=<filedescriptor>[,level=n][,prefix=<prefix>][,truncate]\n"
209 " : write the TPM's log into the given file rather than\n"
210 " to the console; provide '-' for path to avoid logging\n"
211 " log level 5 and higher will enable libtpms logging;\n"
212 " all logged output will be prefixed with prefix;\n"
213 " the log file can be reset (truncate)\n"
214 "--pid file=<path>|fd=<filedescriptor>\n"
215 " : write the process ID into the given file\n"
216 "--tpmstate dir=<dir>[,mode=0...]\n"
217 " : set the directory where the TPM's state will be written\n"
218 " into; the TPM_PATH environment variable can be used\n"
220 " mode allows to set the file mode bits of the state\n"
221 " files; the default mode is 0640;\n"
222 "-r|--runas <user> : after creating the CUSE device, change to the given\n"
224 "--tpm2 : choose TPM2 functionality\n"
226 # ifndef SCMP_ACT_LOG
227 "--seccomp action=none|kill\n"
229 "--seccomp action=none|kill|log\n"
231 " : Choose the action of the seccomp profile when a\n"
232 " blacklisted syscall is executed; default is kill\n"
234 "--print-capabilites : print capabilities and terminate\n"
235 "-h|--help : display this help screen and terminate\n"
239 ptm_io_getlocality(TPM_MODIFIER_INDICATOR
*loc
, uint32_t tpmnum
)
245 static struct libtpms_callbacks cbs
= {
246 .sizeOfStruct
= sizeof(struct libtpms_callbacks
),
247 .tpm_nvram_init
= SWTPM_NVRAM_Init
,
248 .tpm_nvram_loaddata
= SWTPM_NVRAM_LoadData
,
249 .tpm_nvram_storedata
= SWTPM_NVRAM_StoreData
,
250 .tpm_nvram_deletename
= SWTPM_NVRAM_DeleteName
,
251 .tpm_io_getlocality
= ptm_io_getlocality
,
254 /* the current state the transfer interface is in */
255 static transfer_state tx_state
;
257 /* function prototypes */
258 static void ptm_cleanup(void);
260 /************************* cached stateblob *********************************/
262 static stateblob_desc cached_stateblob
;
265 * cached_stateblob_is_loaded: is the stateblob with the given properties
266 * the one in the cache?
268 static bool cached_stateblob_is_loaded(uint32_t blobtype
,
271 return (cached_stateblob
.data
!= NULL
) &&
272 (cached_stateblob
.blobtype
== blobtype
) &&
273 (cached_stateblob
.decrypt
== decrypt
);
277 * cached_stateblob_free: Free any previously loaded state blob
279 static void cached_stateblob_free(void)
281 free(cached_stateblob
.data
);
282 cached_stateblob
.data
= NULL
;
283 cached_stateblob
.data_length
= 0;
287 * cached_stateblob_get_bloblength: get the total length of the cached blob
289 static uint32_t cached_stateblob_get_bloblength(void)
291 return cached_stateblob
.data_length
;
295 * cached_statblob_get: get stateblob data without copying them
297 * @offset: at which offset to get the data
298 * @bufptr: pointer to a buffer pointer used to return buffer start
299 * @length: pointer used to return number of available bytes in returned buffer
301 static int cached_stateblob_get(uint32_t offset
,
302 unsigned char **bufptr
, size_t *length
)
304 if (cached_stateblob
.data
== NULL
||
305 offset
> cached_stateblob
.data_length
)
308 *bufptr
= &cached_stateblob
.data
[offset
];
309 *length
= cached_stateblob
.data_length
- offset
;
315 * cached_stateblob_load: load a state blob into the cache
317 * blobtype: the type of blob
318 * decrypt: whether the blob is to be decrypted
320 static TPM_RESULT
cached_stateblob_load(uint32_t blobtype
, TPM_BOOL decrypt
)
323 const char *blobname
= tpmlib_get_blobname(blobtype
);
324 uint32_t tpm_number
= 0;
327 return TPM_BAD_PARAMETER
;
329 cached_stateblob_free();
331 if (blobtype
== PTM_BLOB_TYPE_VOLATILE
)
332 res
= SWTPM_NVRAM_Store_Volatile();
335 res
= SWTPM_NVRAM_GetStateBlob(&cached_stateblob
.data
,
336 &cached_stateblob
.data_length
,
337 tpm_number
, blobname
, decrypt
,
338 &cached_stateblob
.is_encrypted
);
340 /* make sure the volatile state file is gone */
341 if (blobtype
== PTM_BLOB_TYPE_VOLATILE
)
342 SWTPM_NVRAM_DeleteName(tpm_number
, blobname
, FALSE
);
345 cached_stateblob
.blobtype
= blobtype
;
346 cached_stateblob
.decrypt
= decrypt
;
353 * cached_state_blob_copy: copy the cached state blob to a destination buffer
355 * dest: destination buffer
356 * destlen: size of the buffer
357 * srcoffset: offset to copy from
358 * copied: variable to return the number of copied bytes
359 * is_encrypted: variable to return whether the blob is encrypted
361 static int cached_stateblob_copy(void *dest
, size_t destlen
,
362 uint32_t srcoffset
, uint32_t *copied
,
363 TPM_BOOL
*is_encrypted
)
369 if (cached_stateblob
.data
!= NULL
&& cached_stateblob
.data_length
> 0) {
371 if (srcoffset
< cached_stateblob
.data_length
) {
372 *copied
= min(cached_stateblob
.data_length
- srcoffset
, destlen
);
374 memcpy(dest
, &cached_stateblob
.data
[srcoffset
], *copied
);
376 *is_encrypted
= cached_stateblob
.is_encrypted
;
385 /************************* worker thread ************************************/
388 * worker_thread: the worker thread
390 static void worker_thread(gpointer data
, gpointer user_data
)
392 struct thread_message
*msg
= (struct thread_message
*)data
;
395 case MESSAGE_TPM_CMD
:
396 TPMLIB_Process(&ptm_response
, &ptm_res_len
, &ptm_res_tot
,
397 ptm_request
, ptm_req_len
);
403 /* results are ready */
404 worker_thread_mark_done();
407 /***************************** utility functions ****************************/
410 * tpm_start: Start the TPM
412 * Check whether the TPM's state directory exists and if it does
413 * not exists, try to creat it. Start the thread pool, initilize
414 * libtpms and allocate a global TPM request buffer.
416 * @flags: libtpms init flags
417 * @l_tpmversion: the version of the TPM
418 * @res: the result from starting the TPM
420 static int tpm_start(uint32_t flags
, TPMLIB_TPMVersion l_tpmversion
,
424 const char *tpmdir
= tpmstate_get_dir();
428 dir
= opendir(tpmdir
);
432 if (mkdir(tpmdir
, 0775)) {
433 logprintf(STDERR_FILENO
,
434 "Error: Could not open tpmstate dir %s\n",
440 pool
= g_thread_pool_new(worker_thread
,
446 logprintf(STDERR_FILENO
,
447 "Error: Could not create the thread pool.\n");
452 ptm_request
= malloc(4096);
454 logprintf(STDERR_FILENO
,
455 "Error: Could not allocate memory for request buffer.\n");
459 *res
= tpmlib_start(flags
, l_tpmversion
);
460 if (*res
!= TPM_SUCCESS
)
463 logprintf(STDOUT_FILENO
,
464 "CUSE TPM successfully initialized.\n");
469 g_thread_pool_free(pool
, TRUE
, TRUE
);
476 * ptm_write_fatal_error_response: Write fatal error response
478 * Write a fatal error response into the global ptm_response buffer.
480 static void ptm_write_fatal_error_response(TPMLIB_TPMVersion l_tpmversion
)
482 tpmlib_write_fatal_error_response(&ptm_response
,
488 /************************************ read() support ***************************/
491 * ptm_read_result: Return the TPM response packet
493 * @req: the fuse_req_t
494 * @size: the max. number of bytes to return to the requester
496 static void ptm_read_result(fuse_req_t req
, size_t size
)
501 /* wait until results are ready */
502 worker_thread_wait_done();
507 if (ptm_res_len
> size
) {
514 fuse_reply_buf(req
, (const char *)ptm_response
, len
);
518 * ptm_read_stateblob: get a TPM stateblob via the read() interface
520 * @req: the fuse_req_t
521 * @size: the number of bytes to read
523 * The internal offset into the buffer is advanced by the number
524 * of bytes that were copied. We switch back to command read/write
525 * mode if an error occurred or once all bytes were read.
527 static void ptm_read_stateblob(fuse_req_t req
, size_t size
)
529 unsigned char *bufptr
= NULL
;
533 if (cached_stateblob_get(tx_state
.offset
, &bufptr
, &numbytes
) < 0) {
534 fuse_reply_err(req
, EIO
);
535 tx_state
.state
= TX_STATE_RW_COMMAND
;
537 tocopy
= MIN(size
, numbytes
);
538 tx_state
.offset
+= tocopy
;
540 fuse_reply_buf(req
, (char *)bufptr
, tocopy
);
541 /* last transfer indicated by less bytes available than requested */
542 if (numbytes
< size
) {
543 tx_state
.state
= TX_STATE_RW_COMMAND
;
549 * ptm_read: interface to POSIX read()
552 * @size: number of bytes to read
553 * @off: offset (not used)
554 * @fi: fuse_file_info (not used)
556 * Depending on the current state of the transfer interface (read/write)
557 * return either the results of TPM commands or a data of a TPM state blob.
559 static void ptm_read(fuse_req_t req
, size_t size
, off_t off
,
560 struct fuse_file_info
*fi
)
562 switch (tx_state
.state
) {
563 case TX_STATE_RW_COMMAND
:
564 ptm_read_result(req
, size
);
566 case TX_STATE_SET_STATE_BLOB
:
567 fuse_reply_err(req
, EIO
);
568 tx_state
.state
= TX_STATE_RW_COMMAND
;
570 case TX_STATE_GET_STATE_BLOB
:
571 ptm_read_stateblob(req
, size
);
576 /*************************read/write stateblob support ***********************/
579 * ptm_set_stateblob_append: Append a piece of TPM state blob and transfer to TPM
581 * blobtype: the type of blob
582 * data: the data to append
583 * length: length of the data
584 * is_encrypted: whether the blob is encrypted
585 * is_last: whether this is the last part of the TPM state blob; if it is, the TPM
586 * state blob will then be transferred to the TPM
589 ptm_set_stateblob_append(uint32_t blobtype
,
590 const unsigned char *data
, uint32_t length
,
591 bool is_encrypted
, bool is_last
)
594 static struct stateblob stateblob
;
597 if (stateblob
.type
!= blobtype
) {
598 /* new blob; clear old data */
599 free(stateblob
.data
);
600 stateblob
.data
= NULL
;
601 stateblob
.length
= 0;
602 stateblob
.type
= blobtype
;
603 stateblob
.is_encrypted
= is_encrypted
;
606 * on the first call for a new state blob we allow 0 bytes to be written
607 * this allows the user to transfer via write()
614 tmp
= realloc(stateblob
.data
, stateblob
.length
+ length
);
616 logprintf(STDERR_FILENO
,
617 "Could not allocate %u bytes.\n", stateblob
.length
+ length
);
619 free(stateblob
.data
);
620 stateblob
.data
= NULL
;
621 stateblob
.length
= 0;
626 stateblob
.data
= tmp
;
628 memcpy(&stateblob
.data
[stateblob
.length
], data
, length
);
629 stateblob
.length
+= length
;
632 /* full packet -- expecting more data */
636 res
= SWTPM_NVRAM_SetStateBlob(stateblob
.data
,
638 stateblob
.is_encrypted
,
642 logprintf(STDERR_FILENO
,
643 "Deserialized state type %d (%s), length=%d, res=%d\n",
644 blobtype
, tpmlib_get_blobname(blobtype
),
645 stateblob
.length
, res
);
647 free(stateblob
.data
);
648 stateblob
.data
= NULL
;
649 stateblob
.length
= 0;
652 /* transfer of blob is complete */
653 tx_state
.state
= TX_STATE_RW_COMMAND
;
659 * ptm_set_stateblob: set part of a TPM state blob
662 * pss: ptm_setstate provided via ioctl()
665 ptm_set_stateblob(fuse_req_t req
, ptm_setstate
*pss
)
668 TPM_BOOL is_encrypted
=
669 ((pss
->u
.req
.state_flags
& PTM_STATE_FLAG_ENCRYPTED
) != 0);
670 bool is_last
= (sizeof(pss
->u
.req
.data
) != pss
->u
.req
.length
);
672 if (pss
->u
.req
.length
> sizeof(pss
->u
.req
.data
)) {
673 res
= TPM_BAD_PARAMETER
;
677 /* transfer of blob initiated */
678 tx_state
.state
= TX_STATE_SET_STATE_BLOB
;
679 tx_state
.blobtype
= pss
->u
.req
.type
;
680 tx_state
.blob_is_encrypted
= is_encrypted
;
683 res
= ptm_set_stateblob_append(pss
->u
.req
.type
,
690 tx_state
.state
= TX_STATE_RW_COMMAND
;
693 pss
->u
.resp
.tpm_result
= res
;
695 fuse_reply_ioctl(req
, 0, pss
, sizeof(*pss
));
699 * ptm_get_stateblob_part: get part of a state blob
701 * @blobtype: the type of blob to get
702 * @buffer: the buffer this function will write the blob into
703 * @buffer_size: the size of the buffer
704 * @offset: the offset into the state blob
705 * @copied: pointer to int to indicate the number of bytes that were copied
706 * @is_encryped: returns whether the state blob is encrypted
709 ptm_get_stateblob_part(uint32_t blobtype
,
710 unsigned char *buffer
, size_t buffer_size
,
711 uint32_t offset
, uint32_t *copied
,
712 TPM_BOOL decrypt
, TPM_BOOL
*is_encrypted
)
716 if (!cached_stateblob_is_loaded(blobtype
, decrypt
)) {
717 res
= cached_stateblob_load(blobtype
, decrypt
);
721 cached_stateblob_copy(buffer
, buffer_size
,
722 offset
, copied
, is_encrypted
);
729 * ptm_get_stateblob: Get the state blob from the TPM using ioctl()
732 ptm_get_stateblob(fuse_req_t req
, ptm_getstate
*pgs
)
735 uint32_t blobtype
= pgs
->u
.req
.type
;
737 ((pgs
->u
.req
.state_flags
& PTM_STATE_FLAG_DECRYPTED
) != 0);
738 TPM_BOOL is_encrypted
= FALSE
;
740 uint32_t offset
= pgs
->u
.req
.offset
;
743 res
= ptm_get_stateblob_part(blobtype
,
744 pgs
->u
.resp
.data
, sizeof(pgs
->u
.resp
.data
),
745 pgs
->u
.req
.offset
, &copied
,
746 decrypt
, &is_encrypted
);
748 totlength
= cached_stateblob_get_bloblength();
750 pgs
->u
.resp
.state_flags
= 0;
752 pgs
->u
.resp
.state_flags
|= PTM_STATE_FLAG_ENCRYPTED
;
754 pgs
->u
.resp
.length
= copied
;
755 pgs
->u
.resp
.totlength
= totlength
;
756 pgs
->u
.resp
.tpm_result
= res
;
757 logprintf(STDERR_FILENO
,
758 "Serialized state type %d, length=%d, totlength=%d, res=%d\n",
759 blobtype
, copied
, totlength
, res
);
762 if (offset
+ copied
< totlength
) {
763 /* last byte was not copied */
764 tx_state
.state
= TX_STATE_GET_STATE_BLOB
;
765 tx_state
.blobtype
= pgs
->u
.req
.type
;
766 tx_state
.blob_is_encrypted
= is_encrypted
;
767 tx_state
.offset
= copied
;
769 /* last byte was copied */
770 tx_state
.state
= TX_STATE_RW_COMMAND
;
774 tx_state
.state
= TX_STATE_RW_COMMAND
;
777 fuse_reply_ioctl(req
, 0, pgs
, sizeof(pgs
->u
.resp
));
780 /*********************************** write() support *************************/
783 * ptm_write_stateblob: Write the state blob using the write() interface
785 * @req: the fuse_req_t
786 * @buf: the buffer with the data
787 * @size: the number of bytes in the buffer
789 * The data are appended to an existing buffer that was created with the
792 static void ptm_write_stateblob(fuse_req_t req
, const char *buf
, size_t size
)
796 res
= ptm_set_stateblob_append(tx_state
.blobtype
,
797 (unsigned char *)buf
, size
,
798 tx_state
.blob_is_encrypted
,
801 tx_state
.state
= TX_STATE_RW_COMMAND
;
802 fuse_reply_err(req
, EIO
);
804 fuse_reply_write(req
, size
);
809 * ptm_write_cmd: User writing a TPM command
812 * buf: the buffer containing the TPM command
813 * size: the size of the buffer
814 * tpmversion: the version of the TPM
816 static void ptm_write_cmd(fuse_req_t req
, const char *buf
, size_t size
,
817 TPMLIB_TPMVersion l_tpmversion
)
822 /* prevent other threads from writing or doing ioctls */
823 g_mutex_lock(FILE_OPS_LOCK
);
826 /* ensure that we only ever work on one TPM command */
827 if (worker_thread_is_busy()) {
828 fuse_reply_err(req
, EBUSY
);
832 if (ptm_req_len
> TPM_REQ_MAX
)
833 ptm_req_len
= TPM_REQ_MAX
;
835 /* process SetLocality command, if */
836 tpmlib_process(&ptm_response
, &ptm_res_len
, &ptm_res_tot
,
837 (unsigned char *)buf
, ptm_req_len
,
838 locality_flags
, &locality
, tpmversion
);
842 if (tpmlib_is_request_cancelable(l_tpmversion
,
843 (const unsigned char*)buf
,
845 /* have command processed by thread pool */
846 memcpy(ptm_request
, buf
, ptm_req_len
);
848 msg
.type
= MESSAGE_TPM_CMD
;
850 worker_thread_mark_busy();
852 g_thread_pool_push(pool
, &msg
, NULL
);
854 /* direct processing */
855 TPMLIB_Process(&ptm_response
, &ptm_res_len
, &ptm_res_tot
,
856 (unsigned char *)buf
, ptm_req_len
);
859 /* TPM not initialized; return error */
860 ptm_write_fatal_error_response(l_tpmversion
);
864 fuse_reply_write(req
, ptm_req_len
);
867 g_mutex_unlock(FILE_OPS_LOCK
);
873 * ptm_write: low-level write() interface; calls approriate function depending
874 * on what is being transferred using the write()
876 static void ptm_write(fuse_req_t req
, const char *buf
, size_t size
,
877 off_t off
, struct fuse_file_info
*fi
)
879 switch (tx_state
.state
) {
880 case TX_STATE_RW_COMMAND
:
881 ptm_write_cmd(req
, buf
, size
, tpmversion
);
883 case TX_STATE_GET_STATE_BLOB
:
884 fuse_reply_err(req
, EIO
);
885 tx_state
.state
= TX_STATE_RW_COMMAND
;
887 case TX_STATE_SET_STATE_BLOB
:
888 ptm_write_stateblob(req
, buf
, size
);
894 * ptm_open: interface to POSIX open()
896 static void ptm_open(fuse_req_t req
, struct fuse_file_info
*fi
)
898 tx_state
.state
= TX_STATE_RW_COMMAND
;
900 fuse_reply_open(req
, fi
);
904 * ptm_ioctl : ioctl execution
906 * req: the fuse_req_t used to send response with
907 * cmd: the ioctl request code
908 * arg: the pointer the application used for calling the ioctl (3rd param)
910 * flags: some flags provided by fuse
911 * in_buf: the copy of the input buffer
912 * in_bufsz: size of the input buffer; provided by fuse and has size of
914 * out_bufsz: size of the output buffer; provided by fuse and has size of
917 static void ptm_ioctl(fuse_req_t req
, int cmd
, void *arg
,
918 struct fuse_file_info
*fi
, unsigned flags
,
919 const void *in_buf
, size_t in_bufsz
, size_t out_bufsz
)
921 TPM_RESULT res
= TPM_FAIL
;
922 bool exit_prg
= FALSE
;
924 TPM_MODIFIER_INDICATOR orig_locality
;
926 /* some commands have to wait until the worker thread is done */
928 case PTM_GET_CAPABILITY
:
929 case PTM_SET_LOCALITY
:
930 case PTM_CANCEL_TPM_CMD
:
932 case PTM_SET_BUFFERSIZE
:
933 /* no need to wait */
937 case PTM_GET_TPMESTABLISHED
:
938 case PTM_RESET_TPMESTABLISHED
:
942 case PTM_STORE_VOLATILE
:
943 case PTM_GET_STATEBLOB
:
944 case PTM_SET_STATEBLOB
:
946 worker_thread_wait_done();
950 /* prevent other threads from writing or doing ioctls */
951 g_mutex_lock(FILE_OPS_LOCK
);
954 case PTM_GET_CAPABILITY
:
955 if (out_bufsz
!= sizeof(ptm_cap
)) {
956 struct iovec iov
= { arg
, sizeof(uint8_t) };
957 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
960 switch (tpmversion
) {
961 case TPMLIB_TPM_VERSION_2
:
962 ptm_caps
= PTM_CAP_INIT
| PTM_CAP_SHUTDOWN
963 | PTM_CAP_GET_TPMESTABLISHED
964 | PTM_CAP_SET_LOCALITY
966 | PTM_CAP_CANCEL_TPM_CMD
967 | PTM_CAP_STORE_VOLATILE
968 | PTM_CAP_RESET_TPMESTABLISHED
969 | PTM_CAP_GET_STATEBLOB
970 | PTM_CAP_SET_STATEBLOB
973 | PTM_CAP_SET_BUFFERSIZE
976 case TPMLIB_TPM_VERSION_1_2
:
977 ptm_caps
= PTM_CAP_INIT
| PTM_CAP_SHUTDOWN
978 | PTM_CAP_GET_TPMESTABLISHED
979 | PTM_CAP_SET_LOCALITY
981 | PTM_CAP_CANCEL_TPM_CMD
982 | PTM_CAP_STORE_VOLATILE
983 | PTM_CAP_RESET_TPMESTABLISHED
984 | PTM_CAP_GET_STATEBLOB
985 | PTM_CAP_SET_STATEBLOB
988 | PTM_CAP_SET_BUFFERSIZE
992 fuse_reply_ioctl(req
, 0, &ptm_caps
, sizeof(ptm_caps
));
997 if (in_bufsz
!= sizeof(ptm_init
)) {
998 struct iovec iov
= { arg
, sizeof(uint8_t) };
999 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1001 init_p
= (ptm_init
*)in_buf
;
1003 worker_thread_end();
1007 tpm_running
= false;
1008 if (tpm_start(init_p
->u
.req
.init_flags
, tpmversion
, &res
) < 0) {
1009 logprintf(STDERR_FILENO
,
1010 "Error: Could not initialize the TPM.\n");
1014 init_p
->u
.resp
.tpm_result
= res
;
1015 fuse_reply_ioctl(req
, 0, init_p
, sizeof(*init_p
));
1020 worker_thread_end();
1025 tpm_running
= false;
1028 ptm_response
= NULL
;
1030 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1035 worker_thread_end();
1041 ptm_response
= NULL
;
1043 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1048 case PTM_GET_TPMESTABLISHED
:
1050 goto error_not_running
;
1052 if (out_bufsz
!= sizeof(ptm_est
)) {
1053 struct iovec iov
= { arg
, sizeof(uint8_t) };
1054 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1057 memset(&te
, 0, sizeof(te
));
1058 te
.u
.resp
.tpm_result
= TPM_IO_TpmEstablished_Get(&te
.u
.resp
.bit
);
1059 fuse_reply_ioctl(req
, 0, &te
, sizeof(te
));
1063 case PTM_RESET_TPMESTABLISHED
:
1065 goto error_not_running
;
1067 if (in_bufsz
!= sizeof(ptm_reset_est
)) {
1068 struct iovec iov
= { arg
, sizeof(uint32_t) };
1069 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1071 ptm_reset_est
*re
= (ptm_reset_est
*)in_buf
;
1072 if (re
->u
.req
.loc
> 4) {
1073 res
= TPM_BAD_LOCALITY
;
1075 /* set locality and reset flag in one command */
1076 orig_locality
= locality
;
1077 locality
= re
->u
.req
.loc
;
1079 res
= TPM_IO_TpmEstablished_Reset();
1081 locality
= orig_locality
;
1082 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1087 case PTM_SET_LOCALITY
:
1088 if (in_bufsz
!= sizeof(ptm_loc
)) {
1089 struct iovec iov
= { arg
, sizeof(uint32_t) };
1090 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1092 ptm_loc
*l
= (ptm_loc
*)in_buf
;
1093 if (l
->u
.req
.loc
> 4 ||
1094 (l
->u
.req
.loc
== 4 &&
1095 locality_flags
& LOCALITY_FLAG_REJECT_LOCALITY_4
)) {
1096 res
= TPM_BAD_LOCALITY
;
1099 locality
= l
->u
.req
.loc
;
1101 l
->u
.resp
.tpm_result
= res
;
1102 fuse_reply_ioctl(req
, 0, l
, sizeof(*l
));
1106 case PTM_HASH_START
:
1108 goto error_not_running
;
1110 res
= TPM_IO_Hash_Start();
1111 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1116 goto error_not_running
;
1118 if (in_bufsz
!= sizeof(ptm_hdata
)) {
1119 struct iovec iov
= { arg
, sizeof(uint32_t) };
1120 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1122 ptm_hdata
*data
= (ptm_hdata
*)in_buf
;
1123 if (data
->u
.req
.length
<= sizeof(data
->u
.req
.data
)) {
1124 res
= TPM_IO_Hash_Data(data
->u
.req
.data
,
1125 data
->u
.req
.length
);
1129 data
->u
.resp
.tpm_result
= res
;
1130 fuse_reply_ioctl(req
, 0, data
, sizeof(*data
));
1136 goto error_not_running
;
1138 res
= TPM_IO_Hash_End();
1139 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1142 case PTM_CANCEL_TPM_CMD
:
1144 goto error_not_running
;
1146 /* for cancellation to work, the TPM would have to
1147 * execute in another thread that polls on a cancel
1150 res
= TPMLIB_CancelCommand();
1151 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1154 case PTM_STORE_VOLATILE
:
1156 goto error_not_running
;
1158 res
= SWTPM_NVRAM_Store_Volatile();
1159 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1161 cached_stateblob_free();
1164 case PTM_GET_STATEBLOB
:
1166 goto error_not_running
;
1168 if (in_bufsz
!= sizeof(ptm_getstate
)) {
1169 struct iovec iov
= { arg
, sizeof(uint32_t) };
1170 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1172 ptm_get_stateblob(req
, (ptm_getstate
*)in_buf
);
1176 case PTM_SET_STATEBLOB
:
1180 /* tpm state dir must be set */
1183 if (in_bufsz
!= sizeof(ptm_setstate
)) {
1184 struct iovec iov
= { arg
, sizeof(uint32_t) };
1185 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1187 ptm_set_stateblob(req
, (ptm_setstate
*)in_buf
);
1191 case PTM_GET_CONFIG
:
1192 if (out_bufsz
!= sizeof(ptm_getconfig
)) {
1193 struct iovec iov
= { arg
, sizeof(uint32_t) };
1194 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1197 pgs
.u
.resp
.tpm_result
= 0;
1198 pgs
.u
.resp
.flags
= 0;
1199 if (SWTPM_NVRAM_Has_FileKey())
1200 pgs
.u
.resp
.flags
|= PTM_CONFIG_FLAG_FILE_KEY
;
1201 if (SWTPM_NVRAM_Has_MigrationKey())
1202 pgs
.u
.resp
.flags
|= PTM_CONFIG_FLAG_MIGRATION_KEY
;
1203 fuse_reply_ioctl(req
, 0, &pgs
, sizeof(pgs
));
1207 case PTM_SET_BUFFERSIZE
:
1208 if (out_bufsz
!= sizeof(ptm_setbuffersize
)) {
1209 struct iovec iov
= { arg
, sizeof(uint32_t) };
1210 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1212 ptm_setbuffersize
*in_psbs
= (ptm_setbuffersize
*)in_buf
;
1213 ptm_setbuffersize out_psbs
;
1214 uint32_t buffersize
, minsize
, maxsize
;
1216 buffersize
= in_psbs
->u
.req
.buffersize
;
1218 if (buffersize
> 0 && tpm_running
)
1221 buffersize
= TPMLIB_SetBufferSize(buffersize
,
1225 out_psbs
.u
.resp
.tpm_result
= TPM_SUCCESS
;
1226 out_psbs
.u
.resp
.buffersize
= buffersize
;
1227 out_psbs
.u
.resp
.minsize
= minsize
;
1228 out_psbs
.u
.resp
.maxsize
= maxsize
;
1229 fuse_reply_ioctl(req
, 0, &out_psbs
, sizeof(out_psbs
));
1234 if (out_bufsz
!= sizeof(ptm_getinfo
)) {
1235 struct iovec iov
= { arg
, sizeof(uint32_t) };
1236 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
1238 ptm_getinfo
*in_pgi
= (ptm_getinfo
*)in_buf
;
1239 ptm_getinfo out_pgi
;
1241 uint32_t length
, offset
;
1243 info_data
= TPMLIB_GetInfo(in_pgi
->u
.req
.flags
);
1247 offset
= in_pgi
->u
.req
.offset
;
1248 if (offset
>= strlen(info_data
)) {
1250 goto error_bad_input
;
1253 length
= min(strlen(info_data
) + 1 - offset
,
1254 sizeof(out_pgi
.u
.resp
.buffer
));
1256 out_pgi
.u
.resp
.tpm_result
= 0;
1257 out_pgi
.u
.resp
.totlength
= strlen(info_data
) + 1;
1258 out_pgi
.u
.resp
.length
= length
;
1259 /* client has to collect whole string in case buffer is too small */
1260 memcpy(out_pgi
.u
.resp
.buffer
, &info_data
[offset
], length
);
1263 fuse_reply_ioctl(req
, 0, &out_pgi
, sizeof(out_pgi
));
1268 fuse_reply_err(req
, EINVAL
);
1272 g_mutex_unlock(FILE_OPS_LOCK
);
1275 logprintf(STDOUT_FILENO
, "CUSE TPM is shutting down.\n");
1277 fuse_session_exit(ptm_fuse_session
);
1283 res
= TPM_BAD_PARAMETER
;
1284 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1290 res
= TPM_BAD_ORDINAL
;
1291 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1297 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1302 static void ptm_init_done(void *userdata
)
1304 struct cuse_param
*param
= userdata
;
1307 /* at this point the entry in /dev/ is available */
1308 if (pidfile_write(getpid()) < 0) {
1314 ret
= change_process_owner(param
->runas
);
1319 if (create_seccomp_profile(true, param
->seccomp_action
) < 0) {
1332 static void ptm_cleanup(void)
1336 tpmstate_global_free();
1339 static const struct cuse_lowlevel_ops clops
= {
1344 .init_done
= ptm_init_done
,
1347 /* ptm_cuse_lowlevel_main is like cuse_lowlevel_main with the difference that
1348 * it uses a global ptm_fuse_session so we can call fuse_session_exit() on it
1349 * for a graceful exit with cleanups.
1352 ptm_cuse_lowlevel_main(int argc
, char *argv
[], const struct cuse_info
*ci
,
1353 const struct cuse_lowlevel_ops
*clop
, void *userdata
)
1357 struct cuse_param
*param
= userdata
;
1359 ptm_fuse_session
= cuse_lowlevel_setup(argc
, argv
, ci
, clop
, &mt
,
1361 if (ptm_fuse_session
== NULL
)
1364 if (param
->seccomp_action
== SWTPM_SECCOMP_ACTION_NONE
&& mt
)
1365 ret
= fuse_session_loop_mt(ptm_fuse_session
);
1367 ret
= fuse_session_loop(ptm_fuse_session
);
1369 cuse_lowlevel_teardown(ptm_fuse_session
);
1376 #ifndef HAVE_SWTPM_CUSE_MAIN
1377 int main(int argc
, char **argv
)
1379 const char *prgname
= argv
[0];
1380 const char *iface
= "";
1382 int swtpm_cuse_main(int argc
, char **argv
, const char *prgname
, const char *iface
)
1385 int opt
, longindex
= 0;
1386 static struct option longopts
[] = {
1387 {"maj" , required_argument
, 0, 'M'},
1388 {"min" , required_argument
, 0, 'm'},
1389 {"name" , required_argument
, 0, 'n'},
1390 {"runas" , required_argument
, 0, 'r'},
1391 {"log" , required_argument
, 0, 'l'},
1392 {"locality" , required_argument
, 0, 'L'},
1393 {"key" , required_argument
, 0, 'k'},
1394 {"migration-key" , required_argument
, 0, 'K'},
1395 {"pid" , required_argument
, 0, 'p'},
1396 {"tpmstate" , required_argument
, 0, 's'},
1397 {"tpm2" , no_argument
, 0, '2'},
1398 {"help" , no_argument
, 0, 'h'},
1399 {"version" , no_argument
, 0, 'v'},
1401 {"seccomp" , required_argument
, 0, 'S'},
1403 {"print-capabilities"
1404 , no_argument
, 0, 'a'},
1407 struct cuse_info cinfo
;
1408 struct cuse_param param
;
1409 const char *devname
= NULL
;
1410 char *cinfo_argv
[1] = { 0 };
1412 struct passwd
*passwd
;
1415 char path
[PATH_MAX
];
1418 memset(&cinfo
, 0, sizeof(cinfo
));
1419 memset(¶m
, 0, sizeof(param
));
1421 log_set_prefix("swtpm: ");
1423 tpmversion
= TPMLIB_TPM_VERSION_1_2
;
1426 opt
= getopt_long(argc
, argv
, "M:m:n:r:hv", longopts
, &longindex
);
1432 case 'M': /* major */
1433 if (sscanf(optarg
, "%u", &num
) != 1) {
1434 logprintf(STDERR_FILENO
, "Could not parse major number\n");
1439 logprintf(STDERR_FILENO
,
1440 "Major number outside valid range [0 - 65535]\n");
1444 cinfo
.dev_major
= num
;
1446 case 'm': /* minor */
1447 if (sscanf(optarg
, "%u", &num
) != 1) {
1448 logprintf(STDERR_FILENO
, "Could not parse major number\n");
1453 logprintf(STDERR_FILENO
,
1454 "Major number outside valid range [0 - 65535]\n");
1458 cinfo
.dev_minor
= num
;
1460 case 'n': /* name */
1461 if (!cinfo
.dev_info_argc
) {
1462 cinfo_argv
[0] = calloc(1, strlen("DEVNAME=") + strlen(optarg
) + 1);
1463 if (!cinfo_argv
[0]) {
1464 logprintf(STDERR_FILENO
, "Out of memory\n");
1470 strcpy(cinfo_argv
[0], "DEVNAME=");
1471 strcat(cinfo_argv
[0], optarg
);
1473 cinfo
.dev_info_argc
= 1;
1474 cinfo
.dev_info_argv
= (const char **)cinfo_argv
;
1477 case 'r': /* runas */
1478 param
.runas
= optarg
;
1481 param
.logging
= optarg
;
1484 param
.keydata
= optarg
;
1486 case 'K': /* migration-key */
1487 param
.migkeydata
= optarg
;
1490 param
.piddata
= optarg
;
1492 case 's': /* tpmstate */
1493 param
.tpmstatedata
= optarg
;
1496 param
.localitydata
= optarg
;
1499 tpmversion
= TPMLIB_TPM_VERSION_2
;
1502 param
.seccompdata
= optarg
;
1504 case 'h': /* help */
1505 fprintf(stdout
, usage
, prgname
, iface
);
1508 ret
= capabilities_print_json(true);
1510 case 'v': /* version */
1511 fprintf(stdout
, "TPM emulator CUSE interface version %d.%d.%d, "
1512 "Copyright (c) 2014-2015 IBM Corp.\n",
1520 if (optind
< argc
) {
1521 logprintf(STDERR_FILENO
,
1522 "Unknown parameter '%s'\n", argv
[optind
]);
1528 * choose the TPM version early so that getting/setting
1529 * buffer size works.
1531 if (TPMLIB_ChooseTPMVersion(tpmversion
) != TPM_SUCCESS
) {
1532 logprintf(STDERR_FILENO
,
1533 "Error: Could not choose TPM version.\n");
1538 SWTPM_NVRAM_Set_TPMVersion(tpmversion
);
1540 if (!cinfo
.dev_info_argv
) {
1541 logprintf(STDERR_FILENO
, "Error: device name missing\n");
1546 if (handle_log_options(param
.logging
) < 0 ||
1547 handle_key_options(param
.keydata
) < 0 ||
1548 handle_migration_key_options(param
.migkeydata
) < 0 ||
1549 handle_pid_options(param
.piddata
) < 0 ||
1550 handle_tpmstate_options(param
.tpmstatedata
) < 0 ||
1551 handle_seccomp_options(param
.seccompdata
, ¶m
.seccomp_action
) < 0 ||
1552 handle_locality_options(param
.localitydata
, &locality_flags
) < 0) {
1558 logprintf(STDERR_FILENO
, "Error: Unable to setuid root. uid = %d, "
1559 "euid = %d, gid = %d\n", getuid(), geteuid(), getgid());
1565 if (!(passwd
= getpwnam(param
.runas
))) {
1566 logprintf(STDERR_FILENO
, "User '%s' does not exist\n",
1573 tpmdir
= tpmstate_get_dir();
1574 if (tpmdir
== NULL
) {
1575 logprintf(STDERR_FILENO
,
1576 "Error: No TPM state directory is defined; "
1577 "TPM_PATH is not set\n");
1582 n
= snprintf(path
, sizeof(path
), "/dev/%s", devname
);
1584 logprintf(STDERR_FILENO
,
1585 "Error: Could not create device file name\n");
1589 if (n
>= (int)sizeof(path
)) {
1590 logprintf(STDERR_FILENO
,
1591 "Error: Buffer too small to create device file name\n");
1596 tpmfd
= open(path
, O_RDWR
);
1599 logprintf(STDERR_FILENO
,
1600 "Error: A device '%s' already exists.\n",
1606 if (tpmlib_register_callbacks(&cbs
) != TPM_SUCCESS
) {
1611 worker_thread_init();
1613 #if GLIB_MINOR_VERSION >= 32
1614 g_mutex_init(FILE_OPS_LOCK
);
1616 FILE_OPS_LOCK
= g_mutex_new();
1619 ret
= ptm_cuse_lowlevel_main(1, argv
, &cinfo
, &clops
, ¶m
);
1623 free(cinfo_argv
[0]);