]> git.proxmox.com Git - swtpm.git/blob - src/swtpm/cuse_tpm.c
swtpm: move code to get the TPM state blobs into own function
[swtpm.git] / src / swtpm / cuse_tpm.c
1 /*
2 * ptm - CUSE based TPM PassThrough Multiplexer for QEMU.
3 *
4 * (c) Copyright IBM Corporation 2014, 2015.
5 *
6 * This program instantiates one /dev/vtpm* device, and
7 * calls libtpms to handle requests
8 *
9 * The following code was derived from
10 * http://fuse.sourceforge.net/doxygen/cusexmp_8c.html
11 *
12 * It's original header states:
13 *
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.
19 *
20 *
21 * Authors: David Safford safford@us.ibm.com
22 * Stefan Berger stefanb@us.ibm.com
23 *
24 */
25
26 /*
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.
33 */
34 #define FUSE_USE_VERSION 29
35
36 #include <stddef.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <dirent.h>
42 #include <errno.h>
43 #include <stdbool.h>
44 #include <sys/types.h>
45 #include <ctype.h>
46 #include <pwd.h>
47 #include <grp.h>
48 #include <arpa/inet.h>
49
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>
55
56 #include "cuse_lowlevel.h"
57 #include "fuse_opt.h"
58 #include "tpm_ioctl.h"
59 #include "swtpm.h"
60 #include "swtpm_nvfile.h"
61 #include "key.h"
62 #include "logging.h"
63 #include "main.h"
64 #include "common.h"
65
66 #include <glib.h>
67
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;
76
77 #if GLIB_MAJOR_VERSION >= 2
78 # if GLIB_MINOR_VERSION >= 32
79
80 GCond thread_busy_signal;
81 GMutex thread_busy_lock;
82 GMutex file_ops_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
86
87 # else
88
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
95
96 # endif
97 #else
98
99 #error Unsupport glib version
100
101 #endif
102
103 struct ptm_param {
104 unsigned major;
105 unsigned minor;
106 char *dev_name;
107 int is_help;
108 const char *prgname;
109 char *runas;
110 char *logging;
111 char *keydata;
112 char *migkeydata;
113 };
114
115
116 enum msg_type {
117 MESSAGE_TPM_CMD = 1,
118 MESSAGE_IOCTL,
119 };
120
121 struct thread_message {
122 enum msg_type type;
123 fuse_req_t req;
124 };
125
126 #define min(a,b) ((a) < (b) ? (a) : (b))
127
128 struct stateblob {
129 uint8_t type;
130 uint8_t *data;
131 uint32_t length;
132 };
133
134 typedef struct stateblob_desc {
135 uint32_t blobtype;
136 TPM_BOOL decrypt;
137 TPM_BOOL is_encrypted;
138 unsigned char *data;
139 uint32_t data_length;
140 } stateblob_desc;
141
142
143 static const char *usage =
144 "usage: %s [options]\n"
145 "\n"
146 "The following options are supported:\n"
147 "\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"
172 "\n"
173 "Make sure that TPM_PATH environment variable points to directory\n"
174 "where TPM's NV storage file is kept\n"
175 "\n";
176
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 */
181 };
182
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 */
187 };
188
189 typedef struct TPM_Response_Header {
190 uint16_t tag;
191 uint32_t paramSize;
192 uint32_t returnCode;
193 } __attribute__ ((packed)) TPM_Response_Header;
194
195 static TPM_RESULT
196 ptm_io_getlocality(TPM_MODIFIER_INDICATOR *loc, uint32_t tpmnum)
197 {
198 *loc = locality;
199 return TPM_SUCCESS;
200 }
201
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,
209 };
210
211 static struct thread_message msg;
212
213 /* worker_thread_wait_done
214 *
215 * Wait while the TPM worker thread is busy
216 */
217 static void worker_thread_wait_done(void)
218 {
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,
225 THREAD_BUSY_LOCK,
226 end_time);
227 #else
228 GTimeVal abs_time;
229 /*
230 * seems like occasionally the g_cond_signal did not wake up
231 * the sleeping task; so we poll [TIS Test in BIOS]
232 */
233 abs_time.tv_sec = 1;
234 abs_time.tv_usec = 0;
235 g_cond_timed_wait(THREAD_BUSY_SIGNAL,
236 THREAD_BUSY_LOCK,
237 &abs_time);
238 #endif
239 }
240 g_mutex_unlock(THREAD_BUSY_LOCK);
241 }
242
243 /* worker_thread_mark_busy
244 *
245 * Mark the worker thread as busy; call this with the lock held
246 */
247 static void worker_thread_mark_busy(void)
248 {
249 g_mutex_lock(THREAD_BUSY_LOCK);
250 thread_busy = 1;
251 g_mutex_unlock(THREAD_BUSY_LOCK);
252 }
253
254 /* work_tread_mark_done
255 *
256 * Mark the worker thread as done and wake
257 * up the waiting thread
258 */
259 static void worker_thread_mark_done(void)
260 {
261 g_mutex_lock(THREAD_BUSY_LOCK);
262 thread_busy = 0;
263 g_cond_signal(THREAD_BUSY_SIGNAL);
264 g_mutex_unlock(THREAD_BUSY_LOCK);
265 }
266
267 /* worker_thread_is_busy
268 *
269 * Determine whether the worker thread is busy
270 */
271 static int worker_thread_is_busy()
272 {
273 return thread_busy;
274 }
275
276 static void worker_thread(gpointer data, gpointer user_data)
277 {
278 struct thread_message *msg = (struct thread_message *)data;
279
280 switch (msg->type) {
281 case MESSAGE_TPM_CMD:
282 TPMLIB_Process(&ptm_res, &ptm_res_len, &ptm_res_tot,
283 ptm_req, ptm_req_len);
284 break;
285 case MESSAGE_IOCTL:
286 break;
287 }
288
289 /* results are ready */
290 worker_thread_mark_done();
291 }
292
293 /* worker_thread_end
294 *
295 * finish the worker thread
296 */
297 static void worker_thread_end()
298 {
299 if (pool) {
300 worker_thread_wait_done();
301 g_thread_pool_free(pool, TRUE, TRUE);
302 pool = NULL;
303 }
304 }
305
306 /* _TPM_IO_TpmEstablished_Reset
307 *
308 * Reset the TPM Established bit
309 */
310 static TPM_RESULT
311 _TPM_IO_TpmEstablished_Reset(fuse_req_t req,
312 TPM_MODIFIER_INDICATOR locty)
313 {
314 TPM_RESULT res = TPM_FAIL;
315 TPM_Response_Header *tpmrh;
316 TPM_MODIFIER_INDICATOR orig_locality = locality;
317
318 locality = locty;
319
320 ptm_req_len = sizeof(TPM_ResetEstablishmentBit);
321 memcpy(ptm_req, TPM_ResetEstablishmentBit, ptm_req_len);
322 msg.type = MESSAGE_TPM_CMD;
323 msg.req = req;
324
325 worker_thread_mark_busy();
326
327 g_thread_pool_push(pool, &msg, NULL);
328
329 worker_thread_wait_done();
330
331 if (ptm_res_len >= sizeof(TPM_Response_Header)) {
332 tpmrh = (TPM_Response_Header *)ptm_res;
333 res = ntohl(tpmrh->returnCode);
334 }
335
336 locality = orig_locality;
337
338 return res;
339 }
340
341 static int tpm_start(uint32_t flags)
342 {
343 DIR *dir;
344 char * tpmdir = NULL;
345
346 /* temporary - the backend script lacks the perms to do this */
347 if (tpmdir == NULL) {
348 tpmdir = getenv("TPM_PATH");
349 if (!tpmdir) {
350 logprintf(STDOUT_FILENO,
351 "Error: TPM_PATH is not set\n");
352 return -1;
353 }
354 }
355 dir = opendir(tpmdir);
356 if (dir) {
357 closedir(dir);
358 } else {
359 if (mkdir(tpmdir, 0775)) {
360 logprintf(STDERR_FILENO,
361 "Error: Could not open TPM_PATH dir\n");
362 return -1;
363 }
364 }
365
366 pool = g_thread_pool_new(worker_thread,
367 NULL,
368 1,
369 TRUE,
370 NULL);
371 if (!pool) {
372 logprintf(STDERR_FILENO,
373 "Error: Could not create the thread pool.\n");
374 return -1;
375 }
376
377 if (TPMLIB_RegisterCallbacks(&cbs) != TPM_SUCCESS) {
378 logprintf(STDERR_FILENO,
379 "Error: Could not register the callbacks.\n");
380 goto error_del_pool;
381 }
382
383 if (TPMLIB_MainInit() != TPM_SUCCESS) {
384 logprintf(STDERR_FILENO,
385 "Error: Could not start the CUSE TPM.\n");
386 goto error_del_pool;
387 }
388
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,
393 name,
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;
399 }
400 }
401
402 if(!ptm_req)
403 ptm_req = malloc(4096);
404 if(!ptm_req) {
405 logprintf(STDERR_FILENO,
406 "Error: Could not allocate memory for request buffer.\n");
407 goto error_terminate;
408 }
409
410 logprintf(STDOUT_FILENO,
411 "CUSE TPM successfully initialized.\n");
412
413 return 0;
414
415 error_del_pool:
416 g_thread_pool_free(pool, TRUE, TRUE);
417 pool = NULL;
418
419 error_terminate:
420 TPMLIB_Terminate();
421 return -1;
422 }
423
424 /*
425 * convert the blobtype integer into a string that libtpms
426 * understands
427 */
428 static const char *ptm_get_blobname(uint8_t blobtype)
429 {
430 switch (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;
437 default:
438 return NULL;
439 }
440 }
441
442 static void ptm_open(fuse_req_t req, struct fuse_file_info *fi)
443 {
444 fuse_reply_open(req, fi);
445 }
446
447 /* ptm_write_fatal_error_response
448 *
449 * Write a fatal error response
450 */
451 static void ptm_write_fatal_error_response(void)
452 {
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);
457 }
458 if (ptm_res) {
459 ptm_res_len = sizeof(TPM_Resp_FatalError);
460 memcpy(ptm_res,
461 TPM_Resp_FatalError,
462 sizeof(TPM_Resp_FatalError));
463 }
464 }
465
466 static void ptm_read(fuse_req_t req, size_t size, off_t off,
467 struct fuse_file_info *fi)
468 {
469 int len;
470
471 if (tpm_running) {
472 /* wait until results are ready */
473 worker_thread_wait_done();
474 }
475
476 len = ptm_res_len;
477
478 if (ptm_res_len > size) {
479 len = size;
480 ptm_res_len -= size;
481 } else {
482 ptm_res_len = 0;
483 }
484
485 fuse_reply_buf(req, (const char *)ptm_res, len);
486 }
487
488 static void ptm_write(fuse_req_t req, const char *buf, size_t size,
489 off_t off, struct fuse_file_info *fi)
490 {
491 ptm_req_len = size;
492 ptm_res_len = 0;
493
494 /* prevent other threads from writing or doing ioctls */
495 g_mutex_lock(FILE_OPS_LOCK);
496
497 if (tpm_running) {
498 /* ensure that we only ever work on one TPM command */
499 if (worker_thread_is_busy()) {
500 fuse_reply_err(req, EBUSY);
501 goto cleanup;
502 }
503
504 /* have command processed by thread pool */
505 if (ptm_req_len > TPM_REQ_MAX)
506 ptm_req_len = TPM_REQ_MAX;
507
508 memcpy(ptm_req, buf, ptm_req_len);
509 msg.type = MESSAGE_TPM_CMD;
510 msg.req = req;
511
512 worker_thread_mark_busy();
513
514 g_thread_pool_push(pool, &msg, NULL);
515
516 fuse_reply_write(req, ptm_req_len);
517 } else {
518 /* TPM not initialized; return error */
519 ptm_write_fatal_error_response();
520 fuse_reply_write(req, ptm_req_len);
521 }
522
523 cleanup:
524 g_mutex_unlock(FILE_OPS_LOCK);
525
526 return;
527 }
528
529 static stateblob_desc cached_stateblob;
530
531 static bool
532 cached_stateblob_is_loaded(uint32_t blobtype, TPM_BOOL decrypt)
533 {
534 return (cached_stateblob.data != NULL) &&
535 (cached_stateblob.blobtype == blobtype) &&
536 (cached_stateblob.decrypt == decrypt);
537 }
538
539 /*
540 * cached_stateblob_free: Free any previously loaded state blob
541 */
542 static void
543 cached_stateblob_free(void)
544 {
545 TPM_Free(cached_stateblob.data);
546 cached_stateblob.data = NULL;
547 cached_stateblob.data_length = 0;
548 }
549
550 /*
551 * cached_stateblob_load: load a state blob into the cache
552 *
553 * blobtype: the type of blob
554 * decrypt: whether the blob is to be decrypted
555 */
556 static TPM_RESULT
557 cached_stateblob_load(uint32_t blobtype, TPM_BOOL decrypt)
558 {
559 TPM_RESULT res = 0;
560 const char *blobname = ptm_get_blobname(blobtype);
561 uint32_t tpm_number = 0;
562
563 if (!blobname)
564 return TPM_BAD_PARAMETER;
565
566 cached_stateblob_free();
567
568 if (blobtype == PTM_BLOB_TYPE_VOLATILE)
569 res = SWTPM_NVRAM_Store_Volatile();
570
571 if (res == 0)
572 res = SWTPM_NVRAM_GetStateBlob(&cached_stateblob.data,
573 &cached_stateblob.data_length,
574 tpm_number, blobname, decrypt,
575 &cached_stateblob.is_encrypted);
576
577 /* make sure the volatile state file is gone */
578 if (blobtype == PTM_BLOB_TYPE_VOLATILE)
579 SWTPM_NVRAM_DeleteName(tpm_number, blobname, FALSE);
580
581 if (res == 0) {
582 cached_stateblob.blobtype = blobtype;
583 cached_stateblob.decrypt = decrypt;
584 }
585
586 return res;
587 }
588
589 /*
590 * cached_state_blob_copy: copy the cached state blob to a destination buffer
591 *
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
597 */
598 static int
599 cached_stateblob_copy(void *dest, size_t destlen, uint32_t srcoffset,
600 uint32_t *copied, TPM_BOOL *is_encrypted)
601 {
602 int ret = -1;
603
604 *copied = 0;
605
606 if (cached_stateblob.data != NULL && cached_stateblob.data_length > 0) {
607
608 if (srcoffset < cached_stateblob.data_length) {
609 *copied = min(cached_stateblob.data_length - srcoffset, destlen);
610
611 memcpy(dest, &cached_stateblob.data[srcoffset], *copied);
612
613 *is_encrypted = cached_stateblob.is_encrypted;
614 }
615
616 ret = 0;
617 }
618
619 return ret;
620 }
621
622 /*
623 * ptm_get_stateblob: Get the state blob from the TPM
624 */
625 static void
626 ptm_get_stateblob(fuse_req_t req, ptm_getstate_t *pgs)
627 {
628 TPM_RESULT res = 0;
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;
632 uint32_t copied = 0;
633
634 if (!cached_stateblob_is_loaded(blobtype, decrypt)) {
635 res = cached_stateblob_load(blobtype, decrypt);
636 }
637
638 if (res == 0) {
639 cached_stateblob_copy(&pgs->u.resp.data, sizeof(pgs->u.resp.data),
640 pgs->u.req.offset, &copied, &is_encrypted);
641
642 pgs->u.resp.state_flags = 0;
643 if (is_encrypted) {
644 pgs->u.resp.state_flags |= STATE_FLAG_ENCRYPTED;
645 }
646 }
647
648 pgs->u.resp.length = copied;
649 pgs->u.resp.tpm_result = res;
650
651 fuse_reply_ioctl(req, 0, pgs, sizeof(pgs->u.resp));
652 }
653
654 /*
655 * ptm_ioctl : ioctl execution
656 *
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)
660 * fi:
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
664 * needed buffer
665 * out_bufsz: size of the output buffer; provided by fuse and has size of
666 * needed buffer
667 */
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)
671 {
672 TPM_RESULT res;
673 bool exit_prg = FALSE;
674 ptminit_t *init_p;
675 static struct stateblob stateblob;
676
677 if (flags & FUSE_IOCTL_COMPAT) {
678 fuse_reply_err(req, ENOSYS);
679 return;
680 }
681
682 /* some commands have to wait until the worker thread is done */
683 switch(cmd) {
684 case PTM_GET_CAPABILITY:
685 case PTM_SET_LOCALITY:
686 case PTM_CANCEL_TPM_CMD:
687 case PTM_GET_CONFIG:
688 /* no need to wait */
689 break;
690 case PTM_INIT:
691 case PTM_SHUTDOWN:
692 case PTM_GET_TPMESTABLISHED:
693 case PTM_RESET_TPMESTABLISHED:
694 case PTM_HASH_START:
695 case PTM_HASH_DATA:
696 case PTM_HASH_END:
697 case PTM_STORE_VOLATILE:
698 case PTM_GET_STATEBLOB:
699 case PTM_SET_STATEBLOB:
700 if (tpm_running)
701 worker_thread_wait_done();
702 break;
703 }
704
705 /* prevent other threads from writing or doing ioctls */
706 g_mutex_lock(FILE_OPS_LOCK);
707
708 switch (cmd) {
709 case PTM_GET_CAPABILITY:
710 if (!out_bufsz) {
711 struct iovec iov = { arg, sizeof(uint8_t) };
712 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
713 } else {
714 ptmcap_t ptm_caps;
715 ptm_caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN
716 | PTM_CAP_GET_TPMESTABLISHED
717 | PTM_CAP_SET_LOCALITY
718 | PTM_CAP_HASHING
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
724 | PTM_CAP_STOP
725 | PTM_CAP_GET_CONFIG;
726 fuse_reply_ioctl(req, 0, &ptm_caps, sizeof(ptm_caps));
727 }
728 break;
729
730 case PTM_INIT:
731 init_p = (ptminit_t *)in_buf;
732
733 worker_thread_end();
734
735 TPMLIB_Terminate();
736
737 tpm_running = 0;
738 if ((res = tpm_start(init_p->u.req.init_flags))) {
739 logprintf(STDERR_FILENO,
740 "Error: Could not initialize the TPM.\n");
741 } else {
742 tpm_running = 1;
743 }
744 fuse_reply_ioctl(req, 0, &res, sizeof(res));
745 break;
746
747 case PTM_STOP:
748 worker_thread_end();
749
750 res = TPM_SUCCESS;
751 TPMLIB_Terminate();
752
753 tpm_running = 0;
754
755 TPM_Free(ptm_res);
756 ptm_res = NULL;
757
758 fuse_reply_ioctl(req, 0, &res, sizeof(res));
759
760 break;
761
762 case PTM_SHUTDOWN:
763 worker_thread_end();
764
765 res = TPM_SUCCESS;
766 TPMLIB_Terminate();
767
768 TPM_Free(ptm_res);
769 ptm_res = NULL;
770
771 fuse_reply_ioctl(req, 0, &res, sizeof(res));
772 exit_prg = TRUE;
773
774 break;
775
776 case PTM_GET_TPMESTABLISHED:
777 if (!tpm_running)
778 goto error_not_running;
779
780 if (!out_bufsz) {
781 struct iovec iov = { arg, sizeof(uint8_t) };
782 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
783 } else {
784 ptmest_t te;
785 te.tpm_result = TPM_IO_TpmEstablished_Get(&te.bit);
786 fuse_reply_ioctl(req, 0, &te, sizeof(te));
787 }
788 break;
789
790 case PTM_RESET_TPMESTABLISHED:
791 if (!tpm_running)
792 goto error_not_running;
793
794 if (!in_bufsz) {
795 struct iovec iov = { arg, sizeof(uint32_t) };
796 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
797 } else {
798 ptmreset_est_t *re = (ptmreset_est_t *)in_buf;
799 if (re->u.req.loc > 4) {
800 res = TPM_BAD_LOCALITY;
801 } else {
802 res = _TPM_IO_TpmEstablished_Reset(req, re->u.req.loc);
803 fuse_reply_ioctl(req, 0, &res, sizeof(res));
804 }
805 }
806 break;
807
808 case PTM_SET_LOCALITY:
809 if (!in_bufsz) {
810 struct iovec iov = { arg, sizeof(uint32_t) };
811 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
812 } else {
813 ptmloc_t *l = (ptmloc_t *)in_buf;
814 if (l->u.req.loc > 4) {
815 res = TPM_BAD_LOCALITY;
816 } else {
817 res = 0;
818 locality = l->u.req.loc;
819 }
820 fuse_reply_ioctl(req, 0, &res, sizeof(res));
821 }
822 break;
823
824 case PTM_HASH_START:
825 if (!tpm_running)
826 goto error_not_running;
827
828 res = TPM_IO_Hash_Start();
829 fuse_reply_ioctl(req, 0, &res, sizeof(res));
830 break;
831
832 case PTM_HASH_DATA:
833 if (!tpm_running)
834 goto error_not_running;
835
836 if (!in_bufsz) {
837 struct iovec iov = { arg, sizeof(uint32_t) };
838 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
839 } else {
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,
843 data->u.req.length);
844 } else {
845 res = TPM_FAIL;
846 }
847 fuse_reply_ioctl(req, 0, &res, sizeof(res));
848 }
849 break;
850
851 case PTM_HASH_END:
852 if (!tpm_running)
853 goto error_not_running;
854
855 res = TPM_IO_Hash_End();
856 fuse_reply_ioctl(req, 0, &res, sizeof(res));
857 break;
858
859 case PTM_CANCEL_TPM_CMD:
860 if (!tpm_running)
861 goto error_not_running;
862
863 /* for cancellation to work, the TPM would have to
864 * execute in another thread that polls on a cancel
865 * flag
866 */
867 res = TPM_FAIL;
868 fuse_reply_ioctl(req, 0, &res, sizeof(res));
869 break;
870
871 case PTM_STORE_VOLATILE:
872 if (!tpm_running)
873 goto error_not_running;
874
875 res = SWTPM_NVRAM_Store_Volatile();
876 fuse_reply_ioctl(req, 0, &res, sizeof(res));
877
878 cached_stateblob_free();
879 break;
880
881 case PTM_GET_STATEBLOB:
882 if (!tpm_running)
883 goto error_not_running;
884
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);
888 } else {
889 ptm_get_stateblob(req, (ptm_getstate_t *)in_buf);
890 }
891 break;
892
893 case PTM_SET_STATEBLOB:
894 if (tpm_running)
895 goto error_running;
896
897 /* tpm state dir must be set */
898 SWTPM_NVRAM_Init();
899
900 if (!in_bufsz) {
901 struct iovec iov = { arg, sizeof(uint32_t) };
902 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
903 } else {
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);
908
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));
912 break;
913 }
914
915 if (stateblob.type != pss->u.req.type) {
916 /* clear old data */
917 TPM_Free(stateblob.data);
918 stateblob.data = NULL;
919 stateblob.length = 0;
920 stateblob.type = pss->u.req.type;
921 }
922
923 /* append */
924 res = TPM_Realloc(&stateblob.data,
925 stateblob.length + pss->u.req.length);
926 if (res != 0) {
927 /* error */
928 TPM_Free(stateblob.data);
929 stateblob.data = NULL;
930 stateblob.length = 0;
931 stateblob.type = 0;
932
933 pss->u.resp.tpm_result = res;
934 fuse_reply_ioctl(req, 0, pss, sizeof(*pss));
935 break;
936 }
937
938 memcpy(&stateblob.data[stateblob.length],
939 pss->u.req.data, pss->u.req.length);
940 stateblob.length += pss->u.req.length;
941
942 if (pss->u.req.length == sizeof(pss->u.req.data)) {
943 /* full packet */
944 pss->u.resp.tpm_result = 0;
945 fuse_reply_ioctl(req, 0, pss, sizeof(*pss));
946 break;
947 }
948 blobname = ptm_get_blobname(pss->u.req.type);
949
950 if (blobname) {
951 res = SWTPM_NVRAM_SetStateBlob(stateblob.data,
952 stateblob.length,
953 is_encrypted,
954 pss->u.req.tpm_number,
955 blobname);
956 } else {
957 res = TPM_BAD_PARAMETER;
958 }
959 TPM_Free(stateblob.data);
960 stateblob.data = NULL;
961 stateblob.length = 0;
962 stateblob.type = 0;
963
964 pss->u.resp.tpm_result = res;
965 fuse_reply_ioctl(req, 0, pss, sizeof(*pss));
966 }
967 break;
968
969 case PTM_GET_CONFIG:
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);
973 } else {
974 ptm_getconfig_t pgs;
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));
982 }
983 break;
984
985 default:
986 fuse_reply_err(req, EINVAL);
987 }
988
989 cleanup:
990 g_mutex_unlock(FILE_OPS_LOCK);
991
992 if (exit_prg) {
993 logprintf(STDOUT_FILENO,
994 "CUSE TPM is shutting down.\n");
995 exit(0);
996 }
997
998 return;
999
1000 error_running:
1001 error_not_running:
1002 res = TPM_BAD_ORDINAL;
1003 fuse_reply_ioctl(req, 0, &res, sizeof(res));
1004
1005 goto cleanup;
1006 }
1007
1008 static void ptm_init_done(void *userdata) {
1009 if (passwd) {
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);
1014 exit(-10);
1015 }
1016 if (setgid(passwd->pw_gid) < 0) {
1017 logprintf(STDERR_FILENO,
1018 "Error: setgid(%d) failed.\n",
1019 passwd->pw_gid);
1020 exit(-11);
1021 }
1022 if (setuid(passwd->pw_uid) < 0) {
1023 logprintf(STDERR_FILENO,
1024 "Error: setuid(%d) failed.\n",
1025 passwd->pw_uid);
1026 exit(-12);
1027 }
1028 }
1029 }
1030
1031 static const struct cuse_lowlevel_ops ptm_clop = {
1032 .open = ptm_open,
1033 .read = ptm_read,
1034 .write = ptm_write,
1035 .ioctl = ptm_ioctl,
1036 .init_done = ptm_init_done,
1037 };
1038
1039 #define PTM_OPT(t, p) { t, offsetof(struct ptm_param, p), 1 }
1040
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),
1057 FUSE_OPT_END
1058 };
1059
1060 static int ptm_process_arg(void *data, const char *arg, int key,
1061 struct fuse_args *outargs)
1062 {
1063 struct ptm_param *param = data;
1064
1065 switch (key) {
1066 case 0:
1067 param->is_help = 1;
1068 fprintf(stdout, usage, param->prgname);
1069 return fuse_opt_add_arg(outargs, "-ho");
1070 case 1:
1071 param->is_help = 1;
1072 fprintf(stdout, "TPM emulator CUSE interface version %d.%d.%d, "
1073 "Copyright (c) 2014 IBM Corp.\n",
1074 SWTPM_VER_MAJOR,
1075 SWTPM_VER_MINOR,
1076 SWTPM_VER_MICRO);
1077 return 0;
1078 default:
1079 return -1;
1080 }
1081 return 0;
1082 }
1083
1084 int main(int argc, char **argv)
1085 {
1086 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
1087 struct ptm_param param = {
1088 .major = 0,
1089 .minor = 0,
1090 .dev_name = NULL,
1091 .is_help = 0,
1092 .prgname = argv[0],
1093 .runas = NULL,
1094 .logging = NULL,
1095 .keydata = NULL,
1096 .migkeydata = NULL,
1097 };
1098 char dev_name[128] = "DEVNAME=";
1099 const char *dev_info_argv[] = { dev_name };
1100 struct cuse_info ci;
1101 int ret;
1102
1103 if ((ret = fuse_opt_parse(&args, &param, ptm_opts, ptm_process_arg))) {
1104 fprintf(stderr, "Error: Could not parse option\n");
1105 return ret;
1106 }
1107
1108 if (!param.is_help) {
1109 if (!param.dev_name) {
1110 fprintf(stderr, "Error: device name missing\n");
1111 return -2;
1112 }
1113 strncat(dev_name, param.dev_name, sizeof(dev_name) - 9);
1114 } else {
1115 return 0;
1116 }
1117
1118 if (handle_log_options(param.logging) < 0 ||
1119 handle_key_options(param.keydata) < 0 ||
1120 handle_migration_key_options(param.migkeydata) < 0)
1121 return -3;
1122
1123 if (setuid(0)) {
1124 fprintf(stderr, "Error: Unable to setuid root. uid = %d, "
1125 "euid = %d, gid = %d\n", getuid(), geteuid(), getgid());
1126 return -4;
1127 }
1128
1129 if (param.runas) {
1130 if (!(passwd = getpwnam(param.runas))) {
1131 fprintf(stderr, "User '%s' does not exist\n",
1132 param.runas);
1133 return -5;
1134 }
1135 }
1136
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;
1142
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);
1147 #else
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();
1152 #endif
1153
1154 return cuse_lowlevel_main(args.argc, args.argv, &ci, &ptm_clop,
1155 &param);
1156 }