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

tpm: Store the length of the tpm_buf data separately.

TPM2B buffers, or sized buffers, have a two byte header, which contains the
length of the payload as a 16-bit big-endian number, without counting in
the space taken by the header. This differs from encoding in the TPM header
where the length includes also the bytes taken by the header.

Unbound the length of a tpm_buf from the value stored to the TPM command
header. A separate encoding and decoding step so that different buffer
types can be supported, with variant header format and length encoding.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Tested-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>

+47 -20
+38 -11
drivers/char/tpm/tpm-buf.c
··· 3 3 * Handling of TPM command and other buffers. 4 4 */ 5 5 6 + #include <linux/tpm_command.h> 6 7 #include <linux/module.h> 7 8 #include <linux/tpm.h> 8 9 10 + /** 11 + * tpm_buf_init() - Allocate and initialize a TPM command 12 + * @buf: A &tpm_buf 13 + * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS 14 + * @ordinal: A command ordinal 15 + * 16 + * Return: 0 or -ENOMEM 17 + */ 9 18 int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal) 10 19 { 11 20 buf->data = (u8 *)__get_free_page(GFP_KERNEL); 12 21 if (!buf->data) 13 22 return -ENOMEM; 14 23 15 - buf->flags = 0; 16 24 tpm_buf_reset(buf, tag, ordinal); 17 25 return 0; 18 26 } 19 27 EXPORT_SYMBOL_GPL(tpm_buf_init); 20 28 29 + /** 30 + * tpm_buf_reset() - Initialize a TPM command 31 + * @buf: A &tpm_buf 32 + * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS 33 + * @ordinal: A command ordinal 34 + */ 21 35 void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal) 22 36 { 23 37 struct tpm_header *head = (struct tpm_header *)buf->data; 24 38 39 + WARN_ON(tag != TPM_TAG_RQU_COMMAND && tag != TPM2_ST_NO_SESSIONS && 40 + tag != TPM2_ST_SESSIONS && tag != 0); 41 + 42 + buf->flags = 0; 43 + buf->length = sizeof(*head); 25 44 head->tag = cpu_to_be16(tag); 26 45 head->length = cpu_to_be32(sizeof(*head)); 27 46 head->ordinal = cpu_to_be32(ordinal); ··· 53 34 } 54 35 EXPORT_SYMBOL_GPL(tpm_buf_destroy); 55 36 37 + /** 38 + * tpm_buf_length() - Return the number of bytes consumed by the data 39 + * @buf: A &tpm_buf 40 + * 41 + * Return: The number of bytes consumed by the buffer 42 + */ 56 43 u32 tpm_buf_length(struct tpm_buf *buf) 57 44 { 58 - struct tpm_header *head = (struct tpm_header *)buf->data; 59 - 60 - return be32_to_cpu(head->length); 45 + return buf->length; 61 46 } 62 47 EXPORT_SYMBOL_GPL(tpm_buf_length); 63 48 64 - void tpm_buf_append(struct tpm_buf *buf, 65 - const unsigned char *new_data, 66 - unsigned int new_len) 49 + /** 50 + * tpm_buf_append() - Append data to an initialized buffer 51 + * @buf: A &tpm_buf 52 + * @new_data: A data blob 53 + * @new_length: Size of the appended data 54 + */ 55 + void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length) 67 56 { 68 57 struct tpm_header *head = (struct tpm_header *)buf->data; 69 - u32 len = tpm_buf_length(buf); 70 58 71 59 /* Return silently if overflow has already happened. */ 72 60 if (buf->flags & TPM_BUF_OVERFLOW) 73 61 return; 74 62 75 - if ((len + new_len) > PAGE_SIZE) { 63 + if ((buf->length + new_length) > PAGE_SIZE) { 76 64 WARN(1, "tpm_buf: overflow\n"); 77 65 buf->flags |= TPM_BUF_OVERFLOW; 78 66 return; 79 67 } 80 68 81 - memcpy(&buf->data[len], new_data, new_len); 82 - head->length = cpu_to_be32(len + new_len); 69 + memcpy(&buf->data[buf->length], new_data, new_length); 70 + buf->length += new_length; 71 + head->length = cpu_to_be32(buf->length); 83 72 } 84 73 EXPORT_SYMBOL_GPL(tpm_buf_append); 85 74
+1
drivers/char/tpm/tpm-interface.c
··· 232 232 if (len < min_rsp_body_length + TPM_HEADER_SIZE) 233 233 return -EFAULT; 234 234 235 + buf->length = len; 235 236 return 0; 236 237 } 237 238 EXPORT_SYMBOL_GPL(tpm_transmit_cmd);
-2
include/keys/trusted_tpm.h
··· 6 6 #include <linux/tpm_command.h> 7 7 8 8 /* implementation specific TPM constants */ 9 - #define MAX_BUF_SIZE 1024 10 - #define TPM_GETRANDOM_SIZE 14 11 9 #define TPM_SIZE_OFFSET 2 12 10 #define TPM_RETURN_OFFSET 6 13 11 #define TPM_DATA_OFFSET 10
+3 -3
include/linux/tpm.h
··· 306 306 * A string buffer type for constructing TPM commands. 307 307 */ 308 308 struct tpm_buf { 309 - unsigned int flags; 309 + u32 flags; 310 + u32 length; 310 311 u8 *data; 311 312 }; 312 313 ··· 330 329 void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal); 331 330 void tpm_buf_destroy(struct tpm_buf *buf); 332 331 u32 tpm_buf_length(struct tpm_buf *buf); 333 - void tpm_buf_append(struct tpm_buf *buf, const unsigned char *new_data, 334 - unsigned int new_len); 332 + void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length); 335 333 void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value); 336 334 void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value); 337 335 void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value);
+5 -4
security/keys/trusted-keys/trusted_tpm1.c
··· 367 367 return rc; 368 368 369 369 buf.flags = 0; 370 + buf.length = buflen; 370 371 buf.data = cmd; 371 372 dump_tpm_buf(cmd); 372 373 rc = tpm_transmit_cmd(chip, &buf, 4, "sending data"); ··· 418 417 tpm_buf_append_u32(tb, handle); 419 418 tpm_buf_append(tb, ononce, TPM_NONCE_SIZE); 420 419 421 - ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); 420 + ret = trusted_tpm_send(tb->data, tb->length); 422 421 if (ret < 0) 423 422 return ret; 424 423 ··· 442 441 return -ENODEV; 443 442 444 443 tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP); 445 - ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); 444 + ret = trusted_tpm_send(tb->data, tb->length); 446 445 if (ret < 0) 447 446 return ret; 448 447 ··· 554 553 tpm_buf_append_u8(tb, cont); 555 554 tpm_buf_append(tb, td->pubauth, SHA1_DIGEST_SIZE); 556 555 557 - ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); 556 + ret = trusted_tpm_send(tb->data, tb->length); 558 557 if (ret < 0) 559 558 goto out; 560 559 ··· 645 644 tpm_buf_append_u8(tb, cont); 646 645 tpm_buf_append(tb, authdata2, SHA1_DIGEST_SIZE); 647 646 648 - ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); 647 + ret = trusted_tpm_send(tb->data, tb->length); 649 648 if (ret < 0) { 650 649 pr_info("authhmac failed (%d)\n", ret); 651 650 return ret;