tpm2-space.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*
  2. * Copyright (C) 2016 Intel Corporation
  3. *
  4. * Authors:
  5. * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
  6. *
  7. * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  8. *
  9. * This file contains TPM2 protocol implementations of the commands
  10. * used by the kernel internally.
  11. *
  12. * This program is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU General Public License
  14. * as published by the Free Software Foundation; version 2
  15. * of the License.
  16. */
  17. #include <linux/gfp.h>
  18. #include <asm/unaligned.h>
  19. #include "tpm.h"
  20. enum tpm2_handle_types {
  21. TPM2_HT_HMAC_SESSION = 0x02000000,
  22. TPM2_HT_POLICY_SESSION = 0x03000000,
  23. TPM2_HT_TRANSIENT = 0x80000000,
  24. };
  25. struct tpm2_context {
  26. __be64 sequence;
  27. __be32 saved_handle;
  28. __be32 hierarchy;
  29. __be16 blob_size;
  30. } __packed;
  31. static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space)
  32. {
  33. int i;
  34. for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
  35. if (space->session_tbl[i])
  36. tpm2_flush_context_cmd(chip, space->session_tbl[i],
  37. TPM_TRANSMIT_NESTED);
  38. }
  39. }
  40. int tpm2_init_space(struct tpm_space *space, unsigned int buf_size)
  41. {
  42. space->context_buf = kzalloc(buf_size, GFP_KERNEL);
  43. if (!space->context_buf)
  44. return -ENOMEM;
  45. space->session_buf = kzalloc(buf_size, GFP_KERNEL);
  46. if (space->session_buf == NULL) {
  47. kfree(space->context_buf);
  48. /* Prevent caller getting a dangling pointer. */
  49. space->context_buf = NULL;
  50. return -ENOMEM;
  51. }
  52. space->buf_size = buf_size;
  53. return 0;
  54. }
  55. void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
  56. {
  57. mutex_lock(&chip->tpm_mutex);
  58. tpm2_flush_sessions(chip, space);
  59. mutex_unlock(&chip->tpm_mutex);
  60. kfree(space->context_buf);
  61. kfree(space->session_buf);
  62. }
  63. static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
  64. unsigned int *offset, u32 *handle)
  65. {
  66. struct tpm_buf tbuf;
  67. struct tpm2_context *ctx;
  68. unsigned int body_size;
  69. int rc;
  70. rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
  71. if (rc)
  72. return rc;
  73. ctx = (struct tpm2_context *)&buf[*offset];
  74. body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
  75. tpm_buf_append(&tbuf, &buf[*offset], body_size);
  76. rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4,
  77. TPM_TRANSMIT_NESTED, NULL);
  78. if (rc < 0) {
  79. dev_warn(&chip->dev, "%s: failed with a system error %d\n",
  80. __func__, rc);
  81. tpm_buf_destroy(&tbuf);
  82. return -EFAULT;
  83. } else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
  84. rc == TPM2_RC_REFERENCE_H0) {
  85. /*
  86. * TPM_RC_HANDLE means that the session context can't
  87. * be loaded because of an internal counter mismatch
  88. * that makes the TPM think there might have been a
  89. * replay. This might happen if the context was saved
  90. * and loaded outside the space.
  91. *
  92. * TPM_RC_REFERENCE_H0 means the session has been
  93. * flushed outside the space
  94. */
  95. *handle = 0;
  96. tpm_buf_destroy(&tbuf);
  97. return -ENOENT;
  98. } else if (rc > 0) {
  99. dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
  100. __func__, rc);
  101. tpm_buf_destroy(&tbuf);
  102. return -EFAULT;
  103. }
  104. *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
  105. *offset += body_size;
  106. tpm_buf_destroy(&tbuf);
  107. return 0;
  108. }
  109. static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
  110. unsigned int buf_size, unsigned int *offset)
  111. {
  112. struct tpm_buf tbuf;
  113. unsigned int body_size;
  114. int rc;
  115. rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
  116. if (rc)
  117. return rc;
  118. tpm_buf_append_u32(&tbuf, handle);
  119. rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0,
  120. TPM_TRANSMIT_NESTED, NULL);
  121. if (rc < 0) {
  122. dev_warn(&chip->dev, "%s: failed with a system error %d\n",
  123. __func__, rc);
  124. tpm_buf_destroy(&tbuf);
  125. return -EFAULT;
  126. } else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
  127. tpm_buf_destroy(&tbuf);
  128. return -ENOENT;
  129. } else if (rc) {
  130. dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
  131. __func__, rc);
  132. tpm_buf_destroy(&tbuf);
  133. return -EFAULT;
  134. }
  135. body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
  136. if ((*offset + body_size) > buf_size) {
  137. dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
  138. tpm_buf_destroy(&tbuf);
  139. return -ENOMEM;
  140. }
  141. memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
  142. *offset += body_size;
  143. tpm_buf_destroy(&tbuf);
  144. return 0;
  145. }
  146. static void tpm2_flush_space(struct tpm_chip *chip)
  147. {
  148. struct tpm_space *space = &chip->work_space;
  149. int i;
  150. for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
  151. if (space->context_tbl[i] && ~space->context_tbl[i])
  152. tpm2_flush_context_cmd(chip, space->context_tbl[i],
  153. TPM_TRANSMIT_NESTED);
  154. tpm2_flush_sessions(chip, space);
  155. }
  156. static int tpm2_load_space(struct tpm_chip *chip)
  157. {
  158. struct tpm_space *space = &chip->work_space;
  159. unsigned int offset;
  160. int i;
  161. int rc;
  162. for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
  163. if (!space->context_tbl[i])
  164. continue;
  165. /* sanity check, should never happen */
  166. if (~space->context_tbl[i]) {
  167. dev_err(&chip->dev, "context table is inconsistent");
  168. return -EFAULT;
  169. }
  170. rc = tpm2_load_context(chip, space->context_buf, &offset,
  171. &space->context_tbl[i]);
  172. if (rc)
  173. return rc;
  174. }
  175. for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
  176. u32 handle;
  177. if (!space->session_tbl[i])
  178. continue;
  179. rc = tpm2_load_context(chip, space->session_buf,
  180. &offset, &handle);
  181. if (rc == -ENOENT) {
  182. /* load failed, just forget session */
  183. space->session_tbl[i] = 0;
  184. } else if (rc) {
  185. tpm2_flush_space(chip);
  186. return rc;
  187. }
  188. if (handle != space->session_tbl[i]) {
  189. dev_warn(&chip->dev, "session restored to wrong handle\n");
  190. tpm2_flush_space(chip);
  191. return -EFAULT;
  192. }
  193. }
  194. return 0;
  195. }
  196. static bool tpm2_map_to_phandle(struct tpm_space *space, void *handle)
  197. {
  198. u32 vhandle = be32_to_cpup((__be32 *)handle);
  199. u32 phandle;
  200. int i;
  201. i = 0xFFFFFF - (vhandle & 0xFFFFFF);
  202. if (i >= ARRAY_SIZE(space->context_tbl) || !space->context_tbl[i])
  203. return false;
  204. phandle = space->context_tbl[i];
  205. *((__be32 *)handle) = cpu_to_be32(phandle);
  206. return true;
  207. }
  208. static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
  209. {
  210. struct tpm_space *space = &chip->work_space;
  211. unsigned int nr_handles;
  212. u32 attrs;
  213. __be32 *handle;
  214. int i;
  215. i = tpm2_find_cc(chip, cc);
  216. if (i < 0)
  217. return -EINVAL;
  218. attrs = chip->cc_attrs_tbl[i];
  219. nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0);
  220. handle = (__be32 *)&cmd[TPM_HEADER_SIZE];
  221. for (i = 0; i < nr_handles; i++, handle++) {
  222. if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) {
  223. if (!tpm2_map_to_phandle(space, handle))
  224. return -EINVAL;
  225. }
  226. }
  227. return 0;
  228. }
  229. int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
  230. u8 *cmd)
  231. {
  232. int rc;
  233. if (!space)
  234. return 0;
  235. memcpy(&chip->work_space.context_tbl, &space->context_tbl,
  236. sizeof(space->context_tbl));
  237. memcpy(&chip->work_space.session_tbl, &space->session_tbl,
  238. sizeof(space->session_tbl));
  239. memcpy(chip->work_space.context_buf, space->context_buf,
  240. space->buf_size);
  241. memcpy(chip->work_space.session_buf, space->session_buf,
  242. space->buf_size);
  243. rc = tpm2_load_space(chip);
  244. if (rc) {
  245. tpm2_flush_space(chip);
  246. return rc;
  247. }
  248. rc = tpm2_map_command(chip, cc, cmd);
  249. if (rc) {
  250. tpm2_flush_space(chip);
  251. return rc;
  252. }
  253. return 0;
  254. }
  255. static bool tpm2_add_session(struct tpm_chip *chip, u32 handle)
  256. {
  257. struct tpm_space *space = &chip->work_space;
  258. int i;
  259. for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++)
  260. if (space->session_tbl[i] == 0)
  261. break;
  262. if (i == ARRAY_SIZE(space->session_tbl))
  263. return false;
  264. space->session_tbl[i] = handle;
  265. return true;
  266. }
  267. static u32 tpm2_map_to_vhandle(struct tpm_space *space, u32 phandle, bool alloc)
  268. {
  269. int i;
  270. for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
  271. if (alloc) {
  272. if (!space->context_tbl[i]) {
  273. space->context_tbl[i] = phandle;
  274. break;
  275. }
  276. } else if (space->context_tbl[i] == phandle)
  277. break;
  278. }
  279. if (i == ARRAY_SIZE(space->context_tbl))
  280. return 0;
  281. return TPM2_HT_TRANSIENT | (0xFFFFFF - i);
  282. }
  283. static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
  284. size_t len)
  285. {
  286. struct tpm_space *space = &chip->work_space;
  287. struct tpm_output_header *header = (void *)rsp;
  288. u32 phandle;
  289. u32 phandle_type;
  290. u32 vhandle;
  291. u32 attrs;
  292. int i;
  293. if (be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS)
  294. return 0;
  295. i = tpm2_find_cc(chip, cc);
  296. /* sanity check, should never happen */
  297. if (i < 0)
  298. return -EFAULT;
  299. attrs = chip->cc_attrs_tbl[i];
  300. if (!((attrs >> TPM2_CC_ATTR_RHANDLE) & 1))
  301. return 0;
  302. phandle = be32_to_cpup((__be32 *)&rsp[TPM_HEADER_SIZE]);
  303. phandle_type = phandle & 0xFF000000;
  304. switch (phandle_type) {
  305. case TPM2_HT_TRANSIENT:
  306. vhandle = tpm2_map_to_vhandle(space, phandle, true);
  307. if (!vhandle)
  308. goto out_no_slots;
  309. *(__be32 *)&rsp[TPM_HEADER_SIZE] = cpu_to_be32(vhandle);
  310. break;
  311. case TPM2_HT_HMAC_SESSION:
  312. case TPM2_HT_POLICY_SESSION:
  313. if (!tpm2_add_session(chip, phandle))
  314. goto out_no_slots;
  315. break;
  316. default:
  317. dev_err(&chip->dev, "%s: unknown handle 0x%08X\n",
  318. __func__, phandle);
  319. break;
  320. };
  321. return 0;
  322. out_no_slots:
  323. tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_NESTED);
  324. dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__,
  325. phandle);
  326. return -ENOMEM;
  327. }
  328. struct tpm2_cap_handles {
  329. u8 more_data;
  330. __be32 capability;
  331. __be32 count;
  332. __be32 handles[];
  333. } __packed;
  334. static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp,
  335. size_t len)
  336. {
  337. struct tpm_space *space = &chip->work_space;
  338. struct tpm_output_header *header = (void *)rsp;
  339. struct tpm2_cap_handles *data;
  340. u32 phandle;
  341. u32 phandle_type;
  342. u32 vhandle;
  343. int i;
  344. int j;
  345. if (cc != TPM2_CC_GET_CAPABILITY ||
  346. be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) {
  347. return 0;
  348. }
  349. if (len < TPM_HEADER_SIZE + 9)
  350. return -EFAULT;
  351. data = (void *)&rsp[TPM_HEADER_SIZE];
  352. if (be32_to_cpu(data->capability) != TPM2_CAP_HANDLES)
  353. return 0;
  354. if (len != TPM_HEADER_SIZE + 9 + 4 * be32_to_cpu(data->count))
  355. return -EFAULT;
  356. for (i = 0, j = 0; i < be32_to_cpu(data->count); i++) {
  357. phandle = be32_to_cpup((__be32 *)&data->handles[i]);
  358. phandle_type = phandle & 0xFF000000;
  359. switch (phandle_type) {
  360. case TPM2_HT_TRANSIENT:
  361. vhandle = tpm2_map_to_vhandle(space, phandle, false);
  362. if (!vhandle)
  363. break;
  364. data->handles[j] = cpu_to_be32(vhandle);
  365. j++;
  366. break;
  367. default:
  368. data->handles[j] = cpu_to_be32(phandle);
  369. j++;
  370. break;
  371. }
  372. }
  373. header->length = cpu_to_be32(TPM_HEADER_SIZE + 9 + 4 * j);
  374. data->count = cpu_to_be32(j);
  375. return 0;
  376. }
  377. static int tpm2_save_space(struct tpm_chip *chip)
  378. {
  379. struct tpm_space *space = &chip->work_space;
  380. unsigned int offset;
  381. int i;
  382. int rc;
  383. for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
  384. if (!(space->context_tbl[i] && ~space->context_tbl[i]))
  385. continue;
  386. rc = tpm2_save_context(chip, space->context_tbl[i],
  387. space->context_buf, space->buf_size,
  388. &offset);
  389. if (rc == -ENOENT) {
  390. space->context_tbl[i] = 0;
  391. continue;
  392. } else if (rc)
  393. return rc;
  394. tpm2_flush_context_cmd(chip, space->context_tbl[i],
  395. TPM_TRANSMIT_NESTED);
  396. space->context_tbl[i] = ~0;
  397. }
  398. for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
  399. if (!space->session_tbl[i])
  400. continue;
  401. rc = tpm2_save_context(chip, space->session_tbl[i],
  402. space->session_buf, space->buf_size,
  403. &offset);
  404. if (rc == -ENOENT) {
  405. /* handle error saving session, just forget it */
  406. space->session_tbl[i] = 0;
  407. } else if (rc < 0) {
  408. tpm2_flush_space(chip);
  409. return rc;
  410. }
  411. }
  412. return 0;
  413. }
  414. int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
  415. u32 cc, u8 *buf, size_t *bufsiz)
  416. {
  417. struct tpm_output_header *header = (void *)buf;
  418. int rc;
  419. if (!space)
  420. return 0;
  421. rc = tpm2_map_response_header(chip, cc, buf, *bufsiz);
  422. if (rc) {
  423. tpm2_flush_space(chip);
  424. return rc;
  425. }
  426. rc = tpm2_map_response_body(chip, cc, buf, *bufsiz);
  427. if (rc) {
  428. tpm2_flush_space(chip);
  429. return rc;
  430. }
  431. rc = tpm2_save_space(chip);
  432. if (rc) {
  433. tpm2_flush_space(chip);
  434. return rc;
  435. }
  436. *bufsiz = be32_to_cpu(header->length);
  437. memcpy(&space->context_tbl, &chip->work_space.context_tbl,
  438. sizeof(space->context_tbl));
  439. memcpy(&space->session_tbl, &chip->work_space.session_tbl,
  440. sizeof(space->session_tbl));
  441. memcpy(space->context_buf, chip->work_space.context_buf,
  442. space->buf_size);
  443. memcpy(space->session_buf, chip->work_space.session_buf,
  444. space->buf_size);
  445. return 0;
  446. }