tpm2-space.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2016 Intel Corporation
  4. *
  5. * Authors:
  6. * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
  7. *
  8. * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  9. *
  10. * This file contains TPM2 protocol implementations of the commands
  11. * used by the kernel internally.
  12. */
  13. #include <linux/gfp.h>
  14. #include <linux/unaligned.h>
  15. #include "tpm.h"
  16. enum tpm2_handle_types {
  17. TPM2_HT_HMAC_SESSION = 0x02000000,
  18. TPM2_HT_POLICY_SESSION = 0x03000000,
  19. TPM2_HT_TRANSIENT = 0x80000000,
  20. };
  21. struct tpm2_context {
  22. __be64 sequence;
  23. __be32 saved_handle;
  24. __be32 hierarchy;
  25. __be16 blob_size;
  26. } __packed;
  27. static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space)
  28. {
  29. int i;
  30. for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
  31. if (space->session_tbl[i])
  32. tpm2_flush_context(chip, space->session_tbl[i]);
  33. }
  34. }
  35. int tpm2_init_space(struct tpm_space *space, unsigned int buf_size)
  36. {
  37. space->context_buf = kzalloc(buf_size, GFP_KERNEL);
  38. if (!space->context_buf)
  39. return -ENOMEM;
  40. space->session_buf = kzalloc(buf_size, GFP_KERNEL);
  41. if (space->session_buf == NULL) {
  42. kfree(space->context_buf);
  43. /* Prevent caller getting a dangling pointer. */
  44. space->context_buf = NULL;
  45. return -ENOMEM;
  46. }
  47. space->buf_size = buf_size;
  48. return 0;
  49. }
  50. void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
  51. {
  52. if (tpm_try_get_ops(chip) == 0) {
  53. tpm2_flush_sessions(chip, space);
  54. tpm_put_ops(chip);
  55. }
  56. kfree(space->context_buf);
  57. kfree(space->session_buf);
  58. }
  59. int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
  60. unsigned int *offset, u32 *handle)
  61. {
  62. struct tpm_buf tbuf;
  63. struct tpm2_context *ctx;
  64. unsigned int body_size;
  65. int rc;
  66. rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
  67. if (rc)
  68. return rc;
  69. ctx = (struct tpm2_context *)&buf[*offset];
  70. body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
  71. tpm_buf_append(&tbuf, &buf[*offset], body_size);
  72. rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
  73. if (rc < 0) {
  74. dev_warn(&chip->dev, "%s: failed with a system error %d\n",
  75. __func__, rc);
  76. tpm_buf_destroy(&tbuf);
  77. return -EFAULT;
  78. } else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
  79. rc == TPM2_RC_REFERENCE_H0) {
  80. /*
  81. * TPM_RC_HANDLE means that the session context can't
  82. * be loaded because of an internal counter mismatch
  83. * that makes the TPM think there might have been a
  84. * replay. This might happen if the context was saved
  85. * and loaded outside the space.
  86. *
  87. * TPM_RC_REFERENCE_H0 means the session has been
  88. * flushed outside the space
  89. */
  90. *handle = 0;
  91. tpm_buf_destroy(&tbuf);
  92. return -ENOENT;
  93. } else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) {
  94. tpm_buf_destroy(&tbuf);
  95. return -EINVAL;
  96. } else if (rc > 0) {
  97. dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
  98. __func__, rc);
  99. tpm_buf_destroy(&tbuf);
  100. return -EFAULT;
  101. }
  102. *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
  103. *offset += body_size;
  104. tpm_buf_destroy(&tbuf);
  105. return 0;
  106. }
  107. int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
  108. unsigned int buf_size, unsigned int *offset)
  109. {
  110. struct tpm_buf tbuf;
  111. unsigned int body_size;
  112. int rc;
  113. rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
  114. if (rc)
  115. return rc;
  116. tpm_buf_append_u32(&tbuf, handle);
  117. rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
  118. if (rc < 0) {
  119. dev_warn(&chip->dev, "%s: failed with a system error %d\n",
  120. __func__, rc);
  121. tpm_buf_destroy(&tbuf);
  122. return -EFAULT;
  123. } else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
  124. tpm_buf_destroy(&tbuf);
  125. return -ENOENT;
  126. } else if (rc) {
  127. dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
  128. __func__, rc);
  129. tpm_buf_destroy(&tbuf);
  130. return -EFAULT;
  131. }
  132. body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
  133. if ((*offset + body_size) > buf_size) {
  134. dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
  135. tpm_buf_destroy(&tbuf);
  136. return -ENOMEM;
  137. }
  138. memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
  139. *offset += body_size;
  140. tpm_buf_destroy(&tbuf);
  141. return 0;
  142. }
  143. void tpm2_flush_space(struct tpm_chip *chip)
  144. {
  145. struct tpm_space *space = &chip->work_space;
  146. int i;
  147. if (!space)
  148. return;
  149. for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
  150. if (space->context_tbl[i] && ~space->context_tbl[i])
  151. tpm2_flush_context(chip, space->context_tbl[i]);
  152. tpm2_flush_sessions(chip, space);
  153. }
  154. static int tpm2_load_space(struct tpm_chip *chip)
  155. {
  156. struct tpm_space *space = &chip->work_space;
  157. unsigned int offset;
  158. int i;
  159. int rc;
  160. for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
  161. if (!space->context_tbl[i])
  162. continue;
  163. /* sanity check, should never happen */
  164. if (~space->context_tbl[i]) {
  165. dev_err(&chip->dev, "context table is inconsistent");
  166. return -EFAULT;
  167. }
  168. rc = tpm2_load_context(chip, space->context_buf, &offset,
  169. &space->context_tbl[i]);
  170. if (rc)
  171. return rc;
  172. }
  173. for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
  174. u32 handle;
  175. if (!space->session_tbl[i])
  176. continue;
  177. rc = tpm2_load_context(chip, space->session_buf,
  178. &offset, &handle);
  179. if (rc == -ENOENT) {
  180. /* load failed, just forget session */
  181. space->session_tbl[i] = 0;
  182. } else if (rc) {
  183. tpm2_flush_space(chip);
  184. return rc;
  185. }
  186. if (handle != space->session_tbl[i]) {
  187. dev_warn(&chip->dev, "session restored to wrong handle\n");
  188. tpm2_flush_space(chip);
  189. return -EFAULT;
  190. }
  191. }
  192. return 0;
  193. }
  194. static bool tpm2_map_to_phandle(struct tpm_space *space, void *handle)
  195. {
  196. u32 vhandle = be32_to_cpup((__be32 *)handle);
  197. u32 phandle;
  198. int i;
  199. i = 0xFFFFFF - (vhandle & 0xFFFFFF);
  200. if (i >= ARRAY_SIZE(space->context_tbl) || !space->context_tbl[i])
  201. return false;
  202. phandle = space->context_tbl[i];
  203. *((__be32 *)handle) = cpu_to_be32(phandle);
  204. return true;
  205. }
  206. static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
  207. {
  208. struct tpm_space *space = &chip->work_space;
  209. unsigned int nr_handles;
  210. u32 attrs;
  211. __be32 *handle;
  212. int i;
  213. i = tpm2_find_cc(chip, cc);
  214. if (i < 0)
  215. return -EINVAL;
  216. attrs = chip->cc_attrs_tbl[i];
  217. nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0);
  218. handle = (__be32 *)&cmd[TPM_HEADER_SIZE];
  219. for (i = 0; i < nr_handles; i++, handle++) {
  220. if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) {
  221. if (!tpm2_map_to_phandle(space, handle))
  222. return -EINVAL;
  223. }
  224. }
  225. return 0;
  226. }
  227. static int tpm_find_and_validate_cc(struct tpm_chip *chip,
  228. struct tpm_space *space,
  229. const void *cmd, size_t len)
  230. {
  231. const struct tpm_header *header = (const void *)cmd;
  232. int i;
  233. u32 cc;
  234. u32 attrs;
  235. unsigned int nr_handles;
  236. if (len < TPM_HEADER_SIZE || !chip->nr_commands)
  237. return -EINVAL;
  238. cc = be32_to_cpu(header->ordinal);
  239. i = tpm2_find_cc(chip, cc);
  240. if (i < 0) {
  241. dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
  242. cc);
  243. return -EOPNOTSUPP;
  244. }
  245. attrs = chip->cc_attrs_tbl[i];
  246. nr_handles =
  247. 4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0));
  248. if (len < TPM_HEADER_SIZE + 4 * nr_handles)
  249. goto err_len;
  250. return cc;
  251. err_len:
  252. dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__,
  253. len);
  254. return -EINVAL;
  255. }
  256. int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd,
  257. size_t cmdsiz)
  258. {
  259. int rc;
  260. int cc;
  261. if (!space)
  262. return 0;
  263. cc = tpm_find_and_validate_cc(chip, space, cmd, cmdsiz);
  264. if (cc < 0)
  265. return cc;
  266. memcpy(&chip->work_space.context_tbl, &space->context_tbl,
  267. sizeof(space->context_tbl));
  268. memcpy(&chip->work_space.session_tbl, &space->session_tbl,
  269. sizeof(space->session_tbl));
  270. memcpy(chip->work_space.context_buf, space->context_buf,
  271. space->buf_size);
  272. memcpy(chip->work_space.session_buf, space->session_buf,
  273. space->buf_size);
  274. rc = tpm2_load_space(chip);
  275. if (rc) {
  276. tpm2_flush_space(chip);
  277. return rc;
  278. }
  279. rc = tpm2_map_command(chip, cc, cmd);
  280. if (rc) {
  281. tpm2_flush_space(chip);
  282. return rc;
  283. }
  284. chip->last_cc = cc;
  285. return 0;
  286. }
  287. static bool tpm2_add_session(struct tpm_chip *chip, u32 handle)
  288. {
  289. struct tpm_space *space = &chip->work_space;
  290. int i;
  291. for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++)
  292. if (space->session_tbl[i] == 0)
  293. break;
  294. if (i == ARRAY_SIZE(space->session_tbl))
  295. return false;
  296. space->session_tbl[i] = handle;
  297. return true;
  298. }
  299. static u32 tpm2_map_to_vhandle(struct tpm_space *space, u32 phandle, bool alloc)
  300. {
  301. int i;
  302. for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
  303. if (alloc) {
  304. if (!space->context_tbl[i]) {
  305. space->context_tbl[i] = phandle;
  306. break;
  307. }
  308. } else if (space->context_tbl[i] == phandle)
  309. break;
  310. }
  311. if (i == ARRAY_SIZE(space->context_tbl))
  312. return 0;
  313. return TPM2_HT_TRANSIENT | (0xFFFFFF - i);
  314. }
  315. static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
  316. size_t len)
  317. {
  318. struct tpm_space *space = &chip->work_space;
  319. struct tpm_header *header = (struct tpm_header *)rsp;
  320. u32 phandle;
  321. u32 phandle_type;
  322. u32 vhandle;
  323. u32 attrs;
  324. int i;
  325. if (be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS)
  326. return 0;
  327. i = tpm2_find_cc(chip, cc);
  328. /* sanity check, should never happen */
  329. if (i < 0)
  330. return -EFAULT;
  331. attrs = chip->cc_attrs_tbl[i];
  332. if (!((attrs >> TPM2_CC_ATTR_RHANDLE) & 1))
  333. return 0;
  334. phandle = be32_to_cpup((__be32 *)&rsp[TPM_HEADER_SIZE]);
  335. phandle_type = phandle & 0xFF000000;
  336. switch (phandle_type) {
  337. case TPM2_HT_TRANSIENT:
  338. vhandle = tpm2_map_to_vhandle(space, phandle, true);
  339. if (!vhandle)
  340. goto out_no_slots;
  341. *(__be32 *)&rsp[TPM_HEADER_SIZE] = cpu_to_be32(vhandle);
  342. break;
  343. case TPM2_HT_HMAC_SESSION:
  344. case TPM2_HT_POLICY_SESSION:
  345. if (!tpm2_add_session(chip, phandle))
  346. goto out_no_slots;
  347. break;
  348. default:
  349. dev_err(&chip->dev, "%s: unknown handle 0x%08X\n",
  350. __func__, phandle);
  351. break;
  352. }
  353. return 0;
  354. out_no_slots:
  355. tpm2_flush_context(chip, phandle);
  356. dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__,
  357. phandle);
  358. return -ENOMEM;
  359. }
  360. struct tpm2_cap_handles {
  361. u8 more_data;
  362. __be32 capability;
  363. __be32 count;
  364. __be32 handles[];
  365. } __packed;
  366. static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp,
  367. size_t len)
  368. {
  369. struct tpm_space *space = &chip->work_space;
  370. struct tpm_header *header = (struct tpm_header *)rsp;
  371. struct tpm2_cap_handles *data;
  372. u32 phandle;
  373. u32 phandle_type;
  374. u32 vhandle;
  375. int i;
  376. int j;
  377. if (cc != TPM2_CC_GET_CAPABILITY ||
  378. be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) {
  379. return 0;
  380. }
  381. if (len < TPM_HEADER_SIZE + 9)
  382. return -EFAULT;
  383. data = (void *)&rsp[TPM_HEADER_SIZE];
  384. if (be32_to_cpu(data->capability) != TPM2_CAP_HANDLES)
  385. return 0;
  386. if (be32_to_cpu(data->count) > (UINT_MAX - TPM_HEADER_SIZE - 9) / 4)
  387. return -EFAULT;
  388. if (len != TPM_HEADER_SIZE + 9 + 4 * be32_to_cpu(data->count))
  389. return -EFAULT;
  390. for (i = 0, j = 0; i < be32_to_cpu(data->count); i++) {
  391. phandle = be32_to_cpup((__be32 *)&data->handles[i]);
  392. phandle_type = phandle & 0xFF000000;
  393. switch (phandle_type) {
  394. case TPM2_HT_TRANSIENT:
  395. vhandle = tpm2_map_to_vhandle(space, phandle, false);
  396. if (!vhandle)
  397. break;
  398. data->handles[j] = cpu_to_be32(vhandle);
  399. j++;
  400. break;
  401. default:
  402. data->handles[j] = cpu_to_be32(phandle);
  403. j++;
  404. break;
  405. }
  406. }
  407. header->length = cpu_to_be32(TPM_HEADER_SIZE + 9 + 4 * j);
  408. data->count = cpu_to_be32(j);
  409. return 0;
  410. }
  411. static int tpm2_save_space(struct tpm_chip *chip)
  412. {
  413. struct tpm_space *space = &chip->work_space;
  414. unsigned int offset;
  415. int i;
  416. int rc;
  417. for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
  418. if (!(space->context_tbl[i] && ~space->context_tbl[i]))
  419. continue;
  420. rc = tpm2_save_context(chip, space->context_tbl[i],
  421. space->context_buf, space->buf_size,
  422. &offset);
  423. if (rc == -ENOENT) {
  424. space->context_tbl[i] = 0;
  425. continue;
  426. } else if (rc)
  427. return rc;
  428. tpm2_flush_context(chip, space->context_tbl[i]);
  429. space->context_tbl[i] = ~0;
  430. }
  431. for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
  432. if (!space->session_tbl[i])
  433. continue;
  434. rc = tpm2_save_context(chip, space->session_tbl[i],
  435. space->session_buf, space->buf_size,
  436. &offset);
  437. if (rc == -ENOENT) {
  438. /* handle error saving session, just forget it */
  439. space->session_tbl[i] = 0;
  440. } else if (rc < 0) {
  441. tpm2_flush_space(chip);
  442. return rc;
  443. }
  444. }
  445. return 0;
  446. }
  447. int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
  448. void *buf, size_t *bufsiz)
  449. {
  450. struct tpm_header *header = buf;
  451. int rc;
  452. if (!space)
  453. return 0;
  454. rc = tpm2_map_response_header(chip, chip->last_cc, buf, *bufsiz);
  455. if (rc) {
  456. tpm2_flush_space(chip);
  457. goto out;
  458. }
  459. rc = tpm2_map_response_body(chip, chip->last_cc, buf, *bufsiz);
  460. if (rc) {
  461. tpm2_flush_space(chip);
  462. goto out;
  463. }
  464. rc = tpm2_save_space(chip);
  465. if (rc) {
  466. tpm2_flush_space(chip);
  467. goto out;
  468. }
  469. *bufsiz = be32_to_cpu(header->length);
  470. memcpy(&space->context_tbl, &chip->work_space.context_tbl,
  471. sizeof(space->context_tbl));
  472. memcpy(&space->session_tbl, &chip->work_space.session_tbl,
  473. sizeof(space->session_tbl));
  474. memcpy(space->context_buf, chip->work_space.context_buf,
  475. space->buf_size);
  476. memcpy(space->session_buf, chip->work_space.session_buf,
  477. space->buf_size);
  478. return 0;
  479. out:
  480. dev_err(&chip->dev, "%s: error %d\n", __func__, rc);
  481. return rc;
  482. }
  483. /*
  484. * Put the reference to the main device.
  485. */
  486. static void tpm_devs_release(struct device *dev)
  487. {
  488. struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs);
  489. /* release the master device reference */
  490. put_device(&chip->dev);
  491. }
  492. /*
  493. * Remove the device file for exposed TPM spaces and release the device
  494. * reference. This may also release the reference to the master device.
  495. */
  496. void tpm_devs_remove(struct tpm_chip *chip)
  497. {
  498. cdev_device_del(&chip->cdevs, &chip->devs);
  499. put_device(&chip->devs);
  500. }
  501. /*
  502. * Add a device file to expose TPM spaces. Also take a reference to the
  503. * main device.
  504. */
  505. int tpm_devs_add(struct tpm_chip *chip)
  506. {
  507. int rc;
  508. device_initialize(&chip->devs);
  509. chip->devs.parent = chip->dev.parent;
  510. chip->devs.class = &tpmrm_class;
  511. /*
  512. * Get extra reference on main device to hold on behalf of devs.
  513. * This holds the chip structure while cdevs is in use. The
  514. * corresponding put is in the tpm_devs_release.
  515. */
  516. get_device(&chip->dev);
  517. chip->devs.release = tpm_devs_release;
  518. chip->devs.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES);
  519. cdev_init(&chip->cdevs, &tpmrm_fops);
  520. chip->cdevs.owner = THIS_MODULE;
  521. rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num);
  522. if (rc)
  523. goto err_put_devs;
  524. rc = cdev_device_add(&chip->cdevs, &chip->devs);
  525. if (rc) {
  526. dev_err(&chip->devs,
  527. "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
  528. dev_name(&chip->devs), MAJOR(chip->devs.devt),
  529. MINOR(chip->devs.devt), rc);
  530. goto err_put_devs;
  531. }
  532. return 0;
  533. err_put_devs:
  534. put_device(&chip->devs);
  535. return rc;
  536. }