diff --git a/.gitmodules b/.gitmodules index c213d8b611..c8eada898a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -40,3 +40,6 @@ [submodule "iot-web-layers"] path = iot-web-layers url = https://github.com/intel/iot-web-layers.git +[submodule "meta-measured"] + path = meta-measured + url = https://github.com/flihp/meta-measured.git diff --git a/meta-measured b/meta-measured new file mode 160000 index 0000000000..5f88a6db45 --- /dev/null +++ b/meta-measured @@ -0,0 +1 @@ +Subproject commit 5f88a6db4587589224522d938282b83c52a1409d diff --git a/meta-refkit-core/bbappends/meta-measured/recipes-tpm/tpm2-tss/tpm2-tss_%.bbappend b/meta-refkit-core/bbappends/meta-measured/recipes-tpm/tpm2-tss/tpm2-tss_%.bbappend new file mode 100644 index 0000000000..ae8e16f15c --- /dev/null +++ b/meta-refkit-core/bbappends/meta-measured/recipes-tpm/tpm2-tss/tpm2-tss_%.bbappend @@ -0,0 +1,3 @@ +# Workaround for https://github.com/intel/tpm2-tss/issues/613 +CFLAGS_append_df-refkit-config = " -Wno-error=int-in-bool-context" +CXXFLAGS_append_df-refkit-config = " -Wno-error=int-in-bool-context" diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0001-tpm-Clean-up-driver-registration-lookup.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0001-tpm-Clean-up-driver-registration-lookup.patch new file mode 100644 index 0000000000..1a484b91c3 --- /dev/null +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0001-tpm-Clean-up-driver-registration-lookup.patch @@ -0,0 +1,154 @@ +From a0f8d150794164f41cd7288c9ed059bbf21c95ec Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Thu, 24 Aug 2017 10:45:58 +0200 +Subject: [PATCH 01/12] tpm: Clean up driver registration & lookup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We have a strict separation between enum TpmType and be_drivers[]: + +* TpmType may have any number of members. It just happens to have one. + +* tpm_register_driver() uses the first empty slot in be_drivers[]. + + If you register more than tpm_models[] has space, + tpm_register_driver() fails. Its caller silently ignores the + failure. + + If you register more than one with a given TpmType, + tpm_display_backend_drivers() will shows all of them, but + tpm_driver_find_by_type() and tpm_get_backend_driver() will find + only the one one that registered first. + +Since we only ever register one driver, and be_drivers[] has space for +just that one, this contraption even works. + +Turn be_drivers[] into a straight map from enum TpmType to driver. +Much simpler, and has a decent chance to actually work should we ever +acquire additional drivers. + +While there, use qapi_enum_parse() in tpm_get_backend_driver(). + +Signed-off-by: Marc-André Lureau +Message-Id: <20170822132255.23945-8-marcandre.lureau@redhat.com> +Reviewed-by: Markus Armbruster +[Rebased, superfluous initializer dropped, commit message rewritten] +Cc: Stefan Berger +Signed-off-by: Markus Armbruster +Message-Id: <1503564371-26090-4-git-send-email-armbru@redhat.com> + +Upstream-Status: Backport +--- + include/sysemu/tpm_backend.h | 2 +- + tpm.c | 45 +++++++++++++------------------------------- + 2 files changed, 14 insertions(+), 33 deletions(-) + +diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h +index b58f52d39f..1d21c6b19b 100644 +--- a/include/sysemu/tpm_backend.h ++++ b/include/sysemu/tpm_backend.h +@@ -227,6 +227,6 @@ TPMBackend *qemu_find_tpm(const char *id); + + const TPMDriverOps *tpm_get_backend_driver(const char *type); + int tpm_register_model(enum TpmModel model); +-int tpm_register_driver(const TPMDriverOps *tdo); ++void tpm_register_driver(const TPMDriverOps *tdo); + + #endif +diff --git a/tpm.c b/tpm.c +index 9a7c7114d3..bb45d0c08e 100644 +--- a/tpm.c ++++ b/tpm.c +@@ -14,6 +14,7 @@ + #include "qemu/osdep.h" + + #include "qapi/qmp/qerror.h" ++#include "qapi/util.h" + #include "sysemu/tpm_backend.h" + #include "sysemu/tpm.h" + #include "qemu/config-file.h" +@@ -25,11 +26,8 @@ static QLIST_HEAD(, TPMBackend) tpm_backends = + + + #define TPM_MAX_MODELS 1 +-#define TPM_MAX_DRIVERS 1 + +-static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = { +- NULL, +-}; ++static TPMDriverOps const *be_drivers[TPM_TYPE__MAX]; + + static enum TpmModel tpm_models[TPM_MAX_MODELS] = { + TPM_MODEL__MAX, +@@ -63,31 +61,18 @@ static bool tpm_model_is_registered(enum TpmModel model) + + const TPMDriverOps *tpm_get_backend_driver(const char *type) + { +- int i; +- +- for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) { +- if (!strcmp(TpmType_lookup[be_drivers[i]->type], type)) { +- return be_drivers[i]; +- } +- } ++ int i = qapi_enum_parse(TpmType_lookup, type, TPM_TYPE__MAX, -1, NULL); + +- return NULL; ++ return i >= 0 ? be_drivers[i] : NULL; + } + + #ifdef CONFIG_TPM + +-int tpm_register_driver(const TPMDriverOps *tdo) ++void tpm_register_driver(const TPMDriverOps *tdo) + { +- int i; ++ assert(!be_drivers[tdo->type]); + +- for (i = 0; i < TPM_MAX_DRIVERS; i++) { +- if (!be_drivers[i]) { +- be_drivers[i] = tdo; +- return 0; +- } +- } +- error_report("Could not register TPM driver"); +- return 1; ++ be_drivers[tdo->type] = tdo; + } + + /* +@@ -100,9 +85,12 @@ static void tpm_display_backend_drivers(void) + + fprintf(stderr, "Supported TPM types (choose only one):\n"); + +- for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) { ++ for (i = 0; i < TPM_TYPE__MAX; i++) { ++ if (be_drivers[i] == NULL) { ++ continue; ++ } + fprintf(stderr, "%12s %s\n", +- TpmType_lookup[be_drivers[i]->type], be_drivers[i]->desc()); ++ TpmType_lookup[i], be_drivers[i]->desc()); + } + fprintf(stderr, "\n"); + } +@@ -239,14 +227,7 @@ int tpm_config_parse(QemuOptsList *opts_list, const char *optarg) + + static const TPMDriverOps *tpm_driver_find_by_type(enum TpmType type) + { +- int i; +- +- for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) { +- if (be_drivers[i]->type == type) { +- return be_drivers[i]; +- } +- } +- return NULL; ++ return be_drivers[type]; + } + + static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv) +-- +2.11.0 + diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0002-tpm-Clean-up-model-registration-lookup.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0002-tpm-Clean-up-model-registration-lookup.patch new file mode 100644 index 0000000000..c223ba83b6 --- /dev/null +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0002-tpm-Clean-up-model-registration-lookup.patch @@ -0,0 +1,121 @@ +From 89430c64784484214b3c99562520cdffe79cd801 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Thu, 24 Aug 2017 10:45:59 +0200 +Subject: [PATCH 02/12] tpm: Clean up model registration & lookup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We have a strict separation between enum TpmModel and tpm_models[]: + +* TpmModel may have any number of members. It just happens to have one. + +* tpm_register_model() uses the first empty slot in tpm_models[]. + + If you register more than tpm_models[] has space, + tpn_register_model() fails. Its caller silently ignores the + failure. + + Register the same TpmModel more than once has no effect other than + wasting tpm_models[] slots: tpm_model_is_registered() is happy with + the first one it finds. + +Since we only ever register one model, and tpm_models[] has space for +just that one, this contraption even works. + +Turn tpm_models[] into a straight map from enum TpmType to bool. Much +simpler. + +Cc: Stefan Berger +Signed-off-by: Markus Armbruster +Message-Id: <1503564371-26090-5-git-send-email-armbru@redhat.com> +Reviewed-by: Marc-André Lureau +[Commit message typo fixed] + +Upstream-Status: Backport +--- + include/sysemu/tpm_backend.h | 2 +- + tpm.c | 37 +++++-------------------------------- + 2 files changed, 6 insertions(+), 33 deletions(-) + +diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h +index 1d21c6b19b..b0a9731aee 100644 +--- a/include/sysemu/tpm_backend.h ++++ b/include/sysemu/tpm_backend.h +@@ -226,7 +226,7 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s); + TPMBackend *qemu_find_tpm(const char *id); + + const TPMDriverOps *tpm_get_backend_driver(const char *type); +-int tpm_register_model(enum TpmModel model); ++void tpm_register_model(enum TpmModel model); + void tpm_register_driver(const TPMDriverOps *tdo); + + #endif +diff --git a/tpm.c b/tpm.c +index bb45d0c08e..2dbea70645 100644 +--- a/tpm.c ++++ b/tpm.c +@@ -24,39 +24,12 @@ + static QLIST_HEAD(, TPMBackend) tpm_backends = + QLIST_HEAD_INITIALIZER(tpm_backends); + +- +-#define TPM_MAX_MODELS 1 +- + static TPMDriverOps const *be_drivers[TPM_TYPE__MAX]; ++static bool tpm_models[TPM_MODEL__MAX]; + +-static enum TpmModel tpm_models[TPM_MAX_MODELS] = { +- TPM_MODEL__MAX, +-}; +- +-int tpm_register_model(enum TpmModel model) +-{ +- int i; +- +- for (i = 0; i < TPM_MAX_MODELS; i++) { +- if (tpm_models[i] == TPM_MODEL__MAX) { +- tpm_models[i] = model; +- return 0; +- } +- } +- error_report("Could not register TPM model"); +- return 1; +-} +- +-static bool tpm_model_is_registered(enum TpmModel model) ++void tpm_register_model(enum TpmModel model) + { +- int i; +- +- for (i = 0; i < TPM_MAX_MODELS; i++) { +- if (tpm_models[i] == model) { +- return true; +- } +- } +- return false; ++ tpm_models[model] = true; + } + + const TPMDriverOps *tpm_get_backend_driver(const char *type) +@@ -270,7 +243,7 @@ TPMInfoList *qmp_query_tpm(Error **errp) + TPMInfoList *info, *head = NULL, *cur_item = NULL; + + QLIST_FOREACH(drv, &tpm_backends, list) { +- if (!tpm_model_is_registered(drv->fe_model)) { ++ if (!tpm_models[drv->fe_model]) { + continue; + } + info = g_new0(TPMInfoList, 1); +@@ -317,7 +290,7 @@ TpmModelList *qmp_query_tpm_models(Error **errp) + TpmModelList *head = NULL, *prev = NULL, *cur_item; + + for (i = 0; i < TPM_MODEL__MAX; i++) { +- if (!tpm_model_is_registered(i)) { ++ if (!tpm_models[i]) { + continue; + } + cur_item = g_new0(TpmModelList, 1); +-- +2.11.0 + diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0003-tpm-backend-Initialize-and-free-data-members-in-it-s.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0003-tpm-backend-Initialize-and-free-data-members-in-it-s.patch deleted file mode 100644 index 7b76c67400..0000000000 --- a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0003-tpm-backend-Initialize-and-free-data-members-in-it-s.patch +++ /dev/null @@ -1,114 +0,0 @@ -From cd1452062a2f4754c140bb4c930728d9d5688d13 Mon Sep 17 00:00:00 2001 -From: Amarnath Valluri -Date: Fri, 7 Apr 2017 17:30:25 +0300 -Subject: [PATCH 3/9] tpm-backend: Initialize and free data members in it's own - methods - -Initialize and free TPMBackend data members in it's own instance_init() and -instance_finalize methods. - -Took the opportunity to fix object cleanup in tpm_backend_{create,destroy} -methods - -Signed-off-by: Amarnath Valluri -Upstream-Status: Submitted [http://lists.nongnu.org/archive/html/qemu-devel/2017-04/msg01278.html] -Signed-off-by: Patrick Ohly ---- - backends/tpm.c | 8 ++++++-- - hw/tpm/tpm_passthrough.c | 18 +++++++++++------- - 2 files changed, 17 insertions(+), 9 deletions(-) - -diff --git a/backends/tpm.c b/backends/tpm.c -index 0ec0c672..99d2b2bb 100644 ---- a/backends/tpm.c -+++ b/backends/tpm.c -@@ -57,7 +57,7 @@ void tpm_backend_destroy(TPMBackend *s) - - k->ops->destroy(s); - -- tpm_backend_thread_end(s); -+ object_unref(OBJECT(s)); - } - - int tpm_backend_init(TPMBackend *s, TPMState *state, -@@ -182,11 +182,13 @@ static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp) - - static void tpm_backend_instance_init(Object *obj) - { -+ TPMBackend *s = TPM_BACKEND(obj); -+ - object_property_add_bool(obj, "opened", - tpm_backend_prop_get_opened, - tpm_backend_prop_set_opened, - NULL); -- -+ s->fe_model = -1; - } - - static void tpm_backend_instance_finalize(Object *obj) -@@ -194,6 +196,8 @@ static void tpm_backend_instance_finalize(Object *obj) - TPMBackend *s = TPM_BACKEND(obj); - - g_free(s->id); -+ g_free(s->path); -+ g_free(s->cancel_path); - tpm_backend_thread_end(s); - } - -diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c -index f50d9cff..65831b5b 100644 ---- a/hw/tpm/tpm_passthrough.c -+++ b/hw/tpm/tpm_passthrough.c -@@ -417,8 +417,6 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); - - tb->id = g_strdup(id); -- /* let frontend set the fe_model to proper value */ -- tb->fe_model = -1; - - if (tpm_passthrough_handle_device_opts(opts, tb)) { - goto err_exit; -@@ -432,7 +430,7 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) - return tb; - - err_exit: -- g_free(tb->id); -+ object_unref(obj); - - return NULL; - } -@@ -445,10 +443,6 @@ static void tpm_passthrough_destroy(TPMBackend *tb) - - qemu_close(tpm_pt->tpm_fd); - qemu_close(tpm_pt->cancel_fd); -- -- g_free(tb->id); -- g_free(tb->path); -- g_free(tb->cancel_path); - g_free(tpm_pt->tpm_dev); - } - -@@ -486,10 +480,20 @@ static const TPMDriverOps tpm_passthrough_driver = { - - static void tpm_passthrough_inst_init(Object *obj) - { -+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); -+ -+ tpm_pt->tpm_fd = -1; -+ tpm_pt->cancel_fd = -1; - } - - static void tpm_passthrough_inst_finalize(Object *obj) - { -+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); -+ -+ tpm_passthrough_cancel_cmd(TPM_BACKEND(obj)); -+ -+ qemu_close(tpm_pt->tpm_fd); -+ qemu_close(tpm_pt->cancel_fd); - } - - static void tpm_passthrough_class_init(ObjectClass *klass, void *data) --- -2.11.0 - diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0001-tpm-backend-Remove-unneeded-member-variable-from-bac.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0003-tpm-backend-Remove-unneeded-member-variable-from-bac.patch similarity index 74% rename from meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0001-tpm-backend-Remove-unneeded-member-variable-from-bac.patch rename to meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0003-tpm-backend-Remove-unneeded-member-variable-from-bac.patch index 34e312aac1..6b94eba720 100644 --- a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0001-tpm-backend-Remove-unneeded-member-variable-from-bac.patch +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0003-tpm-backend-Remove-unneeded-member-variable-from-bac.patch @@ -1,8 +1,11 @@ -From d7b3a351f47517ee04d218789d2ce3a929fb52a9 Mon Sep 17 00:00:00 2001 +From cac845f55b8f27e5c90e0f2e3dcbeea7013df67c Mon Sep 17 00:00:00 2001 From: Amarnath Valluri -Date: Fri, 7 Apr 2017 17:30:23 +0300 -Subject: [PATCH 1/9] tpm-backend: Remove unneeded member variable from backend - class +Date: Thu, 30 Mar 2017 15:55:17 +0300 +Subject: [PATCH 03/12] tpm-backend: Remove unneeded member variable from + backend class +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit TPMDriverOps inside TPMBackend is not required, as it is supposed to be a class member. The only possible reason for keeping in TPMBackend was, to get the @@ -10,8 +13,10 @@ backend type in tpm.c where dedicated backend api, tpm_backend_get_type() is present. Signed-off-by: Amarnath Valluri -Upstream-Status: Submitted [http://lists.nongnu.org/archive/html/qemu-devel/2017-04/msg01278.html] -Signed-off-by: Patrick Ohly +Reviewed-by: Marc-André Lureau +Reviewed-by: Stefan Berger + +Upstream-Status: Backport [fb4b0c6765471dad2363875989e7661ca5f9a608] --- hw/tpm/tpm_passthrough.c | 4 ---- include/sysemu/tpm_backend.h | 1 - @@ -19,7 +24,7 @@ Signed-off-by: Patrick Ohly 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c -index 9234eb34..a0baf5f0 100644 +index 9234eb3459..a0baf5f080 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -46,8 +46,6 @@ @@ -41,7 +46,7 @@ index 9234eb34..a0baf5f0 100644 goto err_exit; } diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h -index b58f52d3..e7f590db 100644 +index b0a9731aee..3708413035 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -50,7 +50,6 @@ struct TPMBackend { @@ -53,10 +58,10 @@ index b58f52d3..e7f590db 100644 QLIST_ENTRY(TPMBackend) list; }; diff --git a/tpm.c b/tpm.c -index 9a7c7114..0ee021a3 100644 +index 2dbea70645..b7166ca200 100644 --- a/tpm.c +++ b/tpm.c -@@ -258,7 +258,7 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv) +@@ -212,7 +212,7 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv) res->model = drv->fe_model; res->options = g_new0(TpmTypeOptions, 1); diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0004-tpm-backend-Made-few-interface-methods-optional.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0004-tpm-backend-Made-few-interface-methods-optional.patch deleted file mode 100644 index 101d1d0100..0000000000 --- a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0004-tpm-backend-Made-few-interface-methods-optional.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 1fd3dd2ff16cf3be6ee512f0c0ece542e4396549 Mon Sep 17 00:00:00 2001 -From: Amarnath Valluri -Date: Fri, 7 Apr 2017 17:30:26 +0300 -Subject: [PATCH 4/9] tpm-backend: Made few interface methods optional - -This allows backend implementations left optional interface methods. -For mandatory methods assertion checks added. - -Signed-off-by: Amarnath Valluri -Upstream-Status: Submitted [http://lists.nongnu.org/archive/html/qemu-devel/2017-04/msg01278.html] -Signed-off-by: Patrick Ohly ---- - backends/tpm.c | 28 +++++++++++++++++++++------- - hw/tpm/tpm_passthrough.c | 16 ---------------- - 2 files changed, 21 insertions(+), 23 deletions(-) - -diff --git a/backends/tpm.c b/backends/tpm.c -index 99d2b2bb..c2be17b8 100644 ---- a/backends/tpm.c -+++ b/backends/tpm.c -@@ -48,14 +48,16 @@ const char *tpm_backend_get_desc(TPMBackend *s) - { - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - -- return k->ops->desc(); -+ return k->ops->desc ? k->ops->desc() : ""; - } - - void tpm_backend_destroy(TPMBackend *s) - { - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - -- k->ops->destroy(s); -+ if (k->ops->destroy) { -+ k->ops->destroy(s); -+ } - - object_unref(OBJECT(s)); - } -@@ -68,7 +70,7 @@ int tpm_backend_init(TPMBackend *s, TPMState *state, - s->tpm_state = state; - s->recv_data_callback = datacb; - -- return k->ops->init(s); -+ return k->ops->init ? k->ops->init(s) : 0; - } - - int tpm_backend_startup_tpm(TPMBackend *s) -@@ -82,13 +84,15 @@ int tpm_backend_startup_tpm(TPMBackend *s) - NULL); - g_thread_pool_push(s->thread_pool, (gpointer)TPM_BACKEND_CMD_INIT, NULL); - -- return k->ops->startup_tpm(s); -+ return k->ops->startup_tpm ? k->ops->startup_tpm(s) : 0; - } - - bool tpm_backend_had_startup_error(TPMBackend *s) - { - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - -+ assert(k->ops->had_startup_error); -+ - return k->ops->had_startup_error(s); - } - -@@ -96,6 +100,8 @@ size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb) - { - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - -+ assert(k->ops->realloc_buffer); -+ - return k->ops->realloc_buffer(sb); - } - -@@ -109,7 +115,9 @@ void tpm_backend_reset(TPMBackend *s) - { - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - -- k->ops->reset(s); -+ if (k->ops->reset) { -+ k->ops->reset(s); -+ } - - tpm_backend_thread_end(s); - } -@@ -118,6 +126,8 @@ void tpm_backend_cancel_cmd(TPMBackend *s) - { - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - -+ g_assert(k->ops->cancel_cmd); -+ - k->ops->cancel_cmd(s); - } - -@@ -125,20 +135,24 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s) - { - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - -- return k->ops->get_tpm_established_flag(s); -+ return k->ops->get_tpm_established_flag ? -+ k->ops->get_tpm_established_flag(s) : false; - } - - int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty) - { - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - -- return k->ops->reset_tpm_established_flag(s, locty); -+ return k->ops->reset_tpm_established_flag ? -+ k->ops->reset_tpm_established_flag(s, locty) : 0; - } - - TPMVersion tpm_backend_get_tpm_version(TPMBackend *s) - { - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - -+ assert(k->ops->get_tpm_version); -+ - return k->ops->get_tpm_version(s); - } - -diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c -index 65831b5b..0f543bd7 100644 ---- a/hw/tpm/tpm_passthrough.c -+++ b/hw/tpm/tpm_passthrough.c -@@ -227,15 +227,6 @@ static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd cmd) - } - } - --/* -- * Start the TPM (thread). If it had been started before, then terminate -- * and start it again. -- */ --static int tpm_passthrough_startup_tpm(TPMBackend *tb) --{ -- return 0; --} -- - static void tpm_passthrough_reset(TPMBackend *tb) - { - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); -@@ -247,11 +238,6 @@ static void tpm_passthrough_reset(TPMBackend *tb) - tpm_pt->had_startup_error = false; - } - --static int tpm_passthrough_init(TPMBackend *tb) --{ -- return 0; --} -- - static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb) - { - return false; -@@ -467,8 +453,6 @@ static const TPMDriverOps tpm_passthrough_driver = { - .desc = tpm_passthrough_create_desc, - .create = tpm_passthrough_create, - .destroy = tpm_passthrough_destroy, -- .init = tpm_passthrough_init, -- .startup_tpm = tpm_passthrough_startup_tpm, - .realloc_buffer = tpm_passthrough_realloc_buffer, - .reset = tpm_passthrough_reset, - .had_startup_error = tpm_passthrough_get_startup_error, --- -2.11.0 - diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0002-tpm-backend-Move-thread-handling-inside-TPMBackend.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0004-tpm-backend-Move-thread-handling-inside-TPMBackend.patch similarity index 92% rename from meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0002-tpm-backend-Move-thread-handling-inside-TPMBackend.patch rename to meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0004-tpm-backend-Move-thread-handling-inside-TPMBackend.patch index 3f19785b5c..64e88b6de9 100644 --- a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0002-tpm-backend-Move-thread-handling-inside-TPMBackend.patch +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0004-tpm-backend-Move-thread-handling-inside-TPMBackend.patch @@ -1,7 +1,10 @@ -From 1504562008f80e5b3acf19222046e123114c5055 Mon Sep 17 00:00:00 2001 +From 5767322022d54ceb5a2ed6c650f667a4d24aa150 Mon Sep 17 00:00:00 2001 From: Amarnath Valluri -Date: Fri, 7 Apr 2017 17:30:24 +0300 -Subject: [PATCH 2/9] tpm-backend: Move thread handling inside TPMBackend +Date: Thu, 30 Mar 2017 16:20:25 +0300 +Subject: [PATCH 04/12] tpm-backend: Move thread handling inside TPMBackend +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit Move thread handling inside TPMBackend, this way backend implementations need not to maintain their own thread life cycle, instead they needs to implement @@ -10,18 +13,20 @@ not to maintain their own thread life cycle, instead they needs to implement This change made tpm_backend_int.h kind of useless, hence removed it. Signed-off-by: Amarnath Valluri -Upstream-Status: Submitted [http://lists.nongnu.org/archive/html/qemu-devel/2017-04/msg01278.html] -Signed-off-by: Patrick Ohly +Reviewed-by: Marc-André Lureau +Reviewed-by: Stefan Berger + +Upstream-Status: Backport [b19a5eea5a26e9bd83a48c742172d2a6aa8c4180] --- - backends/tpm.c | 63 +++++++++++++++++++++++++--------------- - hw/tpm/tpm_passthrough.c | 58 +++++------------------------------- - include/sysemu/tpm_backend.h | 32 ++++++++++++-------- + backends/tpm.c | 62 +++++++++++++++++++++++++--------------- + hw/tpm/tpm_passthrough.c | 58 ++++++------------------------------- + include/sysemu/tpm_backend.h | 32 +++++++++++++-------- include/sysemu/tpm_backend_int.h | 41 -------------------------- - 4 files changed, 68 insertions(+), 126 deletions(-) + 4 files changed, 67 insertions(+), 126 deletions(-) delete mode 100644 include/sysemu/tpm_backend_int.h diff --git a/backends/tpm.c b/backends/tpm.c -index 536f262b..0ec0c672 100644 +index 536f262bb7..ce56c3b74d 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -18,7 +18,24 @@ @@ -35,7 +40,7 @@ index 536f262b..0ec0c672 100644 + TPMBackend *s = TPM_BACKEND(user_data); + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + -+ assert (k->handle_request != NULL); ++ assert(k->handle_request != NULL); + k->handle_request(s, (TPMBackendCmd)data); +} + @@ -105,7 +110,7 @@ index 536f262b..0ec0c672 100644 } void tpm_backend_cancel_cmd(TPMBackend *s) -@@ -156,29 +186,15 @@ static void tpm_backend_instance_init(Object *obj) +@@ -156,29 +186,14 @@ static void tpm_backend_instance_init(Object *obj) tpm_backend_prop_get_opened, tpm_backend_prop_set_opened, NULL); @@ -134,12 +139,11 @@ index 536f262b..0ec0c672 100644 - g_thread_pool_free(tbt->pool, FALSE, TRUE); - tbt->pool = NULL; - } -+ g_free(s->id); + tpm_backend_thread_end(s); } static const TypeInfo tpm_backend_info = { -@@ -186,6 +202,7 @@ static const TypeInfo tpm_backend_info = { +@@ -186,6 +201,7 @@ static const TypeInfo tpm_backend_info = { .parent = TYPE_OBJECT, .instance_size = sizeof(TPMBackend), .instance_init = tpm_backend_instance_init, @@ -148,7 +152,7 @@ index 536f262b..0ec0c672 100644 .abstract = true, }; diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c -index a0baf5f0..f50d9cff 100644 +index a0baf5f080..f50d9cffd7 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -30,7 +30,6 @@ @@ -290,7 +294,7 @@ index a0baf5f0..f50d9cff 100644 static const TypeInfo tpm_passthrough_info = { diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h -index e7f590db..a538a7f9 100644 +index 3708413035..58308b3687 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -29,22 +29,24 @@ @@ -363,7 +367,7 @@ index e7f590db..a538a7f9 100644 void (*cancel_cmd)(TPMBackend *t); diff --git a/include/sysemu/tpm_backend_int.h b/include/sysemu/tpm_backend_int.h deleted file mode 100644 -index 00639dd7..00000000 +index 00639dd7de..0000000000 --- a/include/sysemu/tpm_backend_int.h +++ /dev/null @@ -1,41 +0,0 @@ diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0005-tmp-backend-Add-new-api-to-read-backend-TpmInfo.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0005-tmp-backend-Add-new-api-to-read-backend-TpmInfo.patch deleted file mode 100644 index 938fcc1c11..0000000000 --- a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0005-tmp-backend-Add-new-api-to-read-backend-TpmInfo.patch +++ /dev/null @@ -1,413 +0,0 @@ -From dd5bd4e05a606db898e0d14478826479f2b3a126 Mon Sep 17 00:00:00 2001 -From: Amarnath Valluri -Date: Fri, 7 Apr 2017 17:30:27 +0300 -Subject: [PATCH 5/9] tmp backend: Add new api to read backend TpmInfo - -TPM configuration options are backend implementation details and shall not be -part of base TPMBackend object, and these shall not be accessed directly outside -of the class, hence added a new interface method, get_tpm_options() to -TPMDriverOps., which shall be implemented by the derived classes to return -configured tpm options. - -A new tpm backend api - tpm_backend_query_tpm() which uses _get_tpm_options() to -prepare TpmInfo. - -Made TPMPassthroughOptions type inherited from newly defined TPMOptions base type. -The TPMOptions base type is intentionally left empty and supposed to be -inherited by all backend implementations to define their tpm configuration -options. - -Signed-off-by: Amarnath Valluri -Upstream-Status: Submitted [http://lists.nongnu.org/archive/html/qemu-devel/2017-04/msg01278.html] -Signed-off-by: Patrick Ohly ---- - backends/tpm.c | 24 +++++++++++++++++-- - hmp.c | 10 ++++---- - hw/tpm/tpm_passthrough.c | 57 +++++++++++++++++++++++++++++++++++--------- - include/sysemu/tpm_backend.h | 25 +++++++++++++++++-- - qapi-schema.json | 30 ++++++++++++----------- - tpm.c | 32 +------------------------ - 6 files changed, 113 insertions(+), 65 deletions(-) - -diff --git a/backends/tpm.c b/backends/tpm.c -index c2be17b8..c96f4627 100644 ---- a/backends/tpm.c -+++ b/backends/tpm.c -@@ -156,6 +156,28 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s) - return k->ops->get_tpm_version(s); - } - -+TPMOptions *tpm_backend_get_tpm_options(TPMBackend *s) -+{ -+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); -+ -+ assert(k->ops->get_tpm_options); -+ -+ return k->ops->get_tpm_options(s); -+} -+ -+TPMInfo *tpm_backend_query_tpm(TPMBackend *s) -+{ -+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); -+ TPMInfo *info = g_new0(TPMInfo, 1); -+ -+ info->type = k->ops->type; -+ info->id = g_strdup(s->id); -+ info->model = s->fe_model; -+ info->options = tpm_backend_get_tpm_options(s); -+ -+ return info; -+} -+ - static bool tpm_backend_prop_get_opened(Object *obj, Error **errp) - { - TPMBackend *s = TPM_BACKEND(obj); -@@ -210,8 +232,6 @@ static void tpm_backend_instance_finalize(Object *obj) - TPMBackend *s = TPM_BACKEND(obj); - - g_free(s->id); -- g_free(s->path); -- g_free(s->cancel_path); - tpm_backend_thread_end(s); - } - -diff --git a/hmp.c b/hmp.c -index b8696170..8bf42dbd 100644 ---- a/hmp.c -+++ b/hmp.c -@@ -954,18 +954,18 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) - c, TpmModel_lookup[ti->model]); - - monitor_printf(mon, " \\ %s: type=%s", -- ti->id, TpmTypeOptionsKind_lookup[ti->options->type]); -+ ti->id, TpmType_lookup[ti->type]); - -- switch (ti->options->type) { -- case TPM_TYPE_OPTIONS_KIND_PASSTHROUGH: -- tpo = ti->options->u.passthrough.data; -+ switch (ti->type) { -+ case TPM_TYPE_PASSTHROUGH: -+ tpo = (TPMPassthroughOptions *)ti->options; - monitor_printf(mon, "%s%s%s%s", - tpo->has_path ? ",path=" : "", - tpo->has_path ? tpo->path : "", - tpo->has_cancel_path ? ",cancel-path=" : "", - tpo->has_cancel_path ? tpo->cancel_path : ""); - break; -- case TPM_TYPE_OPTIONS_KIND__MAX: -+ default: - break; - } - monitor_printf(mon, "\n"); -diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c -index 0f543bd7..71bdf255 100644 ---- a/hw/tpm/tpm_passthrough.c -+++ b/hw/tpm/tpm_passthrough.c -@@ -49,6 +49,7 @@ - struct TPMPassthruState { - TPMBackend parent; - -+ TPMPassthroughOptions *ops; - char *tpm_dev; - int tpm_fd; - bool tpm_executing; -@@ -313,15 +314,14 @@ static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb) - * in Documentation/ABI/stable/sysfs-class-tpm. - * From /dev/tpm0 create /sys/class/misc/tpm0/device/cancel - */ --static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb) -+static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt) - { -- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); - int fd = -1; - char *dev; - char path[PATH_MAX]; - -- if (tb->cancel_path) { -- fd = qemu_open(tb->cancel_path, O_WRONLY); -+ if (tpm_pt->ops->cancel_path) { -+ fd = qemu_open(tpm_pt->ops->cancel_path, O_WRONLY); - if (fd < 0) { - error_report("Could not open TPM cancel path : %s", - strerror(errno)); -@@ -336,7 +336,7 @@ static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb) - dev) < sizeof(path)) { - fd = qemu_open(path, O_WRONLY); - if (fd >= 0) { -- tb->cancel_path = g_strdup(path); -+ tpm_pt->ops->cancel_path = g_strdup(path); - } else { - error_report("tpm_passthrough: Could not open TPM cancel " - "path %s : %s", path, strerror(errno)); -@@ -356,17 +356,24 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) - const char *value; - - value = qemu_opt_get(opts, "cancel-path"); -- tb->cancel_path = g_strdup(value); -+ if (value) { -+ tpm_pt->ops->cancel_path = g_strdup(value); -+ tpm_pt->ops->has_cancel_path = true; -+ } else { -+ tpm_pt->ops->has_cancel_path = false; -+ } - - value = qemu_opt_get(opts, "path"); - if (!value) { - value = TPM_PASSTHROUGH_DEFAULT_DEVICE; -+ tpm_pt->ops->has_path = false; -+ } else { -+ tpm_pt->ops->has_path = true; - } - -+ tpm_pt->ops->path = g_strdup(value); - tpm_pt->tpm_dev = g_strdup(value); - -- tb->path = g_strdup(tpm_pt->tpm_dev); -- - tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR); - if (tpm_pt->tpm_fd < 0) { - error_report("Cannot access TPM device using '%s': %s", -@@ -387,8 +394,8 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) - tpm_pt->tpm_fd = -1; - - err_free_parameters: -- g_free(tb->path); -- tb->path = NULL; -+ g_free(tpm_pt->ops->path); -+ tpm_pt->ops->path = NULL; - - g_free(tpm_pt->tpm_dev); - tpm_pt->tpm_dev = NULL; -@@ -408,7 +415,7 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) - goto err_exit; - } - -- tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb); -+ tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt); - if (tpm_pt->cancel_fd < 0) { - goto err_exit; - } -@@ -430,6 +437,30 @@ static void tpm_passthrough_destroy(TPMBackend *tb) - qemu_close(tpm_pt->tpm_fd); - qemu_close(tpm_pt->cancel_fd); - g_free(tpm_pt->tpm_dev); -+ -+ qapi_free_TPMPassthroughOptions(tpm_pt->ops); -+} -+ -+static TPMOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb) -+{ -+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); -+ TPMPassthroughOptions *ops = g_new0(TPMPassthroughOptions, 1); -+ -+ if (!ops) { -+ return NULL; -+ } -+ -+ if (tpm_pt->ops->has_path) { -+ ops->has_path = true; -+ ops->path = g_strdup(tpm_pt->ops->path); -+ } -+ -+ if (tpm_pt->ops->has_cancel_path) { -+ ops->has_cancel_path = true; -+ ops->cancel_path = g_strdup(tpm_pt->ops->cancel_path); -+ } -+ -+ return (TPMOptions *)ops; - } - - static const QemuOptDesc tpm_passthrough_cmdline_opts[] = { -@@ -460,12 +491,14 @@ static const TPMDriverOps tpm_passthrough_driver = { - .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag, - .reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag, - .get_tpm_version = tpm_passthrough_get_tpm_version, -+ .get_tpm_options = tpm_passthrough_get_tpm_options, - }; - - static void tpm_passthrough_inst_init(Object *obj) - { - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); - -+ tpm_pt->ops = g_new0(TPMPassthroughOptions, 1); - tpm_pt->tpm_fd = -1; - tpm_pt->cancel_fd = -1; - } -@@ -478,6 +511,8 @@ static void tpm_passthrough_inst_finalize(Object *obj) - - qemu_close(tpm_pt->tpm_fd); - qemu_close(tpm_pt->cancel_fd); -+ -+ qapi_free_TPMPassthroughOptions(tpm_pt->ops); - } - - static void tpm_passthrough_class_init(ObjectClass *klass, void *data) -diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h -index a538a7f9..7f4d6215 100644 ---- a/include/sysemu/tpm_backend.h -+++ b/include/sysemu/tpm_backend.h -@@ -48,10 +48,9 @@ struct TPMBackend { - GThreadPool *thread_pool; - TPMRecvDataCB *recv_data_callback; - -+ /* */ - char *id; - enum TpmModel fe_model; -- char *path; -- char *cancel_path; - - QLIST_ENTRY(TPMBackend) list; - }; -@@ -98,6 +97,8 @@ struct TPMDriverOps { - int (*reset_tpm_established_flag)(TPMBackend *t, uint8_t locty); - - TPMVersion (*get_tpm_version)(TPMBackend *t); -+ -+ TPMOptions *(*get_tpm_options)(TPMBackend *t); - }; - - -@@ -230,6 +231,26 @@ void tpm_backend_open(TPMBackend *s, Error **errp); - */ - TPMVersion tpm_backend_get_tpm_version(TPMBackend *s); - -+/** -+ * tpm_backend_get_tpm_options: -+ * @s: the backend -+ * -+ * Get the backend configuration options -+ * -+ * Returns newly allocated TPMOptions -+ */ -+TPMOptions *tpm_backend_get_tpm_options(TPMBackend *s); -+ -+/** -+ * tpm_backend_query_tpm: -+ * @s: the backend -+ * -+ * Query backend tpm info -+ * -+ * Returns newly allocated TPMInfo -+ */ -+TPMInfo *tpm_backend_query_tpm(TPMBackend *s); -+ - TPMBackend *qemu_find_tpm(const char *id); - - const TPMDriverOps *tpm_get_backend_driver(const char *type); -diff --git a/qapi-schema.json b/qapi-schema.json -index a0d3b5d7..d50d49e5 100644 ---- a/qapi-schema.json -+++ b/qapi-schema.json -@@ -3976,6 +3976,16 @@ - { 'command': 'query-tpm-types', 'returns': ['TpmType'] } - - ## -+# @TPMOptions: -+# -+# Base type for TPM options -+# -+# Since: 2.10 -+## -+{ 'struct': 'TPMOptions', -+ 'data': { } } -+ -+## - # @TPMPassthroughOptions: - # - # Information about the TPM passthrough type -@@ -3987,20 +3997,9 @@ - # - # Since: 1.5 - ## --{ 'struct': 'TPMPassthroughOptions', 'data': { '*path' : 'str', -- '*cancel-path' : 'str'} } -+{ 'struct': 'TPMPassthroughOptions', 'base': 'TPMOptions', -+ 'data': { '*path' : 'str', '*cancel-path' : 'str'} } - --## --# @TpmTypeOptions: --# --# A union referencing different TPM backend types' configuration options --# --# @type: 'passthrough' The configuration options for the TPM passthrough type --# --# Since: 1.5 --## --{ 'union': 'TpmTypeOptions', -- 'data': { 'passthrough' : 'TPMPassthroughOptions' } } - - ## - # @TPMInfo: -@@ -4009,6 +4008,8 @@ - # - # @id: The Id of the TPM - # -+# @type: The TPM backend type -+# - # @model: The TPM frontend model - # - # @options: The TPM (backend) type configuration options -@@ -4017,8 +4018,9 @@ - ## - { 'struct': 'TPMInfo', - 'data': {'id': 'str', -+ 'type': 'TpmType', - 'model': 'TpmModel', -- 'options': 'TpmTypeOptions' } } -+ 'options': 'TPMOptions' } } - - ## - # @query-tpm: -diff --git a/tpm.c b/tpm.c -index 0ee021a3..1b6b5509 100644 ---- a/tpm.c -+++ b/tpm.c -@@ -249,36 +249,6 @@ static const TPMDriverOps *tpm_driver_find_by_type(enum TpmType type) - return NULL; - } - --static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv) --{ -- TPMInfo *res = g_new0(TPMInfo, 1); -- TPMPassthroughOptions *tpo; -- -- res->id = g_strdup(drv->id); -- res->model = drv->fe_model; -- res->options = g_new0(TpmTypeOptions, 1); -- -- switch (tpm_backend_get_type(drv)) { -- case TPM_TYPE_PASSTHROUGH: -- res->options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH; -- tpo = g_new0(TPMPassthroughOptions, 1); -- res->options->u.passthrough.data = tpo; -- if (drv->path) { -- tpo->path = g_strdup(drv->path); -- tpo->has_path = true; -- } -- if (drv->cancel_path) { -- tpo->cancel_path = g_strdup(drv->cancel_path); -- tpo->has_cancel_path = true; -- } -- break; -- case TPM_TYPE__MAX: -- break; -- } -- -- return res; --} -- - /* - * Walk the list of active TPM backends and collect information about them - * following the schema description in qapi-schema.json. -@@ -293,7 +263,7 @@ TPMInfoList *qmp_query_tpm(Error **errp) - continue; - } - info = g_new0(TPMInfoList, 1); -- info->value = qmp_query_tpm_inst(drv); -+ info->value = tpm_backend_query_tpm(drv); - - if (!cur_item) { - head = cur_item = info; --- -2.11.0 - diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0005-tpm-backend-Initialize-and-free-data-members-in-it-s.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0005-tpm-backend-Initialize-and-free-data-members-in-it-s.patch new file mode 100644 index 0000000000..91dd542f45 --- /dev/null +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0005-tpm-backend-Initialize-and-free-data-members-in-it-s.patch @@ -0,0 +1,185 @@ +From 83ef052c60de271a97abb7eb9b5a8aeee52659e6 Mon Sep 17 00:00:00 2001 +From: Amarnath Valluri +Date: Fri, 31 Mar 2017 10:58:11 +0300 +Subject: [PATCH 05/12] tpm-backend: Initialize and free data members in it's + own methods +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Initialize and free TPMBackend data members in it's own instance_init() and +instance_finalize methods. + +Took the opportunity to remove unneeded destroy() method from TpmDriverOps +interface as TPMBackend is a Qemu Object, we can use object_unref() inplace of +tpm_backend_destroy() to free the backend object, hence removed destroy() from +TPMDriverOps interface. + +Signed-off-by: Amarnath Valluri +Reviewed-by: Marc-André Lureau +Reviewed-by: Stefan Berger + +Upstream-Status: Backport [f35fe5cb97bbdaa6a6967f2fefc3fc1f79680601] +--- + backends/tpm.c | 16 ++++++---------- + hw/tpm/tpm_passthrough.c | 31 ++++++++++++------------------- + include/sysemu/tpm_backend.h | 7 ------- + tpm.c | 2 +- + 4 files changed, 19 insertions(+), 37 deletions(-) + +diff --git a/backends/tpm.c b/backends/tpm.c +index ce56c3b74d..cf5abf1582 100644 +--- a/backends/tpm.c ++++ b/backends/tpm.c +@@ -51,15 +51,6 @@ const char *tpm_backend_get_desc(TPMBackend *s) + return k->ops->desc(); + } + +-void tpm_backend_destroy(TPMBackend *s) +-{ +- TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); +- +- k->ops->destroy(s); +- +- tpm_backend_thread_end(s); +-} +- + int tpm_backend_init(TPMBackend *s, TPMState *state, + TPMRecvDataCB *datacb) + { +@@ -182,17 +173,22 @@ static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp) + + static void tpm_backend_instance_init(Object *obj) + { ++ TPMBackend *s = TPM_BACKEND(obj); ++ + object_property_add_bool(obj, "opened", + tpm_backend_prop_get_opened, + tpm_backend_prop_set_opened, + NULL); +- ++ s->fe_model = -1; + } + + static void tpm_backend_instance_finalize(Object *obj) + { + TPMBackend *s = TPM_BACKEND(obj); + ++ g_free(s->id); ++ g_free(s->path); ++ g_free(s->cancel_path); + tpm_backend_thread_end(s); + } + +diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c +index f50d9cffd7..815a72ef9a 100644 +--- a/hw/tpm/tpm_passthrough.c ++++ b/hw/tpm/tpm_passthrough.c +@@ -417,8 +417,6 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); + + tb->id = g_strdup(id); +- /* let frontend set the fe_model to proper value */ +- tb->fe_model = -1; + + if (tpm_passthrough_handle_device_opts(opts, tb)) { + goto err_exit; +@@ -432,26 +430,11 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) + return tb; + + err_exit: +- g_free(tb->id); ++ object_unref(obj); + + return NULL; + } + +-static void tpm_passthrough_destroy(TPMBackend *tb) +-{ +- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); +- +- tpm_passthrough_cancel_cmd(tb); +- +- qemu_close(tpm_pt->tpm_fd); +- qemu_close(tpm_pt->cancel_fd); +- +- g_free(tb->id); +- g_free(tb->path); +- g_free(tb->cancel_path); +- g_free(tpm_pt->tpm_dev); +-} +- + static const QemuOptDesc tpm_passthrough_cmdline_opts[] = { + TPM_STANDARD_CMDLINE_OPTS, + { +@@ -472,7 +455,6 @@ static const TPMDriverOps tpm_passthrough_driver = { + .opts = tpm_passthrough_cmdline_opts, + .desc = tpm_passthrough_create_desc, + .create = tpm_passthrough_create, +- .destroy = tpm_passthrough_destroy, + .init = tpm_passthrough_init, + .startup_tpm = tpm_passthrough_startup_tpm, + .realloc_buffer = tpm_passthrough_realloc_buffer, +@@ -486,10 +468,21 @@ static const TPMDriverOps tpm_passthrough_driver = { + + static void tpm_passthrough_inst_init(Object *obj) + { ++ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); ++ ++ tpm_pt->tpm_fd = -1; ++ tpm_pt->cancel_fd = -1; + } + + static void tpm_passthrough_inst_finalize(Object *obj) + { ++ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); ++ ++ tpm_passthrough_cancel_cmd(TPM_BACKEND(obj)); ++ ++ qemu_close(tpm_pt->tpm_fd); ++ qemu_close(tpm_pt->cancel_fd); ++ g_free(tpm_pt->tpm_dev); + } + + static void tpm_passthrough_class_init(ObjectClass *klass, void *data) +diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h +index 58308b3687..202ec8d5a2 100644 +--- a/include/sysemu/tpm_backend.h ++++ b/include/sysemu/tpm_backend.h +@@ -78,7 +78,6 @@ struct TPMDriverOps { + const char *(*desc)(void); + + TPMBackend *(*create)(QemuOpts *opts, const char *id); +- void (*destroy)(TPMBackend *t); + + /* initialize the backend */ + int (*init)(TPMBackend *t); +@@ -118,12 +117,6 @@ enum TpmType tpm_backend_get_type(TPMBackend *s); + const char *tpm_backend_get_desc(TPMBackend *s); + + /** +- * tpm_backend_destroy: +- * @s: the backend to destroy +- */ +-void tpm_backend_destroy(TPMBackend *s); +- +-/** + * tpm_backend_init: + * @s: the backend to initialized + * @state: TPMState +diff --git a/tpm.c b/tpm.c +index b7166ca200..7feb3b43c9 100644 +--- a/tpm.c ++++ b/tpm.c +@@ -158,7 +158,7 @@ void tpm_cleanup(void) + + QLIST_FOREACH_SAFE(drv, &tpm_backends, list, next) { + QLIST_REMOVE(drv, list); +- tpm_backend_destroy(drv); ++ object_unref(OBJECT(drv)); + } + } + +-- +2.11.0 + diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0006-tpm-backend-Made-few-interface-methods-optional.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0006-tpm-backend-Made-few-interface-methods-optional.patch new file mode 100644 index 0000000000..eb456f01c7 --- /dev/null +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0006-tpm-backend-Made-few-interface-methods-optional.patch @@ -0,0 +1,284 @@ +From 47e6ef6586401e82e652f3c013a349bba3a0479b Mon Sep 17 00:00:00 2001 +From: Amarnath Valluri +Date: Thu, 30 Mar 2017 18:04:16 +0300 +Subject: [PATCH 06/12] tpm-backend: Made few interface methods optional +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows backend implementations left optional interface methods. +For mandatory methods assertion checks added. + +Took the opportunity to remove unused methods: + - tpm_backend_get_desc() + - TPMDriverOps->handle_startup_error + +Signed-off-by: Amarnath Valluri +Reviewed-by: Marc-André Lureau +Reviewed-by: Stefan Berger + +Upstream-Status: Backport [93330cf542b920b6ea5fea8120a08b76bb353113] +--- + backends/tpm.c | 39 ++++++++++++++++++++++++--------------- + hw/tpm/tpm_passthrough.c | 36 +----------------------------------- + include/sysemu/tpm_backend.h | 13 ++----------- + tpm.c | 2 +- + 4 files changed, 28 insertions(+), 62 deletions(-) + +diff --git a/backends/tpm.c b/backends/tpm.c +index cf5abf1582..8911597fab 100644 +--- a/backends/tpm.c ++++ b/backends/tpm.c +@@ -44,13 +44,6 @@ enum TpmType tpm_backend_get_type(TPMBackend *s) + return k->ops->type; + } + +-const char *tpm_backend_get_desc(TPMBackend *s) +-{ +- TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); +- +- return k->ops->desc(); +-} +- + int tpm_backend_init(TPMBackend *s, TPMState *state, + TPMRecvDataCB *datacb) + { +@@ -58,12 +51,14 @@ int tpm_backend_init(TPMBackend *s, TPMState *state, + + s->tpm_state = state; + s->recv_data_callback = datacb; ++ s->had_startup_error = false; + +- return k->ops->init(s); ++ return k->ops->init ? k->ops->init(s) : 0; + } + + int tpm_backend_startup_tpm(TPMBackend *s) + { ++ int res = 0; + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + /* terminate a running TPM */ +@@ -73,20 +68,24 @@ int tpm_backend_startup_tpm(TPMBackend *s) + NULL); + g_thread_pool_push(s->thread_pool, (gpointer)TPM_BACKEND_CMD_INIT, NULL); + +- return k->ops->startup_tpm(s); ++ res = k->ops->startup_tpm ? k->ops->startup_tpm(s) : 0; ++ ++ s->had_startup_error = (res != 0); ++ ++ return res; + } + + bool tpm_backend_had_startup_error(TPMBackend *s) + { +- TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); +- +- return k->ops->had_startup_error(s); ++ return s->had_startup_error; + } + + size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb) + { + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + ++ assert(k->ops->realloc_buffer); ++ + return k->ops->realloc_buffer(sb); + } + +@@ -100,15 +99,21 @@ void tpm_backend_reset(TPMBackend *s) + { + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + +- k->ops->reset(s); ++ if (k->ops->reset) { ++ k->ops->reset(s); ++ } + + tpm_backend_thread_end(s); ++ ++ s->had_startup_error = false; + } + + void tpm_backend_cancel_cmd(TPMBackend *s) + { + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + ++ assert(k->ops->cancel_cmd); ++ + k->ops->cancel_cmd(s); + } + +@@ -116,20 +121,24 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s) + { + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + +- return k->ops->get_tpm_established_flag(s); ++ return k->ops->get_tpm_established_flag ? ++ k->ops->get_tpm_established_flag(s) : false; + } + + int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty) + { + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + +- return k->ops->reset_tpm_established_flag(s, locty); ++ return k->ops->reset_tpm_established_flag ? ++ k->ops->reset_tpm_established_flag(s, locty) : 0; + } + + TPMVersion tpm_backend_get_tpm_version(TPMBackend *s) + { + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + ++ assert(k->ops->get_tpm_version); ++ + return k->ops->get_tpm_version(s); + } + +diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c +index 815a72ef9a..4c21e52b7c 100644 +--- a/hw/tpm/tpm_passthrough.c ++++ b/hw/tpm/tpm_passthrough.c +@@ -54,7 +54,6 @@ struct TPMPassthruState { + bool tpm_executing; + bool tpm_op_canceled; + int cancel_fd; +- bool had_startup_error; + + TPMVersion tpm_version; + }; +@@ -227,29 +226,11 @@ static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd cmd) + } + } + +-/* +- * Start the TPM (thread). If it had been started before, then terminate +- * and start it again. +- */ +-static int tpm_passthrough_startup_tpm(TPMBackend *tb) +-{ +- return 0; +-} +- + static void tpm_passthrough_reset(TPMBackend *tb) + { +- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); +- + DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n"); + + tpm_passthrough_cancel_cmd(tb); +- +- tpm_pt->had_startup_error = false; +-} +- +-static int tpm_passthrough_init(TPMBackend *tb) +-{ +- return 0; + } + + static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb) +@@ -264,13 +245,6 @@ static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb, + return 0; + } + +-static bool tpm_passthrough_get_startup_error(TPMBackend *tb) +-{ +- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); +- +- return tpm_pt->had_startup_error; +-} +- + static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb) + { + size_t wanted_size = 4096; /* Linux tpm.c buffer size */ +@@ -309,11 +283,6 @@ static void tpm_passthrough_cancel_cmd(TPMBackend *tb) + } + } + +-static const char *tpm_passthrough_create_desc(void) +-{ +- return "Passthrough TPM backend driver"; +-} +- + static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb) + { + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); +@@ -453,13 +422,10 @@ static const QemuOptDesc tpm_passthrough_cmdline_opts[] = { + static const TPMDriverOps tpm_passthrough_driver = { + .type = TPM_TYPE_PASSTHROUGH, + .opts = tpm_passthrough_cmdline_opts, +- .desc = tpm_passthrough_create_desc, ++ .desc = "Passthrough TPM backend driver", + .create = tpm_passthrough_create, +- .init = tpm_passthrough_init, +- .startup_tpm = tpm_passthrough_startup_tpm, + .realloc_buffer = tpm_passthrough_realloc_buffer, + .reset = tpm_passthrough_reset, +- .had_startup_error = tpm_passthrough_get_startup_error, + .cancel_cmd = tpm_passthrough_cancel_cmd, + .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag, + .reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag, +diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h +index 202ec8d5a2..9ea707253a 100644 +--- a/include/sysemu/tpm_backend.h ++++ b/include/sysemu/tpm_backend.h +@@ -47,6 +47,7 @@ struct TPMBackend { + TPMState *tpm_state; + GThreadPool *thread_pool; + TPMRecvDataCB *recv_data_callback; ++ bool had_startup_error; + + char *id; + enum TpmModel fe_model; +@@ -75,7 +76,7 @@ struct TPMDriverOps { + enum TpmType type; + const QemuOptDesc *opts; + /* get a descriptive text of the backend to display to the user */ +- const char *(*desc)(void); ++ const char *desc; + + TPMBackend *(*create)(QemuOpts *opts, const char *id); + +@@ -83,8 +84,6 @@ struct TPMDriverOps { + int (*init)(TPMBackend *t); + /* start up the TPM on the backend */ + int (*startup_tpm)(TPMBackend *t); +- /* returns true if nothing will ever answer TPM requests */ +- bool (*had_startup_error)(TPMBackend *t); + + size_t (*realloc_buffer)(TPMSizedBuffer *sb); + +@@ -109,14 +108,6 @@ struct TPMDriverOps { + enum TpmType tpm_backend_get_type(TPMBackend *s); + + /** +- * tpm_backend_get_desc: +- * @s: the backend +- * +- * Returns a human readable description of the backend. +- */ +-const char *tpm_backend_get_desc(TPMBackend *s); +- +-/** + * tpm_backend_init: + * @s: the backend to initialized + * @state: TPMState +diff --git a/tpm.c b/tpm.c +index 7feb3b43c9..9f4f37da50 100644 +--- a/tpm.c ++++ b/tpm.c +@@ -63,7 +63,7 @@ static void tpm_display_backend_drivers(void) + continue; + } + fprintf(stderr, "%12s %s\n", +- TpmType_lookup[i], be_drivers[i]->desc()); ++ TpmType_lookup[i], be_drivers[i]->desc); + } + fprintf(stderr, "\n"); + } +-- +2.11.0 + diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0006-tpm-backend-Remove-unneeded-destroy-method-from-TpmD.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0006-tpm-backend-Remove-unneeded-destroy-method-from-TpmD.patch deleted file mode 100644 index 62ae26b832..0000000000 --- a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0006-tpm-backend-Remove-unneeded-destroy-method-from-TpmD.patch +++ /dev/null @@ -1,115 +0,0 @@ -From b2c3f04c2683074fdc1f168935cb5c0d609b1fe9 Mon Sep 17 00:00:00 2001 -From: Amarnath Valluri -Date: Fri, 7 Apr 2017 17:30:28 +0300 -Subject: [PATCH 6/9] tpm-backend: Remove unneeded destroy() method from - TpmDriverOps interface - -As TPMBackend is a Qemu Object, we can use object_unref() inplace of -tpm_backend_destroy() to free the backend object, hence removed destroy() from -TPMDriverOps interface. - -Signed-off-by: Amarnath Valluri -Upstream-Status: Submitted [http://lists.nongnu.org/archive/html/qemu-devel/2017-04/msg01278.html] -Signed-off-by: Patrick Ohly ---- - backends/tpm.c | 11 ----------- - hw/tpm/tpm_passthrough.c | 14 -------------- - include/sysemu/tpm_backend.h | 7 ------- - tpm.c | 2 +- - 4 files changed, 1 insertion(+), 33 deletions(-) - -diff --git a/backends/tpm.c b/backends/tpm.c -index c96f4627..3493df6e 100644 ---- a/backends/tpm.c -+++ b/backends/tpm.c -@@ -51,17 +51,6 @@ const char *tpm_backend_get_desc(TPMBackend *s) - return k->ops->desc ? k->ops->desc() : ""; - } - --void tpm_backend_destroy(TPMBackend *s) --{ -- TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); -- -- if (k->ops->destroy) { -- k->ops->destroy(s); -- } -- -- object_unref(OBJECT(s)); --} -- - int tpm_backend_init(TPMBackend *s, TPMState *state, - TPMRecvDataCB *datacb) - { -diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c -index 71bdf255..8e11ed3a 100644 ---- a/hw/tpm/tpm_passthrough.c -+++ b/hw/tpm/tpm_passthrough.c -@@ -428,19 +428,6 @@ err_exit: - return NULL; - } - --static void tpm_passthrough_destroy(TPMBackend *tb) --{ -- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); -- -- tpm_passthrough_cancel_cmd(tb); -- -- qemu_close(tpm_pt->tpm_fd); -- qemu_close(tpm_pt->cancel_fd); -- g_free(tpm_pt->tpm_dev); -- -- qapi_free_TPMPassthroughOptions(tpm_pt->ops); --} -- - static TPMOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb) - { - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); -@@ -483,7 +470,6 @@ static const TPMDriverOps tpm_passthrough_driver = { - .opts = tpm_passthrough_cmdline_opts, - .desc = tpm_passthrough_create_desc, - .create = tpm_passthrough_create, -- .destroy = tpm_passthrough_destroy, - .realloc_buffer = tpm_passthrough_realloc_buffer, - .reset = tpm_passthrough_reset, - .had_startup_error = tpm_passthrough_get_startup_error, -diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h -index 7f4d6215..8f8f133e 100644 ---- a/include/sysemu/tpm_backend.h -+++ b/include/sysemu/tpm_backend.h -@@ -77,7 +77,6 @@ struct TPMDriverOps { - const char *(*desc)(void); - - TPMBackend *(*create)(QemuOpts *opts, const char *id); -- void (*destroy)(TPMBackend *t); - - /* initialize the backend */ - int (*init)(TPMBackend *t); -@@ -119,12 +118,6 @@ enum TpmType tpm_backend_get_type(TPMBackend *s); - const char *tpm_backend_get_desc(TPMBackend *s); - - /** -- * tpm_backend_destroy: -- * @s: the backend to destroy -- */ --void tpm_backend_destroy(TPMBackend *s); -- --/** - * tpm_backend_init: - * @s: the backend to initialized - * @state: TPMState -diff --git a/tpm.c b/tpm.c -index 1b6b5509..43d980e0 100644 ---- a/tpm.c -+++ b/tpm.c -@@ -197,7 +197,7 @@ void tpm_cleanup(void) - - QLIST_FOREACH_SAFE(drv, &tpm_backends, list, next) { - QLIST_REMOVE(drv, list); -- tpm_backend_destroy(drv); -+ object_unref(OBJECT(drv)); - } - } - --- -2.11.0 - diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0007-tpm-backend-Add-new-api-to-read-backend-TpmInfo.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0007-tpm-backend-Add-new-api-to-read-backend-TpmInfo.patch new file mode 100644 index 0000000000..6d79ac4d63 --- /dev/null +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0007-tpm-backend-Add-new-api-to-read-backend-TpmInfo.patch @@ -0,0 +1,293 @@ +From 5f698395b5de1ab2826f5aad99d757ce31d7c95f Mon Sep 17 00:00:00 2001 +From: Amarnath Valluri +Date: Mon, 6 Mar 2017 00:10:10 +0200 +Subject: [PATCH 07/12] tpm backend: Add new api to read backend TpmInfo + +TPM configuration options are backend implementation details and shall not be +part of base TPMBackend object, and these shall not be accessed directly outside +of the class, hence added a new interface method, get_tpm_options() to +TPMDriverOps., which shall be implemented by the derived classes to return +configured tpm options. + +A new tpm backend api - tpm_backend_query_tpm() which uses _get_tpm_options() to +prepare TpmInfo. + +Signed-off-by: Amarnath Valluri +Reviewed-by: Stefan Berger + +Upstream-Status: Backport[f59864ba3aedd26aef7c84545cc1e565caccebf7] +--- + backends/tpm.c | 15 +++++++++++-- + hw/tpm/tpm_passthrough.c | 51 +++++++++++++++++++++++++++----------------- + include/sysemu/tpm_backend.h | 15 +++++++++++-- + tpm.c | 32 +-------------------------- + 4 files changed, 59 insertions(+), 54 deletions(-) + +diff --git a/backends/tpm.c b/backends/tpm.c +index 8911597fab..de313c9d5a 100644 +--- a/backends/tpm.c ++++ b/backends/tpm.c +@@ -142,6 +142,19 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s) + return k->ops->get_tpm_version(s); + } + ++TPMInfo *tpm_backend_query_tpm(TPMBackend *s) ++{ ++ TPMInfo *info = g_new0(TPMInfo, 1); ++ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); ++ ++ info->id = g_strdup(s->id); ++ info->model = s->fe_model; ++ info->options = k->ops->get_tpm_options ? ++ k->ops->get_tpm_options(s) : NULL; ++ ++ return info; ++} ++ + static bool tpm_backend_prop_get_opened(Object *obj, Error **errp) + { + TPMBackend *s = TPM_BACKEND(obj); +@@ -196,8 +209,6 @@ static void tpm_backend_instance_finalize(Object *obj) + TPMBackend *s = TPM_BACKEND(obj); + + g_free(s->id); +- g_free(s->path); +- g_free(s->cancel_path); + tpm_backend_thread_end(s); + } + +diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c +index 4c21e52b7c..84fc49a4d3 100644 +--- a/hw/tpm/tpm_passthrough.c ++++ b/hw/tpm/tpm_passthrough.c +@@ -30,6 +30,7 @@ + #include "tpm_int.h" + #include "hw/hw.h" + #include "hw/i386/pc.h" ++#include "qapi/clone-visitor.h" + #include "tpm_tis.h" + #include "tpm_util.h" + +@@ -49,7 +50,8 @@ + struct TPMPassthruState { + TPMBackend parent; + +- char *tpm_dev; ++ TPMPassthroughOptions *options; ++ const char *tpm_dev; + int tpm_fd; + bool tpm_executing; + bool tpm_op_canceled; +@@ -296,15 +298,14 @@ static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb) + * in Documentation/ABI/stable/sysfs-class-tpm. + * From /dev/tpm0 create /sys/class/misc/tpm0/device/cancel + */ +-static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb) ++static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt) + { +- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); + int fd = -1; + char *dev; + char path[PATH_MAX]; + +- if (tb->cancel_path) { +- fd = qemu_open(tb->cancel_path, O_WRONLY); ++ if (tpm_pt->options->cancel_path) { ++ fd = qemu_open(tpm_pt->options->cancel_path, O_WRONLY); + if (fd < 0) { + error_report("Could not open TPM cancel path : %s", + strerror(errno)); +@@ -319,7 +320,7 @@ static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb) + dev) < sizeof(path)) { + fd = qemu_open(path, O_WRONLY); + if (fd >= 0) { +- tb->cancel_path = g_strdup(path); ++ tpm_pt->options->cancel_path = g_strdup(path); + } else { + error_report("tpm_passthrough: Could not open TPM cancel " + "path %s : %s", path, strerror(errno)); +@@ -339,17 +340,18 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) + const char *value; + + value = qemu_opt_get(opts, "cancel-path"); +- tb->cancel_path = g_strdup(value); ++ if (value) { ++ tpm_pt->options->cancel_path = g_strdup(value); ++ tpm_pt->options->has_cancel_path = true; ++ } + + value = qemu_opt_get(opts, "path"); +- if (!value) { +- value = TPM_PASSTHROUGH_DEFAULT_DEVICE; ++ if (value) { ++ tpm_pt->options->has_path = true; ++ tpm_pt->options->path = g_strdup(value); + } + +- tpm_pt->tpm_dev = g_strdup(value); +- +- tb->path = g_strdup(tpm_pt->tpm_dev); +- ++ tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE; + tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR); + if (tpm_pt->tpm_fd < 0) { + error_report("Cannot access TPM device using '%s': %s", +@@ -370,10 +372,8 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) + tpm_pt->tpm_fd = -1; + + err_free_parameters: +- g_free(tb->path); +- tb->path = NULL; +- +- g_free(tpm_pt->tpm_dev); ++ qapi_free_TPMPassthroughOptions(tpm_pt->options); ++ tpm_pt->options = NULL; + tpm_pt->tpm_dev = NULL; + + return 1; +@@ -391,7 +391,7 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) + goto err_exit; + } + +- tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb); ++ tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt); + if (tpm_pt->cancel_fd < 0) { + goto err_exit; + } +@@ -404,6 +404,17 @@ err_exit: + return NULL; + } + ++static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb) ++{ ++ TpmTypeOptions *options = g_new0(TpmTypeOptions, 1); ++ ++ options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH; ++ options->u.passthrough.data = QAPI_CLONE(TPMPassthroughOptions, ++ TPM_PASSTHROUGH(tb)->options); ++ ++ return options; ++} ++ + static const QemuOptDesc tpm_passthrough_cmdline_opts[] = { + TPM_STANDARD_CMDLINE_OPTS, + { +@@ -430,12 +441,14 @@ static const TPMDriverOps tpm_passthrough_driver = { + .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag, + .reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag, + .get_tpm_version = tpm_passthrough_get_tpm_version, ++ .get_tpm_options = tpm_passthrough_get_tpm_options, + }; + + static void tpm_passthrough_inst_init(Object *obj) + { + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); + ++ tpm_pt->options = g_new0(TPMPassthroughOptions, 1); + tpm_pt->tpm_fd = -1; + tpm_pt->cancel_fd = -1; + } +@@ -448,7 +461,7 @@ static void tpm_passthrough_inst_finalize(Object *obj) + + qemu_close(tpm_pt->tpm_fd); + qemu_close(tpm_pt->cancel_fd); +- g_free(tpm_pt->tpm_dev); ++ qapi_free_TPMPassthroughOptions(tpm_pt->options); + } + + static void tpm_passthrough_class_init(ObjectClass *klass, void *data) +diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h +index 9ea707253a..e96c1918cc 100644 +--- a/include/sysemu/tpm_backend.h ++++ b/include/sysemu/tpm_backend.h +@@ -49,10 +49,9 @@ struct TPMBackend { + TPMRecvDataCB *recv_data_callback; + bool had_startup_error; + ++ /* */ + char *id; + enum TpmModel fe_model; +- char *path; +- char *cancel_path; + + QLIST_ENTRY(TPMBackend) list; + }; +@@ -96,6 +95,8 @@ struct TPMDriverOps { + int (*reset_tpm_established_flag)(TPMBackend *t, uint8_t locty); + + TPMVersion (*get_tpm_version)(TPMBackend *t); ++ ++ TpmTypeOptions *(*get_tpm_options)(TPMBackend *t); + }; + + +@@ -214,6 +215,16 @@ void tpm_backend_open(TPMBackend *s, Error **errp); + */ + TPMVersion tpm_backend_get_tpm_version(TPMBackend *s); + ++/** ++ * tpm_backend_query_tpm: ++ * @s: the backend ++ * ++ * Query backend tpm info ++ * ++ * Returns newly allocated TPMInfo ++ */ ++TPMInfo *tpm_backend_query_tpm(TPMBackend *s); ++ + TPMBackend *qemu_find_tpm(const char *id); + + const TPMDriverOps *tpm_get_backend_driver(const char *type); +diff --git a/tpm.c b/tpm.c +index 9f4f37da50..cac400ef3e 100644 +--- a/tpm.c ++++ b/tpm.c +@@ -203,36 +203,6 @@ static const TPMDriverOps *tpm_driver_find_by_type(enum TpmType type) + return be_drivers[type]; + } + +-static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv) +-{ +- TPMInfo *res = g_new0(TPMInfo, 1); +- TPMPassthroughOptions *tpo; +- +- res->id = g_strdup(drv->id); +- res->model = drv->fe_model; +- res->options = g_new0(TpmTypeOptions, 1); +- +- switch (tpm_backend_get_type(drv)) { +- case TPM_TYPE_PASSTHROUGH: +- res->options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH; +- tpo = g_new0(TPMPassthroughOptions, 1); +- res->options->u.passthrough.data = tpo; +- if (drv->path) { +- tpo->path = g_strdup(drv->path); +- tpo->has_path = true; +- } +- if (drv->cancel_path) { +- tpo->cancel_path = g_strdup(drv->cancel_path); +- tpo->has_cancel_path = true; +- } +- break; +- case TPM_TYPE__MAX: +- break; +- } +- +- return res; +-} +- + /* + * Walk the list of active TPM backends and collect information about them + * following the schema description in qapi-schema.json. +@@ -247,7 +217,7 @@ TPMInfoList *qmp_query_tpm(Error **errp) + continue; + } + info = g_new0(TPMInfoList, 1); +- info->value = qmp_query_tpm_inst(drv); ++ info->value = tpm_backend_query_tpm(drv); + + if (!cur_item) { + head = cur_item = info; +-- +2.11.0 + diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0007-tpm-backend-Move-realloc_buffer-implementation-to-ba.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0007-tpm-backend-Move-realloc_buffer-implementation-to-ba.patch deleted file mode 100644 index f9226c6c89..0000000000 --- a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0007-tpm-backend-Move-realloc_buffer-implementation-to-ba.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 81cdfb1348a751d08b13f86af554f1a2935614d1 Mon Sep 17 00:00:00 2001 -From: Amarnath Valluri -Date: Fri, 7 Apr 2017 17:30:29 +0300 -Subject: [PATCH 7/9] tpm-backend: Move realloc_buffer() implementation to base - class - -Provide base implementation of realloc_buffer(), so that backend implementations -can resue. - -Signed-off-by: Amarnath Valluri -Upstream-Status: Submitted [http://lists.nongnu.org/archive/html/qemu-devel/2017-04/msg01278.html] -Signed-off-by: Patrick Ohly ---- - backends/tpm.c | 9 ++++++++- - hw/tpm/tpm_passthrough.c | 12 ------------ - 2 files changed, 8 insertions(+), 13 deletions(-) - -diff --git a/backends/tpm.c b/backends/tpm.c -index 3493df6e..0da73e6c 100644 ---- a/backends/tpm.c -+++ b/backends/tpm.c -@@ -88,8 +88,15 @@ bool tpm_backend_had_startup_error(TPMBackend *s) - size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb) - { - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); -+ if (!k->ops->realloc_buffer) { -+ size_t wanted_size = 4096; /* Linux tpm.c buffer size */ - -- assert(k->ops->realloc_buffer); -+ if (sb->size != wanted_size) { -+ sb->buffer = g_realloc(sb->buffer, wanted_size); -+ sb->size = wanted_size; -+ } -+ return sb->size; -+ } - - return k->ops->realloc_buffer(sb); - } -diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c -index 8e11ed3a..1bffb6da 100644 ---- a/hw/tpm/tpm_passthrough.c -+++ b/hw/tpm/tpm_passthrough.c -@@ -258,17 +258,6 @@ static bool tpm_passthrough_get_startup_error(TPMBackend *tb) - return tpm_pt->had_startup_error; - } - --static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb) --{ -- size_t wanted_size = 4096; /* Linux tpm.c buffer size */ -- -- if (sb->size != wanted_size) { -- sb->buffer = g_realloc(sb->buffer, wanted_size); -- sb->size = wanted_size; -- } -- return sb->size; --} -- - static void tpm_passthrough_cancel_cmd(TPMBackend *tb) - { - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); -@@ -470,7 +459,6 @@ static const TPMDriverOps tpm_passthrough_driver = { - .opts = tpm_passthrough_cmdline_opts, - .desc = tpm_passthrough_create_desc, - .create = tpm_passthrough_create, -- .realloc_buffer = tpm_passthrough_realloc_buffer, - .reset = tpm_passthrough_reset, - .had_startup_error = tpm_passthrough_get_startup_error, - .cancel_cmd = tpm_passthrough_cancel_cmd, --- -2.11.0 - diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0008-tpm-backend-Move-realloc_buffer-implementation-to-tp.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0008-tpm-backend-Move-realloc_buffer-implementation-to-tp.patch new file mode 100644 index 0000000000..94cc6c542c --- /dev/null +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0008-tpm-backend-Move-realloc_buffer-implementation-to-tp.patch @@ -0,0 +1,140 @@ +From 02189909fdc5e73b3ca54362084c16f0b67a3fdf Mon Sep 17 00:00:00 2001 +From: Amarnath Valluri +Date: Fri, 7 Apr 2017 10:57:28 +0300 +Subject: [PATCH 08/12] tpm-backend: Move realloc_buffer() implementation to + tpm-tis model +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +buffer reallocation is very unlikely to be backend specific. Hence move inside +the tis. + +Signed-off-by: Amarnath Valluri +Reviewed-by: Stefan Berger +Reviewed-by: Marc-André Lureau + +Upstream-Status: Backport [d0c519bdffa303d141727369e55b157c45b03147] +--- + backends/tpm.c | 9 --------- + hw/tpm/tpm_passthrough.c | 12 ------------ + hw/tpm/tpm_tis.c | 14 ++++++++++++-- + include/sysemu/tpm_backend.h | 12 ------------ + 4 files changed, 12 insertions(+), 35 deletions(-) + +diff --git a/backends/tpm.c b/backends/tpm.c +index de313c9d5a..37c84b7c66 100644 +--- a/backends/tpm.c ++++ b/backends/tpm.c +@@ -80,15 +80,6 @@ bool tpm_backend_had_startup_error(TPMBackend *s) + return s->had_startup_error; + } + +-size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb) +-{ +- TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); +- +- assert(k->ops->realloc_buffer); +- +- return k->ops->realloc_buffer(sb); +-} +- + void tpm_backend_deliver_request(TPMBackend *s) + { + g_thread_pool_push(s->thread_pool, (gpointer)TPM_BACKEND_CMD_PROCESS_CMD, +diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c +index 84fc49a4d3..22d3460550 100644 +--- a/hw/tpm/tpm_passthrough.c ++++ b/hw/tpm/tpm_passthrough.c +@@ -247,17 +247,6 @@ static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb, + return 0; + } + +-static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb) +-{ +- size_t wanted_size = 4096; /* Linux tpm.c buffer size */ +- +- if (sb->size != wanted_size) { +- sb->buffer = g_realloc(sb->buffer, wanted_size); +- sb->size = wanted_size; +- } +- return sb->size; +-} +- + static void tpm_passthrough_cancel_cmd(TPMBackend *tb) + { + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); +@@ -435,7 +424,6 @@ static const TPMDriverOps tpm_passthrough_driver = { + .opts = tpm_passthrough_cmdline_opts, + .desc = "Passthrough TPM backend driver", + .create = tpm_passthrough_create, +- .realloc_buffer = tpm_passthrough_realloc_buffer, + .reset = tpm_passthrough_reset, + .cancel_cmd = tpm_passthrough_cancel_cmd, + .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag, +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c +index a6440fef91..d5118e7f60 100644 +--- a/hw/tpm/tpm_tis.c ++++ b/hw/tpm/tpm_tis.c +@@ -963,6 +963,16 @@ static int tpm_tis_do_startup_tpm(TPMState *s) + return tpm_backend_startup_tpm(s->be_driver); + } + ++static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb) ++{ ++ size_t wanted_size = 4096; /* Linux tpm.c buffer size */ ++ ++ if (sb->size != wanted_size) { ++ sb->buffer = g_realloc(sb->buffer, wanted_size); ++ sb->size = wanted_size; ++ } ++} ++ + /* + * Get the TPMVersion of the backend device being used + */ +@@ -1010,9 +1020,9 @@ static void tpm_tis_reset(DeviceState *dev) + tis->loc[c].state = TPM_TIS_STATE_IDLE; + + tis->loc[c].w_offset = 0; +- tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer); ++ tpm_tis_realloc_buffer(&tis->loc[c].w_buffer); + tis->loc[c].r_offset = 0; +- tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer); ++ tpm_tis_realloc_buffer(&tis->loc[c].r_buffer); + } + + tpm_tis_do_startup_tpm(s); +diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h +index e96c1918cc..2c798a1eb4 100644 +--- a/include/sysemu/tpm_backend.h ++++ b/include/sysemu/tpm_backend.h +@@ -84,8 +84,6 @@ struct TPMDriverOps { + /* start up the TPM on the backend */ + int (*startup_tpm)(TPMBackend *t); + +- size_t (*realloc_buffer)(TPMSizedBuffer *sb); +- + void (*reset)(TPMBackend *t); + + void (*cancel_cmd)(TPMBackend *t); +@@ -140,16 +138,6 @@ int tpm_backend_startup_tpm(TPMBackend *s); + bool tpm_backend_had_startup_error(TPMBackend *s); + + /** +- * tpm_backend_realloc_buffer: +- * @s: the backend +- * @sb: the TPMSizedBuffer to re-allocated to the size suitable for the +- * backend. +- * +- * This function returns the size of the allocated buffer +- */ +-size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb); +- +-/** + * tpm_backend_deliver_request: + * @s: the backend to send the request to + * +-- +2.11.0 + diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0009-tpm-Added-support-for-TPM-emulator.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0009-tpm-Added-support-for-TPM-emulator.patch deleted file mode 100644 index 6c84f64d20..0000000000 --- a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0009-tpm-Added-support-for-TPM-emulator.patch +++ /dev/null @@ -1,1462 +0,0 @@ -From 68fc282acd341c493b3fc2408ac50d761056c86d Mon Sep 17 00:00:00 2001 -From: Amarnath Valluri -Date: Fri, 7 Apr 2017 17:30:31 +0300 -Subject: [PATCH 9/9] tpm: Added support for TPM emulator - -This change introduces a new TPM backend driver that can communicate with -swtpm(software TPM emulator) using unix domain socket interface. - -Swtpm uses two unix sockets, one for plain TPM commands and responses, and one -for out-of-band control messages. - -The swtpm and associated tools can be found here: - https://github.com/stefanberger/swtpm - -Usage: - # setup TPM state directory - mkdir /tmp/mytpm - chown -R tss:root /tmp/mytpm - /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek - - # Ask qemu to use TPM emulator with given tpm state directory - qemu-system-x86_64 \ - [...] \ - -tpmdev emulator,id=tpm0,tpmstatedir=/tmp/mytpm,logfile=/tmp/swtpm.log \ - -device tpm-tis,tpmdev=tpm0 \ - [...] - -Signed-off-by: Amarnath Valluri -Upstream-Status: Submitted [http://lists.nongnu.org/archive/html/qemu-devel/2017-04/msg01278.html] -Signed-off-by: Patrick Ohly ---- - configure | 15 +- - hmp.c | 21 ++ - hw/tpm/Makefile.objs | 1 + - hw/tpm/tpm_emulator.c | 927 ++++++++++++++++++++++++++++++++++++++++++++++++++ - hw/tpm/tpm_ioctl.h | 243 +++++++++++++ - qapi-schema.json | 34 +- - qemu-options.hx | 53 ++- - tpm.c | 2 +- - 9 files changed, 1306 insertions(+), 8 deletions(-) - create mode 100644 hw/tpm/tpm_emulator.c - create mode 100644 hw/tpm/tpm_ioctl.h - -diff --git a/configure b/configure -index aa9a7daf..e36853e0 100755 ---- a/configure -+++ b/configure -@@ -3298,10 +3298,15 @@ fi - ########################################## - # TPM passthrough is only on x86 Linux - --if test "$targetos" = Linux && test "$cpu" = i386 -o "$cpu" = x86_64; then -- tpm_passthrough=$tpm -+if test "$targetos" = Linux; then -+ tpm_emulator=$tpm -+ if test "$cpu" = i386 -o "$cpu" = x86_64; then -+ tpm_passthrough=$tpm -+ else -+ tpm_passthrough=no -+ fi - else -- tpm_passthrough=no -+ tpm_emulator=no - fi - - ########################################## -@@ -5094,6 +5099,7 @@ echo "gcov enabled $gcov" - echo "TPM support $tpm" - echo "libssh2 support $libssh2" - echo "TPM passthrough $tpm_passthrough" -+echo "TPM emulator $tpm_emulator" - echo "QOM debugging $qom_cast_debug" - echo "lzo support $lzo" - echo "snappy support $snappy" -@@ -5650,6 +5656,9 @@ if test "$tpm" = "yes"; then - if test "$tpm_passthrough" = "yes"; then - echo "CONFIG_TPM_PASSTHROUGH=y" >> $config_host_mak - fi -+ if test "$tpm_emulator" = "yes"; then -+ echo "CONFIG_TPM_EMULATOR=y" >> $config_host_mak -+ fi - fi - - echo "TRACE_BACKENDS=$trace_backends" >> $config_host_mak -diff --git a/hmp.c b/hmp.c -index 8bf42dbd..cb4b21bf 100644 ---- a/hmp.c -+++ b/hmp.c -@@ -936,6 +936,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) - Error *err = NULL; - unsigned int c = 0; - TPMPassthroughOptions *tpo; -+ TPMEmulatorOptions *teo; - - info_list = qmp_query_tpm(&err); - if (err) { -@@ -965,6 +966,26 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) - tpo->has_cancel_path ? ",cancel-path=" : "", - tpo->has_cancel_path ? tpo->cancel_path : ""); - break; -+ case TPM_TYPE_EMULATOR: -+ teo = (TPMEmulatorOptions *)(ti->options); -+ monitor_printf(mon, ",tmpstatedir=%s", teo->tpmstatedir); -+ monitor_printf(mon, ",spawn=%s", teo->spawn ? "on" : "off"); -+ if (teo->has_path) { -+ monitor_printf(mon, ",path=%s", teo->path); -+ } -+ if (teo->has_data_path) { -+ monitor_printf(mon, ",data-path=%s", teo->data_path); -+ } -+ if (teo->has_ctrl_path) { -+ monitor_printf(mon, ",ctrl-path=%s", teo->ctrl_path); -+ } -+ if (teo->has_logfile) { -+ monitor_printf(mon, ",logfile=%s", teo->logfile); -+ } -+ if (teo->has_loglevel) { -+ monitor_printf(mon, ",loglevel=%ld", teo->loglevel); -+ } -+ break; - default: - break; - } -diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs -index 64cecc3b..41f0b7a5 100644 ---- a/hw/tpm/Makefile.objs -+++ b/hw/tpm/Makefile.objs -@@ -1,2 +1,3 @@ - common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o - common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o -+common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o -diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c -new file mode 100644 -index 00000000..d001ed9f ---- /dev/null -+++ b/hw/tpm/tpm_emulator.c -@@ -0,0 +1,927 @@ -+/* -+ * emulator TPM driver -+ * -+ * Copyright (c) 2017 Intel Corporation -+ * Author: Amarnath Valluri -+ * -+ * Copyright (c) 2010 - 2013 IBM Corporation -+ * Authors: -+ * Stefan Berger -+ * -+ * Copyright (C) 2011 IAIK, Graz University of Technology -+ * Author: Andreas Niederl -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, see -+ * -+ */ -+ -+#include "qemu/osdep.h" -+#include "qemu/error-report.h" -+#include "qemu/sockets.h" -+#include "io/channel-socket.h" -+#include "sysemu/tpm_backend.h" -+#include "tpm_int.h" -+#include "hw/hw.h" -+#include "hw/i386/pc.h" -+#include "tpm_util.h" -+#include "tpm_ioctl.h" -+#include "qapi/error.h" -+ -+#include -+#include -+#include -+#include -+ -+#define DEBUG_TPM 0 -+ -+#define DPRINT(fmt, ...) do { \ -+ if (DEBUG_TPM) { \ -+ fprintf(stderr, fmt, ## __VA_ARGS__); \ -+ } \ -+} while (0); -+ -+#define DPRINTF(fmt, ...) DPRINT("tpm-emulator: "fmt"\n", __VA_ARGS__) -+ -+#define TYPE_TPM_EMULATOR "tpm-emulator" -+#define TPM_EMULATOR(obj) \ -+ OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR) -+ -+static const TPMDriverOps tpm_emulator_driver; -+ -+/* data structures */ -+typedef struct TPMEmulator { -+ TPMBackend parent; -+ -+ TPMEmulatorOptions *ops; -+ QIOChannel *data_ioc; -+ QIOChannel *ctrl_ioc; -+ bool op_executing; -+ bool op_canceled; -+ bool child_running; -+ TPMVersion tpm_version; -+ ptm_cap caps; /* capabilities of the TPM */ -+ uint8_t cur_locty_number; /* last set locality */ -+ QemuMutex state_lock; -+} TPMEmulator; -+ -+#define TPM_DEFAULT_EMULATOR "swtpm" -+#define TPM_DEFAULT_LOGLEVEL 5 -+#define TPM_EMULATOR_PIDFILE "/tmp/qemu-tpm.pid" -+#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap)) -+#define TPM_EMULATOR_IOCTL_TO_CMD(ioctlnum) \ -+ ((ioctlnum >> _IOC_NRSHIFT) & _IOC_NRMASK) + 1 -+ -+static int tpm_emulator_ctrlcmd(QIOChannel *ioc, unsigned long cmd, void *msg, -+ size_t msg_len_in, size_t msg_len_out) -+{ -+ ssize_t n; -+ -+ uint32_t cmd_no = cpu_to_be32(TPM_EMULATOR_IOCTL_TO_CMD(cmd)); -+ struct iovec iov[2] = { -+ { .iov_base = &cmd_no, .iov_len = sizeof(cmd_no), }, -+ { .iov_base = msg, .iov_len = msg_len_in, }, -+ }; -+ -+ n = qio_channel_writev(ioc, iov, 2, NULL); -+ if (n > 0) { -+ if (msg_len_out > 0) { -+ n = qio_channel_read(ioc, (char *)msg, msg_len_out, NULL); -+ /* simulate ioctl return value */ -+ if (n > 0) { -+ n = 0; -+ } -+ } else { -+ n = 0; -+ } -+ } -+ return n; -+} -+ -+static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_pt, -+ const uint8_t *in, uint32_t in_len, -+ uint8_t *out, uint32_t out_len, -+ bool *selftest_done) -+{ -+ ssize_t ret; -+ bool is_selftest; -+ const struct tpm_resp_hdr *hdr; -+ -+ if (!tpm_pt->child_running) { -+ return -1; -+ } -+ -+ tpm_pt->op_canceled = false; -+ tpm_pt->op_executing = true; -+ *selftest_done = false; -+ -+ is_selftest = tpm_util_is_selftest(in, in_len); -+ -+ ret = qio_channel_write(tpm_pt->data_ioc, (const char *)in, (size_t)in_len, -+ NULL); -+ if (ret != in_len) { -+ if (!tpm_pt->op_canceled || errno != ECANCELED) { -+ error_report("tpm-emulator: error while transmitting data " -+ "to TPM: %s (%i)", strerror(errno), errno); -+ } -+ goto err_exit; -+ } -+ -+ tpm_pt->op_executing = false; -+ -+ ret = qio_channel_read(tpm_pt->data_ioc, (char *)out, (size_t)out_len, NULL); -+ if (ret < 0) { -+ if (!tpm_pt->op_canceled || errno != ECANCELED) { -+ error_report("tpm-emulator: error while reading data from " -+ "TPM: %s (%i)", strerror(errno), errno); -+ } -+ } else if (ret < sizeof(struct tpm_resp_hdr) || -+ be32_to_cpu(((struct tpm_resp_hdr *)out)->len) != ret) { -+ ret = -1; -+ error_report("tpm-emulator: received invalid response " -+ "packet from TPM"); -+ } -+ -+ if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) { -+ hdr = (struct tpm_resp_hdr *)out; -+ *selftest_done = (be32_to_cpu(hdr->errcode) == 0); -+ } -+ -+err_exit: -+ if (ret < 0) { -+ tpm_util_write_fatal_error_response(out, out_len); -+ } -+ -+ tpm_pt->op_executing = false; -+ -+ return ret; -+} -+ -+static int tpm_emulator_set_locality(TPMEmulator *tpm_pt, -+ uint8_t locty_number) -+{ -+ ptm_loc loc; -+ -+ if (!tpm_pt->child_running) { -+ return -1; -+ } -+ -+ DPRINTF("%s : locality: 0x%x", __func__, locty_number); -+ -+ if (tpm_pt->cur_locty_number != locty_number) { -+ DPRINTF("setting locality : 0x%x", locty_number); -+ loc.u.req.loc = cpu_to_be32(locty_number); -+ if (tpm_emulator_ctrlcmd(tpm_pt->ctrl_ioc, PTM_SET_LOCALITY, &loc, -+ sizeof(loc), sizeof(loc)) < 0) { -+ error_report("tpm-emulator: could not set locality : %s", -+ strerror(errno)); -+ return -1; -+ } -+ loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result); -+ if (loc.u.resp.tpm_result != 0) { -+ error_report("tpm-emulator: TPM result for set locality : 0x%x", -+ loc.u.resp.tpm_result); -+ return -1; -+ } -+ tpm_pt->cur_locty_number = locty_number; -+ } -+ return 0; -+} -+ -+static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd cmd) -+{ -+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb); -+ TPMLocality *locty = NULL; -+ bool selftest_done = false; -+ -+ DPRINTF("processing command type %d", cmd); -+ -+ switch (cmd) { -+ case TPM_BACKEND_CMD_PROCESS_CMD: -+ qemu_mutex_lock(&tpm_pt->state_lock); -+ locty = tb->tpm_state->locty_data; -+ if (tpm_emulator_set_locality(tpm_pt, -+ tb->tpm_state->locty_number) < 0) { -+ tpm_util_write_fatal_error_response(locty->r_buffer.buffer, -+ locty->r_buffer.size); -+ } else { -+ tpm_emulator_unix_tx_bufs(tpm_pt, locty->w_buffer.buffer, -+ locty->w_offset, locty->r_buffer.buffer, -+ locty->r_buffer.size, &selftest_done); -+ } -+ tb->recv_data_callback(tb->tpm_state, tb->tpm_state->locty_number, -+ selftest_done); -+ qemu_mutex_unlock(&tpm_pt->state_lock); -+ break; -+ case TPM_BACKEND_CMD_INIT: -+ case TPM_BACKEND_CMD_END: -+ case TPM_BACKEND_CMD_TPM_RESET: -+ /* nothing to do */ -+ break; -+ } -+} -+ -+/* -+ * Gracefully shut down the external unixio TPM -+ */ -+static void tpm_emulator_shutdown(TPMEmulator *tpm_pt) -+{ -+ ptm_res res; -+ -+ if (!tpm_pt->child_running) { -+ return; -+ } -+ -+ if (tpm_emulator_ctrlcmd(tpm_pt->ctrl_ioc, PTM_SHUTDOWN, &res, 0, -+ sizeof(res)) < 0) { -+ error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s", -+ strerror(errno)); -+ } else if (res != 0) { -+ error_report("tpm-emulator: TPM result for sutdown: 0x%x", -+ be32_to_cpu(res)); -+ } -+} -+ -+static int tpm_emulator_probe_caps(TPMEmulator *tpm_pt) -+{ -+ if (!tpm_pt->child_running) { -+ return -1; -+ } -+ -+ DPRINTF("%s", __func__); -+ if (tpm_emulator_ctrlcmd(tpm_pt->ctrl_ioc, PTM_GET_CAPABILITY, -+ &tpm_pt->caps, 0, sizeof(tpm_pt->caps)) < 0) { -+ error_report("tpm-emulator: probing failed : %s", strerror(errno)); -+ return -1; -+ } -+ -+ tpm_pt->caps = be64_to_cpu(tpm_pt->caps); -+ -+ DPRINTF("capbilities : 0x%lx", tpm_pt->caps); -+ -+ return 0; -+} -+ -+static int tpm_emulator_check_caps(TPMEmulator *tpm_pt) -+{ -+ ptm_cap caps = 0; -+ const char *tpm = NULL; -+ -+ /* check for min. required capabilities */ -+ switch (tpm_pt->tpm_version) { -+ case TPM_VERSION_1_2: -+ caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | -+ PTM_CAP_SET_LOCALITY; -+ tpm = "1.2"; -+ break; -+ case TPM_VERSION_2_0: -+ caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | -+ PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED; -+ tpm = "2"; -+ break; -+ case TPM_VERSION_UNSPEC: -+ error_report("tpm-emulator: TPM version has not been set"); -+ return -1; -+ } -+ -+ if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, caps)) { -+ error_report("tpm-emulator: TPM does not implement minimum set of " -+ "required capabilities for TPM %s (0x%x)", tpm, (int)caps); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int tpm_emulator_init_tpm(TPMEmulator *tpm_pt) -+{ -+ ptm_init init; -+ ptm_res res; -+ -+ if (!tpm_pt->child_running) { -+ return -1; -+ } -+ -+ DPRINTF("%s", __func__); -+ if (tpm_emulator_ctrlcmd(tpm_pt->ctrl_ioc, PTM_INIT, &init, sizeof(init), -+ sizeof(init)) < 0) { -+ error_report("tpm-emulator: could not send INIT: %s", -+ strerror(errno)); -+ return -1; -+ } -+ -+ res = be32_to_cpu(init.u.resp.tpm_result); -+ if (res) { -+ error_report("tpm-emulator: TPM result for PTM_INIT: 0x%x", res); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int tpm_emulator_startup_tpm(TPMBackend *tb) -+{ -+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb); -+ -+ DPRINTF("%s", __func__); -+ -+ tpm_emulator_init_tpm(tpm_pt) ; -+ -+ return 0; -+} -+ -+static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb) -+{ -+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb); -+ ptm_est est; -+ -+ DPRINTF("%s", __func__); -+ if (tpm_emulator_ctrlcmd(tpm_pt->ctrl_ioc, PTM_GET_TPMESTABLISHED, &est, 0, -+ sizeof(est)) < 0) { -+ error_report("tpm-emulator: Could not get the TPM established flag: %s", -+ strerror(errno)); -+ return false; -+ } -+ DPRINTF("established flag: %0x", est.u.resp.bit); -+ -+ return (est.u.resp.bit != 0); -+} -+ -+static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb, -+ uint8_t locty) -+{ -+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb); -+ ptm_reset_est reset_est; -+ ptm_res res; -+ -+ /* only a TPM 2.0 will support this */ -+ if (tpm_pt->tpm_version == TPM_VERSION_2_0) { -+ reset_est.u.req.loc = cpu_to_be32(tpm_pt->cur_locty_number); -+ -+ if (tpm_emulator_ctrlcmd(tpm_pt->ctrl_ioc, PTM_RESET_TPMESTABLISHED, -+ &reset_est, sizeof(reset_est), -+ sizeof(reset_est)) < 0) { -+ error_report("tpm-emulator: Could not reset the establishment bit: " -+ "%s", strerror(errno)); -+ return -1; -+ } -+ -+ res = be32_to_cpu(reset_est.u.resp.tpm_result); -+ if (res) { -+ error_report("tpm-emulator: TPM result for rest establixhed flag: " -+ "0x%x", res); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+static bool tpm_emulator_had_startup_error(TPMBackend *tb) -+{ -+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb); -+ -+ return !tpm_pt->child_running; -+} -+ -+static void tpm_emulator_cancel_cmd(TPMBackend *tb) -+{ -+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb); -+ ptm_res res; -+ -+ /* -+ * As of Linux 3.7 the tpm_tis driver does not properly cancel -+ * commands on all TPM manufacturers' TPMs. -+ * Only cancel if we're busy so we don't cancel someone else's -+ * command, e.g., a command executed on the host. -+ */ -+ if (tpm_pt->op_executing) { -+ if (TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, PTM_CAP_CANCEL_TPM_CMD)) { -+ if (tpm_emulator_ctrlcmd(tpm_pt->ctrl_ioc, PTM_CANCEL_TPM_CMD, &res, -+ 0, sizeof(res)) < 0) { -+ error_report("tpm-emulator: Could not cancel command: %s", -+ strerror(errno)); -+ } else if (res != 0) { -+ error_report("tpm-emulator: Failed to cancel TPM: 0x%x", -+ be32_to_cpu(res)); -+ } else { -+ tpm_pt->op_canceled = true; -+ } -+ } -+ } -+} -+ -+static void tpm_emulator_reset(TPMBackend *tb) -+{ -+ DPRINTF("%s", __func__); -+ -+ tpm_emulator_cancel_cmd(tb); -+} -+ -+static const char *tpm_emulator_desc(void) -+{ -+ return "TPM emulator backend driver"; -+} -+ -+static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb) -+{ -+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb); -+ -+ return tpm_pt->tpm_version; -+} -+ -+static gboolean tpm_emulator_fd_handler(QIOChannel *ioc, GIOCondition cnd, void *opaque) -+{ -+ TPMEmulator *tpm_pt = opaque; -+ -+ if (cnd & G_IO_ERR || cnd & G_IO_HUP) { -+ error_report("TPM backend disappeared"); -+ tpm_pt->child_running = false; -+ return false; -+ } -+ -+ return true; -+} -+ -+static QIOChannel *_iochannel_new(const char *path, int fd, Error **err) -+{ -+ int socket = path ? unix_connect(path, err) : fd; -+ if (socket < 0) { -+ return NULL; -+ } -+ -+ return QIO_CHANNEL(qio_channel_socket_new_fd(socket, err)); -+} -+ -+static int tpm_emulator_spawn_emulator(TPMEmulator *tpm_pt) -+{ -+ int fds[2] = { -1, -1 }; -+ int ctrl_fds[2] = { -1, -1 }; -+ pid_t cpid; -+ -+ if (!tpm_pt->ops->has_data_path) { -+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) { -+ return -1; -+ } -+ } -+ -+ if (!tpm_pt->ops->has_ctrl_path) { -+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ctrl_fds) < 0) { -+ if (!tpm_pt->ops->has_data_path) { -+ closesocket(fds[0]); -+ closesocket(fds[1]); -+ } -+ return -1; -+ } -+ } -+ -+ cpid = qemu_fork(NULL); -+ if (cpid < 0) { -+ error_report("tpm-emulator: Fork failure: %s", strerror(errno)); -+ if (!tpm_pt->ops->has_data_path) { -+ closesocket(fds[0]); -+ closesocket(fds[1]); -+ } -+ if (!tpm_pt->ops->has_ctrl_path) { -+ closesocket(ctrl_fds[0]); -+ closesocket(ctrl_fds[1]); -+ } -+ return -1; -+ } -+ -+ if (cpid == 0) { /* CHILD */ -+ enum { -+ PARAM_PATH, -+ PARAM_IFACE, -+ PARAM_SERVER, PARAM_SERVER_ARGS, -+ PARAM_CTRL, PARAM_CTRL_ARGS, -+ PARAM_STATE, PARAM_STATE_ARGS, -+ PARAM_PIDFILE, PARAM_PIDFILE_ARGS, -+ PARAM_LOG, PARAM_LOG_ARGS, -+ PARAM_MAX -+ }; -+ -+ int i; -+ int data_fd = -1, ctrl_fd = -1; -+ char *argv[PARAM_MAX+1]; -+ -+ /* close all unused inherited sockets */ -+ if (fds[0] >= 0) -+ closesocket(fds[0]); -+ if (ctrl_fds[0] >= 0) -+ closesocket(ctrl_fds[0]); -+ -+ i = STDERR_FILENO + 1; -+ if (fds[1] >= 0) { -+ data_fd = dup2(fds[1], i++); -+ if (data_fd < 0) { -+ error_report("tpm-emulator: dup2() failure - %s", -+ strerror(errno)); -+ goto exit_child; -+ } -+ } -+ if (ctrl_fds[1] >= 0) { -+ ctrl_fd = dup2(ctrl_fds[1], i++); -+ if (ctrl_fd < 0) { -+ error_report("tpm-emulator: dup2() failure - %s", -+ strerror(errno)); -+ goto exit_child; -+ } -+ } -+ for ( ; i < _SC_OPEN_MAX; i++) { -+ closesocket(i); -+ } -+ -+ argv[PARAM_MAX] = NULL; -+ argv[PARAM_PATH] = g_strdup(tpm_pt->ops->path); -+ argv[PARAM_IFACE] = g_strdup("socket"); -+ if (tpm_pt->ops->has_data_path) { -+ argv[PARAM_SERVER] = g_strdup("--server"); -+ argv[PARAM_SERVER_ARGS] = g_strdup_printf("type=unixio,path=%s", -+ tpm_pt->ops->data_path); -+ } else { -+ argv[PARAM_SERVER] = g_strdup("--fd"); -+ argv[PARAM_SERVER_ARGS] = g_strdup_printf("%d", data_fd); -+ } -+ -+ argv[PARAM_CTRL] = g_strdup("--ctrl"); -+ if (tpm_pt->ops->has_ctrl_path) { -+ argv[PARAM_CTRL_ARGS] = g_strdup_printf("type=unixio,path=%s", -+ tpm_pt->ops->ctrl_path); -+ } else { -+ argv[PARAM_CTRL_ARGS] = g_strdup_printf("type=unixio,clientfd=%d", -+ ctrl_fd); -+ } -+ -+ argv[PARAM_STATE] = g_strdup("--tpmstate"); -+ argv[PARAM_STATE_ARGS] = g_strdup_printf("dir=%s", -+ tpm_pt->ops->tpmstatedir); -+ argv[PARAM_PIDFILE] = g_strdup("--pid"); -+ argv[PARAM_PIDFILE_ARGS] = g_strdup_printf("file=%s", -+ TPM_EMULATOR_PIDFILE); -+ if (tpm_pt->ops->has_logfile) { -+ argv[PARAM_LOG] = g_strdup("--log"); -+ argv[PARAM_LOG_ARGS] = g_strdup_printf("file=%s,level=%d", -+ tpm_pt->ops->logfile, (int)tpm_pt->ops->loglevel); -+ } else { -+ /* truncate logs */ -+ argv[PARAM_LOG] = NULL; -+ } -+ DPRINTF("%s", "Running cmd: ") -+ for (i = 0; argv[i]; i++) { -+ DPRINT(" %s", argv[i]) -+ } -+ DPRINT("\n") -+ if (execv(tpm_pt->ops->path, (char * const *)argv) < 0) { -+ error_report("execv() failure : %s", strerror(errno)); -+ } -+ -+exit_child: -+ g_strfreev(argv); -+ if (data_fd >= 0) -+ closesocket(data_fd); -+ if (ctrl_fd >= 0) -+ closesocket(ctrl_fd); -+ -+ exit(0); -+ } else { /* self */ -+ struct stat st; -+ DPRINTF("child pid: %d", cpid); -+ int rc; -+ int timeout = 3; /* wait for max 3 seconds */ -+ -+ /* close unsed sockets */ -+ if (fds[1] >= 0) -+ closesocket(fds[1]); -+ if (ctrl_fds[1] >= 0) -+ closesocket(ctrl_fds[1]); -+ -+ while((rc = stat(TPM_EMULATOR_PIDFILE, &st)) < 0 && timeout--) { -+ sleep(1); -+ } -+ -+ if (timeout == -1) { -+ error_report("tpm-emulator: failed to find pid file: %s", -+ strerror(errno)); -+ goto err_kill_child; -+ } -+ -+ tpm_pt->data_ioc = _iochannel_new(tpm_pt->ops->data_path, fds[0], NULL); -+ if (!tpm_pt->data_ioc) { -+ error_report("tpm-emulator: Unable to connect socket : %s", -+ tpm_pt->ops->data_path); -+ goto err_kill_child; -+ } -+ -+ tpm_pt->ctrl_ioc = _iochannel_new(tpm_pt->ops->ctrl_path, ctrl_fds[0], NULL); -+ if (!tpm_pt->ctrl_ioc) { -+ error_report("tpm-emulator: Unable to connect socket : %s", -+ tpm_pt->ops->ctrl_path); -+ goto err_kill_child; -+ } -+ -+ tpm_pt->child_running = true; -+ -+ qemu_add_child_watch(cpid); -+ -+ qio_channel_add_watch(tpm_pt->data_ioc, G_IO_HUP|G_IO_ERR, -+ tpm_emulator_fd_handler, tpm_pt, NULL); -+ } -+ -+ return 0; -+ -+err_kill_child: -+ kill(cpid, SIGTERM); -+ closesocket(fds[0]); -+ closesocket(ctrl_fds[0]); -+ tpm_pt->child_running = false; -+ -+ return -1; -+} -+ -+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_pt, QemuOpts *opts) -+{ -+ const char *value; -+ -+ value = qemu_opt_get(opts, "tpmstatedir"); -+ if (!value) { -+ error_report("tpm-emulator: Missing tpm state directory"); -+ return -1; -+ } -+ tpm_pt->ops->tpmstatedir = g_strdup(value); -+ -+ tpm_pt->ops->spawn = qemu_opt_get_bool(opts, "spawn", false); -+ -+ value = qemu_opt_get(opts, "path"); -+ if (!value) { -+ value = TPM_DEFAULT_EMULATOR; -+ tpm_pt->ops->has_path = false; -+ } else { -+ tpm_pt->ops->has_path = true; -+ if (value[0] == '/') { -+ struct stat st; -+ if (stat(value, &st) < 0 || !(S_ISREG(st.st_mode) -+ || S_ISLNK(st.st_mode))) { -+ error_report("tpm-emulator: Invalid emulator path: %s", value); -+ return -1; -+ } -+ } -+ } -+ tpm_pt->ops->path = g_strdup(value); -+ -+ value = qemu_opt_get(opts, "data-path"); -+ if (value) { -+ tpm_pt->ops->has_data_path = true; -+ tpm_pt->ops->data_path = g_strdup(value); -+ } else { -+ tpm_pt->ops->has_data_path = false; -+ if (!tpm_pt->ops->spawn) { -+ error_report("tpm-emulator: missing mandatory data-path"); -+ return -1; -+ } -+ } -+ -+ value = qemu_opt_get(opts, "ctrl-path"); -+ if (value) { -+ tpm_pt->ops->has_ctrl_path = true; -+ tpm_pt->ops->ctrl_path = g_strdup(value); -+ } else { -+ tpm_pt->ops->has_ctrl_path = false; -+ if (!tpm_pt->ops->spawn) { -+ error_report("tpm-emulator: missing mandatory ctrl-path"); -+ return -1; -+ } -+ } -+ -+ value = qemu_opt_get(opts, "logfile"); -+ if (value) { -+ tpm_pt->ops->has_logfile = true; -+ tpm_pt->ops->logfile = g_strdup(value); -+ tpm_pt->ops->loglevel = qemu_opt_get_number(opts, "loglevel", -+ TPM_DEFAULT_LOGLEVEL); -+ tpm_pt->ops->has_loglevel = tpm_pt->ops->loglevel != -+ TPM_DEFAULT_LOGLEVEL; -+ } -+ -+ if (tpm_pt->ops->spawn) { -+ if (tpm_emulator_spawn_emulator(tpm_pt) < 0) { -+ goto err_close_dev; -+ } -+ } else { -+ tpm_pt->data_ioc = _iochannel_new(tpm_pt->ops->data_path, -1, NULL); -+ if (tpm_pt->data_ioc == NULL) { -+ error_report("tpm-emulator: Failed to connect data socket: %s", -+ tpm_pt->ops->data_path); -+ goto err_close_dev; -+ } -+ tpm_pt->ctrl_ioc = _iochannel_new(tpm_pt->ops->ctrl_path, -1, NULL); -+ if (tpm_pt->ctrl_ioc == NULL) { -+ DPRINTF("Failed to connect control socket: %s", -+ strerror(errno)); -+ goto err_close_dev; -+ } -+ tpm_pt->child_running = true; -+ } -+ -+ if (tpm_emulator_probe_caps(tpm_pt) || -+ tpm_emulator_init_tpm(tpm_pt)) { -+ goto err_close_dev; -+ } -+ -+ /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used -+ * by passthrough driver, which not yet using GIOChannel. -+ */ -+ if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_pt->data_ioc)->fd, -+ &tpm_pt->tpm_version)) { -+ error_report("'%s' is not emulating TPM device.", tpm_pt->ops->path); -+ goto err_close_dev; -+ } -+ -+ DPRINTF("TPM Version %s", tpm_pt->tpm_version == TPM_VERSION_1_2 ? "1.2" : -+ (tpm_pt->tpm_version == TPM_VERSION_2_0 ? "2.0" : "Unspecified")); -+ -+ if (tpm_emulator_check_caps(tpm_pt)) { -+ goto err_close_dev; -+ } -+ -+ return 0; -+ -+err_close_dev: -+ DPRINTF("%s", "Startup error, shutting down..."); -+ tpm_emulator_shutdown(tpm_pt); -+ return -1; -+} -+ -+static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id) -+{ -+ TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR)); -+ -+ tb->id = g_strdup(id); -+ -+ if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) { -+ goto err_exit; -+ } -+ -+ return tb; -+ -+err_exit: -+ object_unref(OBJECT(tb)); -+ -+ return NULL; -+} -+ -+static TPMOptions *tpm_emulator_get_tpm_options(TPMBackend *tb) -+{ -+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb); -+ TPMEmulatorOptions *ops = g_new0(TPMEmulatorOptions, 1); -+ -+ if (!ops) { -+ return NULL; -+ } -+ DPRINTF("%s", __func__); -+ -+ ops->tpmstatedir = g_strdup(tpm_pt->ops->tpmstatedir); -+ ops->spawn = tpm_pt->ops->spawn; -+ if (tpm_pt->ops->has_path) { -+ ops->has_path = true; -+ ops->path = g_strdup(tpm_pt->ops->path); -+ } -+ if (tpm_pt->ops->has_data_path) { -+ ops->has_data_path = true; -+ ops->data_path = g_strdup(tpm_pt->ops->data_path); -+ } -+ if (tpm_pt->ops->has_ctrl_path) { -+ ops->has_ctrl_path = true; -+ ops->ctrl_path = g_strdup(tpm_pt->ops->ctrl_path); -+ } -+ if (tpm_pt->ops->has_logfile) { -+ ops->has_logfile = true; -+ ops->logfile = g_strdup(tpm_pt->ops->logfile); -+ } -+ if (tpm_pt->ops->has_loglevel) { -+ ops->has_loglevel = true; -+ ops->loglevel = tpm_pt->ops->loglevel; -+ } -+ -+ return (TPMOptions *)ops; -+} -+ -+static const QemuOptDesc tpm_emulator_cmdline_opts[] = { -+ TPM_STANDARD_CMDLINE_OPTS, -+ { -+ .name = "tpmstatedir", -+ .type = QEMU_OPT_STRING, -+ .help = "TPM state directroy", -+ }, -+ { -+ .name = "spawn", -+ .type = QEMU_OPT_BOOL, -+ .help = "Wether to spwan given emlatory binary", -+ }, -+ { -+ .name = "path", -+ .type = QEMU_OPT_STRING, -+ .help = "Path to TPM emulator binary", -+ }, -+ { -+ .name = "data-path", -+ .type = QEMU_OPT_STRING, -+ .help = "Socket path to use for data exhange", -+ }, -+ { -+ .name = "ctrl-path", -+ .type = QEMU_OPT_STRING, -+ .help = "Socket path to use for out-of-band control messages", -+ }, -+ { -+ .name = "logfile", -+ .type = QEMU_OPT_STRING, -+ .help = "Path to log file", -+ }, -+ { -+ .name = "level", -+ .type = QEMU_OPT_STRING, -+ .help = "Log level number", -+ }, -+ { /* end of list */ }, -+}; -+ -+static const TPMDriverOps tpm_emulator_driver = { -+ .type = TPM_TYPE_EMULATOR, -+ .opts = tpm_emulator_cmdline_opts, -+ .desc = tpm_emulator_desc, -+ .create = tpm_emulator_create, -+ .startup_tpm = tpm_emulator_startup_tpm, -+ .reset = tpm_emulator_reset, -+ .had_startup_error = tpm_emulator_had_startup_error, -+ .cancel_cmd = tpm_emulator_cancel_cmd, -+ .get_tpm_established_flag = tpm_emulator_get_tpm_established_flag, -+ .reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag, -+ .get_tpm_version = tpm_emulator_get_tpm_version, -+ .get_tpm_options = tpm_emulator_get_tpm_options, -+}; -+ -+static void tpm_emulator_inst_init(Object *obj) -+{ -+ TPMEmulator *tpm_pt = TPM_EMULATOR(obj); -+ -+ DPRINTF("%s", __func__); -+ tpm_pt->ops = g_new0(TPMEmulatorOptions, 1); -+ tpm_pt->data_ioc = tpm_pt->ctrl_ioc = NULL; -+ tpm_pt->op_executing = tpm_pt->op_canceled = false; -+ tpm_pt->child_running = false; -+ tpm_pt->cur_locty_number = ~0; -+ qemu_mutex_init(&tpm_pt->state_lock); -+} -+ -+static void tpm_emulator_inst_finalize(Object *obj) -+{ -+ TPMEmulator *tpm_pt = TPM_EMULATOR(obj); -+ -+ tpm_emulator_cancel_cmd(TPM_BACKEND(obj)); -+ tpm_emulator_shutdown(tpm_pt); -+ -+ if (tpm_pt->data_ioc) { -+ qio_channel_close(tpm_pt->data_ioc, NULL); -+ } -+ if (tpm_pt->ctrl_ioc) { -+ qio_channel_close(tpm_pt->ctrl_ioc, NULL); -+ } -+ if (tpm_pt->ops) { -+ qapi_free_TPMEmulatorOptions(tpm_pt->ops); -+ } -+} -+ -+static void tpm_emulator_class_init(ObjectClass *klass, void *data) -+{ -+ TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass); -+ tbc->ops = &tpm_emulator_driver; -+ tbc->handle_request = tpm_emulator_handle_request; -+} -+ -+static const TypeInfo tpm_emulator_info = { -+ .name = TYPE_TPM_EMULATOR, -+ .parent = TYPE_TPM_BACKEND, -+ .instance_size = sizeof(TPMEmulator), -+ .class_init = tpm_emulator_class_init, -+ .instance_init = tpm_emulator_inst_init, -+ .instance_finalize = tpm_emulator_inst_finalize, -+}; -+ -+static void tpm_emulator_register(void) -+{ -+ type_register_static(&tpm_emulator_info); -+ tpm_register_driver(&tpm_emulator_driver); -+} -+ -+type_init(tpm_emulator_register) -diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h -new file mode 100644 -index 00000000..af49708a ---- /dev/null -+++ b/hw/tpm/tpm_ioctl.h -@@ -0,0 +1,243 @@ -+/* -+ * tpm_ioctl.h -+ * -+ * (c) Copyright IBM Corporation 2014, 2015. -+ * -+ * This file is licensed under the terms of the 3-clause BSD license -+ */ -+#ifndef _TPM_IOCTL_H_ -+#define _TPM_IOCTL_H_ -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * Every response from a command involving a TPM command execution must hold -+ * the ptm_res as the first element. -+ * ptm_res corresponds to the error code of a command executed by the TPM. -+ */ -+ -+typedef uint32_t ptm_res; -+ -+/* PTM_GET_TPMESTABLISHED: get the establishment bit */ -+struct ptm_est { -+ union { -+ struct { -+ ptm_res tpm_result; -+ unsigned char bit; /* TPM established bit */ -+ } resp; /* response */ -+ } u; -+}; -+ -+/* PTM_RESET_TPMESTABLISHED: reset establishment bit */ -+struct ptm_reset_est { -+ union { -+ struct { -+ uint8_t loc; /* locality to use */ -+ } req; /* request */ -+ struct { -+ ptm_res tpm_result; -+ } resp; /* response */ -+ } u; -+}; -+ -+/* PTM_INIT */ -+struct ptm_init { -+ union { -+ struct { -+ uint32_t init_flags; /* see definitions below */ -+ } req; /* request */ -+ struct { -+ ptm_res tpm_result; -+ } resp; /* response */ -+ } u; -+}; -+ -+/* above init_flags */ -+#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0) -+ /* delete volatile state file after reading it */ -+ -+/* PTM_SET_LOCALITY */ -+struct ptm_loc { -+ union { -+ struct { -+ uint8_t loc; /* locality to set */ -+ } req; /* request */ -+ struct { -+ ptm_res tpm_result; -+ } resp; /* response */ -+ } u; -+}; -+ -+/* PTM_HASH_DATA: hash given data */ -+struct ptm_hdata { -+ union { -+ struct { -+ uint32_t length; -+ uint8_t data[4096]; -+ } req; /* request */ -+ struct { -+ ptm_res tpm_result; -+ } resp; /* response */ -+ } u; -+}; -+ -+/* -+ * size of the TPM state blob to transfer; x86_64 can handle 8k, -+ * ppc64le only ~7k; keep the response below a 4k page size -+ */ -+#define PTM_STATE_BLOB_SIZE (3 * 1024) -+ -+/* -+ * The following is the data structure to get state blobs from the TPM. -+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple reads -+ * with this ioctl and with adjusted offset are necessary. All bytes -+ * must be transferred and the transfer is done once the last byte has been -+ * returned. -+ * It is possible to use the read() interface for reading the data; however, the -+ * first bytes of the state blob will be part of the response to the ioctl(); a -+ * subsequent read() is only necessary if the total length (totlength) exceeds -+ * the number of received bytes. seek() is not supported. -+ */ -+struct ptm_getstate { -+ union { -+ struct { -+ uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */ -+ uint32_t type; /* which blob to pull */ -+ uint32_t offset; /* offset from where to read */ -+ } req; /* request */ -+ struct { -+ ptm_res tpm_result; -+ uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */ -+ uint32_t totlength; /* total length that will be transferred */ -+ uint32_t length; /* number of bytes in following buffer */ -+ uint8_t data[PTM_STATE_BLOB_SIZE]; -+ } resp; /* response */ -+ } u; -+}; -+ -+/* TPM state blob types */ -+#define PTM_BLOB_TYPE_PERMANENT 1 -+#define PTM_BLOB_TYPE_VOLATILE 2 -+#define PTM_BLOB_TYPE_SAVESTATE 3 -+ -+/* state_flags above : */ -+#define PTM_STATE_FLAG_DECRYPTED 1 /* on input: get decrypted state */ -+#define PTM_STATE_FLAG_ENCRYPTED 2 /* on output: state is encrypted */ -+ -+/* -+ * The following is the data structure to set state blobs in the TPM. -+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple -+ * 'writes' using this ioctl are necessary. The last packet is indicated -+ * by the length being smaller than the PTM_STATE_BLOB_SIZE. -+ * The very first packet may have a length indicator of '0' enabling -+ * a write() with all the bytes from a buffer. If the write() interface -+ * is used, a final ioctl with a non-full buffer must be made to indicate -+ * that all data were transferred (a write with 0 bytes would not work). -+ */ -+struct ptm_setstate { -+ union { -+ struct { -+ uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */ -+ uint32_t type; /* which blob to set */ -+ uint32_t length; /* length of the data; -+ use 0 on the first packet to -+ transfer using write() */ -+ uint8_t data[PTM_STATE_BLOB_SIZE]; -+ } req; /* request */ -+ struct { -+ ptm_res tpm_result; -+ } resp; /* response */ -+ } u; -+}; -+ -+/* -+ * PTM_GET_CONFIG: Data structure to get runtime configuration information -+ * such as which keys are applied. -+ */ -+struct ptm_getconfig { -+ union { -+ struct { -+ ptm_res tpm_result; -+ uint32_t flags; -+ } resp; /* response */ -+ } u; -+}; -+ -+#define PTM_CONFIG_FLAG_FILE_KEY 0x1 -+#define PTM_CONFIG_FLAG_MIGRATION_KEY 0x2 -+ -+ -+typedef uint64_t ptm_cap; -+typedef struct ptm_est ptm_est; -+typedef struct ptm_reset_est ptm_reset_est; -+typedef struct ptm_loc ptm_loc; -+typedef struct ptm_hdata ptm_hdata; -+typedef struct ptm_init ptm_init; -+typedef struct ptm_getstate ptm_getstate; -+typedef struct ptm_setstate ptm_setstate; -+typedef struct ptm_getconfig ptm_getconfig; -+ -+/* capability flags returned by PTM_GET_CAPABILITY */ -+#define PTM_CAP_INIT (1) -+#define PTM_CAP_SHUTDOWN (1 << 1) -+#define PTM_CAP_GET_TPMESTABLISHED (1 << 2) -+#define PTM_CAP_SET_LOCALITY (1 << 3) -+#define PTM_CAP_HASHING (1 << 4) -+#define PTM_CAP_CANCEL_TPM_CMD (1 << 5) -+#define PTM_CAP_STORE_VOLATILE (1 << 6) -+#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7) -+#define PTM_CAP_GET_STATEBLOB (1 << 8) -+#define PTM_CAP_SET_STATEBLOB (1 << 9) -+#define PTM_CAP_STOP (1 << 10) -+#define PTM_CAP_GET_CONFIG (1 << 11) -+ -+enum { -+ PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap), -+ PTM_INIT = _IOWR('P', 1, ptm_init), -+ PTM_SHUTDOWN = _IOR('P', 2, ptm_res), -+ PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est), -+ PTM_SET_LOCALITY = _IOWR('P', 4, ptm_loc), -+ PTM_HASH_START = _IOR('P', 5, ptm_res), -+ PTM_HASH_DATA = _IOWR('P', 6, ptm_hdata), -+ PTM_HASH_END = _IOR('P', 7, ptm_res), -+ PTM_CANCEL_TPM_CMD = _IOR('P', 8, ptm_res), -+ PTM_STORE_VOLATILE = _IOR('P', 9, ptm_res), -+ PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est), -+ PTM_GET_STATEBLOB = _IOWR('P', 11, ptm_getstate), -+ PTM_SET_STATEBLOB = _IOWR('P', 12, ptm_setstate), -+ PTM_STOP = _IOR('P', 13, ptm_res), -+ PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig), -+}; -+ -+/* -+ * Commands used by the non-CUSE TPMs -+ * -+ * All messages container big-endian data. -+ * -+ * The return messages only contain the 'resp' part of the unions -+ * in the data structures above. Besides that the limits in the -+ * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data -+ * and ptm_set_state:u.req.data) are 0xffffffff. -+ */ -+enum { -+ CMD_GET_CAPABILITY = 1, -+ CMD_INIT, -+ CMD_SHUTDOWN, -+ CMD_GET_TPMESTABLISHED, -+ CMD_SET_LOCALITY, -+ CMD_HASH_START, -+ CMD_HASH_DATA, -+ CMD_HASH_END, -+ CMD_CANCEL_TPM_CMD, -+ CMD_STORE_VOLATILE, -+ CMD_RESET_TPMESTABLISHED, -+ CMD_GET_STATEBLOB, -+ CMD_SET_STATEBLOB, -+ CMD_STOP, -+ CMD_GET_CONFIG, -+}; -+ -+#endif /* _TPM_IOCTL_H */ -diff --git a/qapi-schema.json b/qapi-schema.json -index d50d49e5..a065d721 100644 ---- a/qapi-schema.json -+++ b/qapi-schema.json -@@ -3959,10 +3959,12 @@ - # An enumeration of TPM types - # - # @passthrough: TPM passthrough type -+# @emulator: Software Emulator TPM type -+# Since: 2.10 - # - # Since: 1.5 - ## --{ 'enum': 'TpmType', 'data': [ 'passthrough' ] } -+{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ] } - - ## - # @query-tpm-types: -@@ -4000,6 +4002,36 @@ - { 'struct': 'TPMPassthroughOptions', 'base': 'TPMOptions', - 'data': { '*path' : 'str', '*cancel-path' : 'str'} } - -+## -+# @TPMEmulatorOptions: -+# -+# Information about the TPM emulator -+# -+# @tpmstatedir: TPM emulator state directory -+# @spawn: true if, qemu has to spawn a new emulator process with given @path, -+# otherwise it connects to already rinning emulator with given @data-path -+# and @ctrl-path sockets. (default: 'false') -+# @path: TPM emulator binary path to spawn.(default: 'swtpm') -+# @data-path: path of the unix socket to use for exchanging data messages, if -+# not provided socket pairs are used when @sapwn is true. -+# @ctrl-path: path of the unix socket file to use for exchagning out-of-band -+# control messages, if not provided socket pairs are used when -+# @spawn is true. -+# @logfile: file to use to place TPM emulator logs, if not provided logging is -+# disabled. -+# @loglevel: optional log level number, loglevel is ignored if no logfile -+# provided. (default: 5) -+# -+# Since: 2.10 -+## -+{ 'struct': 'TPMEmulatorOptions', 'base': 'TPMOptions', -+ 'data': { 'tpmstatedir' : 'str', -+ 'spawn': 'bool', -+ '*path': 'str', -+ '*data-path': 'str', -+ '*ctrl-path': 'str', -+ '*logfile': 'str', -+ '*loglevel': 'int' } } - - ## - # @TPMInfo: -diff --git a/qemu-options.hx b/qemu-options.hx -index c534a2f7..649ffbf0 100644 ---- a/qemu-options.hx -+++ b/qemu-options.hx -@@ -2793,7 +2793,15 @@ DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \ - "-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n" - " use path to provide path to a character device; default is /dev/tpm0\n" - " use cancel-path to provide path to TPM's cancel sysfs entry; if\n" -- " not provided it will be searched for in /sys/class/misc/tpm?/device\n", -+ " not provided it will be searched for in /sys/class/misc/tpm?/device\n" -+ "-tpmdev emulator,id=id,spawn=on|off,tpmstatedir=dir[,path=emulator-path,data-path=path,ctrl-path=path,logfile=path,loglevel=level]\n" -+ " spawn=on|off controls spawning support\n" -+ " use tpmstatedir to provide path to the tpm state dirctory\n" -+ " use path to provide the emulator binary to launch; default is 'swtpm'\n" -+ " use data-path to provide the socket path for exchanging data messages\n" -+ " use ctrl-path to provide the socket path for sending control messages to software emulator\n" -+ " use logfile to provide where to place the swtpm logs\n" -+ " use loglevel to controls the swtpm log level\n", - QEMU_ARCH_ALL) - STEXI - -@@ -2802,8 +2810,8 @@ The general form of a TPM device option is: - - @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}] - @findex -tpmdev --Backend type must be: --@option{passthrough}. -+Backend type must be either one of the following: -+@option{passthrough}, @option{emulator}. - - The specific backend type will determine the applicable options. - The @code{-tpmdev} option creates the TPM backend and requires a -@@ -2853,6 +2861,45 @@ To create a passthrough TPM use the following two options: - Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by - @code{tpmdev=tpm0} in the device option. - -+@item -tpmdev emulator, id=@var{id}, tpmstatedir=@var{path}, spawn=@var{on|off}, path=@var{emulator-binary-path}, data-path=@var{path}, ctrl-path=@var{path}, logfile=@var{path}, loglevel=@var{level} -+ -+(Linux-host only) Enable access to a TPM emulator using unix domain sockets. -+ -+@option{tpmstatedir} specifies the tpm state directory -+ -+@option{spawn} specifies if qemu should spawn new emulator process with given @option{path} -+ -+@option{path} specifies the emulator binary path to use for spawning -+ -+@option{data-path} optional socket path to use for exchanging TPM data with emulator -+ -+@option{ctrl-path} optional socket path to use for sending control data to emulator -+ -+@option{logfile} optional log file to use to place log messages -+ -+@option{loglevel} specifies the log level to use -+ -+To create TPM emulator backend device that spawns new swtpm binary and communicate with socket pairs: -+@example -+ -+-tpmdev emulator,id=tpm0,tpmstatedir=/tmp/my-tpm,spawn=on,path=/usr/local/bin/swtpm,logfile=/tmp/qemu-tpm.log,loglevel=5 -device tpm-tis,tpmdev=tpm0 -+ -+@end example -+ -+To create TPM emulator backend device that spawns new swtpm binary and communicate using unix file system sockets: -+@example -+ -+-tpmdev emulator,id=tpm0,tpmstatedir=/tmp/my-tpm,spawn=on,path=/usr/local/bin/swtpm,data-path=/tmp/swtpm-data.socket,ctrl-path=/tmp/swtpm-ctrl.socket,logfile=/tmp/qemu-tpm.log,loglevel=5 -device tpm-tis,tpmdev=tpm0 -+ -+@end example -+ -+To create a TOM emulator backend device that connects to already running swtpm binary using file system sockets: -+@example -+ -+-tpmdev emulator,id=tpm0,tpmstatedir=/tmp/my-tpm,spawn=off,data-path=/tmp/swtpm-data.socket,ctrl-path=/tmp/swtpm-ctrl.socket,logfile=/tmp/qemu-tpm.log,loglevel=5 -device tpm-tis,tpmdev=tpm0 -+ -+@end example -+ - @end table - - ETEXI -diff --git a/tpm.c b/tpm.c -index 43d980e0..ce07c407 100644 ---- a/tpm.c -+++ b/tpm.c -@@ -25,7 +25,7 @@ static QLIST_HEAD(, TPMBackend) tpm_backends = - - - #define TPM_MAX_MODELS 1 --#define TPM_MAX_DRIVERS 1 -+#define TPM_MAX_DRIVERS 2 - - static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = { - NULL, --- -2.11.0 - diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0008-tpm-passthrough-move-reusable-code-to-utils.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0009-tpm-passthrough-move-reusable-code-to-utils.patch similarity index 89% rename from meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0008-tpm-passthrough-move-reusable-code-to-utils.patch rename to meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0009-tpm-passthrough-move-reusable-code-to-utils.patch index fec10ba971..8670b8a0d3 100644 --- a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0008-tpm-passthrough-move-reusable-code-to-utils.patch +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0009-tpm-passthrough-move-reusable-code-to-utils.patch @@ -1,11 +1,16 @@ -From c97d727c193d8f30800fe14a7d546e252a84ffa4 Mon Sep 17 00:00:00 2001 +From b8322aaa2f31995e1b7b776e7efae68416573bc3 Mon Sep 17 00:00:00 2001 From: Amarnath Valluri -Date: Fri, 7 Apr 2017 17:30:30 +0300 -Subject: [PATCH 8/9] tpm-passthrough: move reusable code to utils +Date: Wed, 29 Mar 2017 15:36:47 +0300 +Subject: [PATCH 09/12] tpm-passthrough: move reusable code to utils +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit Signed-off-by: Amarnath Valluri -Upstream-Status: Submitted [http://lists.nongnu.org/archive/html/qemu-devel/2017-04/msg01278.html] -Signed-off-by: Patrick Ohly +Reviewed-by: Stefan Berger +Reviewed-by: Marc-André Lureau + +Upstream-Status: Backport [4a3d80980ebf71d8faf9d0ce2e2e23bdda5728df] --- hw/tpm/tpm_passthrough.c | 64 ++++-------------------------------------------- hw/tpm/tpm_util.c | 25 +++++++++++++++++++ @@ -13,7 +18,7 @@ Signed-off-by: Patrick Ohly 3 files changed, 34 insertions(+), 59 deletions(-) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c -index 1bffb6da..ca7c8bb9 100644 +index 22d3460550..e6ace28b04 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -68,27 +68,6 @@ typedef struct TPMPassthruState TPMPassthruState; @@ -108,7 +113,7 @@ index 1bffb6da..ca7c8bb9 100644 } } else if (ret < sizeof(struct tpm_resp_hdr) || - tpm_passthrough_get_size_from_buffer(out) != ret) { -+ ((struct tpm_resp_hdr *)out)->len != ret) { ++ be32_to_cpu(((struct tpm_resp_hdr *)out)->len) != ret) { ret = -1; error_report("tpm_passthrough: received invalid response " "packet from TPM"); @@ -122,7 +127,7 @@ index 1bffb6da..ca7c8bb9 100644 tpm_pt->tpm_executing = false; diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c -index 7b354297..fb929f6e 100644 +index 7b35429725..fb929f6e92 100644 --- a/hw/tpm/tpm_util.c +++ b/hw/tpm/tpm_util.c @@ -24,6 +24,31 @@ @@ -158,7 +163,7 @@ index 7b354297..fb929f6e 100644 * (error response is fine) within one second. */ diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h -index df76245e..2f7c9614 100644 +index df76245e6e..2f7c96146d 100644 --- a/hw/tpm/tpm_util.h +++ b/hw/tpm/tpm_util.h @@ -24,6 +24,10 @@ diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0010-tpm-Added-support-for-TPM-emulator.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0010-tpm-Added-support-for-TPM-emulator.patch new file mode 100644 index 0000000000..968e12e88a --- /dev/null +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0010-tpm-Added-support-for-TPM-emulator.patch @@ -0,0 +1,1059 @@ +From 70e73b7c6c7cf982d645db9c81c74588e6b10a2b Mon Sep 17 00:00:00 2001 +From: Amarnath Valluri +Date: Wed, 29 Mar 2017 15:39:41 +0300 +Subject: [PATCH 10/12] tpm: Added support for TPM emulator + +This change introduces a new TPM backend driver that can communicate with +swtpm(software TPM emulator) using unix domain socket interface. QEMU talks to +TPM emulator using QEMU's socket-based chardev backend device. + +Swtpm uses two Unix sockets for communications, one for plain TPM commands and +responses, and one for out-of-band control messages. QEMU passes data socket to +be used over the control channel. + +The swtpm and associated tools can be found here: + https://github.com/stefanberger/swtpm + +The swtpm's control channel protocol specification can be found here: + https://github.com/stefanberger/swtpm/wiki/Control-Channel-Specification + +Usage: + # setup TPM state directory + mkdir /tmp/mytpm + chown -R tss:root /tmp/mytpm + /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek + + # Ask qemu to use TPM emulator with given tpm state directory + qemu-system-x86_64 \ + [...] \ + -chardev socket,id=chrtpm,path=/tmp/swtpm-sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 \ + [...] + +Signed-off-by: Amarnath Valluri + +Upstream-Status: Backport [f4ede81eed29e6140374177d1f2808248c5b5650] +--- + configure | 13 +- + hmp.c | 5 + + hw/tpm/Makefile.objs | 1 + + hw/tpm/tpm_emulator.c | 583 ++++++++++++++++++++++++++++++++++++++++++++++++++ + hw/tpm/tpm_ioctl.h | 246 +++++++++++++++++++++ + qapi-schema.json | 18 +- + qemu-options.hx | 22 +- + 7 files changed, 882 insertions(+), 6 deletions(-) + create mode 100644 hw/tpm/tpm_emulator.c + create mode 100644 hw/tpm/tpm_ioctl.h + +diff --git a/configure b/configure +index dd73cce62f..9a25537096 100755 +--- a/configure ++++ b/configure +@@ -3503,6 +3503,12 @@ else + tpm_passthrough=no + fi + ++# TPM emulator is for all posix systems ++if test "$mingw32" != "yes"; then ++ tpm_emulator=$tpm ++else ++ tpm_emulator=no ++fi + ########################################## + # attr probe + +@@ -5396,6 +5402,7 @@ echo "gcov enabled $gcov" + echo "TPM support $tpm" + echo "libssh2 support $libssh2" + echo "TPM passthrough $tpm_passthrough" ++echo "TPM emulator $tpm_emulator" + echo "QOM debugging $qom_cast_debug" + echo "Live block migration $live_block_migration" + echo "lzo support $lzo" +@@ -5983,12 +5990,16 @@ else + echo "HOST_USB=stub" >> $config_host_mak + fi + +-# TPM passthrough support? + if test "$tpm" = "yes"; then + echo 'CONFIG_TPM=$(CONFIG_SOFTMMU)' >> $config_host_mak ++ # TPM passthrough support? + if test "$tpm_passthrough" = "yes"; then + echo "CONFIG_TPM_PASSTHROUGH=y" >> $config_host_mak + fi ++ # TPM emulator support? ++ if test "$tpm_emulator" = "yes"; then ++ echo "CONFIG_TPM_EMULATOR=y" >> $config_host_mak ++ fi + fi + + echo "TRACE_BACKENDS=$trace_backends" >> $config_host_mak +diff --git a/hmp.c b/hmp.c +index fd80dce758..820aa8f002 100644 +--- a/hmp.c ++++ b/hmp.c +@@ -995,6 +995,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) + Error *err = NULL; + unsigned int c = 0; + TPMPassthroughOptions *tpo; ++ TPMEmulatorOptions *teo; + + info_list = qmp_query_tpm(&err); + if (err) { +@@ -1024,6 +1025,10 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) + tpo->has_cancel_path ? ",cancel-path=" : "", + tpo->has_cancel_path ? tpo->cancel_path : ""); + break; ++ case TPM_TYPE_OPTIONS_KIND_EMULATOR: ++ teo = ti->options->u.emulator.data; ++ monitor_printf(mon, ",chardev=%s", teo->chardev); ++ break; + case TPM_TYPE_OPTIONS_KIND__MAX: + break; + } +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index 64cecc3b67..41f0b7a590 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -1,2 +1,3 @@ + common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o ++common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o +diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c +new file mode 100644 +index 0000000000..433bc4fa8a +--- /dev/null ++++ b/hw/tpm/tpm_emulator.c +@@ -0,0 +1,583 @@ ++/* ++ * Emulator TPM driver ++ * ++ * Copyright (c) 2017 Intel Corporation ++ * Author: Amarnath Valluri ++ * ++ * Copyright (c) 2010 - 2013 IBM Corporation ++ * Authors: ++ * Stefan Berger ++ * ++ * Copyright (C) 2011 IAIK, Graz University of Technology ++ * Author: Andreas Niederl ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/error-report.h" ++#include "qemu/sockets.h" ++#include "io/channel-socket.h" ++#include "sysemu/tpm_backend.h" ++#include "tpm_int.h" ++#include "hw/hw.h" ++#include "hw/i386/pc.h" ++#include "tpm_util.h" ++#include "tpm_ioctl.h" ++#include "migration/blocker.h" ++#include "qapi/error.h" ++#include "qapi/clone-visitor.h" ++#include "chardev/char-fe.h" ++ ++#include ++#include ++#include ++#include ++ ++#define DEBUG_TPM 0 ++ ++#define DPRINTF(fmt, ...) do { \ ++ if (DEBUG_TPM) { \ ++ fprintf(stderr, "tpm-emulator:"fmt"\n", ## __VA_ARGS__); \ ++ } \ ++} while (0) ++ ++#define TYPE_TPM_EMULATOR "tpm-emulator" ++#define TPM_EMULATOR(obj) \ ++ OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR) ++ ++#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap)) ++ ++static const TPMDriverOps tpm_emulator_driver; ++ ++/* data structures */ ++typedef struct TPMEmulator { ++ TPMBackend parent; ++ ++ TPMEmulatorOptions *options; ++ CharBackend ctrl_chr; ++ QIOChannel *data_ioc; ++ TPMVersion tpm_version; ++ ptm_cap caps; /* capabilities of the TPM */ ++ uint8_t cur_locty_number; /* last set locality */ ++ Error *migration_blocker; ++} TPMEmulator; ++ ++ ++static int tpm_emulator_ctrlcmd(CharBackend *dev, unsigned long cmd, void *msg, ++ size_t msg_len_in, size_t msg_len_out) ++{ ++ uint32_t cmd_no = cpu_to_be32(cmd); ++ ssize_t n = sizeof(uint32_t) + msg_len_in; ++ uint8_t *buf = NULL; ++ ++ buf = g_alloca(n); ++ memcpy(buf, &cmd_no, sizeof(cmd_no)); ++ memcpy(buf + sizeof(cmd_no), msg, msg_len_in); ++ ++ n = qemu_chr_fe_write_all(dev, buf, n); ++ if (n <= 0) { ++ return -1; ++ } ++ ++ if (msg_len_out != 0) { ++ n = qemu_chr_fe_read_all(dev, msg, msg_len_out); ++ if (n <= 0) { ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, ++ const uint8_t *in, uint32_t in_len, ++ uint8_t *out, uint32_t out_len, ++ bool *selftest_done, ++ Error **err) ++{ ++ ssize_t ret; ++ bool is_selftest = false; ++ const struct tpm_resp_hdr *hdr = NULL; ++ ++ if (selftest_done) { ++ *selftest_done = false; ++ is_selftest = tpm_util_is_selftest(in, in_len); ++ } ++ ++ ret = qio_channel_write(tpm_emu->data_ioc, (char *)in, in_len, err); ++ if (ret != in_len) { ++ return -1; ++ } ++ ++ ret = qio_channel_read(tpm_emu->data_ioc, (char *)out, out_len, err); ++ if (ret <= 0 || ret < sizeof(*hdr)) { ++ return -1; ++ } ++ ++ hdr = (struct tpm_resp_hdr *)out; ++ if (be32_to_cpu(hdr->len) != ret) { ++ return -1; ++ } ++ ++ if (is_selftest) { ++ *selftest_done = (be32_to_cpu(hdr->errcode) == 0); ++ } ++ ++ return 0; ++} ++ ++static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number) ++{ ++ ptm_loc loc; ++ ++ DPRINTF("%s : locality: 0x%x", __func__, locty_number); ++ ++ if (tpm_emu->cur_locty_number == locty_number) { ++ return 0; ++ } ++ ++ DPRINTF("setting locality : 0x%x", locty_number); ++ loc.u.req.loc = locty_number; ++ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_SET_LOCALITY, &loc, ++ sizeof(loc), sizeof(loc)) < 0) { ++ error_report("tpm-emulator: could not set locality : %s", ++ strerror(errno)); ++ return -1; ++ } ++ ++ loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result); ++ if (loc.u.resp.tpm_result != 0) { ++ error_report("tpm-emulator: TPM result for set locality : 0x%x", ++ loc.u.resp.tpm_result); ++ return -1; ++ } ++ ++ tpm_emu->cur_locty_number = locty_number; ++ ++ return 0; ++} ++ ++static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd cmd) ++{ ++ TPMEmulator *tpm_emu = TPM_EMULATOR(tb); ++ TPMLocality *locty = NULL; ++ bool selftest_done = false; ++ Error *err = NULL; ++ ++ DPRINTF("processing command type %d", cmd); ++ ++ switch (cmd) { ++ case TPM_BACKEND_CMD_PROCESS_CMD: ++ locty = tb->tpm_state->locty_data; ++ if (tpm_emulator_set_locality(tpm_emu, ++ tb->tpm_state->locty_number) < 0 || ++ tpm_emulator_unix_tx_bufs(tpm_emu, locty->w_buffer.buffer, ++ locty->w_offset, locty->r_buffer.buffer, ++ locty->r_buffer.size, &selftest_done, ++ &err) < 0) { ++ tpm_util_write_fatal_error_response(locty->r_buffer.buffer, ++ locty->r_buffer.size); ++ error_report_err(err); ++ } ++ ++ tb->recv_data_callback(tb->tpm_state, tb->tpm_state->locty_number, ++ selftest_done); ++ ++ break; ++ case TPM_BACKEND_CMD_INIT: ++ case TPM_BACKEND_CMD_END: ++ case TPM_BACKEND_CMD_TPM_RESET: ++ /* nothing to do */ ++ break; ++ } ++} ++ ++static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu) ++{ ++ DPRINTF("%s", __func__); ++ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_GET_CAPABILITY, ++ &tpm_emu->caps, 0, sizeof(tpm_emu->caps)) < 0) { ++ error_report("tpm-emulator: probing failed : %s", strerror(errno)); ++ return -1; ++ } ++ ++ tpm_emu->caps = be64_to_cpu(tpm_emu->caps); ++ ++ DPRINTF("capbilities : 0x%lx", tpm_emu->caps); ++ ++ return 0; ++} ++ ++static int tpm_emulator_check_caps(TPMEmulator *tpm_emu) ++{ ++ ptm_cap caps = 0; ++ const char *tpm = NULL; ++ ++ /* check for min. required capabilities */ ++ switch (tpm_emu->tpm_version) { ++ case TPM_VERSION_1_2: ++ caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | ++ PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD; ++ tpm = "1.2"; ++ break; ++ case TPM_VERSION_2_0: ++ caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | ++ PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED | ++ PTM_CAP_SET_DATAFD; ++ tpm = "2"; ++ break; ++ case TPM_VERSION_UNSPEC: ++ error_report("tpm-emulator: TPM version has not been set"); ++ return -1; ++ } ++ ++ if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) { ++ error_report("tpm-emulator: TPM does not implement minimum set of " ++ "required capabilities for TPM %s (0x%x)", tpm, (int)caps); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int tpm_emulator_startup_tpm(TPMBackend *tb) ++{ ++ TPMEmulator *tpm_emu = TPM_EMULATOR(tb); ++ ptm_init init; ++ ptm_res res; ++ ++ DPRINTF("%s", __func__); ++ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_INIT, &init, sizeof(init), ++ sizeof(init)) < 0) { ++ error_report("tpm-emulator: could not send INIT: %s", ++ strerror(errno)); ++ goto err_exit; ++ } ++ ++ res = be32_to_cpu(init.u.resp.tpm_result); ++ if (res) { ++ error_report("tpm-emulator: TPM result for CMD_INIT: 0x%x", res); ++ goto err_exit; ++ } ++ return 0; ++ ++err_exit: ++ return -1; ++} ++ ++static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb) ++{ ++ TPMEmulator *tpm_emu = TPM_EMULATOR(tb); ++ ptm_est est; ++ ++ DPRINTF("%s", __func__); ++ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_GET_TPMESTABLISHED, &est, ++ 0, sizeof(est)) < 0) { ++ error_report("tpm-emulator: Could not get the TPM established flag: %s", ++ strerror(errno)); ++ return false; ++ } ++ DPRINTF("established flag: %0x", est.u.resp.bit); ++ ++ return (est.u.resp.bit != 0); ++} ++ ++static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb, ++ uint8_t locty) ++{ ++ TPMEmulator *tpm_emu = TPM_EMULATOR(tb); ++ ptm_reset_est reset_est; ++ ptm_res res; ++ ++ /* only a TPM 2.0 will support this */ ++ if (tpm_emu->tpm_version != TPM_VERSION_2_0) { ++ return 0; ++ } ++ ++ reset_est.u.req.loc = tpm_emu->cur_locty_number; ++ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_RESET_TPMESTABLISHED, ++ &reset_est, sizeof(reset_est), ++ sizeof(reset_est)) < 0) { ++ error_report("tpm-emulator: Could not reset the establishment bit: %s", ++ strerror(errno)); ++ return -1; ++ } ++ ++ res = be32_to_cpu(reset_est.u.resp.tpm_result); ++ if (res) { ++ error_report("tpm-emulator: TPM result for rest establixhed flag: 0x%x", ++ res); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void tpm_emulator_cancel_cmd(TPMBackend *tb) ++{ ++ TPMEmulator *tpm_emu = TPM_EMULATOR(tb); ++ ptm_res res; ++ ++ if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_CANCEL_TPM_CMD)) { ++ DPRINTF("Backend does not support CANCEL_TPM_CMD"); ++ return; ++ } ++ ++ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_CANCEL_TPM_CMD, &res, 0, ++ sizeof(res)) < 0) { ++ error_report("tpm-emulator: Could not cancel command: %s", ++ strerror(errno)); ++ } else if (res != 0) { ++ error_report("tpm-emulator: Failed to cancel TPM: 0x%x", ++ be32_to_cpu(res)); ++ } ++} ++ ++static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb) ++{ ++ TPMEmulator *tpm_emu = TPM_EMULATOR(tb); ++ ++ return tpm_emu->tpm_version; ++} ++ ++static int tpm_emulator_block_migration(TPMEmulator *tpm_emu) ++{ ++ Error *err = NULL; ++ ++ error_setg(&tpm_emu->migration_blocker, ++ "Migration disabled: TPM emulator not yet migratable"); ++ migrate_add_blocker(tpm_emu->migration_blocker, &err); ++ if (err) { ++ error_report_err(err); ++ error_free(tpm_emu->migration_blocker); ++ tpm_emu->migration_blocker = NULL; ++ ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu) ++{ ++ ptm_res res; ++ Error *err = NULL; ++ int fds[2] = { -1, -1 }; ++ ++ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { ++ error_report("tpm-emulator: Failed to create socketpair"); ++ return -1; ++ } ++ ++ qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1); ++ ++ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_SET_DATAFD, &res, 0, ++ sizeof(res)) || res != 0) { ++ error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s", ++ strerror(errno)); ++ goto err_exit; ++ } ++ ++ tpm_emu->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err)); ++ if (err) { ++ error_prepend(&err, "tpm-emulator: Failed to create io channel: "); ++ error_report_err(err); ++ goto err_exit; ++ } ++ ++ closesocket(fds[1]); ++ ++ return 0; ++ ++err_exit: ++ closesocket(fds[0]); ++ closesocket(fds[1]); ++ return -1; ++} ++ ++static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts) ++{ ++ const char *value; ++ ++ value = qemu_opt_get(opts, "chardev"); ++ if (value) { ++ Error *err = NULL; ++ Chardev *dev = qemu_chr_find(value); ++ ++ if (!dev) { ++ error_report("tpm-emulator: tpm chardev '%s' not found.", value); ++ goto err; ++ } ++ ++ if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) { ++ error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':", ++ value); ++ error_report_err(err); ++ goto err; ++ } ++ ++ tpm_emu->options->chardev = g_strdup(value); ++ } ++ ++ if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) { ++ goto err; ++ } ++ ++ /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used ++ * by passthrough driver, which not yet using GIOChannel. ++ */ ++ if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd, ++ &tpm_emu->tpm_version)) { ++ error_report("'%s' is not emulating TPM device. Error: %s", ++ tpm_emu->options->chardev, strerror(errno)); ++ goto err; ++ } ++ ++ DPRINTF("TPM Version %s", tpm_emu->tpm_version == TPM_VERSION_1_2 ? "1.2" : ++ (tpm_emu->tpm_version == TPM_VERSION_2_0 ? "2.0" : "Unspecified")); ++ ++ if (tpm_emulator_probe_caps(tpm_emu) || ++ tpm_emulator_check_caps(tpm_emu)) { ++ goto err; ++ } ++ ++ return tpm_emulator_block_migration(tpm_emu); ++ ++err: ++ DPRINTF("Startup error"); ++ return -1; ++} ++ ++static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id) ++{ ++ TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR)); ++ ++ tb->id = g_strdup(id); ++ ++ if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) { ++ goto err_exit; ++ } ++ ++ return tb; ++ ++err_exit: ++ object_unref(OBJECT(tb)); ++ ++ return NULL; ++} ++ ++static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb) ++{ ++ TPMEmulator *tpm_emu = TPM_EMULATOR(tb); ++ TpmTypeOptions *options = g_new0(TpmTypeOptions, 1); ++ ++ options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR; ++ options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options); ++ ++ return options; ++} ++ ++static const QemuOptDesc tpm_emulator_cmdline_opts[] = { ++ TPM_STANDARD_CMDLINE_OPTS, ++ { ++ .name = "chardev", ++ .type = QEMU_OPT_STRING, ++ .help = "Character device to use for out-of-band control messages", ++ }, ++ { /* end of list */ }, ++}; ++ ++static const TPMDriverOps tpm_emulator_driver = { ++ .type = TPM_TYPE_EMULATOR, ++ .opts = tpm_emulator_cmdline_opts, ++ .desc = "TPM emulator backend driver", ++ ++ .create = tpm_emulator_create, ++ .startup_tpm = tpm_emulator_startup_tpm, ++ .cancel_cmd = tpm_emulator_cancel_cmd, ++ .get_tpm_established_flag = tpm_emulator_get_tpm_established_flag, ++ .reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag, ++ .get_tpm_version = tpm_emulator_get_tpm_version, ++ .get_tpm_options = tpm_emulator_get_tpm_options, ++}; ++ ++static void tpm_emulator_inst_init(Object *obj) ++{ ++ TPMEmulator *tpm_emu = TPM_EMULATOR(obj); ++ ++ DPRINTF("%s", __func__); ++ tpm_emu->options = g_new0(TPMEmulatorOptions, 1); ++ tpm_emu->cur_locty_number = ~0; ++} ++ ++/* ++ * Gracefully shut down the external TPM ++ */ ++static void tpm_emulator_shutdown(TPMEmulator *tpm_emu) ++{ ++ ptm_res res; ++ ++ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_SHUTDOWN, &res, 0, ++ sizeof(res)) < 0) { ++ error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s", ++ strerror(errno)); ++ } else if (res != 0) { ++ error_report("tpm-emulator: TPM result for sutdown: 0x%x", ++ be32_to_cpu(res)); ++ } ++} ++ ++static void tpm_emulator_inst_finalize(Object *obj) ++{ ++ TPMEmulator *tpm_emu = TPM_EMULATOR(obj); ++ ++ tpm_emulator_shutdown(tpm_emu); ++ ++ object_unref(OBJECT(tpm_emu->data_ioc)); ++ ++ qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false); ++ ++ qapi_free_TPMEmulatorOptions(tpm_emu->options); ++ ++ if (tpm_emu->migration_blocker) { ++ migrate_del_blocker(tpm_emu->migration_blocker); ++ error_free(tpm_emu->migration_blocker); ++ } ++} ++ ++static void tpm_emulator_class_init(ObjectClass *klass, void *data) ++{ ++ TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass); ++ tbc->ops = &tpm_emulator_driver; ++ tbc->handle_request = tpm_emulator_handle_request; ++} ++ ++static const TypeInfo tpm_emulator_info = { ++ .name = TYPE_TPM_EMULATOR, ++ .parent = TYPE_TPM_BACKEND, ++ .instance_size = sizeof(TPMEmulator), ++ .class_init = tpm_emulator_class_init, ++ .instance_init = tpm_emulator_inst_init, ++ .instance_finalize = tpm_emulator_inst_finalize, ++}; ++ ++static void tpm_emulator_register(void) ++{ ++ type_register_static(&tpm_emulator_info); ++ tpm_register_driver(&tpm_emulator_driver); ++} ++ ++type_init(tpm_emulator_register) +diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h +new file mode 100644 +index 0000000000..33564b11de +--- /dev/null ++++ b/hw/tpm/tpm_ioctl.h +@@ -0,0 +1,246 @@ ++/* ++ * tpm_ioctl.h ++ * ++ * (c) Copyright IBM Corporation 2014, 2015. ++ * ++ * This file is licensed under the terms of the 3-clause BSD license ++ */ ++#ifndef _TPM_IOCTL_H_ ++#define _TPM_IOCTL_H_ ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * Every response from a command involving a TPM command execution must hold ++ * the ptm_res as the first element. ++ * ptm_res corresponds to the error code of a command executed by the TPM. ++ */ ++ ++typedef uint32_t ptm_res; ++ ++/* PTM_GET_TPMESTABLISHED: get the establishment bit */ ++struct ptm_est { ++ union { ++ struct { ++ ptm_res tpm_result; ++ unsigned char bit; /* TPM established bit */ ++ } resp; /* response */ ++ } u; ++}; ++ ++/* PTM_RESET_TPMESTABLISHED: reset establishment bit */ ++struct ptm_reset_est { ++ union { ++ struct { ++ uint8_t loc; /* locality to use */ ++ } req; /* request */ ++ struct { ++ ptm_res tpm_result; ++ } resp; /* response */ ++ } u; ++}; ++ ++/* PTM_INIT */ ++struct ptm_init { ++ union { ++ struct { ++ uint32_t init_flags; /* see definitions below */ ++ } req; /* request */ ++ struct { ++ ptm_res tpm_result; ++ } resp; /* response */ ++ } u; ++}; ++ ++/* above init_flags */ ++#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0) ++ /* delete volatile state file after reading it */ ++ ++/* PTM_SET_LOCALITY */ ++struct ptm_loc { ++ union { ++ struct { ++ uint8_t loc; /* locality to set */ ++ } req; /* request */ ++ struct { ++ ptm_res tpm_result; ++ } resp; /* response */ ++ } u; ++}; ++ ++/* PTM_HASH_DATA: hash given data */ ++struct ptm_hdata { ++ union { ++ struct { ++ uint32_t length; ++ uint8_t data[4096]; ++ } req; /* request */ ++ struct { ++ ptm_res tpm_result; ++ } resp; /* response */ ++ } u; ++}; ++ ++/* ++ * size of the TPM state blob to transfer; x86_64 can handle 8k, ++ * ppc64le only ~7k; keep the response below a 4k page size ++ */ ++#define PTM_STATE_BLOB_SIZE (3 * 1024) ++ ++/* ++ * The following is the data structure to get state blobs from the TPM. ++ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple reads ++ * with this ioctl and with adjusted offset are necessary. All bytes ++ * must be transferred and the transfer is done once the last byte has been ++ * returned. ++ * It is possible to use the read() interface for reading the data; however, the ++ * first bytes of the state blob will be part of the response to the ioctl(); a ++ * subsequent read() is only necessary if the total length (totlength) exceeds ++ * the number of received bytes. seek() is not supported. ++ */ ++struct ptm_getstate { ++ union { ++ struct { ++ uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */ ++ uint32_t type; /* which blob to pull */ ++ uint32_t offset; /* offset from where to read */ ++ } req; /* request */ ++ struct { ++ ptm_res tpm_result; ++ uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */ ++ uint32_t totlength; /* total length that will be transferred */ ++ uint32_t length; /* number of bytes in following buffer */ ++ uint8_t data[PTM_STATE_BLOB_SIZE]; ++ } resp; /* response */ ++ } u; ++}; ++ ++/* TPM state blob types */ ++#define PTM_BLOB_TYPE_PERMANENT 1 ++#define PTM_BLOB_TYPE_VOLATILE 2 ++#define PTM_BLOB_TYPE_SAVESTATE 3 ++ ++/* state_flags above : */ ++#define PTM_STATE_FLAG_DECRYPTED 1 /* on input: get decrypted state */ ++#define PTM_STATE_FLAG_ENCRYPTED 2 /* on output: state is encrypted */ ++ ++/* ++ * The following is the data structure to set state blobs in the TPM. ++ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple ++ * 'writes' using this ioctl are necessary. The last packet is indicated ++ * by the length being smaller than the PTM_STATE_BLOB_SIZE. ++ * The very first packet may have a length indicator of '0' enabling ++ * a write() with all the bytes from a buffer. If the write() interface ++ * is used, a final ioctl with a non-full buffer must be made to indicate ++ * that all data were transferred (a write with 0 bytes would not work). ++ */ ++struct ptm_setstate { ++ union { ++ struct { ++ uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */ ++ uint32_t type; /* which blob to set */ ++ uint32_t length; /* length of the data; ++ use 0 on the first packet to ++ transfer using write() */ ++ uint8_t data[PTM_STATE_BLOB_SIZE]; ++ } req; /* request */ ++ struct { ++ ptm_res tpm_result; ++ } resp; /* response */ ++ } u; ++}; ++ ++/* ++ * PTM_GET_CONFIG: Data structure to get runtime configuration information ++ * such as which keys are applied. ++ */ ++struct ptm_getconfig { ++ union { ++ struct { ++ ptm_res tpm_result; ++ uint32_t flags; ++ } resp; /* response */ ++ } u; ++}; ++ ++#define PTM_CONFIG_FLAG_FILE_KEY 0x1 ++#define PTM_CONFIG_FLAG_MIGRATION_KEY 0x2 ++ ++ ++typedef uint64_t ptm_cap; ++typedef struct ptm_est ptm_est; ++typedef struct ptm_reset_est ptm_reset_est; ++typedef struct ptm_loc ptm_loc; ++typedef struct ptm_hdata ptm_hdata; ++typedef struct ptm_init ptm_init; ++typedef struct ptm_getstate ptm_getstate; ++typedef struct ptm_setstate ptm_setstate; ++typedef struct ptm_getconfig ptm_getconfig; ++ ++/* capability flags returned by PTM_GET_CAPABILITY */ ++#define PTM_CAP_INIT (1) ++#define PTM_CAP_SHUTDOWN (1 << 1) ++#define PTM_CAP_GET_TPMESTABLISHED (1 << 2) ++#define PTM_CAP_SET_LOCALITY (1 << 3) ++#define PTM_CAP_HASHING (1 << 4) ++#define PTM_CAP_CANCEL_TPM_CMD (1 << 5) ++#define PTM_CAP_STORE_VOLATILE (1 << 6) ++#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7) ++#define PTM_CAP_GET_STATEBLOB (1 << 8) ++#define PTM_CAP_SET_STATEBLOB (1 << 9) ++#define PTM_CAP_STOP (1 << 10) ++#define PTM_CAP_GET_CONFIG (1 << 11) ++#define PTM_CAP_SET_DATAFD (1 << 12) ++ ++enum { ++ PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap), ++ PTM_INIT = _IOWR('P', 1, ptm_init), ++ PTM_SHUTDOWN = _IOR('P', 2, ptm_res), ++ PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est), ++ PTM_SET_LOCALITY = _IOWR('P', 4, ptm_loc), ++ PTM_HASH_START = _IOR('P', 5, ptm_res), ++ PTM_HASH_DATA = _IOWR('P', 6, ptm_hdata), ++ PTM_HASH_END = _IOR('P', 7, ptm_res), ++ PTM_CANCEL_TPM_CMD = _IOR('P', 8, ptm_res), ++ PTM_STORE_VOLATILE = _IOR('P', 9, ptm_res), ++ PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est), ++ PTM_GET_STATEBLOB = _IOWR('P', 11, ptm_getstate), ++ PTM_SET_STATEBLOB = _IOWR('P', 12, ptm_setstate), ++ PTM_STOP = _IOR('P', 13, ptm_res), ++ PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig), ++ PTM_SET_DATAFD = _IOR('P', 15, ptm_res), ++}; ++ ++/* ++ * Commands used by the non-CUSE TPMs ++ * ++ * All messages container big-endian data. ++ * ++ * The return messages only contain the 'resp' part of the unions ++ * in the data structures above. Besides that the limits in the ++ * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data ++ * and ptm_set_state:u.req.data) are 0xffffffff. ++ */ ++enum { ++ CMD_GET_CAPABILITY = 1, ++ CMD_INIT, ++ CMD_SHUTDOWN, ++ CMD_GET_TPMESTABLISHED, ++ CMD_SET_LOCALITY, ++ CMD_HASH_START, ++ CMD_HASH_DATA, ++ CMD_HASH_END, ++ CMD_CANCEL_TPM_CMD, ++ CMD_STORE_VOLATILE, ++ CMD_RESET_TPMESTABLISHED, ++ CMD_GET_STATEBLOB, ++ CMD_SET_STATEBLOB, ++ CMD_STOP, ++ CMD_GET_CONFIG, ++ CMD_SET_DATAFD ++}; ++ ++#endif /* _TPM_IOCTL_H */ +diff --git a/qapi-schema.json b/qapi-schema.json +index 802ea53d00..78a00bc868 100644 +--- a/qapi-schema.json ++++ b/qapi-schema.json +@@ -5314,10 +5314,12 @@ + # An enumeration of TPM types + # + # @passthrough: TPM passthrough type ++# @emulator: Software Emulator TPM type ++# Since: 2.11 + # + # Since: 1.5 + ## +-{ 'enum': 'TpmType', 'data': [ 'passthrough' ] } ++{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ] } + + ## + # @query-tpm-types: +@@ -5352,6 +5354,17 @@ + '*cancel-path' : 'str'} } + + ## ++# @TPMEmulatorOptions: ++# ++# Information about the TPM emulator type ++# ++# @chardev: Name of a unix socket chardev ++# ++# Since: 2.11 ++## ++{ 'struct': 'TPMEmulatorOptions', 'data': { 'chardev' : 'str' } } ++ ++## + # @TpmTypeOptions: + # + # A union referencing different TPM backend types' configuration options +@@ -5361,7 +5374,8 @@ + # Since: 1.5 + ## + { 'union': 'TpmTypeOptions', +- 'data': { 'passthrough' : 'TPMPassthroughOptions' } } ++ 'data': { 'passthrough' : 'TPMPassthroughOptions', ++ 'emulator': 'TPMEmulatorOptions'} } + + ## + # @TPMInfo: +diff --git a/qemu-options.hx b/qemu-options.hx +index 9f6e2adfff..60eb193c23 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -3121,7 +3121,9 @@ DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \ + "-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n" + " use path to provide path to a character device; default is /dev/tpm0\n" + " use cancel-path to provide path to TPM's cancel sysfs entry; if\n" +- " not provided it will be searched for in /sys/class/misc/tpm?/device\n", ++ " not provided it will be searched for in /sys/class/misc/tpm?/device\n" ++ "-tpmdev emulator,id=id,chardev=dev\n" ++ " configure the TPM device using chardev backend\n", + QEMU_ARCH_ALL) + STEXI + +@@ -3130,8 +3132,8 @@ The general form of a TPM device option is: + + @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}] + @findex -tpmdev +-Backend type must be: +-@option{passthrough}. ++Backend type must be either one of the following: ++@option{passthrough}, @option{emulator}. + + The specific backend type will determine the applicable options. + The @code{-tpmdev} option creates the TPM backend and requires a +@@ -3181,6 +3183,20 @@ To create a passthrough TPM use the following two options: + Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by + @code{tpmdev=tpm0} in the device option. + ++@item -tpmdev emulator, id=@var{id}, chardev=@var{dev} ++ ++(Linux-host only) Enable access to a TPM emulator using Unix domain socket based ++chardev backend. ++ ++@option{chardev} specifies the unique ID of a character device backend that provides connection to the software TPM server. ++ ++To create a TPM emulator backend device with chardev socket backend: ++@example ++ ++-chardev socket,id=chrtpm,path=/tmp/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0 ++ ++@end example ++ + @end table + + ETEXI +-- +2.11.0 + diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0011-tpm-Move-tpm_cleanup-to-right-place.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0011-tpm-Move-tpm_cleanup-to-right-place.patch new file mode 100644 index 0000000000..f4998e1681 --- /dev/null +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0011-tpm-Move-tpm_cleanup-to-right-place.patch @@ -0,0 +1,43 @@ +From 22429d175911af2e57617a30e0ac097af74f2791 Mon Sep 17 00:00:00 2001 +From: Amarnath Valluri +Date: Fri, 29 Sep 2017 12:57:33 +0300 +Subject: [PATCH 11/12] tpm: Move tpm_cleanup() to right place + +As Emulator TPM backend uses chardev, tpm cleanup should happen before chardev +similar to other vhost-users. + +Signed-off-by: Amarnath Valluri + +Upstream-Status: Backport [c37cacabf2285b0731b44c1f667781fdd4f2b658] +--- + tpm.c | 1 - + vl.c | 1 + + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tpm.c b/tpm.c +index cac400ef3e..4a9d3d739e 100644 +--- a/tpm.c ++++ b/tpm.c +@@ -173,7 +173,6 @@ int tpm_init(void) + return -1; + } + +- atexit(tpm_cleanup); + return 0; + } + +diff --git a/vl.c b/vl.c +index 8e247cc2a2..5df0b7f205 100644 +--- a/vl.c ++++ b/vl.c +@@ -4797,6 +4797,7 @@ int main(int argc, char **argv, char **envp) + res_free(); + + /* vhost-user must be cleaned up before chardevs. */ ++ tpm_cleanup(); + net_cleanup(); + audio_cleanup(); + monitor_cleanup(); +-- +2.11.0 + diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0012-tpm-Use-EMSGSIZE-instead-of-EBADMSG-to-compile-on-Op.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0012-tpm-Use-EMSGSIZE-instead-of-EBADMSG-to-compile-on-Op.patch new file mode 100644 index 0000000000..430fe1b1c4 --- /dev/null +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/0012-tpm-Use-EMSGSIZE-instead-of-EBADMSG-to-compile-on-Op.patch @@ -0,0 +1,67 @@ +From c559d599c6880caf7aa0f0a60c6c023584e1b8ad Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Wed, 11 Oct 2017 08:52:43 -0400 +Subject: [PATCH 12/12] tpm: Use EMSGSIZE instead of EBADMSG to compile on + OpenBSD +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +EBADMSG was only added to OpenBSD very recently. To make QEMU compilable +on older OpenBSD versions use EMSGSIZE instead when a mismatch between +number of received bytes and message size indicated in the header was +found. + +Return -EMSGSIZE and convert all other errnos in the same functions to +return the negative errno. + +Signed-off-by: Stefan Berger +Reviewed-by: Marc-André Lureau + +Upstream-Status: Backport [98979cdca44ba0e21055ee7736694aa5ebb54347] +--- + hw/tpm/tpm_util.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c +index fb929f6e92..73d77965fd 100644 +--- a/hw/tpm/tpm_util.c ++++ b/hw/tpm/tpm_util.c +@@ -68,10 +68,10 @@ static int tpm_util_test(int fd, + + n = write(fd, request, requestlen); + if (n < 0) { +- return errno; ++ return -errno; + } + if (n != requestlen) { +- return EFAULT; ++ return -EFAULT; + } + + FD_ZERO(&readfds); +@@ -80,18 +80,18 @@ static int tpm_util_test(int fd, + /* wait for a second */ + n = select(fd + 1, &readfds, NULL, NULL, &tv); + if (n != 1) { +- return errno; ++ return -errno; + } + + n = read(fd, &buf, sizeof(buf)); + if (n < sizeof(struct tpm_resp_hdr)) { +- return EFAULT; ++ return -EFAULT; + } + + resp = (struct tpm_resp_hdr *)buf; + /* check the header */ + if (be32_to_cpu(resp->len) != n) { +- return EBADMSG; ++ return -EMSGSIZE; + } + + *return_tag = be16_to_cpu(resp->tag); +-- +2.11.0 + diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/chardev-connect-socket-to-a-spawned-command.patch b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/chardev-connect-socket-to-a-spawned-command.patch new file mode 100644 index 0000000000..49d4af2e5e --- /dev/null +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu/chardev-connect-socket-to-a-spawned-command.patch @@ -0,0 +1,227 @@ +From aa3aef4cf5f4dd98f9133df085e825ff5da7dcbd Mon Sep 17 00:00:00 2001 +From: Patrick Ohly +Date: Fri, 27 Oct 2017 15:23:35 +0200 +Subject: [PATCH] chardev: connect socket to a spawned command + +The command is started in a shell (sh -c) with stdin connect to QEMU +via a Unix domain stream socket. QEMU then exchanges data via its own +end of the socket, just like it normally does. + +"-chardev socket" supports some ways of connecting via protocols like +telnet, but that is only a subset of the functionality supported by +tools socat. To use socat instead, for example to connect via a socks +proxy, use: + + -chardev 'socket,id=socat,cmd=exec socat FD:0 SOCKS4A:socks-proxy.localdomain:example.com:9999,,socksuser=nobody' \ + -device usb-serial,chardev=socat + +Beware that commas in the command must be escaped as double commas. + +Or interactively in the console: + (qemu) chardev-add socket,id=cat,cmd=cat + (qemu) device_add usb-serial,chardev=cat + ^ac + # cat >/dev/ttyUSB0 + hello + hello + +Another usage is starting swtpm from inside QEMU. swtpm will +automatically shut down once it looses the connection to the parent +QEMU, so there is no risk of lingering processes: + + -chardev 'socket,id=chrtpm0,cmd=exec swtpm socket --terminate --ctrl type=unixio,,clientfd=0 --tpmstate dir=... --log file=swtpm.log' \ + -tpmdev emulator,id=tpm0,chardev=chrtpm0 \ + -device tpm-tis,tpmdev=tpm0 + +The patch was discussed upstream, but QEMU developers believe that the +code calling QEMU should be responsible for managing additional +processes. In OE-core, that would imply enhancing runqemu and +oeqa. This patch is a simpler solution. + +Because it is not going upstream, the patch was written so that it is +as simple as possible. + +Upstream-Status: Inappropriate [embedded specific] + +Signed-off-by: Patrick Ohly + +--- + chardev/char-socket.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++--- + chardev/char.c | 3 ++ + qapi-schema.json | 5 +++ + 3 files changed, 90 insertions(+), 4 deletions(-) + +diff --git a/chardev/char-socket.c b/chardev/char-socket.c +index 1ae730a4..c366a02a 100644 +--- a/chardev/char-socket.c ++++ b/chardev/char-socket.c +@@ -854,6 +854,66 @@ static gboolean socket_reconnect_timeout(gpointer opaque) + return false; + } + ++static void chardev_open_socket_cmd(Chardev *chr, ++ const char *cmd, ++ Error **errp) ++{ ++ int fds[2] = { -1, -1 }; ++ QIOChannelSocket *sioc = NULL; ++ pid_t pid = -1; ++ const char *argv[] = { "/bin/sh", "-c", cmd, NULL }; ++ ++ /* ++ * We need a Unix domain socket for commands like swtpm and a single ++ * connection, therefore we cannot use qio_channel_command_new_spawn() ++ * without patching it first. Duplicating the functionality is easier. ++ */ ++ if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, fds)) { ++ error_setg_errno(errp, errno, "Error creating socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC)"); ++ goto error; ++ } ++ ++ pid = qemu_fork(errp); ++ if (pid < 0) { ++ goto error; ++ } ++ ++ if (!pid) { ++ /* child */ ++ dup2(fds[1], STDIN_FILENO); ++ execv(argv[0], (char * const *)argv); ++ _exit(1); ++ } ++ ++ /* ++ * Hand over our end of the socket pair to the qio channel. ++ * ++ * We don't reap the child because it is expected to keep ++ * running. We also don't support the "reconnect" option for the ++ * same reason. ++ */ ++ sioc = qio_channel_socket_new_fd(fds[0], errp); ++ if (!sioc) { ++ goto error; ++ } ++ fds[0] = -1; ++ ++ g_free(chr->filename); ++ chr->filename = g_strdup_printf("cmd:%s", cmd); ++ tcp_chr_new_client(chr, sioc); ++ ++ error: ++ if (fds[0] >= 0) { ++ close(fds[0]); ++ } ++ if (fds[1] >= 0) { ++ close(fds[1]); ++ } ++ if (sioc) { ++ object_unref(OBJECT(sioc)); ++ } ++} ++ + static void qmp_chardev_open_socket(Chardev *chr, + ChardevBackend *backend, + bool *be_opened, +@@ -861,6 +921,7 @@ static void qmp_chardev_open_socket(Chardev *chr, + { + SocketChardev *s = SOCKET_CHARDEV(chr); + ChardevSocket *sock = backend->u.socket.data; ++ const char *cmd = sock->cmd; + bool do_nodelay = sock->has_nodelay ? sock->nodelay : false; + bool is_listen = sock->has_server ? sock->server : true; + bool is_telnet = sock->has_telnet ? sock->telnet : false; +@@ -928,7 +989,12 @@ static void qmp_chardev_open_socket(Chardev *chr, + s->reconnect_time = reconnect; + } + +- if (s->reconnect_time) { ++ if (cmd) { ++ chardev_open_socket_cmd(chr, cmd, errp); ++ ++ /* everything ready (or failed permanently) before we return */ ++ *be_opened = true; ++ } else if (s->reconnect_time) { + sioc = qio_channel_socket_new(); + tcp_chr_set_client_ioc_name(chr, sioc); + qio_channel_socket_connect_async(sioc, s->addr, +@@ -987,11 +1053,22 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, + const char *host = qemu_opt_get(opts, "host"); + const char *port = qemu_opt_get(opts, "port"); + const char *tls_creds = qemu_opt_get(opts, "tls-creds"); ++ const char *cmd = qemu_opt_get(opts, "cmd"); + SocketAddressLegacy *addr; + ChardevSocket *sock; + + backend->type = CHARDEV_BACKEND_KIND_SOCKET; +- if (!path) { ++ if (cmd) { ++ /* ++ * Here we have to ensure that no options are set which are incompatible with ++ * spawning a command, otherwise unmodified code that doesn't know about ++ * command spawning (like socket_reconnect_timeout()) might get called. ++ */ ++ if (path || is_listen || is_telnet || is_tn3270 || reconnect || host || port || tls_creds) { ++ error_setg(errp, "chardev: socket: cmd does not support any additional options"); ++ return; ++ } ++ } else if (!path) { + if (!host) { + error_setg(errp, "chardev: socket: no host given"); + return; +@@ -1023,13 +1100,14 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, + sock->has_reconnect = true; + sock->reconnect = reconnect; + sock->tls_creds = g_strdup(tls_creds); ++ sock->cmd = g_strdup(cmd); + + addr = g_new0(SocketAddressLegacy, 1); +- if (path) { ++ if (path || cmd) { + UnixSocketAddress *q_unix; + addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX; + q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1); +- q_unix->path = g_strdup(path); ++ q_unix->path = cmd ? g_strdup_printf("cmd:%s", cmd) : g_strdup(path); + } else { + addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET; + addr->u.inet.data = g_new(InetSocketAddress, 1); +diff --git a/chardev/char.c b/chardev/char.c +index 5d283b90..ccb329d4 100644 +--- a/chardev/char.c ++++ b/chardev/char.c +@@ -782,6 +782,9 @@ QemuOptsList qemu_chardev_opts = { + .name = "path", + .type = QEMU_OPT_STRING, + },{ ++ .name = "cmd", ++ .type = QEMU_OPT_STRING, ++ },{ + .name = "host", + .type = QEMU_OPT_STRING, + },{ +diff --git a/qapi-schema.json b/qapi-schema.json +index 78a00bc8..790b026d 100644 +--- a/qapi-schema.json ++++ b/qapi-schema.json +@@ -5004,6 +5004,10 @@ + # + # @addr: socket address to listen on (server=true) + # or connect to (server=false) ++# @cmd: command to run via "sh -c" with stdin as one end of ++# a AF_UNIX SOCK_DSTREAM socket pair. The other end ++# is used by the chardev. Either an addr or a cmd can ++# be specified, but not both. + # @tls-creds: the ID of the TLS credentials object (since 2.6) + # @server: create server socket (default: true) + # @wait: wait for incoming connection on server +@@ -5021,6 +5025,7 @@ + # Since: 1.4 + ## + { 'struct': 'ChardevSocket', 'data': { 'addr' : 'SocketAddressLegacy', ++ '*cmd' : 'str', + '*tls-creds' : 'str', + '*server' : 'bool', + '*wait' : 'bool', +-- +2.11.0 + diff --git a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu_%.bbappend b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu_%.bbappend index d2c2e4c48c..a7ce181162 100644 --- a/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu_%.bbappend +++ b/meta-refkit-core/bbappends/openembedded-core/meta/recipes-devtools/qemu/qemu_%.bbappend @@ -8,13 +8,17 @@ SRC_URI_remove_df-refkit-config = " \ file://0004-Add-support-for-VM-suspend-resume-for-TPM-TIS-v2.9.patch \ " SRC_URI_append_df-refkit-config = " \ - file://0001-tpm-backend-Remove-unneeded-member-variable-from-bac.patch \ - file://0002-tpm-backend-Move-thread-handling-inside-TPMBackend.patch \ - file://0003-tpm-backend-Initialize-and-free-data-members-in-it-s.patch \ - file://0004-tpm-backend-Made-few-interface-methods-optional.patch \ - file://0005-tmp-backend-Add-new-api-to-read-backend-TpmInfo.patch \ - file://0006-tpm-backend-Remove-unneeded-destroy-method-from-TpmD.patch \ - file://0007-tpm-backend-Move-realloc_buffer-implementation-to-ba.patch \ - file://0008-tpm-passthrough-move-reusable-code-to-utils.patch \ - file://0009-tpm-Added-support-for-TPM-emulator.patch \ + file://0001-tpm-Clean-up-driver-registration-lookup.patch \ + file://0002-tpm-Clean-up-model-registration-lookup.patch \ + file://0003-tpm-backend-Remove-unneeded-member-variable-from-bac.patch \ + file://0004-tpm-backend-Move-thread-handling-inside-TPMBackend.patch \ + file://0005-tpm-backend-Initialize-and-free-data-members-in-it-s.patch \ + file://0006-tpm-backend-Made-few-interface-methods-optional.patch \ + file://0007-tpm-backend-Add-new-api-to-read-backend-TpmInfo.patch \ + file://0008-tpm-backend-Move-realloc_buffer-implementation-to-tp.patch \ + file://0009-tpm-passthrough-move-reusable-code-to-utils.patch \ + file://0010-tpm-Added-support-for-TPM-emulator.patch \ + file://0011-tpm-Move-tpm_cleanup-to-right-place.patch \ + file://0012-tpm-Use-EMSGSIZE-instead-of-EBADMSG-to-compile-on-Op.patch \ + file://chardev-connect-socket-to-a-spawned-command.patch \ " diff --git a/meta-refkit-core/conf/distro/include/refkit-config.inc b/meta-refkit-core/conf/distro/include/refkit-config.inc index 95b25bd6f3..228179ab2c 100644 --- a/meta-refkit-core/conf/distro/include/refkit-config.inc +++ b/meta-refkit-core/conf/distro/include/refkit-config.inc @@ -27,7 +27,8 @@ REFKIT_DEFAULT_DISTRO_FEATURES = " \ pam \ pulseaudio \ systemd \ - tpm1.2 \ + tpm \ + tpm2 \ " # ptests are useful for QA. Enabling them in the distro creates @@ -97,14 +98,9 @@ DISTRO_FEATURES_OVERRIDES += " \ REFKIT_IMAGE_MODE ??= "" REFKIT_IMAGE_MODE_VALID ??= "development production" -# Depending on the distro features we need certain kernel features. The assumption -# here is that all kernels we use support KERNEL_FEATURES *and* have these -# features. -KERNEL_FEATURES_append_df-refkit-config = " \ - ${@ bb.utils.contains('DISTRO_FEATURES', 'dm-verity', ' features/device-mapper/dm-verity.scc', '', d) } \ - ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm1.2', ' features/tpm/tpm.scc', '', d) } \ - ${@ bb.utils.contains('DISTRO_FEATURES', 'refkit-firewall', ' features/nf_tables/nf_tables.scc', '', d) } \ -" +# The kernel also gets reconfigured in +# meta-refkit-core/recipes-kernel/linux/linux-%.bbappend. +# See that file for details. # Use UEFI-based "dsk" image format for machines supporting UEFI. # Defined here because it influences several different recipes. diff --git a/meta-refkit-core/conf/layer.conf b/meta-refkit-core/conf/layer.conf index 2ff82da5d9..40082df809 100644 --- a/meta-refkit-core/conf/layer.conf +++ b/meta-refkit-core/conf/layer.conf @@ -5,9 +5,12 @@ BBPATH .= ":${LAYERDIR}" BBFILES += "${LAYERDIR}/recipes-*/*/*.bb" # All our .bbappends for other layers are in a separate -# "bbappends/" hierarchy. We activate only those -# bbappends for which the layer they apply to is actually -# present. +# "bbappends/" hierarchy, except for the kernel +# configuration .bbappend. +BBFILES += "${LAYERDIR}/recipes-kernel/linux/linux-%.bbappend" + +# We activate only those bbappends for which the layer they apply to +# is actually present. # # Sorted by layer path to keep related layers together. BBFILES_DYNAMIC += " \ @@ -18,6 +21,7 @@ BBFILES_DYNAMIC += " \ librealsense:${LAYERDIR}/bbappends/meta-intel-realsense/*/*/*.bbappend \ iotqa:${LAYERDIR}/bbappends/meta-iotqa/*/*/*.bbappend \ iot-web:${LAYERDIR}/bbappends/iot-web-layers/meta-iot-web/*/*/*.bbappend \ + measured:${LAYERDIR}/bbappends/meta-measured/*/*/*.bbappend \ oic:${LAYERDIR}/bbappends/meta-oic/*/*/*.bbappend \ efl-layer:${LAYERDIR}/bbappends/meta-openembedded/meta-efl/*/*/*.bbappend \ filesystems-layer:${LAYERDIR}/bbappends/meta-openembedded/meta-filesystems/*/*/*.bbappend \ diff --git a/meta-refkit-core/lib/oeqa/selftest/cases/image_installer.py b/meta-refkit-core/lib/oeqa/selftest/cases/image_installer.py index 62cc80f419..fb3874c609 100644 --- a/meta-refkit-core/lib/oeqa/selftest/cases/image_installer.py +++ b/meta-refkit-core/lib/oeqa/selftest/cases/image_installer.py @@ -68,7 +68,7 @@ def setUpLocal(self): # The tests depend on images done in "development" mode, so set that here # temporarily in a way that it overrides some other IMAGE_MODE setting in local.conf. self.append_config('IMAGE_MODE_forcevariable = "development"') - targets = 'refkit-installer-image ovmf swtpm-wrappers-native' + targets = 'refkit-installer-image ovmf swtpm2-wrappers-native' result = bitbake(targets, output_log=self.logger) ImageInstaller.image_is_ready = True @@ -91,12 +91,22 @@ def do_install(self, fixed_password="", tpm=False): self.create_internal_disk() if tpm: - swtpm = glob('%s/work/*/swtpm-wrappers-native/1.0-r0/swtpm_setup_oe.sh' % self.installer_test_vars['TMPDIR']) + swtpm = glob('%s/work/*/swtpm2-wrappers-native/1.0-r0/swtpm_setup_oe.sh' % self.installer_test_vars['TMPDIR']) self.assertEqual(len(swtpm), 1, msg='Expected exactly one swtpm_setup_oe.sh: %s' % swtpm) - cmd = '%s --tpm-state %s --createek' % (swtpm[0], self.resultdir) + if tpm == '2.0': + tpmmode = ' --tpm2' + else: + tpmmode = '' + cmd = '%s %s --tpm-state %s --createek' % (swtpm[0], tpmmode, self.resultdir) self.assertEqual(0, runCmd(cmd).status) - qemuparams_tpm = " -tpmdev emulator,id=tpm0,spawn=on,tpmstatedir=%s,logfile=%s/swtpm.log,path=%s -device tpm-tis,tpmdev=tpm0" % \ - (self.resultdir, self.resultdir, os.path.join(os.path.dirname(swtpm[0]), 'swtpm_oe.sh')) + # Comma is the parameter separator in qemu. Double-comma can be used to embed a comma in a parameter, + # which we need here for the cmd's --ctrl value. + # --terminate is a workaround for swtpm not doing that automatically when it looses the + # connection and doesn't have a listenting socket (as in this case here). + swtpm_log = os.path.join(self.resultdir, 'swtpm.log') + qemuparams_tpm = " -chardev 'socket,id=chrtpm0,cmd=exec %s socket --terminate --ctrl type=unixio,,clientfd=0 --tpmstate dir=%s --log level=10,,file=%s%s'" % \ + (os.path.join(os.path.dirname(swtpm[0]), 'swtpm_oe.sh'), self.resultdir, swtpm_log, tpmmode) + qemuparams_tpm += " -tpmdev emulator,id=tpm0,chardev=chrtpm0 -device tpm-tis,tpmdev=tpm0 " else: qemuparams_tpm = "" @@ -114,17 +124,24 @@ def do_install(self, fixed_password="", tpm=False): self.assertEqual('/dev/mapper/rootfs', output) else: self.assertIn('vda', output) + # Now install, non-interactively. Driving the script # interactively would be also a worthwhile test... cmd = "CHOSEN_INPUT=refkit-image-common-%s.wic CHOSEN_OUTPUT=vdb FORCE=yes %s%simage-installer" % \ (self.image_arch, ("FIXED_PASSWORD=%s " % fixed_password) if fixed_password else "", - "TPM12=yes " if tpm else "", + "TPM=%s " % tpm if tpm else "", ) status, output = qemu.run_serial(cmd, timeout=300) self.assertEqual(1, status, 'Failed to run command "%s":\n%s' % (cmd, output)) - self.logger.info('Installed successfully:\n%s' % output) + self.logger.info('Installed successfully:\n%s\n%s' % (cmd, output)) self.assertTrue(output.endswith('Installed refkit-image-common-%s.wic on vdb successfully.' % self.image_arch)) + if tpm: + self.assertIn('cryptsetup', output) + if tpm == '2.0': + self.assertIn('tpm2_nvdefine', output) + else: + self.assertIn('tpm_nvdefine', output) # Test installation by replacing the normal image with our internal one. overrides = { @@ -163,6 +180,10 @@ def test_install_fixed_password(self): # (see refkit-boot-settings.inc). self.do_install(fixed_password="refkit") - def test_install_tpm(self): - """Test image installation under qemu without virtual TPM, using a fixed password""" - self.do_install(tpm=True) + def test_install_tpm12(self): + """Test image installation under qemu with virtual TPM 1.2, using a fixed password""" + self.do_install(tpm='1.2') + + def test_install_tpm20(self): + """Test image installation under qemu with virtual TPM 2.0, using a fixed password""" + self.do_install(tpm='2.0') diff --git a/meta-refkit-core/recipes-images/images/initramfs-framework-refkit-luks.bb b/meta-refkit-core/recipes-images/images/initramfs-framework-refkit-luks.bb index 26e34cf194..1793b2e28a 100644 --- a/meta-refkit-core/recipes-images/images/initramfs-framework-refkit-luks.bb +++ b/meta-refkit-core/recipes-images/images/initramfs-framework-refkit-luks.bb @@ -65,18 +65,56 @@ refkit_luks () { keyfile=$(mktemp) keyfile_offset= tcsd_pid= + IFDOWN=true luks_cleanup () { - dd if=/dev/zero of="$keyfile" count=1 bs="$(stat -c '%s' "$keyfile")" + dd if=/dev/zero of="$keyfile" count="$(stat -c '%s' "$keyfile")" bs=1 >/dev/null rm "$keyfile" if [ "$tcsd_pid" ]; then kill "$tcsd_pid" fi - ifdown lo + $IFDOWN lo } - if ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm1.2', 'true', 'false', d) } && + if ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm2', 'true', 'false', d) } && + [ -e /dev/tpm0 ] && + TPM2TOOLS_TCTI_NAME=device tpm2_dump_capability -c commands >/dev/null 2>/dev/null; then + TPM2TOOLS_TCTI_NAME=device + TPM2TOOLS_DEVICE_FILE=/dev/tpm0 + export TPM2TOOLS_TCTI_NAME TPM2TOOLS_DEVICE_FILE + + size="$( expr "${REFKIT_DISK_ENCRYPTION_NVRAM_ID_LEN}" + "${REFKIT_DISK_ENCRYPTION_KEY_SIZE}" )" + if tpm2_nvread -v | grep -q "version 2.1"; then + # Reading the data is weird. We have to parse stdout to extract the actual bytes: + # $ tpm2_nvread -x 0x1500001 -a 0x40000001 -o 0 -s 8 + # + # The size of data:8 + # 68 65 6c 6c 6f 0a ff ff + if ! out="$(tpm2_nvread -x '${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX_TPM2}' -a 0x40000001 -s $size -o 0)"; then + luks_cleanup + fatal "Error reading NVRAM area with index ${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX_TPM2}" + fi + for c in $(echo "$out" | grep -v 'The size of data'); do printf "\\x$c"; done >"$keyfile" + else + # tpm2.0-tools 3.x can write into a file. + if ! tpm2_nvread -x '${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX_TPM2}' -a 0x40000001 -s $size -o 0 "$keyfile"; then + luks_cleanup + fatal "Error reading NVRAM area with index ${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX_TPM2}" + fi + fi + keyfile_offset="${REFKIT_DISK_ENCRYPTION_NVRAM_ID_LEN}" + if [ "$(head -c "$keyfile_offset" "$keyfile")" != "${REFKIT_DISK_ENCRYPTION_NVRAM_ID}" ]; then + luks_cleanup + fatal "Unexpected content in NVRAM area" + fi + # Lock access until next reboot. + if ! tpm2_nvreadlock -x '${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX_TPM2}' -a 0x40000001 -P ""; then + luks_cleanup + fatal "Error locking NVRAM area with index ${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX_TPM2}" + fi + elif ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm', 'true', 'false', d) } && ls /dev/tpm* >/dev/null 2>&1; then # Bring up IPv4 (needed by tcsd and tpm-tools) and tcsd itself. ifup lo + IFDOWN=ifdown tcsd -f & tcsd_pid=$! while true; do @@ -97,7 +135,6 @@ refkit_luks () { fatal "Error reading NVRAM area with index ${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX}" fi keyfile_offset="${REFKIT_DISK_ENCRYPTION_NVRAM_ID_LEN}" - od "$keyfile" if [ "$(head -c "$keyfile_offset" "$keyfile")" != "${REFKIT_DISK_ENCRYPTION_NVRAM_ID}" ]; then luks_cleanup fatal "Unexpected content in NVRAM area" @@ -108,10 +145,14 @@ refkit_luks () { fatal "Error locking NVRAM area with index ${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX}" fi fi - if [ ! -s "$keyfile" ] && - [ "${REFKIT_DISK_ENCRYPTION_PASSWORD}" ]; then - printf "%s" "${REFKIT_DISK_ENCRYPTION_PASSWORD}" >"$keyfile" - keyfile_offset=0 + if [ ! -s "$keyfile" ]; then + if [ "${REFKIT_DISK_ENCRYPTION_PASSWORD}" ]; then + printf "%s" "${REFKIT_DISK_ENCRYPTION_PASSWORD}" >"$keyfile" + keyfile_offset=0 + else + # Empty keyfile is almost certainly not right. Warn about it, but then proceed just in case. + msg "Empty LUKS key! Retrieving it from TPM was disabled or impossible and no fixed password was set either. 'cryptsetup open' is probably going to fail now, but will try anyway." + fi fi if cryptsetup open --type luks "$bootparam_root" "${REFKIT_DEVICE_MAPPER_ROOTFS_NAME}" --key-file "$keyfile" --keyfile-offset "$keyfile_offset"; then bootparam_root="/dev/mapper/${REFKIT_DEVICE_MAPPER_ROOTFS_NAME}" @@ -119,6 +160,9 @@ refkit_luks () { return fi luks_cleanup + # We allow booting to continue instead of aborting. Perhaps the error was temporary + # and the next loop iteration will succeed. If not, we'll return eventually and + # then the normal "no rootfs" handling takes over. ;; 1) # not a LUKS volume, which might be a problem (attacker replaced encrypted rootfs with modified unencrypted one) if [ "$bootparam_use_encryption" ] ; then @@ -157,5 +201,6 @@ python do_install () { FILES_${PN} = "/init.d" RDEPENDS_${PN} = " \ cryptsetup \ - ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm1.2', 'trousers tpm-tools libgcc strace netbase init-ifupdown', '', d) } \ + ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm', 'trousers tpm-tools libgcc strace netbase init-ifupdown', '', d) } \ + ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm2', 'tpm2-tools', '', d) } \ " diff --git a/meta-refkit-core/recipes-images/images/refkit-boot-settings.inc b/meta-refkit-core/recipes-images/images/refkit-boot-settings.inc index f51012af74..89118bbab3 100644 --- a/meta-refkit-core/recipes-images/images/refkit-boot-settings.inc +++ b/meta-refkit-core/recipes-images/images/refkit-boot-settings.inc @@ -35,6 +35,7 @@ SECURE_BOOT_SIGNING_CERT ??= "${@ '${META_REFKIT_CORE_BASE}/files/secureboot/ref # Index of the TPM NVRAM area used for random the per-machine disk encryption key. # The area contains a short ID + version, followed by the key. REFKIT_DISK_ENCRYPTION_NVRAM_INDEX ??= "1" +REFKIT_DISK_ENCRYPTION_NVRAM_INDEX_TPM2 ??= "0x1500001" REFKIT_DISK_ENCRYPTION_NVRAM_ID ??= "REFKIT_0" REFKIT_DISK_ENCRYPTION_NVRAM_ID_LEN = "${@ len('${REFKIT_DISK_ENCRYPTION_NVRAM_ID}') }" diff --git a/meta-refkit-core/recipes-images/images/refkit-installer-image.bb b/meta-refkit-core/recipes-images/images/refkit-installer-image.bb index 906afc7f04..03cc80c7cb 100644 --- a/meta-refkit-core/recipes-images/images/refkit-installer-image.bb +++ b/meta-refkit-core/recipes-images/images/refkit-installer-image.bb @@ -63,39 +63,89 @@ REFKIT_INSTALLER_UEFI_COMBO () { # Encryption with key stored in a TPM is optional, both at the distro # level (support not compiled in at all) and at the hardware level (not # all target machines have support). The use of a TPM can be configured - # explicitly by setting the TPM12 env variable to "yes" or "no". - # The default is "true" if there is a /dev/tpm* device. - TPM12=${TPM12:-$(ls /dev/tpm* >/dev/null 2>&1 && echo yes || echo no)} - - if ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm1.2', 'true', 'false', d) } && - istrue TPM12; then - # This uses the well-known (all zero) owner and SRK secrets, - # thus granting any process running on the device access to the - # TPM. - # TODO: lock down access to system processes? - if ! execute tpm_takeownership -y -z; then - fatal "taking ownership of TPM failed - needs to be reset?" - fi - # We store a random key in the TPM NVRAM where it is accessible - # to the initramfs. The initramfs will turn off read-access - # after it has retrieved the key, so nothing else that gets started - # later will have access to the key. - if ! execute tpm_nvdefine -i "${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX}" -s "$( expr "${REFKIT_DISK_ENCRYPTION_NVRAM_ID_LEN}" + "${REFKIT_DISK_ENCRYPTION_KEY_SIZE}" )" -p 'AUTHREAD|AUTHWRITE|READ_STCLEAR' -y -z; then - fatal "creating NVRAM area failed" - fi - if ! (printf "%s" "${REFKIT_DISK_ENCRYPTION_NVRAM_ID}" && - dd if=/dev/urandom bs="${REFKIT_DISK_ENCRYPTION_KEY_SIZE}" count=1) >"$keyfile"; then - fatal "key creation failed" - fi - keyfile_offset="${REFKIT_DISK_ENCRYPTION_NVRAM_ID_LEN}" - if ! execute tpm_nvwrite -i "${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX}" -z -f "$keyfile"; then - fatal "storing key in NVRAM failed" - fi - # Lock access until reboot. - if ! execute tpm_nvread -i "${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX}" -z -s 0; then - fatal "locking key in NVRAM failed" - fi - fi + # explicitly by setting the TPM env variable to "1.2", "2.0", or "no". + # The default is "no". + TPM=${TPM:-no} + case "$TPM" in + 2.0) + if ! ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm2', 'true', 'false', d) }; then + fatal "support for TPM 2.0 is not enabled" + fi + + # This tells tpm2.0-tools that we want to access the /dev/tpm0 device. + # Setting these environment variables works with tpm2.0-tools 2.x and 3.x, + # whereas command line parameters changed between that. + TPM2TOOLS_TCTI_NAME=device + TPM2TOOLS_DEVICE_FILE=/dev/tpm0 + export TPM2TOOLS_TCTI_NAME TPM2TOOLS_DEVICE_FILE + + # NVRAM can be used with TPM 2.0 without taking ownership, so we skip that step. + # + # We store a random key in the TPM NVRAM where it is accessible + # to the initramfs. The initramfs will turn off read-access + # after it has retrieved the key, so nothing else that gets started + # later will have access to the key. + # + # -t 0x80020002 = TPMA_NV_OWNERWRITE|TPMA_NV_OWNERREAD|TPMA_NV_READ_STCLEAR + # (https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf) + # + # tpm2.0-tools master supports --attibutes=ownerwrite|ownerread|read_stdclear, but + # 2.1.0 only supports the hex value. + if ! execute tpm2_nvdefine -x "${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX_TPM2}" -s "$( expr "${REFKIT_DISK_ENCRYPTION_NVRAM_ID_LEN}" + "${REFKIT_DISK_ENCRYPTION_KEY_SIZE}" )" -a 0x40000001 -t 0x80020002; then + fatal "creating NVRAM area failed" + fi + if ! (printf "%s" "${REFKIT_DISK_ENCRYPTION_NVRAM_ID}" && + dd if=/dev/urandom bs="${REFKIT_DISK_ENCRYPTION_KEY_SIZE}" count=1) >"$keyfile"; then + fatal "key creation failed" + fi + keyfile_offset="${REFKIT_DISK_ENCRYPTION_NVRAM_ID_LEN}" + if ! execute tpm2_nvwrite -x "${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX_TPM2}" -a 0x40000001 -f "$keyfile"; then + fatal "storing key in NVRAM failed" + fi + # Lock access until reboot. + # Empty password has to be specified here (https://github.com/01org/tpm2-tools/issues/607). + if ! execute tpm2_nvreadlock -x "${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX_TPM2}" -a 0x40000001 -P ""; then + fatal "locking key in NVRAM failed" + fi + ;; + 1.2) + if ! ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm', 'true', 'false', d) }; then + fatal "support for TPM 1.2 is not enabled" + fi + # This uses the well-known (all zero) owner and SRK secrets, + # thus granting any process running on the device access to the + # TPM. + # TODO: lock down access to system processes? + if ! execute tpm_takeownership -y -z; then + fatal "taking ownership of TPM failed - needs to be reset?" + fi + # We store a random key in the TPM NVRAM where it is accessible + # to the initramfs. The initramfs will turn off read-access + # after it has retrieved the key, so nothing else that gets started + # later will have access to the key. + if ! execute tpm_nvdefine -i "${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX}" -s "$( expr "${REFKIT_DISK_ENCRYPTION_NVRAM_ID_LEN}" + "${REFKIT_DISK_ENCRYPTION_KEY_SIZE}" )" -p 'AUTHREAD|AUTHWRITE|READ_STCLEAR' -y -z; then + fatal "creating NVRAM area failed" + fi + if ! (printf "%s" "${REFKIT_DISK_ENCRYPTION_NVRAM_ID}" && + dd if=/dev/urandom bs="${REFKIT_DISK_ENCRYPTION_KEY_SIZE}" count=1) >"$keyfile"; then + fatal "key creation failed" + fi + keyfile_offset="${REFKIT_DISK_ENCRYPTION_NVRAM_ID_LEN}" + if ! execute tpm_nvwrite -i "${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX}" -z -f "$keyfile"; then + fatal "storing key in NVRAM failed" + fi + # Lock access until reboot. + if ! execute tpm_nvread -i "${REFKIT_DISK_ENCRYPTION_NVRAM_INDEX}" -z -s 0; then + fatal "locking key in NVRAM failed" + fi + ;; + no) + : + ;; + *) + fatal "invalid value for TPM: $TPM" + ;; + esac # Unsafe fallback without TPM: well-known password. Not used unless explicitly set. FIXED_PASSWORD=${FIXED_PASSWORD:-} @@ -252,7 +302,8 @@ INSTALLER_RDEPENDS_append = " \ kpartx \ rsync \ ${@ bb.utils.contains('DISTRO_FEATURES', 'luks', 'cryptsetup', '', d) } \ - ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm1.2', 'trousers tpm-tools', '', d) } \ + ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm', 'trousers tpm-tools', '', d) } \ + ${@ bb.utils.contains('DISTRO_FEATURES', 'tpm2', 'tpm2-tools', '', d) } \ " diff --git a/meta-refkit-core/recipes-kernel/linux/linux-%.bbappend b/meta-refkit-core/recipes-kernel/linux/linux-%.bbappend new file mode 100644 index 0000000000..93b6b431e2 --- /dev/null +++ b/meta-refkit-core/recipes-kernel/linux/linux-%.bbappend @@ -0,0 +1,51 @@ +# Typically, generic BSPs do not enable special features that are +# needed only by some distros. For example, TPM, dm-verity and +# nf-tables are disabled in meta-intel BSPs. +# +# But refkit wants certain kernel features enabled depending on distro +# features. Expecting the developer to know about this and then make +# changes to the BSP he is using is not very developer-friendly and +# also makes automated testing in the CI harder. +# +# Therefore we use this .bbappend to reconfigure all kernel recipes +# called linux-. Using a .bbappend instead of manipulating +# SRC_URI in refkit-config.inc is a performance tweak: this way +# we avoid touching the SRC_URI of all recipes. The same code would +# also work in global scope. +# +# Reconfiguring works for kernel recipes that support kernel config +# fragments. If the default is undesired, then override or modify +# REFKIT_KERNEL_SRC_URI for the kernel recipe(s) that this bbappend is +# not meant to modify. +REFKIT_KERNEL_SRC_URI ??= "${@ refkit_kernel_config(d) }" + +# The refkit distro cannot make assumptions about which features are +# available in the kernel recipe that we are modifying here. +# Therefore we have our own feature definitions. +# +# For a full discussion of this topic see: +# https://bugzilla.yoctoproject.org/show_bug.cgi?id=8191 +FILESEXTRAPATHS_prepend := "${THISDIR}/refkit-kernel-cache:" + +# Both .scc and .cfg files are listed here to ensure that the kernel +# gets recompiled when any of them change. +def refkit_kernel_config(d): + # This maps distro features to the corresponding feature definition file(s). + distro2config = { + 'dm-verity': 'dm-verity.scc dm-verity.cfg', + 'tpm': 'tpm.scc tpm.cfg', + 'tpm2': 'tpm2.scc tpm2.cfg', + 'refkit-firewall': 'nf_tables.scc nf_tables.cfg', + } + uris = [] + for feature in d.getVar('DISTRO_FEATURES').split(): + config = distro2config.get(feature, None) + if config: + uris.extend(['file://' + x for x in config.split()]) + return ' '.join(uris) + +SRC_URI_append_df-refkit-config = " \ + ${@ d.getVar('REFKIT_KERNEL_SRC_URI') if \ + bb.data.inherits_class('kernel', d) \ + else '' } \ +" diff --git a/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/dm-verity.cfg b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/dm-verity.cfg new file mode 100644 index 0000000000..6505076d9a --- /dev/null +++ b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/dm-verity.cfg @@ -0,0 +1 @@ +CONFIG_DM_VERITY=y diff --git a/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/dm-verity.scc b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/dm-verity.scc new file mode 100644 index 0000000000..ed7a6c681d --- /dev/null +++ b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/dm-verity.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable dm-verity (device-mapper block integrity checking target)" +define KFEATURE_COMPATIBILITY all + +kconf non-hardware dm-verity.cfg diff --git a/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/nf_tables.cfg b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/nf_tables.cfg new file mode 100644 index 0000000000..5f518f1ddb --- /dev/null +++ b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/nf_tables.cfg @@ -0,0 +1,31 @@ +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_INET=m +CONFIG_NFT_EXTHDR=m +CONFIG_NFT_META=m +CONFIG_NFT_CT=m +CONFIG_NFT_SET_RBTREE=m +CONFIG_NFT_SET_HASH=m +CONFIG_NFT_RBTREE=m +CONFIG_NFT_HASH=m +CONFIG_NFT_COUNTER=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_REDIR_IPV4=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_NAT=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_REJECT_INET=m +CONFIG_NFT_COMPAT=m +CONFIG_NF_TABLES_IPV4=m +CONFIG_NFT_CHAIN_ROUTE_IPV4=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_REJECT_IPV4=m +CONFIG_NFT_REJECT_IPV6=m +CONFIG_NF_TABLES_ARP=m +CONFIG_NF_TABLES_IPV6=m +CONFIG_NFT_CHAIN_ROUTE_IPV6=m +CONFIG_NFT_REJECT_IPV6=m +CONFIG_NF_TABLES_BRIDGE=m diff --git a/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/nf_tables.scc b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/nf_tables.scc new file mode 100644 index 0000000000..b261acbbff --- /dev/null +++ b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/nf_tables.scc @@ -0,0 +1,8 @@ +# +# Not directly sourced via a kernel type but via an external bb +# + +define KFEATURE_DESCRIPTION "netfilter nf_tables" +define KFEATURE_COMPATIBILITY all + +kconf non-hardware nf_tables.cfg diff --git a/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm.cfg b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm.cfg new file mode 100644 index 0000000000..73d9516d02 --- /dev/null +++ b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm.cfg @@ -0,0 +1,18 @@ +.......................................................................... +. WARNING +. +. This file is a kernel configuration fragment, and not a full kernel +. configuration file. The final kernel configuration is made up of +. an assembly of processed fragments, each of which is designed to +. capture a specific part of the final configuration (e.g. platform +. configuration, feature configuration, and board specific hardware +. configuration). For more information on kernel configuration, please +. consult the product documentation. +. +.......................................................................... + +CONFIG_TCG_TPM=y +CONFIG_TCG_TIS=y +CONFIG_TCG_NSC=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m diff --git a/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm.scc b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm.scc new file mode 100644 index 0000000000..46704c4bd7 --- /dev/null +++ b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable TPM" + +kconf hardware tpm.cfg + diff --git a/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm2.cfg b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm2.cfg new file mode 100644 index 0000000000..c9d0dd0f21 --- /dev/null +++ b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm2.cfg @@ -0,0 +1,15 @@ +.......................................................................... +. WARNING +. +. This file is a kernel configuration fragment, and not a full kernel +. configuration file. The final kernel configuration is made up of +. an assembly of processed fragments, each of which is designed to +. capture a specific part of the final configuration (e.g. platform +. configuration, feature configuration, and board specific hardware +. configuration). For more information on kernel configuration, please +. consult the product documentation. +. +.......................................................................... + +CONFIG_TCG_TPM=y +CONFIG_TCG_CRB=y diff --git a/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm2.scc b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm2.scc new file mode 100644 index 0000000000..5e56d8cb0a --- /dev/null +++ b/meta-refkit-core/recipes-kernel/linux/refkit-kernel-cache/tpm2.scc @@ -0,0 +1,4 @@ +define KFEATURE_DESCRIPTION "Enable TPM2" + +kconf hardware tpm2.cfg + diff --git a/meta-refkit-core/recipes-security/swtpm2/libtpms2_git.bb b/meta-refkit-core/recipes-security/swtpm2/libtpms2_git.bb new file mode 100644 index 0000000000..21f388a5b3 --- /dev/null +++ b/meta-refkit-core/recipes-security/swtpm2/libtpms2_git.bb @@ -0,0 +1,20 @@ +SUMMARY = "LIBPM - Software TPM Library" +LICENSE = "BSD-3-Clause" +LIC_FILES_CHKSUM = "file://LICENSE;md5=97e5eea8d700d76b3ddfd35c4c96485f" + +SRCREV = "362fb5f5ef980133e00d6433ac880178ddf2c304" +SRC_URI = "git://github.com/stefanberger/libtpms.git;nobranch=1 \ +" +PV = "v0.6.0-dev1" + +S = "${WORKDIR}/git" +inherit autotools-brokensep pkgconfig + +PACKAGECONFIG ?= "openssl tpm2" +PACKAGECONFIG[openssl] = "--with-openssl, --without-openssl, openssl" +PACKAGECONFIG[tpm2] = "--with-tpm2, --without-tpm2" +PACKAGECONFIG[debug] = "--enable-debug, --disable-debug" + +PV = "1.0+git${SRCPV}" + +BBCLASSEXTEND = "native nativesdk" diff --git a/meta-refkit-core/recipes-security/swtpm2/swtpm2-wrappers-native.bb b/meta-refkit-core/recipes-security/swtpm2/swtpm2-wrappers-native.bb new file mode 100644 index 0000000000..e408a6f228 --- /dev/null +++ b/meta-refkit-core/recipes-security/swtpm2/swtpm2-wrappers-native.bb @@ -0,0 +1,53 @@ +SUMMARY = "SWTPM - OpenEmbedded wrapper scripts for native swtpm tools" +LICENSE = "MIT" +DEPENDS = "swtpm2-native tpm-tools-native net-tools-native" + +inherit native + +# The whole point of the recipe is to make files available +# for use after the build is done, so don't clean up... +RM_WORK_EXCLUDE += "${PN}" + +do_create_wrapper () { + # Wrap (almost) all swtpm binaries. Some get special wrappers and some + # are not needed. + for i in `find ${bindir} ${base_bindir} ${sbindir} ${base_sbindir} -name 'swtpm*' -perm /+x -type f`; do + exe=`basename $i` + case $exe in + swtpm_setup.sh) + cat >${WORKDIR}/swtpm_setup_oe.sh <${WORKDIR}/${exe}_oe.sh < +Date: Thu, 13 Oct 2016 02:03:56 -0700 +Subject: [PATCH 1/2] swtpm: add new package + +Upstream-Status: Inappropriate [OE config] + +Signed-off-by: Armin Kuster + +Rebased to current tip. + +Signed-off-by: Patrick Ohly + +--- + configure.ac | 34 ++++++++++------------------------ + 1 file changed, 10 insertions(+), 24 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 661b91a..65bca4d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -399,31 +399,17 @@ CFLAGS="$CFLAGS -Wformat -Wformat-security" + dnl We have to make sure libtpms is using the same crypto library + dnl to avoid problems + AC_MSG_CHECKING([the crypto library libtpms is using]) +-dirs=$($CC $CFLAGS -Xlinker --verbose 2>/dev/null | \ +- sed -n '/SEARCH_DIR/p' | \ +- sed 's/SEARCH_DIR("\(@<:@^"@:>@*\)"); */\1 /g' | \ +- sed 's|=/|/|g') +-for dir in $dirs $LIBRARY_PATH; do +- if test -r $dir/libtpms.so; then +- if test -n "`ldd $dir/libtpms.so | grep libcrypto.so`"; then +- libtpms_cryptolib="openssl" +- break +- fi +- if test -n "`ldd $dir/libtpms.so | grep libnss3.so`"; then +- libtpms_cryptolib="freebl" +- break +- fi ++dir="$SEARCH_DIR" ++if test -r $dir/libtpms.so; then ++ if test -n "`ldd $dir/libtpms.so | grep libcrypto.so`"; then ++ libtpms_cryptolib="openssl" ++ break + fi +- case $host_os in +- cygwin|openbsd*) +- if test -r $dir/libtpms.a; then +- if test -n "$(nm $dir/libtpms.a | grep "U AES_encrypt")"; then +- libtpms_cryptolib="openssl" +- fi +- fi +- ;; +- esac +-done ++ if test -n "`ldd $dir/libtpms.so | grep libnss3.so`"; then ++ libtpms_cryptolib="freebl" ++ break ++ fi ++fi + + if test -z "$libtpms_cryptolib"; then + AC_MSG_ERROR([Could not determine libtpms crypto library.]) +-- +2.11.0 + diff --git a/meta-refkit-core/recipes-security/swtpm2/swtpm2/ioctl_h.patch b/meta-refkit-core/recipes-security/swtpm2/swtpm2/ioctl_h.patch new file mode 100644 index 0000000000..d736bc66f5 --- /dev/null +++ b/meta-refkit-core/recipes-security/swtpm2/swtpm2/ioctl_h.patch @@ -0,0 +1,22 @@ +tpm_ioctl: fix musl for missing ioctl + +tpm_ioctl.c: In function 'ioctl_to_cmd': +tpm_ioctl.c:86:26: error: '_IOC_NRSHIFT' undeclared (first use in this function) + return ((ioctlnum >> _IOC_NRSHIFT) & _IOC_NRMASK) + 1; + + +Upstream-status: +Signed-off-by: Armin Kuster + +Index: git/src/swtpm_ioctl/tpm_ioctl.c +=================================================================== +--- git.orig/src/swtpm_ioctl/tpm_ioctl.c ++++ git/src/swtpm_ioctl/tpm_ioctl.c +@@ -58,6 +58,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/meta-refkit-core/recipes-security/swtpm2/swtpm2_git.bb b/meta-refkit-core/recipes-security/swtpm2/swtpm2_git.bb new file mode 100644 index 0000000000..661ece7514 --- /dev/null +++ b/meta-refkit-core/recipes-security/swtpm2/swtpm2_git.bb @@ -0,0 +1,57 @@ +SUMMARY = "SWTPM2.0 - Software TPM2.0 Emulator" +LICENSE = "BSD-3-Clause" +LIC_FILES_CHKSUM = "file://LICENSE;md5=fe8092c832b71ef20dfe4c6d3decb3a8" +SECTION = "apps" + +DEPENDS = "libtasn1 fuse expect socat glib-2.0 libtpms2" + +# configure checks for the tools already during compilation and +# then swtpm_setup needs them at runtime +DEPENDS += "tpm-tools-native expect-native socat-native" +RDEPENDS_${PN} += "tpm-tools" + +SRCREV = "adf9b3fe5d4df6708e9f801b8c9dcfdf7274d457" +SRC_URI = " \ + git://github.com/stefanberger/swtpm.git;nobranch=1 \ + file://fix_lib_search_path.patch \ + file://ioctl_h.patch \ + " +PV = "0.1.0-dev2" + +S = "${WORKDIR}/git" + +inherit autotools-brokensep pkgconfig +PARALLEL_MAKE = "" + +TSS_USER="tss" +TSS_GROUP="tss" + +PACKAGECONFIG ?= "openssl" +PACKAGECONFIG += "${@bb.utils.contains('DISTRO_FEATURES', 'selinux', 'selinux', '', d)}" +PACKAGECONFIG[openssl] = "--with-openssl, --without-openssl, openssl" +PACKAGECONFIG[gnutls] = "--with-gnutls, --without-gnutls, gnutls" +PACKAGECONFIG[selinux] = "--with-selinux, --without-selinux, libselinux" +PACKAGECONFIG[cuse] = "--with-cuse, --without-cuse" +PACKAGECONFIG[debug] = "--enable-debug, --disable-debug" + +EXTRA_OECONF += "--with-tss-user=${TSS_USER} --with-tss-group=${TSS_GROUP}" + +export SEARCH_DIR = "${STAGING_LIBDIR_NATIVE}" + +# dup bootstrap +do_configure_prepend () { + libtoolize --force --copy + autoheader + aclocal + automake --add-missing -c + autoconf +} + +USERADD_PACKAGES = "${PN}" +GROUPADD_PARAM_${PN} = "--system ${TSS_USER}" +USERADD_PARAM_${PN} = "--system -g ${TSS_GROUP} --home-dir \ + --no-create-home --shell /bin/false ${BPN}" + +RDEPENDS_${PN} = "libtpm expect socat bash" + +BBCLASSEXTEND = "native nativesdk" diff --git a/meta-refkit/conf/bblayers.conf.sample b/meta-refkit/conf/bblayers.conf.sample index 7e11cd7791..7c94ac4a51 100644 --- a/meta-refkit/conf/bblayers.conf.sample +++ b/meta-refkit/conf/bblayers.conf.sample @@ -1,6 +1,6 @@ # LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf # changes incompatibly -LCONF_VERSION = "11" +LCONF_VERSION = "12" BBPATH = "${TOPDIR}" BBFILES ?= "" @@ -21,6 +21,7 @@ REFKIT_LAYERS = " \ ##OEROOT##/../meta-security/meta-tpm \ ##OEROOT##/../meta-security-isafw \ ##OEROOT##/../meta-intel-realsense \ + ##OEROOT##/../meta-measured \ ##OEROOT##/../meta-clang \ ##OEROOT##/../meta-ros \ ##OEROOT##/../meta-flatpak \ diff --git a/meta-refkit/conf/distro/include/refkit-ci.inc b/meta-refkit/conf/distro/include/refkit-ci.inc index 575bb5ff69..0d62b1a4eb 100644 --- a/meta-refkit/conf/distro/include/refkit-ci.inc +++ b/meta-refkit/conf/distro/include/refkit-ci.inc @@ -67,7 +67,7 @@ REFKIT_CI_BUILD_TARGETS=" \ refkit-image-gateway \ refkit-image-industrial \ refkit-installer-image \ - swtpm-wrappers-native \ + swtpm2-wrappers-native \ ovmf \ fwupd \ " diff --git a/meta-refkit/conf/distro/include/refkit-supported-recipes.txt b/meta-refkit/conf/distro/include/refkit-supported-recipes.txt index 9629f050ca..2096610dc9 100644 --- a/meta-refkit/conf/distro/include/refkit-supported-recipes.txt +++ b/meta-refkit/conf/distro/include/refkit-supported-recipes.txt @@ -469,6 +469,8 @@ thermald@intel thin-provisioning-tools@openembedded-layer tiff@core tpm-tools@tpm-layer +tpm2-tools@measured +tpm2-tss@measured trajectory-msgs@ros-layer tremor@core trousers@tpm-layer diff --git a/meta-refkit/conf/distro/refkit.conf b/meta-refkit/conf/distro/refkit.conf index 80ee1f28f6..6f3e13709c 100644 --- a/meta-refkit/conf/distro/refkit.conf +++ b/meta-refkit/conf/distro/refkit.conf @@ -187,6 +187,19 @@ BBMASK += " \ meta-intel/common/recipes-core/ovmf \ " +# Without this we end up taking TPM2.0 recipes from meta-security +# instead of meta-measured. We only need meta-tpm because of swtpm. +# If we move that to meta-measured, we could instead drop meta-tpm. +BBMASK += "meta-security/meta-tpm/recipes-tpm/tpm2" + +# Both meta-security and meta-measured have linux-yocto bbappends +# which reconfigure the kernel to support TPM. We want to control +# that via distro features and also do it in a way that works for +# linux-intel, therefore we disable those bbappends here: +BBMASK += "meta-security/meta-tpm/recipes-kernel/linux/linux-yocto/" +BBMASK += "meta-measured/recipes-kernel/linux/linux-yocto/" +BBMASK += "meta-measured/intel/recipes-kernel/linux/" + # IoT Reference OS Kit removes certain packages from images because the components are known # to have compile issues and/or are not supported. Can be modified in derived # distros or via local.conf. diff --git a/meta-refkit/conf/layer.conf b/meta-refkit/conf/layer.conf index b537871c18..41c9cfd760 100644 --- a/meta-refkit/conf/layer.conf +++ b/meta-refkit/conf/layer.conf @@ -33,7 +33,7 @@ REFKIT_LOCALCONF_VERSION = "3" LOCALCONF_VERSION = "${REFKIT_LOCALCONF_VERSION}" # Same for LCONF_VERSION in bblayer.conf.sample. -REFKIT_LAYER_CONF_VERSION = "11" +REFKIT_LAYER_CONF_VERSION = "12" LAYER_CONF_VERSION = "${REFKIT_LAYER_CONF_VERSION}" # The default error messages use shell meta* wildcards to find the