ia64/xen-unstable

view tools/vtpm_manager/manager/vtpm_manager.c @ 8977:f84d5cdd9895

Clean up segment selector fixup and validation.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu Feb 23 14:43:45 2006 +0100 (2006-02-23)
parents 8a3549172896
children f3661f9a95dd
line source
1 // ===================================================================
2 //
3 // Copyright (c) 2005, Intel Corp.
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
8 // are met:
9 //
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following
14 // disclaimer in the documentation and/or other materials provided
15 // with the distribution.
16 // * Neither the name of Intel Corporation nor the names of its
17 // contributors may be used to endorse or promote products derived
18 // from this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 // OF THE POSSIBILITY OF SUCH DAMAGE.
32 // ===================================================================
33 //
34 // vtpm_manager.c
35 //
36 // This file will house the main logic of the VTPM Manager
37 //
38 // ==================================================================
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <string.h>
47 #ifndef VTPM_MULTI_VM
48 #include <pthread.h>
49 #include <errno.h>
50 #include <aio.h>
51 #include <time.h>
52 #endif
54 #include "vtpm_manager.h"
55 #include "vtpmpriv.h"
56 #include "vtsp.h"
57 #include "bsg.h"
58 #include "hashtable.h"
59 #include "hashtable_itr.h"
61 #include "log.h"
62 #include "buffer.h"
64 VTPM_GLOBALS *vtpm_globals=NULL;
66 #ifdef VTPM_MULTI_VM
67 #define vtpmhandlerloginfo(module,fmt,args...) vtpmloginfo (module, fmt, ##args );
68 #define vtpmhandlerloginfomore(module,fmt,args...) vtpmloginfomore (module, fmt, ##args );
69 #define vtpmhandlerlogerror(module,fmt,args...) vtpmlogerror (module, fmt, ##args );
70 #else
71 #define vtpmhandlerloginfo(module,fmt,args...) vtpmloginfo (module, "[%d]: " fmt, threadType, ##args );
72 #define vtpmhandlerloginfomore(module,fmt,args...) vtpmloginfomore (module, fmt, ##args );
73 #define vtpmhandlerlogerror(module,fmt,args...) vtpmlogerror (module, "[%d]: " fmt, threadType, ##args );
74 #endif
76 // --------------------------- Well Known Auths --------------------------
77 const TPM_AUTHDATA SRK_AUTH = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
78 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
80 #ifdef WELL_KNOWN_OWNER_AUTH
81 static BYTE FIXED_OWNER_AUTH[20] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
82 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
83 #endif
86 // -------------------------- Hash table functions --------------------
88 static unsigned int hashfunc32(void *ky) {
89 return (* (UINT32 *) ky);
90 }
92 static int equals32(void *k1, void *k2) {
93 return (*(UINT32 *) k1 == *(UINT32 *) k2);
94 }
96 // --------------------------- Functions ------------------------------
98 TPM_RESULT VTPM_Create_Service(){
100 TPM_RESULT status = TPM_SUCCESS;
102 // Generate Auth for Owner
103 #ifdef WELL_KNOWN_OWNER_AUTH
104 memcpy(vtpm_globals->owner_usage_auth, FIXED_OWNER_AUTH, sizeof(TPM_AUTHDATA));
105 #else
106 Crypto_GetRandom(vtpm_globals->owner_usage_auth, sizeof(TPM_AUTHDATA) );
107 #endif
109 // Take Owership of TPM
110 CRYPTO_INFO ek_cryptoInfo;
112 status = VTSP_ReadPubek(vtpm_globals->manager_tcs_handle, &ek_cryptoInfo);
114 // If we can read PubEK then there is no owner and we should take it.
115 if (status == TPM_SUCCESS) {
116 vtpmloginfo(VTPM_LOG_VTPM, "Failed to readEK meaning TPM has an owner. Creating Keys off existing SRK.\n");
117 TPMTRYRETURN(VTSP_TakeOwnership(vtpm_globals->manager_tcs_handle,
118 (const TPM_AUTHDATA*)&vtpm_globals->owner_usage_auth,
119 &SRK_AUTH,
120 &ek_cryptoInfo,
121 &vtpm_globals->keyAuth));
123 TPMTRYRETURN(VTSP_DisablePubekRead(vtpm_globals->manager_tcs_handle,
124 (const TPM_AUTHDATA*)&vtpm_globals->owner_usage_auth,
125 &vtpm_globals->keyAuth));
126 }
128 // Generate storage key's auth
129 Crypto_GetRandom( &vtpm_globals->storage_key_usage_auth,
130 sizeof(TPM_AUTHDATA) );
132 TCS_AUTH osap;
133 TPM_AUTHDATA sharedsecret;
135 TPMTRYRETURN( VTSP_OSAP(vtpm_globals->manager_tcs_handle,
136 TPM_ET_KEYHANDLE,
137 TPM_SRK_KEYHANDLE,
138 &SRK_AUTH,
139 &sharedsecret,
140 &osap) );
142 osap.fContinueAuthSession = FALSE;
145 TPMTRYRETURN( VTSP_CreateWrapKey( vtpm_globals->manager_tcs_handle,
146 TPM_KEY_BIND,
147 (const TPM_AUTHDATA*)&vtpm_globals->storage_key_usage_auth,
148 TPM_SRK_KEYHANDLE,
149 (const TPM_AUTHDATA*)&sharedsecret,
150 &vtpm_globals->storageKeyWrap,
151 &osap) );
153 // Generate boot key's auth
154 TPM_AUTHDATA bootKeyWrapAuth;
155 memset(&bootKeyWrapAuth, 0, sizeof(bootKeyWrapAuth));
157 TPMTRYRETURN( VTSP_OSAP(vtpm_globals->manager_tcs_handle,
158 TPM_ET_KEYHANDLE,
159 TPM_SRK_KEYHANDLE,
160 &SRK_AUTH,
161 &sharedsecret,
162 &osap) );
164 osap.fContinueAuthSession = FALSE;
166 // FIXME: This key protects the global secrets on disk. It should use TPM
167 // PCR bindings to limit its use to legit configurations.
168 // Current binds are open, implying a Trusted VM contains this code.
169 // If this VM is not Trusted, use measurement and PCR bindings.
170 TPMTRYRETURN( VTSP_CreateWrapKey( vtpm_globals->manager_tcs_handle,
171 TPM_KEY_BIND,
172 (const TPM_AUTHDATA*)&bootKeyWrapAuth,
173 TPM_SRK_KEYHANDLE,
174 (const TPM_AUTHDATA*)&sharedsecret,
175 &vtpm_globals->bootKeyWrap,
176 &osap) );
178 // Populate CRYPTO_INFO vtpm_globals->bootKey. This does not load it into the TPM
179 TPMTRYRETURN( VTSP_LoadKey( vtpm_globals->manager_tcs_handle,
180 TPM_SRK_KEYHANDLE,
181 &vtpm_globals->bootKeyWrap,
182 NULL,
183 NULL,
184 NULL,
185 &vtpm_globals->bootKey,
186 TRUE ) );
187 goto egress;
189 abort_egress:
190 exit(1);
192 egress:
193 vtpmloginfo(VTPM_LOG_VTPM, "Finished initialized new VTPM service (Status = %d).\n", status);
194 return status;
196 }
199 //////////////////////////////////////////////////////////////////////////////
200 #ifdef VTPM_MULTI_VM
201 int VTPM_Service_Handler(){
202 #else
203 void *VTPM_Service_Handler(void *threadTypePtr){
204 #endif
205 TPM_RESULT status = TPM_FAIL; // Should never return
206 UINT32 dmi, in_param_size, cmd_size, out_param_size, out_message_size, out_message_size_full;
207 BYTE *cmd_header, *in_param, *out_message;
208 buffer_t *command_buf=NULL, *result_buf=NULL;
209 TPM_TAG tag;
210 TPM_COMMAND_CODE ord;
211 VTPM_DMI_RESOURCE *dmi_res;
212 int size_read, size_write, i;
214 #ifndef VTPM_MULTI_VM
215 UINT32 dmi_cmd_size;
216 BYTE *dmi_cmd;
217 int threadType = *(int *) threadTypePtr;
219 // async io structures
220 struct aiocb dmi_aio;
221 struct aiocb *dmi_aio_a[1];
222 dmi_aio_a[0] = &dmi_aio;
223 #endif
225 #ifdef DUMMY_BACKEND
226 int dummy_rx;
227 #endif
229 cmd_header = (BYTE *) malloc(VTPM_COMMAND_HEADER_SIZE_SRV);
230 command_buf = (buffer_t *) malloc(sizeof(buffer_t));
231 result_buf = (buffer_t *) malloc(sizeof(buffer_t));
233 #ifndef VTPM_MULTI_VM
234 TPM_RESULT *ret_value = (TPM_RESULT *) malloc(sizeof(TPM_RESULT));
235 #endif
237 int *tx_fh, // Pointer to the filehandle this function will write to
238 *rx_fh; // Pointer to the filehandle this function will read from
239 // For a multi VM VTPM system, this function tx/rx with the BE
240 // via vtpm_globals->be_fh.
241 // For a single VM system, the BE_LISTENER_THREAD tx/rx with theBE
242 // via vtpm_globals->be_fh, and the DMI_LISTENER_THREAD rx from
243 // vtpm_globals->vtpm_rx_fh and tx to dmi_res->vtpm_tx_fh
245 // Set rx_fh to point to the correct fh based on this mode.
246 #ifdef VTPM_MULTI_VM
247 rx_fh = &vtpm_globals->be_fh;
248 #else
249 if (threadType == BE_LISTENER_THREAD) {
250 #ifdef DUMMY_BACKEND
251 dummy_rx = -1;
252 rx_fh = &dummy_rx;
253 #else
254 rx_fh = &vtpm_globals->be_fh;
255 #endif
256 } else { // DMI_LISTENER_THREAD
257 rx_fh = &vtpm_globals->vtpm_rx_fh;
258 }
259 #endif
261 // Set tx_fh to point to the correct fh based on this mode (If static)
262 // Create any fifos that these fh will use.
263 #ifndef VTPM_MULTI_VM
264 int fh;
265 if (threadType == BE_LISTENER_THREAD) {
266 tx_fh = &vtpm_globals->be_fh;
267 if ( (fh = open(GUEST_RX_FIFO, O_RDWR)) == -1) {
268 if ( mkfifo(GUEST_RX_FIFO, S_IWUSR | S_IRUSR ) ){
269 vtpmlogerror(VTPM_LOG_VTPM, "Unable to create FIFO: %s.\n", GUEST_RX_FIFO);
270 *ret_value = TPM_FAIL;
271 pthread_exit(ret_value);
272 }
273 } else
274 close(fh);
276 } else { // else DMI_LISTENER_THREAD
277 // tx_fh will be set once the DMI is identified
278 // But we need to make sure the read pip is created.
279 if ( (fh = open(VTPM_RX_FIFO, O_RDWR)) == -1) {
280 if ( mkfifo(VTPM_RX_FIFO, S_IWUSR | S_IRUSR ) ){
281 vtpmlogerror(VTPM_LOG_VTPM, "Unable to create FIFO: %s.\n", VTPM_RX_FIFO);
282 *ret_value = TPM_FAIL;
283 pthread_exit(ret_value);
284 }
285 } else
286 close(fh);
288 }
289 #else
290 tx_fh = &vtpm_globals->be_fh;
291 #endif
293 ////////////////////////// Main Loop //////////////////////////////////
294 while(1) {
296 #ifdef VTPM_MULTI_VM
297 vtpmhandlerloginfo(VTPM_LOG_VTPM, "Waiting for DMI messages.\n");
298 #else
299 if (threadType == BE_LISTENER_THREAD) {
300 vtpmhandlerloginfo(VTPM_LOG_VTPM, "Waiting for Guest requests & ctrl messages.\n");
301 } else
302 vtpmhandlerloginfo(VTPM_LOG_VTPM, "Waiting for DMI messages.\n");
303 #endif
305 // Check status of rx_fh. If necessary attempt to re-open it.
306 char* s = NULL;
307 if (*rx_fh < 0) {
308 #ifdef VTPM_MULTI_VM
309 s = VTPM_BE_DEV;
310 #else
311 if (threadType == BE_LISTENER_THREAD)
312 #ifdef DUMMY_BACKEND
313 s = "/tmp/in.fifo";
314 #else
315 s = VTPM_BE_DEV;
316 #endif
317 else // DMI Listener
318 s = VTPM_RX_FIFO;
319 *rx_fh = open(s, O_RDWR);
320 #endif
321 }
323 // Respond to failures to open rx_fh
324 if (*rx_fh < 0) {
325 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Can't open inbound fh for %s.\n", s);
326 #ifdef VTPM_MULTI_VM
327 return TPM_IOERROR;
328 #else
329 *ret_value = TPM_IOERROR;
330 pthread_exit(ret_value);
331 #endif
332 }
334 // Read command header from rx_fh
335 size_read = read(*rx_fh, cmd_header, VTPM_COMMAND_HEADER_SIZE_SRV);
336 if (size_read > 0) {
337 vtpmhandlerloginfo(VTPM_LOG_VTPM_DEEP, "RECV[%d}: 0x", size_read);
338 for (i=0; i<size_read; i++)
339 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", cmd_header[i]);
340 } else {
341 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Can't read from BE. Aborting... \n");
342 close(*rx_fh);
343 *rx_fh = -1;
344 goto abort_command;
345 }
347 if (size_read < (int) VTPM_COMMAND_HEADER_SIZE_SRV) {
348 vtpmhandlerloginfo(VTPM_LOG_VTPM_DEEP, "\n");
349 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Command shorter than normal header (%d bytes). Aborting...\n", size_read);
350 goto abort_command;
351 }
353 // Unpack header
354 BSG_UnpackList(cmd_header, 4,
355 BSG_TYPE_UINT32, &dmi,
356 BSG_TPM_TAG, &tag,
357 BSG_TYPE_UINT32, &in_param_size,
358 BSG_TPM_COMMAND_CODE, &ord );
360 // Using the header info, read from rx_fh the parameters of the command
361 // Note that in_param_size is in the client's context
362 cmd_size = in_param_size - VTPM_COMMAND_HEADER_SIZE_CLT;
363 if (cmd_size > 0) {
364 in_param = (BYTE *) malloc(cmd_size);
365 size_read = read( *rx_fh, in_param, cmd_size);
366 if (size_read > 0) {
367 for (i=0; i<size_read; i++)
368 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", in_param[i]);
370 } else {
371 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Error reading from cmd. Aborting... \n");
372 close(*rx_fh);
373 *rx_fh = -1;
374 goto abort_command;
375 }
376 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
378 if (size_read < (int) cmd_size) {
379 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
380 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Command read(%d) is shorter than header indicates(%d). Aborting...\n", size_read, cmd_size);
381 goto abort_command;
382 }
383 } else {
384 in_param = NULL;
385 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
386 }
388 #ifndef VTPM_MULTI_VM
389 // It's illegal to receive a Dom0 command from a DMI.
390 if ((threadType != BE_LISTENER_THREAD) && (dmi == 0)) {
391 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Attempt to access dom0 commands from DMI interface. Aborting...\n");
392 goto abort_command;
393 }
394 #endif
396 // Fetch infomation about the DMI issuing the request.
397 dmi_res = (VTPM_DMI_RESOURCE *) hashtable_search(vtpm_globals->dmi_map, &dmi);
398 if (dmi_res == NULL) {
399 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Attempted access to non-existent DMI in domain: %d. Aborting...\n", dmi);
400 goto abort_command;
401 }
402 if (!dmi_res->connected) {
403 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Attempted access to disconnected DMI in domain: %d. Aborting...\n", dmi);
404 goto abort_command;
405 }
407 #ifndef VTPM_MULTI_VM
408 // Now that we know which DMI this is, we can set the tx_fh handle.
409 if (threadType != BE_LISTENER_THREAD)
410 tx_fh = &dmi_res->vtpm_tx_fh;
411 // else we set this before the while loop since it doesn't change.
412 #endif
414 // Init the buffers used to handle the command and the response
415 if ( (buffer_init_convert(command_buf, cmd_size, in_param) != TPM_SUCCESS) ||
416 (buffer_init(result_buf, 0, 0) != TPM_SUCCESS) ) {
417 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Failed to setup buffers. Aborting...\n");
418 goto abort_command;
419 }
421 // Dispatch it as either control or user request.
422 if (tag == VTPM_TAG_REQ) {
423 if (dmi_res->dmi_id == VTPM_CTL_DM){
424 switch (ord) {
425 case VTPM_ORD_OPEN:
426 status = VTPM_Handle_New_DMI(command_buf);
427 break;
429 case VTPM_ORD_CLOSE:
430 status = VTPM_Handle_Close_DMI(command_buf);
431 break;
433 case VTPM_ORD_DELETE:
434 status = VTPM_Handle_Delete_DMI(command_buf);
435 break;
436 default:
437 status = TPM_BAD_ORDINAL;
438 } // switch
439 } else {
441 switch (ord) {
442 case VTPM_ORD_SAVENVM:
443 status= VTPM_Handle_Save_NVM(dmi_res,
444 command_buf,
445 result_buf);
446 break;
447 case VTPM_ORD_LOADNVM:
448 status= VTPM_Handle_Load_NVM(dmi_res,
449 command_buf,
450 result_buf);
451 break;
453 case VTPM_ORD_TPMCOMMAND:
454 status= VTPM_Handle_TPM_Command(dmi_res,
455 command_buf,
456 result_buf);
457 break;
459 default:
460 status = TPM_BAD_ORDINAL;
461 } // switch
462 }
463 } else { // This is not a VTPM Command at all.
464 // This happens in two cases.
465 // MULTI_VM = A DMI illegally sent a raw TPM command to the manager
466 // Single VM:
467 // BE_LISTENER_THREAD: Guest issued a TPM command.
468 // Send this to DMI and wait for response
469 // DMI_LISTENER_THREAD: A DMI illegally sent a raw TPM command.
471 #ifdef VTPM_MULTI_VM
472 // Raw TPM commands are not supported from the DMI
473 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Attempt to use unsupported direct access to TPM.\n");
474 vtpmhandlerloginfo(VTPM_LOG_VTPM_DEEP, "Bad Command. dmi:%d, tag:%d, size:%d, ord:%d, Params: ", dmi, tag, in_param_size, ord);
475 for (i=0; i<cmd_size; i++)
476 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", in_param[i]);
478 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
479 status = TPM_FAIL;
481 #else
482 // If BE_LISTENER_THREAD then this is a TPM command from a guest
483 if (threadType == BE_LISTENER_THREAD) {
484 // Dom0 can't talk to the BE, so this must be a broken FE/BE or badness
485 if (dmi == 0) {
486 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Illegal use of TPM command from dom0\n");
487 status = TPM_FAIL;
488 } else {
489 vtpmhandlerloginfo(VTPM_LOG_VTPM, "Forwarding command to DMI.\n");
491 // open the dmi_res->guest_tx_fh to send command to DMI
492 if (dmi_res->guest_tx_fh < 0)
493 dmi_res->guest_tx_fh = open(dmi_res->guest_tx_fname, O_WRONLY | O_NONBLOCK);
495 // handle failed opens dmi_res->guest_tx_fh
496 if (dmi_res->guest_tx_fh < 0){
497 vtpmhandlerlogerror(VTPM_LOG_VTPM, "VTPM ERROR: Can't open outbound fh to dmi.\n");
498 status = TPM_IOERROR;
499 goto abort_with_error;
500 }
502 //Forward TPM CMD stamped with dmi_id to DMI for handling
503 if (cmd_size) {
504 dmi_cmd = (BYTE *) malloc(VTPM_COMMAND_HEADER_SIZE_SRV + cmd_size);
505 dmi_cmd_size = VTPM_COMMAND_HEADER_SIZE_SRV + cmd_size;
506 memcpy(dmi_cmd, cmd_header, VTPM_COMMAND_HEADER_SIZE_SRV);
507 memcpy(dmi_cmd + VTPM_COMMAND_HEADER_SIZE_SRV, in_param, cmd_size);
508 size_write = write(dmi_res->guest_tx_fh, dmi_cmd, dmi_cmd_size);
510 if (size_write > 0) {
511 vtpmhandlerloginfo(VTPM_LOG_VTPM_DEEP, "SENT (DMI): 0x");
512 for (i=0; i<VTPM_COMMAND_HEADER_SIZE_SRV + cmd_size; i++) {
513 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", dmi_cmd[i]);
514 }
515 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
516 } else {
517 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Error writing to DMI. Aborting... \n");
518 close(dmi_res->guest_tx_fh);
519 dmi_res->guest_tx_fh = -1;
520 status = TPM_IOERROR;
521 goto abort_with_error;
522 }
523 free(dmi_cmd);
524 } else {
525 dmi_cmd_size = VTPM_COMMAND_HEADER_SIZE_SRV;
526 size_write = write(dmi_res->guest_tx_fh, cmd_header, VTPM_COMMAND_HEADER_SIZE_SRV );
527 if (size_write > 0) {
528 for (i=0; i<VTPM_COMMAND_HEADER_SIZE_SRV; i++)
529 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", cmd_header[i]);
531 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
532 } else {
533 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Error writing to DMI. Aborting... \n");
534 close(dmi_res->guest_tx_fh);
535 dmi_res->guest_tx_fh = -1;
536 status = TPM_IOERROR;
537 goto abort_with_error;
538 }
539 }
541 if (size_write != (int) dmi_cmd_size)
542 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Could not write entire command to DMI (%d/%d)\n", size_write, dmi_cmd_size);
543 buffer_free(command_buf);
545 // Open vtpm_globals->guest_rx_fh to receive DMI response
546 if (vtpm_globals->guest_rx_fh < 0)
547 vtpm_globals->guest_rx_fh = open(GUEST_RX_FIFO, O_RDONLY);
549 // Handle open failures
550 if (vtpm_globals->guest_rx_fh < 0){
551 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Can't open inbound fh to dmi.\n");
552 status = TPM_IOERROR;
553 goto abort_with_error;
554 }
556 // Read header for response to TPM command from DMI
557 size_read = read( vtpm_globals->guest_rx_fh, cmd_header, VTPM_COMMAND_HEADER_SIZE_SRV);
558 if (size_read > 0) {
559 vtpmhandlerloginfo(VTPM_LOG_VTPM_DEEP, "RECV (DMI): 0x");
560 for (i=0; i<size_read; i++)
561 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", cmd_header[i]);
563 } else {
564 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Error reading from DMI. Aborting... \n");
565 close(vtpm_globals->guest_rx_fh);
566 vtpm_globals->guest_rx_fh = -1;
567 status = TPM_IOERROR;
568 goto abort_with_error;
569 }
571 if (size_read < (int) VTPM_COMMAND_HEADER_SIZE_SRV) {
572 //vtpmdeepsublog("\n");
573 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Command from DMI shorter than normal header. Aborting...\n");
574 status = TPM_IOERROR;
575 goto abort_with_error;
576 }
578 // Unpack response from DMI for TPM command
579 BSG_UnpackList(cmd_header, 4,
580 BSG_TYPE_UINT32, &dmi,
581 BSG_TPM_TAG, &tag,
582 BSG_TYPE_UINT32, &in_param_size,
583 BSG_TPM_COMMAND_CODE, &status );
585 // If response has parameters, read them.
586 // Note that in_param_size is in the client's context
587 cmd_size = in_param_size - VTPM_COMMAND_HEADER_SIZE_CLT;
588 if (cmd_size > 0) {
589 in_param = (BYTE *) malloc(cmd_size);
590 size_read = read( vtpm_globals->guest_rx_fh, in_param, cmd_size);
591 if (size_read > 0) {
592 for (i=0; i<size_read; i++)
593 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", in_param[i]);
595 } else {
596 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Error reading from BE. Aborting... \n");
597 close(vtpm_globals->guest_rx_fh);
598 vtpm_globals->guest_rx_fh = -1;
599 status = TPM_IOERROR;
600 goto abort_with_error;
601 }
602 vtpmhandlerloginfomore(VTPM_LOG_VTPM, "\n");
604 if (size_read < (int)cmd_size) {
605 vtpmhandlerloginfomore(VTPM_LOG_VTPM, "\n");
606 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Command read(%d) from DMI is shorter than header indicates(%d). Aborting...\n", size_read, cmd_size);
607 status = TPM_IOERROR;
608 goto abort_with_error;
609 }
610 } else {
611 in_param = NULL;
612 vtpmhandlerloginfomore(VTPM_LOG_VTPM, "\n");
613 }
615 if (buffer_init_convert(result_buf, cmd_size, in_param) != TPM_SUCCESS) {
616 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Failed to setup buffers. Aborting...\n");
617 status = TPM_FAIL;
618 goto abort_with_error;
619 }
621 vtpmhandlerloginfo(VTPM_LOG_VTPM, "Sending DMI's response to guest.\n");
622 } // end else for if (dmi==0)
624 } else { // This is a DMI lister thread. Thus this is from a DMI
625 // Raw TPM commands are not supported from the DMI
626 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Attempt to use unsupported direct access to TPM.\n");
627 vtpmhandlerloginfo(VTPM_LOG_VTPM_DEEP, "Bad Command. dmi:%d, tag:%d, size:%d, ord:%d, Params: ", dmi, tag, in_param_size, ord);
628 for (i=0; i<cmd_size; i++)
629 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", in_param[i]);
631 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
633 status = TPM_FAIL;
634 } // end else for if BE Listener
635 #endif
637 } // end else for is VTPM Command
639 // This marks the beginning of preparing response to be sent out.
640 // Errors while handling responses jump here to reply with error messages
641 // NOTE: Currently there are no recoverable errors in multi-VM mode. If one
642 // is added to the code, this ifdef should be removed.
643 // Also note this is NOT referring to errors in commands, but rather
644 // this is about I/O errors and such.
645 #ifndef VTPM_MULTI_VM
646 abort_with_error:
647 #endif
649 // Open tx_fh in preperation to send reponse back
650 if (*tx_fh < 0) {
651 #ifdef VTPM_MULTI_VM
652 *tx_fh = open(VTPM_BE_DEV, O_RDWR);
653 #else
654 if (threadType == BE_LISTENER_THREAD)
655 #ifdef DUMMY_BACKEND
656 *tx_fh = open("/tmp/out.fifo", O_RDWR);
657 #else
658 *tx_fh = open(VTPM_BE_DEV, O_RDWR);
659 #endif
660 else // DMI Listener
661 *tx_fh = open(dmi_res->vtpm_tx_fname, O_WRONLY);
662 #endif
663 }
666 // Handle failed open
667 if (*tx_fh < 0) {
668 vtpmhandlerlogerror(VTPM_LOG_VTPM, "VTPM ERROR: Can't open outbound fh.\n");
669 #ifdef VTPM_MULTI_VM
670 return TPM_IOERROR;
671 #else
672 *ret_value = TPM_IOERROR;
673 pthread_exit(ret_value);
674 #endif
675 }
677 // Prepend VTPM header with destination DM stamped
678 out_param_size = buffer_len(result_buf);
679 out_message_size = VTPM_COMMAND_HEADER_SIZE_CLT + out_param_size;
680 out_message_size_full = VTPM_COMMAND_HEADER_SIZE_SRV + out_param_size;
681 out_message = (BYTE *) malloc (out_message_size_full);
683 BSG_PackList(out_message, 4,
684 BSG_TYPE_UINT32, (BYTE *) &dmi,
685 BSG_TPM_TAG, (BYTE *) &tag,
686 BSG_TYPE_UINT32, (BYTE *) &out_message_size,
687 BSG_TPM_RESULT, (BYTE *) &status);
689 if (buffer_len(result_buf) > 0)
690 memcpy(out_message + VTPM_COMMAND_HEADER_SIZE_SRV, result_buf->bytes, out_param_size);
693 //Note: Send message + dmi_id
694 size_write = write(*tx_fh, out_message, out_message_size_full );
695 if (size_write > 0) {
696 vtpmhandlerloginfo(VTPM_LOG_VTPM_DEEP, "SENT: 0x");
697 for (i=0; i < out_message_size_full; i++)
698 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", out_message[i]);
700 vtpmhandlerloginfomore(VTPM_LOG_VTPM_DEEP, "\n");
701 } else {
702 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Error writing to BE. Aborting... \n");
703 close(*tx_fh);
704 *tx_fh = -1;
705 goto abort_command;
706 }
707 free(out_message);
709 if (size_write < (int)out_message_size_full) {
710 vtpmhandlerlogerror(VTPM_LOG_VTPM, "Unable to write full command to BE (%d/%d)\n", size_write, out_message_size_full);
711 goto abort_command;
712 }
714 // On certain failures an error message cannot be sent.
715 // This marks the beginning of cleanup in preperation for the next command.
716 abort_command:
717 //free buffers
718 bzero(cmd_header, VTPM_COMMAND_HEADER_SIZE_SRV);
719 //free(in_param); // This was converted to command_buf. No need to free
720 if (command_buf != result_buf)
721 buffer_free(result_buf);
723 buffer_free(command_buf);
725 #ifndef VTPM_MULTI_VM
726 if (threadType != BE_LISTENER_THREAD) {
727 #endif
728 if ( (vtpm_globals->DMI_table_dirty) &&
729 (VTPM_SaveService() != TPM_SUCCESS) ) {
730 vtpmhandlerlogerror(VTPM_LOG_VTPM, "ERROR: Unable to save manager data.\n");
731 }
732 #ifndef VTPM_MULTI_VM
733 }
734 #endif
736 } // End while(1)
738 }
741 ///////////////////////////////////////////////////////////////////////////////
742 TPM_RESULT VTPM_Init_Service() {
743 TPM_RESULT status = TPM_FAIL, serviceStatus;
744 BYTE *randomsead;
745 UINT32 randomsize;
747 if ((vtpm_globals = (VTPM_GLOBALS *) malloc(sizeof(VTPM_GLOBALS))) == NULL){
748 status = TPM_FAIL;
749 goto abort_egress;
750 }
751 memset(vtpm_globals, 0, sizeof(VTPM_GLOBALS));
752 vtpm_globals->be_fh = -1;
754 #ifndef VTPM_MULTI_VM
755 vtpm_globals->vtpm_rx_fh = -1;
756 vtpm_globals->guest_rx_fh = -1;
757 #endif
758 if ((vtpm_globals->dmi_map = create_hashtable(10, hashfunc32, equals32)) == NULL){
759 status = TPM_FAIL;
760 goto abort_egress;
761 }
763 vtpm_globals->DMI_table_dirty = FALSE;
765 // Create new TCS Object
766 vtpm_globals->manager_tcs_handle = 0;
768 TPMTRYRETURN(TCS_create());
770 // Create TCS Context for service
771 TPMTRYRETURN( TCS_OpenContext(&vtpm_globals->manager_tcs_handle ) );
773 TPMTRYRETURN( TCSP_GetRandom(vtpm_globals->manager_tcs_handle,
774 &randomsize,
775 &randomsead));
777 Crypto_Init(randomsead, randomsize);
778 TPMTRYRETURN( TCS_FreeMemory (vtpm_globals->manager_tcs_handle, randomsead));
780 // Create OIAP session for service's authorized commands
781 TPMTRYRETURN( VTSP_OIAP( vtpm_globals->manager_tcs_handle,
782 &vtpm_globals->keyAuth) );
783 vtpm_globals->keyAuth.fContinueAuthSession = TRUE;
785 // If failed, create new Service.
786 serviceStatus = VTPM_LoadService();
787 if (serviceStatus == TPM_IOERROR) {
788 vtpmloginfo(VTPM_LOG_VTPM, "Failed to read service file. Assuming first time initialization.\n");
789 TPMTRYRETURN( VTPM_Create_Service() );
790 } else if (serviceStatus != TPM_SUCCESS) {
791 vtpmlogerror(VTPM_LOG_VTPM, "Failed to read existing service file");
792 exit(1);
793 }
795 //Load Storage Key
796 TPMTRYRETURN( VTSP_LoadKey( vtpm_globals->manager_tcs_handle,
797 TPM_SRK_KEYHANDLE,
798 &vtpm_globals->storageKeyWrap,
799 &SRK_AUTH,
800 &vtpm_globals->storageKeyHandle,
801 &vtpm_globals->keyAuth,
802 &vtpm_globals->storageKey,
803 FALSE ) );
805 // Create entry for Dom0 for control messages
806 TPMTRYRETURN( VTPM_Handle_New_DMI(NULL) );
808 // --------------------- Command handlers ---------------------------
810 goto egress;
812 abort_egress:
813 egress:
815 return(status);
816 }
818 void VTPM_Stop_Service() {
819 VTPM_DMI_RESOURCE *dmi_res;
820 struct hashtable_itr *dmi_itr;
822 // Close all the TCS contexts. TCS should evict keys based on this
823 if (hashtable_count(vtpm_globals->dmi_map) > 0) {
824 dmi_itr = hashtable_iterator(vtpm_globals->dmi_map);
825 do {
826 dmi_res = (VTPM_DMI_RESOURCE *) hashtable_iterator_value(dmi_itr);
827 if (dmi_res->connected)
828 close_dmi( dmi_res ); // Not really interested in return code
830 } while (hashtable_iterator_advance(dmi_itr));
831 free (dmi_itr);
832 }
834 if ( (vtpm_globals->DMI_table_dirty) && (VTPM_SaveService() != TPM_SUCCESS) )
835 vtpmlogerror(VTPM_LOG_VTPM, "Unable to save manager data.\n");
837 TCS_CloseContext(vtpm_globals->manager_tcs_handle);
838 TCS_destroy();
840 hashtable_destroy(vtpm_globals->dmi_map, 1);
841 free(vtpm_globals);
843 close(vtpm_globals->be_fh);
844 Crypto_Exit();
846 vtpmloginfo(VTPM_LOG_VTPM, "VTPM Manager stopped.\n");
847 }