> + buf->flags |= TPM_BUF_ERROR;
> + }
> + } else {
> + if (buf_size != buf->capacity + sizeof(*buf)) {
> + WARN(1, "%s: size mismatch: %u != %u\n", __func__,
buf_size,
> + buf->capacity + sizeof(*buf));
> + buf->flags |= TPM_BUF_ERROR;
> + }
> + }
> }
> -EXPORT_SYMBOL_GPL(tpm_buf_init);
>
> -/**
> - * tpm_buf_reset() - Initialize a TPM command
> - * @buf: A &tpm_buf
> - * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
> - * @ordinal: A command ordinal
> - */
> -void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
> +static void __tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag, u32
ordinal)
> {
> struct tpm_header *head = (struct tpm_header *)buf->data;
>
> + __tpm_buf_size_invariant(buf, buf_size);
> +
> + if (buf->flags & TPM_BUF_ERROR)
> + return;
> +
> WARN_ON(tag != TPM_TAG_RQU_COMMAND && tag != TPM2_ST_NO_SESSIONS &&
> tag != TPM2_ST_SESSIONS && tag != 0);
>
> buf->flags = 0;
> buf->length = sizeof(*head);
> + buf->capacity = buf_size - sizeof(*buf);
> + buf->handles = 0;
> head->tag = cpu_to_be16(tag);
> head->length = cpu_to_be32(sizeof(*head));
> head->ordinal = cpu_to_be32(ordinal);
> +}
> +
> +static void __tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size)
> +{
> + __tpm_buf_size_invariant(buf, buf_size);
> +
> + if (buf->flags & TPM_BUF_ERROR)
> + return;
> +
> + buf->flags = TPM_BUF_TPM2B;
> + buf->length = 2;
> + buf->capacity = buf_size - sizeof(*buf);
> buf->handles = 0;
> + buf->data[0] = 0;
> + buf->data[1] = 0;
> }
> -EXPORT_SYMBOL_GPL(tpm_buf_reset);
>
> /**
> - * tpm_buf_init_sized() - Allocate and initialize a sized (TPM2B) buffer
> - * @buf: A @tpm_buf
> - *
> - * Return: 0 or -ENOMEM
> + * tpm_buf_init() - Initialize a TPM command
> + * @buf: A &tpm_buf
> + * @buf_size: Size of the buffer.
> */
> -int tpm_buf_init_sized(struct tpm_buf *buf)
> +void tpm_buf_init(struct tpm_buf *buf, u16 buf_size)
> {
> - buf->data = (u8 *)__get_free_page(GFP_KERNEL);
> - if (!buf->data)
> - return -ENOMEM;
> + memset(buf, 0, buf_size);
> + __tpm_buf_reset(buf, buf_size, TPM_TAG_RQU_COMMAND, 0);
> +}
> +EXPORT_SYMBOL_GPL(tpm_buf_init);
>
> - tpm_buf_reset_sized(buf);
> - return 0;
> +/**
> + * tpm_buf_init_sized() - Initialize a sized buffer
> + * @buf: A &tpm_buf
> + * @buf_size: Size of the buffer.
> + */
> +void tpm_buf_init_sized(struct tpm_buf *buf, u16 buf_size)
> +{
> + memset(buf, 0, buf_size);
> + __tpm_buf_reset_sized(buf, buf_size);
> }
> EXPORT_SYMBOL_GPL(tpm_buf_init_sized);
>
> /**
> - * tpm_buf_reset_sized() - Initialize a sized buffer
> + * tpm_buf_reset() - Re-initialize a TPM command
> * @buf: A &tpm_buf
> + * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
> + * @ordinal: A command ordinal
> */
> -void tpm_buf_reset_sized(struct tpm_buf *buf)
> +void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
> {
> - buf->flags = TPM_BUF_TPM2B;
> - buf->length = 2;
> - buf->data[0] = 0;
> - buf->data[1] = 0;
> + u16 buf_size = buf->capacity + sizeof(*buf);
> +
> + __tpm_buf_reset(buf, buf_size, tag, ordinal);
> }
> -EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
> +EXPORT_SYMBOL_GPL(tpm_buf_reset);
>
> -void tpm_buf_destroy(struct tpm_buf *buf)
> +/**
> + * tpm_buf_reset_sized() - Re-initialize a sized buffer
> + * @buf: A &tpm_buf
> + */
> +void tpm_buf_reset_sized(struct tpm_buf *buf)
> {
> - free_page((unsigned long)buf->data);
> + u16 buf_size = buf->capacity + sizeof(*buf);
> +
> + __tpm_buf_reset_sized(buf, buf_size);
> }
> -EXPORT_SYMBOL_GPL(tpm_buf_destroy);
> +EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
>
> /**
> * tpm_buf_length() - Return the number of bytes consumed by the data
> @@ -92,6 +117,9 @@ EXPORT_SYMBOL_GPL(tpm_buf_destroy);
> */
> u32 tpm_buf_length(struct tpm_buf *buf)
> {
> + if (buf->flags & TPM_BUF_ERROR)
> + return 0;
> +
> return buf->length;
> }
> EXPORT_SYMBOL_GPL(tpm_buf_length);
> @@ -104,13 +132,14 @@ EXPORT_SYMBOL_GPL(tpm_buf_length);
> */
> void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length)
> {
> - /* Return silently if overflow has already happened. */
> - if (buf->flags & TPM_BUF_OVERFLOW)
> + u32 total_length = (u32)buf->length + (u32)new_length;
> +
> + if (buf->flags & TPM_BUF_ERROR)
> return;
>
> - if ((buf->length + new_length) > PAGE_SIZE) {
> + if (total_length > (u32)buf->capacity) {
> WARN(1, "tpm_buf: write overflow\n");
> - buf->flags |= TPM_BUF_OVERFLOW;
> + buf->flags |= TPM_BUF_ERROR;
> return;
> }
>
> @@ -157,8 +186,12 @@ EXPORT_SYMBOL_GPL(tpm_buf_append_u32);
> */
> void tpm_buf_append_handle(struct tpm_chip *chip, struct tpm_buf *buf, u32
handle)
> {
> + if (buf->flags & TPM_BUF_ERROR)
> + return;
> +
> if (buf->flags & TPM_BUF_TPM2B) {
> - dev_err(&chip->dev, "Invalid buffer type (TPM2B)\n");
> + dev_err(&chip->dev, "%s: invalid for buffer type: TPM2B\n",
__func__);
> + buf->flags |= TPM_BUF_ERROR;
> return;
> }
>
> @@ -178,13 +211,13 @@ static void tpm_buf_read(struct tpm_buf *buf, off_t
*offset, size_t count, void
> off_t next_offset;
>
> /* Return silently if overflow has already happened. */
> - if (buf->flags & TPM_BUF_BOUNDARY_ERROR)
> + if (buf->flags & TPM_BUF_ERROR)
> return;
>
> next_offset = *offset + count;
> if (next_offset > buf->length) {
> WARN(1, "tpm_buf: read out of boundary\n");
> - buf->flags |= TPM_BUF_BOUNDARY_ERROR;
> + buf->flags |= TPM_BUF_ERROR;
> return;
> }
>
> @@ -242,5 +275,3 @@ u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset)
> return be32_to_cpu(value);
> }
> EXPORT_SYMBOL_GPL(tpm_buf_read_u32);
> -
> -
> diff --git a/drivers/char/tpm/tpm-dev-common.c
b/drivers/char/tpm/tpm-dev-common.c
> index f2a5e09257dd..4f5893555fb7 100644
> --- a/drivers/char/tpm/tpm-dev-common.c
> +++ b/drivers/char/tpm/tpm-dev-common.c
> @@ -147,7 +147,7 @@ ssize_t tpm_common_read(struct file *file, char __user
*buf,
>
> rc = copy_to_user(buf, priv->data_buffer + *off,
ret_size);
> if (rc) {
> - memset(priv->data_buffer, 0, TPM_BUFSIZE);
> + memset(priv->data_buffer, 0, TPM_BUF_MAX_SIZE);
> priv->response_length = 0;
> ret_size = -EFAULT;
> } else {
> @@ -173,7 +173,7 @@ ssize_t tpm_common_write(struct file *file, const char
__user *buf,
> struct file_priv *priv = file->private_data;
> int ret = 0;
>
> - if (size > TPM_BUFSIZE)
> + if (size > TPM_BUF_MAX_SIZE)
> return -E2BIG;
>
> mutex_lock(&priv->buffer_mutex);
> diff --git a/drivers/char/tpm/tpm-dev.h b/drivers/char/tpm/tpm-dev.h
> index f3742bcc73e3..700e3d9d8b64 100644
> --- a/drivers/char/tpm/tpm-dev.h
> +++ b/drivers/char/tpm/tpm-dev.h
> @@ -18,7 +18,7 @@ struct file_priv {
> bool response_read;
> bool command_enqueued;
>
> - u8 data_buffer[TPM_BUFSIZE];
> + u8 data_buffer[TPM_BUF_MAX_SIZE];
> };
>
> void tpm_common_open(struct file *file, struct tpm_chip *chip,
> diff --git a/drivers/char/tpm/tpm-interface.c
b/drivers/char/tpm/tpm-interface.c
> index c9f173001d0e..b0d5098fb92b 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -100,8 +100,8 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
void *buf, size_t bufsiz)
> if (bufsiz < TPM_HEADER_SIZE)
> return -EINVAL;
>
> - if (bufsiz > TPM_BUFSIZE)
> - bufsiz = TPM_BUFSIZE;
> + if (bufsiz > TPM_BUF_MAX_SIZE)
> + bufsiz = TPM_BUF_MAX_SIZE;
>
> count = be32_to_cpu(header->length);
> ordinal = be32_to_cpu(header->ordinal);
> diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
> index 94231f052ea7..4213a8285ed0 100644
> --- a/drivers/char/tpm/tpm-sysfs.c
> +++ b/drivers/char/tpm/tpm-sysfs.c
> @@ -32,28 +32,30 @@ struct tpm_readpubek_out {
> static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> {
> - struct tpm_buf tpm_buf;
> struct tpm_readpubek_out *out;
> int i;
> char *str = buf;
> struct tpm_chip *chip = to_tpm_chip(dev);
> char anti_replay[20];
>
> + struct tpm_buf *tpm_buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
We're using PAGE_SIZE instead of TPM_BUF_MAX_SIZE to reduce the pressure on
the allocator, right?
I was wondering if we could create an inline function or a macro that calls
kzalloc() and tpm_buf_init().
Just because we do it often, it's not a strong opinion, just something that
came to mind while doing the review.
I mean something like this (untested):
struct tpm_buf *tpm_buf_alloc_max(void) {
struct tpm_buf *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
return NULL;
tpm_buf_init(buf, TPM_BUF_MAX_SIZE);
return buf;
}