These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / hw / tpm / tpm_passthrough.c
1 /*
2  *  passthrough TPM driver
3  *
4  *  Copyright (c) 2010 - 2013 IBM Corporation
5  *  Authors:
6  *    Stefan Berger <stefanb@us.ibm.com>
7  *
8  *  Copyright (C) 2011 IAIK, Graz University of Technology
9  *    Author: Andreas Niederl
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, see <http://www.gnu.org/licenses/>
23  */
24
25 #include "qemu/osdep.h"
26 #include "qemu-common.h"
27 #include "qemu/error-report.h"
28 #include "qemu/sockets.h"
29 #include "sysemu/tpm_backend.h"
30 #include "tpm_int.h"
31 #include "hw/hw.h"
32 #include "hw/i386/pc.h"
33 #include "sysemu/tpm_backend_int.h"
34 #include "tpm_tis.h"
35 #include "tpm_util.h"
36
37 #define DEBUG_TPM 0
38
39 #define DPRINTF(fmt, ...) do { \
40     if (DEBUG_TPM) { \
41         fprintf(stderr, fmt, ## __VA_ARGS__); \
42     } \
43 } while (0);
44
45 #define TYPE_TPM_PASSTHROUGH "tpm-passthrough"
46 #define TPM_PASSTHROUGH(obj) \
47     OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
48
49 static const TPMDriverOps tpm_passthrough_driver;
50
51 /* data structures */
52 typedef struct TPMPassthruThreadParams {
53     TPMState *tpm_state;
54
55     TPMRecvDataCB *recv_data_callback;
56     TPMBackend *tb;
57 } TPMPassthruThreadParams;
58
59 struct TPMPassthruState {
60     TPMBackend parent;
61
62     TPMBackendThread tbt;
63
64     TPMPassthruThreadParams tpm_thread_params;
65
66     char *tpm_dev;
67     int tpm_fd;
68     bool tpm_executing;
69     bool tpm_op_canceled;
70     int cancel_fd;
71     bool had_startup_error;
72
73     TPMVersion tpm_version;
74 };
75
76 typedef struct TPMPassthruState TPMPassthruState;
77
78 #define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
79
80 /* functions */
81
82 static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
83
84 static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t len)
85 {
86     int ret, remain;
87
88     remain = len;
89     while (remain > 0) {
90         ret = write(fd, buf, remain);
91         if (ret < 0) {
92             if (errno != EINTR && errno != EAGAIN) {
93                 return -1;
94             }
95         } else if (ret == 0) {
96             break;
97         } else {
98             buf += ret;
99             remain -= ret;
100         }
101     }
102     return len - remain;
103 }
104
105 static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
106 {
107     int ret;
108  reread:
109     ret = read(fd, buf, len);
110     if (ret < 0) {
111         if (errno != EINTR && errno != EAGAIN) {
112             return -1;
113         }
114         goto reread;
115     }
116     return ret;
117 }
118
119 static uint32_t tpm_passthrough_get_size_from_buffer(const uint8_t *buf)
120 {
121     struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)buf;
122
123     return be32_to_cpu(resp->len);
124 }
125
126 /*
127  * Write an error message in the given output buffer.
128  */
129 static void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len)
130 {
131     if (out_len >= sizeof(struct tpm_resp_hdr)) {
132         struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)out;
133
134         resp->tag = cpu_to_be16(TPM_TAG_RSP_COMMAND);
135         resp->len = cpu_to_be32(sizeof(struct tpm_resp_hdr));
136         resp->errcode = cpu_to_be32(TPM_FAIL);
137     }
138 }
139
140 static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t in_len)
141 {
142     struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
143
144     if (in_len >= sizeof(*hdr)) {
145         return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
146     }
147
148     return false;
149 }
150
151 static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
152                                         const uint8_t *in, uint32_t in_len,
153                                         uint8_t *out, uint32_t out_len,
154                                         bool *selftest_done)
155 {
156     int ret;
157     bool is_selftest;
158     const struct tpm_resp_hdr *hdr;
159
160     tpm_pt->tpm_op_canceled = false;
161     tpm_pt->tpm_executing = true;
162     *selftest_done = false;
163
164     is_selftest = tpm_passthrough_is_selftest(in, in_len);
165
166     ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
167     if (ret != in_len) {
168         if (!tpm_pt->tpm_op_canceled ||
169             (tpm_pt->tpm_op_canceled && errno != ECANCELED)) {
170             error_report("tpm_passthrough: error while transmitting data "
171                          "to TPM: %s (%i)",
172                          strerror(errno), errno);
173         }
174         goto err_exit;
175     }
176
177     tpm_pt->tpm_executing = false;
178
179     ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len);
180     if (ret < 0) {
181         if (!tpm_pt->tpm_op_canceled ||
182             (tpm_pt->tpm_op_canceled && errno != ECANCELED)) {
183             error_report("tpm_passthrough: error while reading data from "
184                          "TPM: %s (%i)",
185                          strerror(errno), errno);
186         }
187     } else if (ret < sizeof(struct tpm_resp_hdr) ||
188                tpm_passthrough_get_size_from_buffer(out) != ret) {
189         ret = -1;
190         error_report("tpm_passthrough: received invalid response "
191                      "packet from TPM");
192     }
193
194     if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) {
195         hdr = (struct tpm_resp_hdr *)out;
196         *selftest_done = (be32_to_cpu(hdr->errcode) == 0);
197     }
198
199 err_exit:
200     if (ret < 0) {
201         tpm_write_fatal_error_response(out, out_len);
202     }
203
204     tpm_pt->tpm_executing = false;
205
206     return ret;
207 }
208
209 static int tpm_passthrough_unix_transfer(TPMPassthruState *tpm_pt,
210                                          const TPMLocality *locty_data,
211                                          bool *selftest_done)
212 {
213     return tpm_passthrough_unix_tx_bufs(tpm_pt,
214                                         locty_data->w_buffer.buffer,
215                                         locty_data->w_offset,
216                                         locty_data->r_buffer.buffer,
217                                         locty_data->r_buffer.size,
218                                         selftest_done);
219 }
220
221 static void tpm_passthrough_worker_thread(gpointer data,
222                                           gpointer user_data)
223 {
224     TPMPassthruThreadParams *thr_parms = user_data;
225     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(thr_parms->tb);
226     TPMBackendCmd cmd = (TPMBackendCmd)data;
227     bool selftest_done = false;
228
229     DPRINTF("tpm_passthrough: processing command type %d\n", cmd);
230
231     switch (cmd) {
232     case TPM_BACKEND_CMD_PROCESS_CMD:
233         tpm_passthrough_unix_transfer(tpm_pt,
234                                       thr_parms->tpm_state->locty_data,
235                                       &selftest_done);
236
237         thr_parms->recv_data_callback(thr_parms->tpm_state,
238                                       thr_parms->tpm_state->locty_number,
239                                       selftest_done);
240         break;
241     case TPM_BACKEND_CMD_INIT:
242     case TPM_BACKEND_CMD_END:
243     case TPM_BACKEND_CMD_TPM_RESET:
244         /* nothing to do */
245         break;
246     }
247 }
248
249 /*
250  * Start the TPM (thread). If it had been started before, then terminate
251  * and start it again.
252  */
253 static int tpm_passthrough_startup_tpm(TPMBackend *tb)
254 {
255     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
256
257     /* terminate a running TPM */
258     tpm_backend_thread_end(&tpm_pt->tbt);
259
260     tpm_backend_thread_create(&tpm_pt->tbt,
261                               tpm_passthrough_worker_thread,
262                               &tpm_pt->tpm_thread_params);
263
264     return 0;
265 }
266
267 static void tpm_passthrough_reset(TPMBackend *tb)
268 {
269     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
270
271     DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n");
272
273     tpm_passthrough_cancel_cmd(tb);
274
275     tpm_backend_thread_end(&tpm_pt->tbt);
276
277     tpm_pt->had_startup_error = false;
278 }
279
280 static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
281                                 TPMRecvDataCB *recv_data_cb)
282 {
283     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
284
285     tpm_pt->tpm_thread_params.tpm_state = s;
286     tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb;
287     tpm_pt->tpm_thread_params.tb = tb;
288
289     return 0;
290 }
291
292 static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
293 {
294     return false;
295 }
296
297 static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
298                                                       uint8_t locty)
299 {
300     /* only a TPM 2.0 will support this */
301     return 0;
302 }
303
304 static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
305 {
306     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
307
308     return tpm_pt->had_startup_error;
309 }
310
311 static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb)
312 {
313     size_t wanted_size = 4096; /* Linux tpm.c buffer size */
314
315     if (sb->size != wanted_size) {
316         sb->buffer = g_realloc(sb->buffer, wanted_size);
317         sb->size = wanted_size;
318     }
319     return sb->size;
320 }
321
322 static void tpm_passthrough_deliver_request(TPMBackend *tb)
323 {
324     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
325
326     tpm_backend_thread_deliver_request(&tpm_pt->tbt);
327 }
328
329 static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
330 {
331     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
332     int n;
333
334     /*
335      * As of Linux 3.7 the tpm_tis driver does not properly cancel
336      * commands on all TPM manufacturers' TPMs.
337      * Only cancel if we're busy so we don't cancel someone else's
338      * command, e.g., a command executed on the host.
339      */
340     if (tpm_pt->tpm_executing) {
341         if (tpm_pt->cancel_fd >= 0) {
342             n = write(tpm_pt->cancel_fd, "-", 1);
343             if (n != 1) {
344                 error_report("Canceling TPM command failed: %s",
345                              strerror(errno));
346             } else {
347                 tpm_pt->tpm_op_canceled = true;
348             }
349         } else {
350             error_report("Cannot cancel TPM command due to missing "
351                          "TPM sysfs cancel entry");
352         }
353     }
354 }
355
356 static const char *tpm_passthrough_create_desc(void)
357 {
358     return "Passthrough TPM backend driver";
359 }
360
361 static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
362 {
363     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
364
365     return tpm_pt->tpm_version;
366 }
367
368 /*
369  * Unless path or file descriptor set has been provided by user,
370  * determine the sysfs cancel file following kernel documentation
371  * in Documentation/ABI/stable/sysfs-class-tpm.
372  * From /dev/tpm0 create /sys/class/misc/tpm0/device/cancel
373  */
374 static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb)
375 {
376     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
377     int fd = -1;
378     char *dev;
379     char path[PATH_MAX];
380
381     if (tb->cancel_path) {
382         fd = qemu_open(tb->cancel_path, O_WRONLY);
383         if (fd < 0) {
384             error_report("Could not open TPM cancel path : %s",
385                          strerror(errno));
386         }
387         return fd;
388     }
389
390     dev = strrchr(tpm_pt->tpm_dev, '/');
391     if (dev) {
392         dev++;
393         if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel",
394                      dev) < sizeof(path)) {
395             fd = qemu_open(path, O_WRONLY);
396             if (fd >= 0) {
397                 tb->cancel_path = g_strdup(path);
398             } else {
399                 error_report("tpm_passthrough: Could not open TPM cancel "
400                              "path %s : %s", path, strerror(errno));
401             }
402         }
403     } else {
404        error_report("tpm_passthrough: Bad TPM device path %s",
405                     tpm_pt->tpm_dev);
406     }
407
408     return fd;
409 }
410
411 static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
412 {
413     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
414     const char *value;
415
416     value = qemu_opt_get(opts, "cancel-path");
417     tb->cancel_path = g_strdup(value);
418
419     value = qemu_opt_get(opts, "path");
420     if (!value) {
421         value = TPM_PASSTHROUGH_DEFAULT_DEVICE;
422     }
423
424     tpm_pt->tpm_dev = g_strdup(value);
425
426     tb->path = g_strdup(tpm_pt->tpm_dev);
427
428     tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR);
429     if (tpm_pt->tpm_fd < 0) {
430         error_report("Cannot access TPM device using '%s': %s",
431                      tpm_pt->tpm_dev, strerror(errno));
432         goto err_free_parameters;
433     }
434
435     if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) {
436         error_report("'%s' is not a TPM device.",
437                      tpm_pt->tpm_dev);
438         goto err_close_tpmdev;
439     }
440
441     return 0;
442
443  err_close_tpmdev:
444     qemu_close(tpm_pt->tpm_fd);
445     tpm_pt->tpm_fd = -1;
446
447  err_free_parameters:
448     g_free(tb->path);
449     tb->path = NULL;
450
451     g_free(tpm_pt->tpm_dev);
452     tpm_pt->tpm_dev = NULL;
453
454     return 1;
455 }
456
457 static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
458 {
459     Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
460     TPMBackend *tb = TPM_BACKEND(obj);
461     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
462
463     tb->id = g_strdup(id);
464     /* let frontend set the fe_model to proper value */
465     tb->fe_model = -1;
466
467     tb->ops = &tpm_passthrough_driver;
468
469     if (tpm_passthrough_handle_device_opts(opts, tb)) {
470         goto err_exit;
471     }
472
473     tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb);
474     if (tpm_pt->cancel_fd < 0) {
475         goto err_exit;
476     }
477
478     return tb;
479
480 err_exit:
481     g_free(tb->id);
482
483     return NULL;
484 }
485
486 static void tpm_passthrough_destroy(TPMBackend *tb)
487 {
488     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
489
490     tpm_passthrough_cancel_cmd(tb);
491
492     tpm_backend_thread_end(&tpm_pt->tbt);
493
494     qemu_close(tpm_pt->tpm_fd);
495     qemu_close(tpm_pt->cancel_fd);
496
497     g_free(tb->id);
498     g_free(tb->path);
499     g_free(tb->cancel_path);
500     g_free(tpm_pt->tpm_dev);
501 }
502
503 static const QemuOptDesc tpm_passthrough_cmdline_opts[] = {
504     TPM_STANDARD_CMDLINE_OPTS,
505     {
506         .name = "cancel-path",
507         .type = QEMU_OPT_STRING,
508         .help = "Sysfs file entry for canceling TPM commands",
509     },
510     {
511         .name = "path",
512         .type = QEMU_OPT_STRING,
513         .help = "Path to TPM device on the host",
514     },
515     { /* end of list */ },
516 };
517
518 static const TPMDriverOps tpm_passthrough_driver = {
519     .type                     = TPM_TYPE_PASSTHROUGH,
520     .opts                     = tpm_passthrough_cmdline_opts,
521     .desc                     = tpm_passthrough_create_desc,
522     .create                   = tpm_passthrough_create,
523     .destroy                  = tpm_passthrough_destroy,
524     .init                     = tpm_passthrough_init,
525     .startup_tpm              = tpm_passthrough_startup_tpm,
526     .realloc_buffer           = tpm_passthrough_realloc_buffer,
527     .reset                    = tpm_passthrough_reset,
528     .had_startup_error        = tpm_passthrough_get_startup_error,
529     .deliver_request          = tpm_passthrough_deliver_request,
530     .cancel_cmd               = tpm_passthrough_cancel_cmd,
531     .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
532     .reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag,
533     .get_tpm_version          = tpm_passthrough_get_tpm_version,
534 };
535
536 static void tpm_passthrough_inst_init(Object *obj)
537 {
538 }
539
540 static void tpm_passthrough_inst_finalize(Object *obj)
541 {
542 }
543
544 static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
545 {
546     TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
547
548     tbc->ops = &tpm_passthrough_driver;
549 }
550
551 static const TypeInfo tpm_passthrough_info = {
552     .name = TYPE_TPM_PASSTHROUGH,
553     .parent = TYPE_TPM_BACKEND,
554     .instance_size = sizeof(TPMPassthruState),
555     .class_init = tpm_passthrough_class_init,
556     .instance_init = tpm_passthrough_inst_init,
557     .instance_finalize = tpm_passthrough_inst_finalize,
558 };
559
560 static void tpm_passthrough_register(void)
561 {
562     type_register_static(&tpm_passthrough_info);
563     tpm_register_driver(&tpm_passthrough_driver);
564 }
565
566 type_init(tpm_passthrough_register)