tpm2_errata.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <stdarg.h>
  3. #include <stdbool.h>
  4. #include <stdlib.h>
  5. #include "log.h"
  6. #include "tpm2_errata.h"
  7. #include "tpm2_capability.h"
  8. struct tpm2_errata_desc {
  9. UINT32 spec_level; /* spec level */
  10. UINT32 spec_rev; /* spec revision */
  11. UINT32 errata_ver; /* errata version */
  12. void (*fixup)(va_list *ap); /* errata correction handler */
  13. const char *name; /* full section name in errata doc */
  14. };
  15. /*
  16. * Published spec and errata information.
  17. *
  18. * Note that TPM2_PT_YEAR and TPM2_PT_DAY_OF_YEAR retrieved
  19. * from capability query only have the values of the
  20. * release date of the specification if the TPM does not
  21. * implement an errata. So the spec info are also given.
  22. */
  23. static struct tpm2_errata_info {
  24. UINT32 spec_level;
  25. UINT32 spec_rev;
  26. UINT32 errata_ver;
  27. UINT32 year;
  28. UINT32 day_of_year;
  29. } known_errata_info[] = {
  30. /* Specification Revision 1.16 October 30, 2014 */
  31. { 00, 116, 000, 2014, 303 },
  32. /* Errata Version 1.2 February 16, 2015 */
  33. { 00, 116, 120, 2015, 4 },
  34. /* Errata Version 1.3 June 16, 2015 */
  35. { 00, 116, 130, 2015, 167 },
  36. /* Errata Version 1.4 January 15, 2016 */
  37. { 00, 116, 140, 2016, 15 },
  38. /* Errata Version 1.5 September 21, 2016 */
  39. { 00, 116, 150, 2016, 265 },
  40. /* Specification Revision 1.38 September 29, 2016 */
  41. { 00, 138, 000, 2016, 273 },
  42. /* Errata Version 1.0 January 16, 2017 */
  43. { 00, 138, 100, 2017, 16 },
  44. /* Errata Version 1.1 March 2, 2017 */
  45. { 00, 138, 110, 2017, 61 },
  46. };
  47. static struct tpm2_errata_info *this_errata_info;
  48. static void fixup_sign_decrypt_attribute_encoding(va_list *ap);
  49. /*
  50. * Beware of that each record contains the first errata
  51. * version with the corresponding correction. This rule
  52. * allows errata_match() to function properly.
  53. */
  54. static struct tpm2_errata_desc errata_desc_list[] = {
  55. [SPEC_116_ERRATA_2_7] = {
  56. .spec_level = 00,
  57. .spec_rev = 116,
  58. .errata_ver = 120,
  59. .fixup = fixup_sign_decrypt_attribute_encoding,
  60. .name = "Sign/decrypt attribute encoding",
  61. },
  62. /*
  63. * Append the new errata descriptor here.
  64. */
  65. };
  66. static bool errata_match(struct tpm2_errata_desc *errata);
  67. static struct tpm2_errata_desc *errata_query(tpm2_errata_index_t index);
  68. /*
  69. * Request an errata correction.
  70. * @index: the errata to be queried.
  71. *
  72. * This function requests an errata correction to work
  73. * around a known issue well documented in errata doc.
  74. * If the request is valid and known, the queried errata
  75. * will be applied by the corresponding pre-defined errata
  76. * correction handler. The fixup process is transparent to
  77. * the callers so there is no return values. Any tools can
  78. * call this function to apply an errata if necessary.
  79. *
  80. * Return value:
  81. * N/A
  82. */
  83. void tpm2_errata_fixup(tpm2_errata_index_t index, ...) {
  84. struct tpm2_errata_desc *errata;
  85. /*
  86. * There was no match against the TPMs details to a
  87. * known errata.
  88. */
  89. if (!this_errata_info) {
  90. return;
  91. }
  92. /* Look up what errata the caller wants us to fix. */
  93. errata = errata_query(index);
  94. if (!errata) {
  95. return;
  96. }
  97. /*
  98. * Check to see if that errata matches the tpm's
  99. * information and thus needs to be applied.
  100. */
  101. bool res = errata_match(errata);
  102. if (res == false) {
  103. return;
  104. }
  105. va_list ap;
  106. va_start(ap, index);
  107. errata->fixup(&ap);
  108. va_end(ap);
  109. LOG_INFO("Errata %s applied", errata->name);
  110. }
  111. static void process(TPMS_CAPABILITY_DATA *capability_data) {
  112. /* Distinguish current spec level 0 */
  113. UINT32 spec_level = -1;
  114. UINT32 spec_rev = 0;
  115. UINT32 day_of_year = 0;
  116. UINT32 year = 0;
  117. TPML_TAGGED_TPM_PROPERTY *properties = &capability_data->data.tpmProperties;
  118. size_t i;
  119. for (i = 0; i < properties->count; ++i) {
  120. TPMS_TAGGED_PROPERTY *property = properties->tpmProperty + i;
  121. if (property->property == TPM2_PT_LEVEL) {
  122. spec_level = property->value;
  123. } else if (property->property == TPM2_PT_REVISION) {
  124. spec_rev = property->value;
  125. } else if (property->property == TPM2_PT_DAY_OF_YEAR) {
  126. day_of_year = property->value;
  127. } else if (property->property == TPM2_PT_YEAR) {
  128. year = property->value;
  129. /* Short circuit because this is the last item we need */
  130. break;
  131. } else if (property->property > TPM2_PT_YEAR) {
  132. break;
  133. }
  134. }
  135. if (!spec_rev || !day_of_year || !year) {
  136. LOG_WARN("Invalid TPM_SPEC parameter");
  137. return;
  138. }
  139. /* Determine the TPM spec and errata */
  140. for (i = 0; i < ARRAY_LEN(known_errata_info); ++i) {
  141. if (known_errata_info[i].day_of_year == day_of_year &&
  142. known_errata_info[i].year == year &&
  143. known_errata_info[i].spec_rev == spec_rev &&
  144. known_errata_info[i].spec_level == spec_level) {
  145. this_errata_info = known_errata_info + i;
  146. LOG_INFO("TPM_SPEC: spec level %d, spec rev %f, errata ver %f",
  147. this_errata_info->spec_level,
  148. (float )this_errata_info->spec_rev / 100,
  149. (float )this_errata_info->errata_ver / 100);
  150. return;
  151. }
  152. }
  153. LOG_INFO("Unknown TPM_SPEC. spec_level: %d, spec_rev: 0x%x, "
  154. "year: %d, day_of_year: %d", spec_level, spec_rev, year,
  155. day_of_year);
  156. }
  157. void tpm2_errata_init(ESYS_CONTEXT *ctx) {
  158. TPMS_CAPABILITY_DATA *capability_data;
  159. tool_rc rc = tpm2_capability_get(ctx, TPM2_CAP_TPM_PROPERTIES,
  160. TPM2_PT_LEVEL, TPM2_PT_YEAR - TPM2_PT_LEVEL + 1, &capability_data);
  161. if (rc != tool_rc_success) {
  162. LOG_ERR("Failed to GetCapability: capability: 0x%x, property: 0x%x, ",
  163. TPM2_CAP_TPM_PROPERTIES, TPM2_PT_LEVEL);
  164. return;
  165. }
  166. process(capability_data);
  167. free(capability_data);
  168. }
  169. static void fixup_sign_decrypt_attribute_encoding(va_list *ap) {
  170. TPMA_OBJECT *attrs = va_arg(*ap, TPMA_OBJECT *);
  171. *attrs &= ~TPMA_OBJECT_SIGN_ENCRYPT;
  172. }
  173. static bool errata_match(struct tpm2_errata_desc *errata) {
  174. return errata->errata_ver > this_errata_info->errata_ver
  175. && errata->spec_rev >= this_errata_info->spec_rev
  176. && errata->spec_level == this_errata_info->spec_level;
  177. }
  178. static struct tpm2_errata_desc *errata_query(tpm2_errata_index_t index) {
  179. if ((size_t) index >= ARRAY_LEN(errata_desc_list)) {
  180. LOG_WARN("Invalid errata index queried: %u", (unsigned int )index);
  181. return NULL;
  182. }
  183. return &errata_desc_list[index];
  184. }