1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2004 IBM Corporation |
4 | * Authors: |
5 | * Leendert van Doorn <leendert@watson.ibm.com> |
6 | * Dave Safford <safford@watson.ibm.com> |
7 | * Reiner Sailer <sailer@watson.ibm.com> |
8 | * Kylene Hall <kjhall@us.ibm.com> |
9 | * |
10 | * Copyright (C) 2013 Obsidian Research Corp |
11 | * Jason Gunthorpe <jgunthorpe@obsidianresearch.com> |
12 | * |
13 | * sysfs filesystem inspection interface to the TPM |
14 | */ |
15 | #include <linux/device.h> |
16 | #include "tpm.h" |
17 | |
18 | struct tpm_readpubek_out { |
19 | u8 algorithm[4]; |
20 | u8 encscheme[2]; |
21 | u8 sigscheme[2]; |
22 | __be32 paramsize; |
23 | u8 parameters[12]; |
24 | __be32 keysize; |
25 | u8 modulus[256]; |
26 | u8 checksum[20]; |
27 | } __packed; |
28 | |
29 | #define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256) |
30 | #define TPM_ORD_READPUBEK 124 |
31 | |
32 | static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, |
33 | char *buf) |
34 | { |
35 | struct tpm_buf tpm_buf; |
36 | struct tpm_readpubek_out *out; |
37 | int i; |
38 | char *str = buf; |
39 | struct tpm_chip *chip = to_tpm_chip(dev); |
40 | char anti_replay[20]; |
41 | |
42 | memset(&anti_replay, 0, sizeof(anti_replay)); |
43 | |
44 | if (tpm_try_get_ops(chip)) |
45 | return 0; |
46 | |
47 | if (tpm_buf_init(buf: &tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK)) |
48 | goto out_ops; |
49 | |
50 | tpm_buf_append(buf: &tpm_buf, new_data: anti_replay, new_len: sizeof(anti_replay)); |
51 | |
52 | if (tpm_transmit_cmd(chip, buf: &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE, |
53 | desc: "attempting to read the PUBEK" )) |
54 | goto out_buf; |
55 | |
56 | out = (struct tpm_readpubek_out *)&tpm_buf.data[10]; |
57 | str += |
58 | sprintf(buf: str, |
59 | fmt: "Algorithm: %4ph\n" |
60 | "Encscheme: %2ph\n" |
61 | "Sigscheme: %2ph\n" |
62 | "Parameters: %12ph\n" |
63 | "Modulus length: %d\n" |
64 | "Modulus:\n" , |
65 | out->algorithm, |
66 | out->encscheme, |
67 | out->sigscheme, |
68 | out->parameters, |
69 | be32_to_cpu(out->keysize)); |
70 | |
71 | for (i = 0; i < 256; i += 16) |
72 | str += sprintf(buf: str, fmt: "%16ph\n" , &out->modulus[i]); |
73 | |
74 | out_buf: |
75 | tpm_buf_destroy(buf: &tpm_buf); |
76 | out_ops: |
77 | tpm_put_ops(chip); |
78 | return str - buf; |
79 | } |
80 | static DEVICE_ATTR_RO(pubek); |
81 | |
82 | static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, |
83 | char *buf) |
84 | { |
85 | cap_t cap; |
86 | u8 digest[TPM_DIGEST_SIZE]; |
87 | u32 i, j, num_pcrs; |
88 | char *str = buf; |
89 | struct tpm_chip *chip = to_tpm_chip(dev); |
90 | |
91 | if (tpm_try_get_ops(chip)) |
92 | return 0; |
93 | |
94 | if (tpm1_getcap(chip, subcap_id: TPM_CAP_PROP_PCR, cap: &cap, |
95 | desc: "attempting to determine the number of PCRS" , |
96 | min_cap_length: sizeof(cap.num_pcrs))) { |
97 | tpm_put_ops(chip); |
98 | return 0; |
99 | } |
100 | |
101 | num_pcrs = be32_to_cpu(cap.num_pcrs); |
102 | for (i = 0; i < num_pcrs; i++) { |
103 | if (tpm1_pcr_read(chip, pcr_idx: i, res_buf: digest)) { |
104 | str = buf; |
105 | break; |
106 | } |
107 | str += sprintf(buf: str, fmt: "PCR-%02d: " , i); |
108 | for (j = 0; j < TPM_DIGEST_SIZE; j++) |
109 | str += sprintf(buf: str, fmt: "%02X " , digest[j]); |
110 | str += sprintf(buf: str, fmt: "\n" ); |
111 | } |
112 | tpm_put_ops(chip); |
113 | return str - buf; |
114 | } |
115 | static DEVICE_ATTR_RO(pcrs); |
116 | |
117 | static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, |
118 | char *buf) |
119 | { |
120 | struct tpm_chip *chip = to_tpm_chip(dev); |
121 | ssize_t rc = 0; |
122 | cap_t cap; |
123 | |
124 | if (tpm_try_get_ops(chip)) |
125 | return 0; |
126 | |
127 | if (tpm1_getcap(chip, subcap_id: TPM_CAP_FLAG_PERM, cap: &cap, |
128 | desc: "attempting to determine the permanent enabled state" , |
129 | min_cap_length: sizeof(cap.perm_flags))) |
130 | goto out_ops; |
131 | |
132 | rc = sprintf(buf, fmt: "%d\n" , !cap.perm_flags.disable); |
133 | out_ops: |
134 | tpm_put_ops(chip); |
135 | return rc; |
136 | } |
137 | static DEVICE_ATTR_RO(enabled); |
138 | |
139 | static ssize_t active_show(struct device *dev, struct device_attribute *attr, |
140 | char *buf) |
141 | { |
142 | struct tpm_chip *chip = to_tpm_chip(dev); |
143 | ssize_t rc = 0; |
144 | cap_t cap; |
145 | |
146 | if (tpm_try_get_ops(chip)) |
147 | return 0; |
148 | |
149 | if (tpm1_getcap(chip, subcap_id: TPM_CAP_FLAG_PERM, cap: &cap, |
150 | desc: "attempting to determine the permanent active state" , |
151 | min_cap_length: sizeof(cap.perm_flags))) |
152 | goto out_ops; |
153 | |
154 | rc = sprintf(buf, fmt: "%d\n" , !cap.perm_flags.deactivated); |
155 | out_ops: |
156 | tpm_put_ops(chip); |
157 | return rc; |
158 | } |
159 | static DEVICE_ATTR_RO(active); |
160 | |
161 | static ssize_t owned_show(struct device *dev, struct device_attribute *attr, |
162 | char *buf) |
163 | { |
164 | struct tpm_chip *chip = to_tpm_chip(dev); |
165 | ssize_t rc = 0; |
166 | cap_t cap; |
167 | |
168 | if (tpm_try_get_ops(chip)) |
169 | return 0; |
170 | |
171 | if (tpm1_getcap(to_tpm_chip(dev), subcap_id: TPM_CAP_PROP_OWNER, cap: &cap, |
172 | desc: "attempting to determine the owner state" , |
173 | min_cap_length: sizeof(cap.owned))) |
174 | goto out_ops; |
175 | |
176 | rc = sprintf(buf, fmt: "%d\n" , cap.owned); |
177 | out_ops: |
178 | tpm_put_ops(chip); |
179 | return rc; |
180 | } |
181 | static DEVICE_ATTR_RO(owned); |
182 | |
183 | static ssize_t temp_deactivated_show(struct device *dev, |
184 | struct device_attribute *attr, char *buf) |
185 | { |
186 | struct tpm_chip *chip = to_tpm_chip(dev); |
187 | ssize_t rc = 0; |
188 | cap_t cap; |
189 | |
190 | if (tpm_try_get_ops(chip)) |
191 | return 0; |
192 | |
193 | if (tpm1_getcap(to_tpm_chip(dev), subcap_id: TPM_CAP_FLAG_VOL, cap: &cap, |
194 | desc: "attempting to determine the temporary state" , |
195 | min_cap_length: sizeof(cap.stclear_flags))) |
196 | goto out_ops; |
197 | |
198 | rc = sprintf(buf, fmt: "%d\n" , cap.stclear_flags.deactivated); |
199 | out_ops: |
200 | tpm_put_ops(chip); |
201 | return rc; |
202 | } |
203 | static DEVICE_ATTR_RO(temp_deactivated); |
204 | |
205 | static ssize_t caps_show(struct device *dev, struct device_attribute *attr, |
206 | char *buf) |
207 | { |
208 | struct tpm_chip *chip = to_tpm_chip(dev); |
209 | struct tpm1_version *version; |
210 | ssize_t rc = 0; |
211 | char *str = buf; |
212 | cap_t cap; |
213 | |
214 | if (tpm_try_get_ops(chip)) |
215 | return 0; |
216 | |
217 | if (tpm1_getcap(chip, subcap_id: TPM_CAP_PROP_MANUFACTURER, cap: &cap, |
218 | desc: "attempting to determine the manufacturer" , |
219 | min_cap_length: sizeof(cap.manufacturer_id))) |
220 | goto out_ops; |
221 | |
222 | str += sprintf(buf: str, fmt: "Manufacturer: 0x%x\n" , |
223 | be32_to_cpu(cap.manufacturer_id)); |
224 | |
225 | /* TPM 1.2 */ |
226 | if (!tpm1_getcap(chip, subcap_id: TPM_CAP_VERSION_1_2, cap: &cap, |
227 | desc: "attempting to determine the 1.2 version" , |
228 | min_cap_length: sizeof(cap.version2))) { |
229 | version = &cap.version2.version; |
230 | goto out_print; |
231 | } |
232 | |
233 | /* TPM 1.1 */ |
234 | if (tpm1_getcap(chip, subcap_id: TPM_CAP_VERSION_1_1, cap: &cap, |
235 | desc: "attempting to determine the 1.1 version" , |
236 | min_cap_length: sizeof(cap.version1))) { |
237 | goto out_ops; |
238 | } |
239 | |
240 | version = &cap.version1; |
241 | |
242 | out_print: |
243 | str += sprintf(buf: str, |
244 | fmt: "TCG version: %d.%d\nFirmware version: %d.%d\n" , |
245 | version->major, version->minor, |
246 | version->rev_major, version->rev_minor); |
247 | |
248 | rc = str - buf; |
249 | |
250 | out_ops: |
251 | tpm_put_ops(chip); |
252 | return rc; |
253 | } |
254 | static DEVICE_ATTR_RO(caps); |
255 | |
256 | static ssize_t cancel_store(struct device *dev, struct device_attribute *attr, |
257 | const char *buf, size_t count) |
258 | { |
259 | struct tpm_chip *chip = to_tpm_chip(dev); |
260 | |
261 | if (tpm_try_get_ops(chip)) |
262 | return 0; |
263 | |
264 | chip->ops->cancel(chip); |
265 | tpm_put_ops(chip); |
266 | return count; |
267 | } |
268 | static DEVICE_ATTR_WO(cancel); |
269 | |
270 | static ssize_t durations_show(struct device *dev, struct device_attribute *attr, |
271 | char *buf) |
272 | { |
273 | struct tpm_chip *chip = to_tpm_chip(dev); |
274 | |
275 | if (chip->duration[TPM_LONG] == 0) |
276 | return 0; |
277 | |
278 | return sprintf(buf, fmt: "%d %d %d [%s]\n" , |
279 | jiffies_to_usecs(j: chip->duration[TPM_SHORT]), |
280 | jiffies_to_usecs(j: chip->duration[TPM_MEDIUM]), |
281 | jiffies_to_usecs(j: chip->duration[TPM_LONG]), |
282 | chip->duration_adjusted |
283 | ? "adjusted" : "original" ); |
284 | } |
285 | static DEVICE_ATTR_RO(durations); |
286 | |
287 | static ssize_t timeouts_show(struct device *dev, struct device_attribute *attr, |
288 | char *buf) |
289 | { |
290 | struct tpm_chip *chip = to_tpm_chip(dev); |
291 | |
292 | return sprintf(buf, fmt: "%d %d %d %d [%s]\n" , |
293 | jiffies_to_usecs(j: chip->timeout_a), |
294 | jiffies_to_usecs(j: chip->timeout_b), |
295 | jiffies_to_usecs(j: chip->timeout_c), |
296 | jiffies_to_usecs(j: chip->timeout_d), |
297 | chip->timeout_adjusted |
298 | ? "adjusted" : "original" ); |
299 | } |
300 | static DEVICE_ATTR_RO(timeouts); |
301 | |
302 | static ssize_t tpm_version_major_show(struct device *dev, |
303 | struct device_attribute *attr, char *buf) |
304 | { |
305 | struct tpm_chip *chip = to_tpm_chip(dev); |
306 | |
307 | return sprintf(buf, fmt: "%s\n" , chip->flags & TPM_CHIP_FLAG_TPM2 |
308 | ? "2" : "1" ); |
309 | } |
310 | static DEVICE_ATTR_RO(tpm_version_major); |
311 | |
312 | static struct attribute *tpm1_dev_attrs[] = { |
313 | &dev_attr_pubek.attr, |
314 | &dev_attr_pcrs.attr, |
315 | &dev_attr_enabled.attr, |
316 | &dev_attr_active.attr, |
317 | &dev_attr_owned.attr, |
318 | &dev_attr_temp_deactivated.attr, |
319 | &dev_attr_caps.attr, |
320 | &dev_attr_cancel.attr, |
321 | &dev_attr_durations.attr, |
322 | &dev_attr_timeouts.attr, |
323 | &dev_attr_tpm_version_major.attr, |
324 | NULL, |
325 | }; |
326 | |
327 | static struct attribute *tpm2_dev_attrs[] = { |
328 | &dev_attr_tpm_version_major.attr, |
329 | NULL |
330 | }; |
331 | |
332 | static const struct attribute_group tpm1_dev_group = { |
333 | .attrs = tpm1_dev_attrs, |
334 | }; |
335 | |
336 | static const struct attribute_group tpm2_dev_group = { |
337 | .attrs = tpm2_dev_attrs, |
338 | }; |
339 | |
340 | struct tpm_pcr_attr { |
341 | int alg_id; |
342 | int pcr; |
343 | struct device_attribute attr; |
344 | }; |
345 | |
346 | #define to_tpm_pcr_attr(a) container_of(a, struct tpm_pcr_attr, attr) |
347 | |
348 | static ssize_t pcr_value_show(struct device *dev, |
349 | struct device_attribute *attr, |
350 | char *buf) |
351 | { |
352 | struct tpm_pcr_attr *ha = to_tpm_pcr_attr(attr); |
353 | struct tpm_chip *chip = to_tpm_chip(dev); |
354 | struct tpm_digest digest; |
355 | int i; |
356 | int digest_size = 0; |
357 | int rc; |
358 | char *str = buf; |
359 | |
360 | for (i = 0; i < chip->nr_allocated_banks; i++) |
361 | if (ha->alg_id == chip->allocated_banks[i].alg_id) |
362 | digest_size = chip->allocated_banks[i].digest_size; |
363 | /* should never happen */ |
364 | if (!digest_size) |
365 | return -EINVAL; |
366 | |
367 | digest.alg_id = ha->alg_id; |
368 | rc = tpm_pcr_read(chip, pcr_idx: ha->pcr, digest: &digest); |
369 | if (rc) |
370 | return rc; |
371 | for (i = 0; i < digest_size; i++) |
372 | str += sprintf(buf: str, fmt: "%02X" , digest.digest[i]); |
373 | str += sprintf(buf: str, fmt: "\n" ); |
374 | |
375 | return str - buf; |
376 | } |
377 | |
378 | /* |
379 | * The following set of defines represents all the magic to build |
380 | * the per hash attribute groups for displaying each bank of PCRs. |
381 | * The only slight problem with this approach is that every PCR is |
382 | * hard coded to be present, so you don't know if an PCR is missing |
383 | * until a cat of the file returns -EINVAL |
384 | * |
385 | * Also note you must ignore checkpatch warnings in this macro |
386 | * code. This is deep macro magic that checkpatch.pl doesn't |
387 | * understand. |
388 | */ |
389 | |
390 | /* Note, this must match TPM2_PLATFORM_PCR which is fixed at 24. */ |
391 | #define _TPM_HELPER(_alg, _hash, F) \ |
392 | F(_alg, _hash, 0) \ |
393 | F(_alg, _hash, 1) \ |
394 | F(_alg, _hash, 2) \ |
395 | F(_alg, _hash, 3) \ |
396 | F(_alg, _hash, 4) \ |
397 | F(_alg, _hash, 5) \ |
398 | F(_alg, _hash, 6) \ |
399 | F(_alg, _hash, 7) \ |
400 | F(_alg, _hash, 8) \ |
401 | F(_alg, _hash, 9) \ |
402 | F(_alg, _hash, 10) \ |
403 | F(_alg, _hash, 11) \ |
404 | F(_alg, _hash, 12) \ |
405 | F(_alg, _hash, 13) \ |
406 | F(_alg, _hash, 14) \ |
407 | F(_alg, _hash, 15) \ |
408 | F(_alg, _hash, 16) \ |
409 | F(_alg, _hash, 17) \ |
410 | F(_alg, _hash, 18) \ |
411 | F(_alg, _hash, 19) \ |
412 | F(_alg, _hash, 20) \ |
413 | F(_alg, _hash, 21) \ |
414 | F(_alg, _hash, 22) \ |
415 | F(_alg, _hash, 23) |
416 | |
417 | /* ignore checkpatch warning about trailing ; in macro. */ |
418 | #define PCR_ATTR(_alg, _hash, _pcr) \ |
419 | static struct tpm_pcr_attr dev_attr_pcr_##_hash##_##_pcr = { \ |
420 | .alg_id = _alg, \ |
421 | .pcr = _pcr, \ |
422 | .attr = { \ |
423 | .attr = { \ |
424 | .name = __stringify(_pcr), \ |
425 | .mode = 0444 \ |
426 | }, \ |
427 | .show = pcr_value_show \ |
428 | } \ |
429 | }; |
430 | |
431 | #define PCR_ATTRS(_alg, _hash) \ |
432 | _TPM_HELPER(_alg, _hash, PCR_ATTR) |
433 | |
434 | /* ignore checkpatch warning about trailing , in macro. */ |
435 | #define PCR_ATTR_VAL(_alg, _hash, _pcr) \ |
436 | &dev_attr_pcr_##_hash##_##_pcr.attr.attr, |
437 | |
438 | #define PCR_ATTR_GROUP_ARRAY(_alg, _hash) \ |
439 | static struct attribute *pcr_group_attrs_##_hash[] = { \ |
440 | _TPM_HELPER(_alg, _hash, PCR_ATTR_VAL) \ |
441 | NULL \ |
442 | } |
443 | |
444 | #define PCR_ATTR_GROUP(_alg, _hash) \ |
445 | static struct attribute_group pcr_group_##_hash = { \ |
446 | .name = "pcr-" __stringify(_hash), \ |
447 | .attrs = pcr_group_attrs_##_hash \ |
448 | } |
449 | |
450 | #define PCR_ATTR_BUILD(_alg, _hash) \ |
451 | PCR_ATTRS(_alg, _hash) \ |
452 | PCR_ATTR_GROUP_ARRAY(_alg, _hash); \ |
453 | PCR_ATTR_GROUP(_alg, _hash) |
454 | /* |
455 | * End of macro structure to build an attribute group containing 24 |
456 | * PCR value files for each supported hash algorithm |
457 | */ |
458 | |
459 | /* |
460 | * The next set of macros implements the cleverness for each hash to |
461 | * build a static attribute group called pcr_group_<hash> which can be |
462 | * added to chip->groups[]. |
463 | * |
464 | * The first argument is the TPM algorithm id and the second is the |
465 | * hash used as both the suffix and the group name. Note: the group |
466 | * name is a directory in the top level tpm class with the name |
467 | * pcr-<hash>, so it must not clash with any other names already |
468 | * in the sysfs directory. |
469 | */ |
470 | PCR_ATTR_BUILD(TPM_ALG_SHA1, sha1); |
471 | PCR_ATTR_BUILD(TPM_ALG_SHA256, sha256); |
472 | PCR_ATTR_BUILD(TPM_ALG_SHA384, sha384); |
473 | PCR_ATTR_BUILD(TPM_ALG_SHA512, sha512); |
474 | PCR_ATTR_BUILD(TPM_ALG_SM3_256, sm3); |
475 | |
476 | |
477 | void tpm_sysfs_add_device(struct tpm_chip *chip) |
478 | { |
479 | int i; |
480 | |
481 | WARN_ON(chip->groups_cnt != 0); |
482 | |
483 | if (tpm_is_firmware_upgrade(chip)) |
484 | return; |
485 | |
486 | if (chip->flags & TPM_CHIP_FLAG_TPM2) |
487 | chip->groups[chip->groups_cnt++] = &tpm2_dev_group; |
488 | else |
489 | chip->groups[chip->groups_cnt++] = &tpm1_dev_group; |
490 | |
491 | /* add one group for each bank hash */ |
492 | for (i = 0; i < chip->nr_allocated_banks; i++) { |
493 | switch (chip->allocated_banks[i].alg_id) { |
494 | case TPM_ALG_SHA1: |
495 | chip->groups[chip->groups_cnt++] = &pcr_group_sha1; |
496 | break; |
497 | case TPM_ALG_SHA256: |
498 | chip->groups[chip->groups_cnt++] = &pcr_group_sha256; |
499 | break; |
500 | case TPM_ALG_SHA384: |
501 | chip->groups[chip->groups_cnt++] = &pcr_group_sha384; |
502 | break; |
503 | case TPM_ALG_SHA512: |
504 | chip->groups[chip->groups_cnt++] = &pcr_group_sha512; |
505 | break; |
506 | case TPM_ALG_SM3_256: |
507 | chip->groups[chip->groups_cnt++] = &pcr_group_sm3; |
508 | break; |
509 | default: |
510 | /* |
511 | * If triggers, send a patch to add both a |
512 | * PCR_ATTR_BUILD() macro above for the |
513 | * missing algorithm as well as an additional |
514 | * case in this switch statement. |
515 | */ |
516 | dev_err(&chip->dev, |
517 | "TPM with unsupported bank algorithm 0x%04x" , |
518 | chip->allocated_banks[i].alg_id); |
519 | break; |
520 | } |
521 | } |
522 | |
523 | /* |
524 | * This will only trigger if someone has added an additional |
525 | * hash to the tpm_algorithms enum without incrementing |
526 | * TPM_MAX_HASHES. |
527 | */ |
528 | WARN_ON(chip->groups_cnt > TPM_MAX_HASHES + 1); |
529 | } |
530 | |