2 * ptm - CUSE based TPM PassThrough Multiplexer for QEMU.
4 * (c) Copyright IBM Corporation 2014, 2015.
6 * This program instantiates one /dev/vtpm* device, and
7 * calls libtpms to handle requests
9 * The following code was derived from
10 * http://fuse.sourceforge.net/doxygen/cusexmp_8c.html
12 * It's original header states:
14 * CUSE example: Character device in Userspace
15 * Copyright (C) 2008-2009 SUSE Linux Products GmbH
16 * Copyright (C) 2008-2009 Tejun Heo <tj@kernel.org>
17 * This program can be distributed under the terms of the GNU GPL.
18 * See the file COPYING.
21 * Authors: David Safford safford@us.ibm.com
22 * Stefan Berger stefanb@us.ibm.com
27 * Note: It's possible for multiple process to open access to
28 * the same character device. Concurrency problems may arise
29 * if those processes all write() to the device and then try
30 * to pick up the results. Proper usage of the device is to
31 * have one process (QEMU) use ioctl, read and write and have
32 * other processes (libvirt, etc.) only use ioctl.
34 #define FUSE_USE_VERSION 29
44 #include <sys/types.h>
48 #include <arpa/inet.h>
50 #include <libtpms/tpm_library.h>
51 #include <libtpms/tpm_tis.h>
52 #include <libtpms/tpm_error.h>
53 #include <libtpms/tpm_memory.h>
54 #include <libtpms/tpm_nvfilename.h>
56 #include "cuse_lowlevel.h"
58 #include "tpm_ioctl.h"
60 #include "swtpm_nvfile.h"
68 #define TPM_REQ_MAX 4096
69 static unsigned char *ptm_req
, *ptm_res
;
70 static uint32_t ptm_req_len
, ptm_res_len
, ptm_res_tot
;
71 static TPM_MODIFIER_INDICATOR locality
;
72 static int tpm_running
;
73 static int thread_busy
;
74 static GThreadPool
*pool
;
75 static struct passwd
*passwd
;
77 #if GLIB_MAJOR_VERSION >= 2
78 # if GLIB_MINOR_VERSION >= 32
80 GCond thread_busy_signal
;
81 GMutex thread_busy_lock
;
83 # define THREAD_BUSY_SIGNAL &thread_busy_signal
84 # define THREAD_BUSY_LOCK &thread_busy_lock
85 # define FILE_OPS_LOCK &file_ops_lock
89 GCond
*thread_busy_signal
;
90 GMutex
*thread_busy_lock
;
91 GMutex
*file_ops_lock
;
92 # define THREAD_BUSY_SIGNAL thread_busy_signal
93 # define THREAD_BUSY_LOCK thread_busy_lock
94 # define FILE_OPS_LOCK file_ops_lock
99 #error Unsupport glib version
121 struct thread_message
{
126 #define min(a,b) ((a) < (b) ? (a) : (b))
134 typedef struct stateblob_desc
{
137 TPM_BOOL is_encrypted
;
139 uint32_t data_length
;
143 static const char *usage
=
144 "usage: %s [options]\n"
146 "The following options are supported:\n"
148 "-n NAME|--name=NAME : device name (mandatory)\n"
149 "-M MAJ|--maj=MAJ : device major number\n"
150 "-m MIN|--min=MIN : device minor number\n"
151 "--key file=<path>[,mode=aes-cbc][,format=hex|binary][,remove=[true|false]]\n"
152 " : use an AES key for the encryption of the TPM's state\n"
153 " files; use the given mode for the block encryption;\n"
154 " the key is to be provided as a hex string or in binary\n"
155 " format; the keyfile can be automatically removed using\n"
156 " the remove parameter\n"
157 "--key pwdfile=<path>[,mode=aes-cbc][,remove=[true|false]]\n"
158 " : provide a passphrase in a file; the AES key will be\n"
159 " derived from this passphrase\n"
160 "--migration-key file=<path>,[,mode=aes-cbc][,format=hex|binary][,remove=[true|false]]\n"
161 " : use an AES key for the encryption of the TPM's state\n"
162 " when it is retrieved from the TPM via ioctls;\n"
163 " Setting this key ensures that the TPM's state will always\n"
164 " be encrypted when migrated\n"
165 "--migration-key pwdfile=<path>[,mode=aes-cbc][,remove=[true|false]]\n"
166 " : provide a passphrase in a file; the AES key will be\n"
167 " derived from this passphrase\n"
168 "--log file=<path>|fd=<filedescriptor>\n"
169 " : write the TPM's log into the given file rather than\n"
170 " to the console; provide '-' for path to avoid logging\n"
171 "-h|--help : display this help screen and terminate\n"
173 "Make sure that TPM_PATH environment variable points to directory\n"
174 "where TPM's NV storage file is kept\n"
177 const static unsigned char TPM_Resp_FatalError
[] = {
178 0x00, 0xC4, /* TPM Response */
179 0x00, 0x00, 0x00, 0x0A, /* length (10) */
180 0x00, 0x00, 0x00, 0x09 /* TPM_FAIL */
183 const static unsigned char TPM_ResetEstablishmentBit
[] = {
184 0x00, 0xC1, /* TPM Request */
185 0x00, 0x00, 0x00, 0x0A, /* length (10) */
186 0x40, 0x00, 0x00, 0x0B /* TPM_ORD_ResetEstablishmentBit */
189 typedef struct TPM_Response_Header
{
193 } __attribute__ ((packed
)) TPM_Response_Header
;
196 ptm_io_getlocality(TPM_MODIFIER_INDICATOR
*loc
, uint32_t tpmnum
)
202 static struct libtpms_callbacks cbs
= {
203 .sizeOfStruct
= sizeof(struct libtpms_callbacks
),
204 .tpm_nvram_init
= SWTPM_NVRAM_Init
,
205 .tpm_nvram_loaddata
= SWTPM_NVRAM_LoadData
,
206 .tpm_nvram_storedata
= SWTPM_NVRAM_StoreData
,
207 .tpm_nvram_deletename
= SWTPM_NVRAM_DeleteName
,
208 .tpm_io_getlocality
= ptm_io_getlocality
,
211 static struct thread_message msg
;
213 /* worker_thread_wait_done
215 * Wait while the TPM worker thread is busy
217 static void worker_thread_wait_done(void)
219 g_mutex_lock(THREAD_BUSY_LOCK
);
220 while (thread_busy
) {
221 #if GLIB_MINOR_VERSION >= 32
222 gint64 end_time
= g_get_monotonic_time() +
223 1 * G_TIME_SPAN_SECOND
;
224 g_cond_wait_until(THREAD_BUSY_SIGNAL
,
230 * seems like occasionally the g_cond_signal did not wake up
231 * the sleeping task; so we poll [TIS Test in BIOS]
234 abs_time
.tv_usec
= 0;
235 g_cond_timed_wait(THREAD_BUSY_SIGNAL
,
240 g_mutex_unlock(THREAD_BUSY_LOCK
);
243 /* worker_thread_mark_busy
245 * Mark the worker thread as busy; call this with the lock held
247 static void worker_thread_mark_busy(void)
249 g_mutex_lock(THREAD_BUSY_LOCK
);
251 g_mutex_unlock(THREAD_BUSY_LOCK
);
254 /* work_tread_mark_done
256 * Mark the worker thread as done and wake
257 * up the waiting thread
259 static void worker_thread_mark_done(void)
261 g_mutex_lock(THREAD_BUSY_LOCK
);
263 g_cond_signal(THREAD_BUSY_SIGNAL
);
264 g_mutex_unlock(THREAD_BUSY_LOCK
);
267 /* worker_thread_is_busy
269 * Determine whether the worker thread is busy
271 static int worker_thread_is_busy()
276 static void worker_thread(gpointer data
, gpointer user_data
)
278 struct thread_message
*msg
= (struct thread_message
*)data
;
281 case MESSAGE_TPM_CMD
:
282 TPMLIB_Process(&ptm_res
, &ptm_res_len
, &ptm_res_tot
,
283 ptm_req
, ptm_req_len
);
289 /* results are ready */
290 worker_thread_mark_done();
295 * finish the worker thread
297 static void worker_thread_end()
300 worker_thread_wait_done();
301 g_thread_pool_free(pool
, TRUE
, TRUE
);
306 /* _TPM_IO_TpmEstablished_Reset
308 * Reset the TPM Established bit
311 _TPM_IO_TpmEstablished_Reset(fuse_req_t req
,
312 TPM_MODIFIER_INDICATOR locty
)
314 TPM_RESULT res
= TPM_FAIL
;
315 TPM_Response_Header
*tpmrh
;
316 TPM_MODIFIER_INDICATOR orig_locality
= locality
;
320 ptm_req_len
= sizeof(TPM_ResetEstablishmentBit
);
321 memcpy(ptm_req
, TPM_ResetEstablishmentBit
, ptm_req_len
);
322 msg
.type
= MESSAGE_TPM_CMD
;
325 worker_thread_mark_busy();
327 g_thread_pool_push(pool
, &msg
, NULL
);
329 worker_thread_wait_done();
331 if (ptm_res_len
>= sizeof(TPM_Response_Header
)) {
332 tpmrh
= (TPM_Response_Header
*)ptm_res
;
333 res
= ntohl(tpmrh
->returnCode
);
336 locality
= orig_locality
;
341 static int tpm_start(uint32_t flags
)
344 char * tpmdir
= NULL
;
346 /* temporary - the backend script lacks the perms to do this */
347 if (tpmdir
== NULL
) {
348 tpmdir
= getenv("TPM_PATH");
350 logprintf(STDOUT_FILENO
,
351 "Error: TPM_PATH is not set\n");
355 dir
= opendir(tpmdir
);
359 if (mkdir(tpmdir
, 0775)) {
360 logprintf(STDERR_FILENO
,
361 "Error: Could not open TPM_PATH dir\n");
366 pool
= g_thread_pool_new(worker_thread
,
372 logprintf(STDERR_FILENO
,
373 "Error: Could not create the thread pool.\n");
377 if (TPMLIB_RegisterCallbacks(&cbs
) != TPM_SUCCESS
) {
378 logprintf(STDERR_FILENO
,
379 "Error: Could not register the callbacks.\n");
383 if (TPMLIB_MainInit() != TPM_SUCCESS
) {
384 logprintf(STDERR_FILENO
,
385 "Error: Could not start the CUSE TPM.\n");
389 if (flags
& INIT_FLAG_DELETE_VOLATILE
) {
390 uint32_t tpm_number
= 0;
391 char *name
= TPM_VOLATILESTATE_NAME
;
392 if (SWTPM_NVRAM_DeleteName(tpm_number
,
394 FALSE
) != TPM_SUCCESS
) {
395 logprintf(STDERR_FILENO
,
396 "Error: Could not delete the volatile "
397 "state of the TPM.\n");
398 goto error_terminate
;
403 ptm_req
= malloc(4096);
405 logprintf(STDERR_FILENO
,
406 "Error: Could not allocate memory for request buffer.\n");
407 goto error_terminate
;
410 logprintf(STDOUT_FILENO
,
411 "CUSE TPM successfully initialized.\n");
416 g_thread_pool_free(pool
, TRUE
, TRUE
);
425 * convert the blobtype integer into a string that libtpms
428 static const char *ptm_get_blobname(uint8_t blobtype
)
431 case PTM_BLOB_TYPE_PERMANENT
:
432 return TPM_PERMANENT_ALL_NAME
;
433 case PTM_BLOB_TYPE_VOLATILE
:
434 return TPM_VOLATILESTATE_NAME
;
435 case PTM_BLOB_TYPE_SAVESTATE
:
436 return TPM_SAVESTATE_NAME
;
442 static void ptm_open(fuse_req_t req
, struct fuse_file_info
*fi
)
444 fuse_reply_open(req
, fi
);
447 /* ptm_write_fatal_error_response
449 * Write a fatal error response
451 static void ptm_write_fatal_error_response(void)
453 if (ptm_res
== NULL
||
454 ptm_res_tot
< sizeof(TPM_Resp_FatalError
)) {
455 ptm_res_tot
= sizeof(TPM_Resp_FatalError
);
456 TPM_Realloc(&ptm_res
, ptm_res_tot
);
459 ptm_res_len
= sizeof(TPM_Resp_FatalError
);
462 sizeof(TPM_Resp_FatalError
));
466 static void ptm_read(fuse_req_t req
, size_t size
, off_t off
,
467 struct fuse_file_info
*fi
)
472 /* wait until results are ready */
473 worker_thread_wait_done();
478 if (ptm_res_len
> size
) {
485 fuse_reply_buf(req
, (const char *)ptm_res
, len
);
488 static void ptm_write(fuse_req_t req
, const char *buf
, size_t size
,
489 off_t off
, struct fuse_file_info
*fi
)
494 /* prevent other threads from writing or doing ioctls */
495 g_mutex_lock(FILE_OPS_LOCK
);
498 /* ensure that we only ever work on one TPM command */
499 if (worker_thread_is_busy()) {
500 fuse_reply_err(req
, EBUSY
);
504 /* have command processed by thread pool */
505 if (ptm_req_len
> TPM_REQ_MAX
)
506 ptm_req_len
= TPM_REQ_MAX
;
508 memcpy(ptm_req
, buf
, ptm_req_len
);
509 msg
.type
= MESSAGE_TPM_CMD
;
512 worker_thread_mark_busy();
514 g_thread_pool_push(pool
, &msg
, NULL
);
516 fuse_reply_write(req
, ptm_req_len
);
518 /* TPM not initialized; return error */
519 ptm_write_fatal_error_response();
520 fuse_reply_write(req
, ptm_req_len
);
524 g_mutex_unlock(FILE_OPS_LOCK
);
529 static stateblob_desc cached_stateblob
;
532 cached_stateblob_is_loaded(uint32_t blobtype
, TPM_BOOL decrypt
)
534 return (cached_stateblob
.data
!= NULL
) &&
535 (cached_stateblob
.blobtype
== blobtype
) &&
536 (cached_stateblob
.decrypt
== decrypt
);
540 * cached_stateblob_free: Free any previously loaded state blob
543 cached_stateblob_free(void)
545 TPM_Free(cached_stateblob
.data
);
546 cached_stateblob
.data
= NULL
;
547 cached_stateblob
.data_length
= 0;
551 * cached_stateblob_load: load a state blob into the cache
553 * blobtype: the type of blob
554 * decrypt: whether the blob is to be decrypted
557 cached_stateblob_load(uint32_t blobtype
, TPM_BOOL decrypt
)
560 const char *blobname
= ptm_get_blobname(blobtype
);
561 uint32_t tpm_number
= 0;
564 return TPM_BAD_PARAMETER
;
566 cached_stateblob_free();
568 if (blobtype
== PTM_BLOB_TYPE_VOLATILE
)
569 res
= SWTPM_NVRAM_Store_Volatile();
572 res
= SWTPM_NVRAM_GetStateBlob(&cached_stateblob
.data
,
573 &cached_stateblob
.data_length
,
574 tpm_number
, blobname
, decrypt
,
575 &cached_stateblob
.is_encrypted
);
577 /* make sure the volatile state file is gone */
578 if (blobtype
== PTM_BLOB_TYPE_VOLATILE
)
579 SWTPM_NVRAM_DeleteName(tpm_number
, blobname
, FALSE
);
582 cached_stateblob
.blobtype
= blobtype
;
583 cached_stateblob
.decrypt
= decrypt
;
590 * cached_state_blob_copy: copy the cached state blob to a destination buffer
592 * dest: destination buffer
593 * destlen: size of the buffer
594 * srcoffset: offset to copy from
595 * copied: variable to return the number of copied bytes
596 * is_encrypted: variable to return whether the blob is encrypted
599 cached_stateblob_copy(void *dest
, size_t destlen
, uint32_t srcoffset
,
600 uint32_t *copied
, TPM_BOOL
*is_encrypted
)
606 if (cached_stateblob
.data
!= NULL
&& cached_stateblob
.data_length
> 0) {
608 if (srcoffset
< cached_stateblob
.data_length
) {
609 *copied
= min(cached_stateblob
.data_length
- srcoffset
, destlen
);
611 memcpy(dest
, &cached_stateblob
.data
[srcoffset
], *copied
);
613 *is_encrypted
= cached_stateblob
.is_encrypted
;
623 * ptm_get_stateblob: Get the state blob from the TPM
626 ptm_get_stateblob(fuse_req_t req
, ptm_getstate_t
*pgs
)
629 uint32_t blobtype
= pgs
->u
.req
.type
;
630 TPM_BOOL decrypt
= ((pgs
->u
.req
.state_flags
& STATE_FLAG_DECRYPTED
) != 0);
631 TPM_BOOL is_encrypted
= FALSE
;
634 if (!cached_stateblob_is_loaded(blobtype
, decrypt
)) {
635 res
= cached_stateblob_load(blobtype
, decrypt
);
639 cached_stateblob_copy(&pgs
->u
.resp
.data
, sizeof(pgs
->u
.resp
.data
),
640 pgs
->u
.req
.offset
, &copied
, &is_encrypted
);
642 pgs
->u
.resp
.state_flags
= 0;
644 pgs
->u
.resp
.state_flags
|= STATE_FLAG_ENCRYPTED
;
648 pgs
->u
.resp
.length
= copied
;
649 pgs
->u
.resp
.tpm_result
= res
;
651 fuse_reply_ioctl(req
, 0, pgs
, sizeof(pgs
->u
.resp
));
655 * ptm_ioctl : ioctl execution
657 * req: the fuse_req_t used to send response with
658 * cmd: the ioctl request code
659 * arg: the pointer the application used for calling the ioctl (3rd param)
661 * flags: some flags provided by fuse
662 * in_buf: the copy of the input buffer
663 * in_bufsz: size of the input buffer; provided by fuse and has size of
665 * out_bufsz: size of the output buffer; provided by fuse and has size of
668 static void ptm_ioctl(fuse_req_t req
, int cmd
, void *arg
,
669 struct fuse_file_info
*fi
, unsigned flags
,
670 const void *in_buf
, size_t in_bufsz
, size_t out_bufsz
)
673 bool exit_prg
= FALSE
;
675 static struct stateblob stateblob
;
677 if (flags
& FUSE_IOCTL_COMPAT
) {
678 fuse_reply_err(req
, ENOSYS
);
682 /* some commands have to wait until the worker thread is done */
684 case PTM_GET_CAPABILITY
:
685 case PTM_SET_LOCALITY
:
686 case PTM_CANCEL_TPM_CMD
:
688 /* no need to wait */
692 case PTM_GET_TPMESTABLISHED
:
693 case PTM_RESET_TPMESTABLISHED
:
697 case PTM_STORE_VOLATILE
:
698 case PTM_GET_STATEBLOB
:
699 case PTM_SET_STATEBLOB
:
701 worker_thread_wait_done();
705 /* prevent other threads from writing or doing ioctls */
706 g_mutex_lock(FILE_OPS_LOCK
);
709 case PTM_GET_CAPABILITY
:
711 struct iovec iov
= { arg
, sizeof(uint8_t) };
712 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
715 ptm_caps
= PTM_CAP_INIT
| PTM_CAP_SHUTDOWN
716 | PTM_CAP_GET_TPMESTABLISHED
717 | PTM_CAP_SET_LOCALITY
719 | PTM_CAP_CANCEL_TPM_CMD
720 | PTM_CAP_STORE_VOLATILE
721 | PTM_CAP_RESET_TPMESTABLISHED
722 | PTM_CAP_GET_STATEBLOB
723 | PTM_CAP_SET_STATEBLOB
725 | PTM_CAP_GET_CONFIG
;
726 fuse_reply_ioctl(req
, 0, &ptm_caps
, sizeof(ptm_caps
));
731 init_p
= (ptminit_t
*)in_buf
;
738 if ((res
= tpm_start(init_p
->u
.req
.init_flags
))) {
739 logprintf(STDERR_FILENO
,
740 "Error: Could not initialize the TPM.\n");
744 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
758 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
771 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
776 case PTM_GET_TPMESTABLISHED
:
778 goto error_not_running
;
781 struct iovec iov
= { arg
, sizeof(uint8_t) };
782 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
785 te
.tpm_result
= TPM_IO_TpmEstablished_Get(&te
.bit
);
786 fuse_reply_ioctl(req
, 0, &te
, sizeof(te
));
790 case PTM_RESET_TPMESTABLISHED
:
792 goto error_not_running
;
795 struct iovec iov
= { arg
, sizeof(uint32_t) };
796 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
798 ptmreset_est_t
*re
= (ptmreset_est_t
*)in_buf
;
799 if (re
->u
.req
.loc
> 4) {
800 res
= TPM_BAD_LOCALITY
;
802 res
= _TPM_IO_TpmEstablished_Reset(req
, re
->u
.req
.loc
);
803 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
808 case PTM_SET_LOCALITY
:
810 struct iovec iov
= { arg
, sizeof(uint32_t) };
811 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
813 ptmloc_t
*l
= (ptmloc_t
*)in_buf
;
814 if (l
->u
.req
.loc
> 4) {
815 res
= TPM_BAD_LOCALITY
;
818 locality
= l
->u
.req
.loc
;
820 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
826 goto error_not_running
;
828 res
= TPM_IO_Hash_Start();
829 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
834 goto error_not_running
;
837 struct iovec iov
= { arg
, sizeof(uint32_t) };
838 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
840 ptmhdata_t
*data
= (ptmhdata_t
*)in_buf
;
841 if (data
->u
.req
.length
<= sizeof(data
->u
.req
.data
)) {
842 res
= TPM_IO_Hash_Data(data
->u
.req
.data
,
847 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
853 goto error_not_running
;
855 res
= TPM_IO_Hash_End();
856 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
859 case PTM_CANCEL_TPM_CMD
:
861 goto error_not_running
;
863 /* for cancellation to work, the TPM would have to
864 * execute in another thread that polls on a cancel
868 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
871 case PTM_STORE_VOLATILE
:
873 goto error_not_running
;
875 res
= SWTPM_NVRAM_Store_Volatile();
876 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
878 cached_stateblob_free();
881 case PTM_GET_STATEBLOB
:
883 goto error_not_running
;
885 if (in_bufsz
!= sizeof(ptm_getstate_t
)) {
886 struct iovec iov
= { arg
, sizeof(uint32_t) };
887 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
889 ptm_get_stateblob(req
, (ptm_getstate_t
*)in_buf
);
893 case PTM_SET_STATEBLOB
:
897 /* tpm state dir must be set */
901 struct iovec iov
= { arg
, sizeof(uint32_t) };
902 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
904 ptm_setstate_t
*pss
= (ptm_setstate_t
*)in_buf
;
905 const char *blobname
;
906 TPM_BOOL is_encrypted
=
907 ((pss
->u
.req
.state_flags
& STATE_FLAG_ENCRYPTED
) != 0);
909 if (pss
->u
.req
.length
> sizeof(pss
->u
.req
.data
)) {
910 pss
->u
.resp
.tpm_result
= TPM_BAD_PARAMETER
;
911 fuse_reply_ioctl(req
, 0, pss
, sizeof(*pss
));
915 if (stateblob
.type
!= pss
->u
.req
.type
) {
917 TPM_Free(stateblob
.data
);
918 stateblob
.data
= NULL
;
919 stateblob
.length
= 0;
920 stateblob
.type
= pss
->u
.req
.type
;
924 res
= TPM_Realloc(&stateblob
.data
,
925 stateblob
.length
+ pss
->u
.req
.length
);
928 TPM_Free(stateblob
.data
);
929 stateblob
.data
= NULL
;
930 stateblob
.length
= 0;
933 pss
->u
.resp
.tpm_result
= res
;
934 fuse_reply_ioctl(req
, 0, pss
, sizeof(*pss
));
938 memcpy(&stateblob
.data
[stateblob
.length
],
939 pss
->u
.req
.data
, pss
->u
.req
.length
);
940 stateblob
.length
+= pss
->u
.req
.length
;
942 if (pss
->u
.req
.length
== sizeof(pss
->u
.req
.data
)) {
944 pss
->u
.resp
.tpm_result
= 0;
945 fuse_reply_ioctl(req
, 0, pss
, sizeof(*pss
));
948 blobname
= ptm_get_blobname(pss
->u
.req
.type
);
951 res
= SWTPM_NVRAM_SetStateBlob(stateblob
.data
,
954 pss
->u
.req
.tpm_number
,
957 res
= TPM_BAD_PARAMETER
;
959 TPM_Free(stateblob
.data
);
960 stateblob
.data
= NULL
;
961 stateblob
.length
= 0;
964 pss
->u
.resp
.tpm_result
= res
;
965 fuse_reply_ioctl(req
, 0, pss
, sizeof(*pss
));
970 if (out_bufsz
!= sizeof(ptm_getconfig_t
)) {
971 struct iovec iov
= { arg
, sizeof(uint32_t) };
972 fuse_reply_ioctl_retry(req
, &iov
, 1, NULL
, 0);
975 pgs
.u
.resp
.tpm_result
= 0;
976 pgs
.u
.resp
.flags
= 0;
977 if (SWTPM_NVRAM_Has_FileKey())
978 pgs
.u
.resp
.flags
|= CONFIG_FLAG_FILE_KEY
;
979 if (SWTPM_NVRAM_Has_MigrationKey())
980 pgs
.u
.resp
.flags
|= CONFIG_FLAG_MIGRATION_KEY
;
981 fuse_reply_ioctl(req
, 0, &pgs
, sizeof(pgs
));
986 fuse_reply_err(req
, EINVAL
);
990 g_mutex_unlock(FILE_OPS_LOCK
);
993 logprintf(STDOUT_FILENO
,
994 "CUSE TPM is shutting down.\n");
1002 res
= TPM_BAD_ORDINAL
;
1003 fuse_reply_ioctl(req
, 0, &res
, sizeof(res
));
1008 static void ptm_init_done(void *userdata
) {
1010 if (initgroups(passwd
->pw_name
, passwd
->pw_gid
) < 0) {
1011 logprintf(STDERR_FILENO
,
1012 "Error: initgroups(%s, %d) failed.\n",
1013 passwd
->pw_name
, passwd
->pw_gid
);
1016 if (setgid(passwd
->pw_gid
) < 0) {
1017 logprintf(STDERR_FILENO
,
1018 "Error: setgid(%d) failed.\n",
1022 if (setuid(passwd
->pw_uid
) < 0) {
1023 logprintf(STDERR_FILENO
,
1024 "Error: setuid(%d) failed.\n",
1031 static const struct cuse_lowlevel_ops ptm_clop
= {
1036 .init_done
= ptm_init_done
,
1039 #define PTM_OPT(t, p) { t, offsetof(struct ptm_param, p), 1 }
1041 static const struct fuse_opt ptm_opts
[] = {
1042 PTM_OPT("-M %u", major
),
1043 PTM_OPT("--maj=%u", major
),
1044 PTM_OPT("-m %u", minor
),
1045 PTM_OPT("--min=%u", minor
),
1046 PTM_OPT("-n %s", dev_name
),
1047 PTM_OPT("--name=%s", dev_name
),
1048 PTM_OPT("-r %s", runas
),
1049 PTM_OPT("--runas=%s", runas
),
1050 PTM_OPT("--log %s", logging
),
1051 PTM_OPT("--key %s", keydata
),
1052 PTM_OPT("--migration-key %s", migkeydata
),
1053 FUSE_OPT_KEY("-h", 0),
1054 FUSE_OPT_KEY("--help", 0),
1055 FUSE_OPT_KEY("-v", 1),
1056 FUSE_OPT_KEY("--version", 1),
1060 static int ptm_process_arg(void *data
, const char *arg
, int key
,
1061 struct fuse_args
*outargs
)
1063 struct ptm_param
*param
= data
;
1068 fprintf(stdout
, usage
, param
->prgname
);
1069 return fuse_opt_add_arg(outargs
, "-ho");
1072 fprintf(stdout
, "TPM emulator CUSE interface version %d.%d.%d, "
1073 "Copyright (c) 2014 IBM Corp.\n",
1084 int main(int argc
, char **argv
)
1086 struct fuse_args args
= FUSE_ARGS_INIT(argc
, argv
);
1087 struct ptm_param param
= {
1098 char dev_name
[128] = "DEVNAME=";
1099 const char *dev_info_argv
[] = { dev_name
};
1100 struct cuse_info ci
;
1103 if ((ret
= fuse_opt_parse(&args
, ¶m
, ptm_opts
, ptm_process_arg
))) {
1104 fprintf(stderr
, "Error: Could not parse option\n");
1108 if (!param
.is_help
) {
1109 if (!param
.dev_name
) {
1110 fprintf(stderr
, "Error: device name missing\n");
1113 strncat(dev_name
, param
.dev_name
, sizeof(dev_name
) - 9);
1118 if (handle_log_options(param
.logging
) < 0 ||
1119 handle_key_options(param
.keydata
) < 0 ||
1120 handle_migration_key_options(param
.migkeydata
) < 0)
1124 fprintf(stderr
, "Error: Unable to setuid root. uid = %d, "
1125 "euid = %d, gid = %d\n", getuid(), geteuid(), getgid());
1130 if (!(passwd
= getpwnam(param
.runas
))) {
1131 fprintf(stderr
, "User '%s' does not exist\n",
1137 memset(&ci
, 0, sizeof(ci
));
1138 ci
.dev_major
= param
.major
;
1139 ci
.dev_minor
= param
.minor
;
1140 ci
.dev_info_argc
= 1;
1141 ci
.dev_info_argv
= dev_info_argv
;
1143 #if GLIB_MINOR_VERSION >= 32
1144 g_mutex_init(THREAD_BUSY_LOCK
);
1145 g_cond_init(THREAD_BUSY_SIGNAL
);
1146 g_mutex_init(FILE_OPS_LOCK
);
1148 g_thread_init(NULL
);
1149 THREAD_BUSY_LOCK
= g_mutex_new();
1150 THREAD_BUSY_SIGNAL
= g_cond_new();
1151 FILE_OPS_LOCK
= g_mutex_new();
1154 return cuse_lowlevel_main(args
.argc
, args
.argv
, &ci
, &ptm_clop
,