Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tpm: fix byte order related arithmetic inconsistency in tpm_getcap()

You should not do arithmetic with __be32 or __le32 types because
sometimes it results incorrect results. Calculations must be done only
with integers that are in in the CPU byte order. This commit migrates
tpm_getcap() to struct tpm_buf in order to sort out these issues.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Reviewed-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>

+16 -27
+16 -14
drivers/char/tpm/tpm-interface.c
··· 552 552 ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, 553 553 const char *desc, size_t min_cap_length) 554 554 { 555 - struct tpm_cmd_t tpm_cmd; 555 + struct tpm_buf buf; 556 556 int rc; 557 557 558 - tpm_cmd.header.in = tpm_getcap_header; 558 + rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP); 559 + if (rc) 560 + return rc; 561 + 559 562 if (subcap_id == TPM_CAP_VERSION_1_1 || 560 563 subcap_id == TPM_CAP_VERSION_1_2) { 561 - tpm_cmd.params.getcap_in.cap = cpu_to_be32(subcap_id); 562 - /*subcap field not necessary */ 563 - tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0); 564 - tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32)); 564 + tpm_buf_append_u32(&buf, subcap_id); 565 + tpm_buf_append_u32(&buf, 0); 565 566 } else { 566 567 if (subcap_id == TPM_CAP_FLAG_PERM || 567 568 subcap_id == TPM_CAP_FLAG_VOL) 568 - tpm_cmd.params.getcap_in.cap = 569 - cpu_to_be32(TPM_CAP_FLAG); 569 + tpm_buf_append_u32(&buf, TPM_CAP_FLAG); 570 570 else 571 - tpm_cmd.params.getcap_in.cap = 572 - cpu_to_be32(TPM_CAP_PROP); 573 - tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); 574 - tpm_cmd.params.getcap_in.subcap = cpu_to_be32(subcap_id); 571 + tpm_buf_append_u32(&buf, TPM_CAP_PROP); 572 + 573 + tpm_buf_append_u32(&buf, 4); 574 + tpm_buf_append_u32(&buf, subcap_id); 575 575 } 576 - rc = tpm_transmit_cmd(chip, NULL, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 576 + rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 577 577 min_cap_length, 0, desc); 578 578 if (!rc) 579 - *cap = tpm_cmd.params.getcap_out.cap; 579 + *cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4]; 580 + 581 + tpm_buf_destroy(&buf); 580 582 return rc; 581 583 } 582 584 EXPORT_SYMBOL_GPL(tpm_getcap);
-13
drivers/char/tpm/tpm.h
··· 339 339 TPM_CAP_PROP_TIS_DURATION = 0x120, 340 340 }; 341 341 342 - struct tpm_getcap_params_in { 343 - __be32 cap; 344 - __be32 subcap_size; 345 - __be32 subcap; 346 - } __packed; 347 - 348 - struct tpm_getcap_params_out { 349 - __be32 cap_size; 350 - cap_t cap; 351 - } __packed; 352 - 353 342 struct tpm_readpubek_params_out { 354 343 u8 algorithm[4]; 355 344 u8 encscheme[2]; ··· 388 399 } __packed; 389 400 390 401 typedef union { 391 - struct tpm_getcap_params_out getcap_out; 392 402 struct tpm_readpubek_params_out readpubek_out; 393 403 u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)]; 394 - struct tpm_getcap_params_in getcap_in; 395 404 struct tpm_pcrread_in pcrread_in; 396 405 struct tpm_pcrread_out pcrread_out; 397 406 struct tpm_pcrextend_in pcrextend_in;