.../admin-guide/kernel-parameters.txt | 9 ++++ drivers/char/tpm/tpm-buf.c | 20 ++++++++ drivers/char/tpm/tpm2-cmd.c | 30 ++++++++--- drivers/char/tpm/tpm2-sessions.c | 51 ++++++++++--------- include/linux/tpm.h | 3 ++ 5 files changed, 82 insertions(+), 31 deletions(-)
The initial HMAC session feature added TPM bus encryption and/or integrity
protection to various in-kernel TPM operations. This can cause performance
bottlenecks with IMA, as it heavily utilizes PCR extend operations.
In order to mitigate this performance issue, introduce a kernel
command-line parameter to the TPM driver for disabling the integrity
protection for PCR extend operations (i.e. TPM2_PCR_Extend).
Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
Link: https://lore.kernel.org/linux-integrity/20241015193916.59964-1-zohar@linux.ibm.com/
Fixes: 6519fea6fd37 ("tpm: add hmac checks to tpm2_pcr_extend()")
Co-developed-by: Roberto Sassu <roberto.sassu@huawei.com>
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Co-developed-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
v3:
- Please test this too ;-) I did quick testing only.
- Fixed the reported glitches and mistakes.
v2:
- Followed Mimi's suggestions.
---
.../admin-guide/kernel-parameters.txt | 9 ++++
drivers/char/tpm/tpm-buf.c | 20 ++++++++
drivers/char/tpm/tpm2-cmd.c | 30 ++++++++---
drivers/char/tpm/tpm2-sessions.c | 51 ++++++++++---------
include/linux/tpm.h | 3 ++
5 files changed, 82 insertions(+), 31 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 1666576acc0e..7107ad322b2e 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6727,6 +6727,15 @@
torture.verbose_sleep_duration= [KNL]
Duration of each verbose-printk() sleep in jiffies.
+ tpm.disable_pcr_integrity_protection= [HW,TPM]
+ Do not protect PCR registers from unintended physical
+ access, or interposers in the bus by the means of
+ having an integrity protected session wrapped around
+ TPM2_PCR_Extend command. Consider this in a situation
+ where TPM is heavily utilized by IMA, thus protection
+ causing a major performance hit, and the space where
+ machines are deployed is by other means guarded.
+
tpm_suspend_pcr=[HW,TPM]
Format: integer pcr id
Specify that at suspend time, the tpm driver
diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c
index cad0048bcc3c..e49a19fea3bd 100644
--- a/drivers/char/tpm/tpm-buf.c
+++ b/drivers/char/tpm/tpm-buf.c
@@ -146,6 +146,26 @@ void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
}
EXPORT_SYMBOL_GPL(tpm_buf_append_u32);
+/**
+ * tpm_buf_append_handle() - Add a handle
+ * @chip: &tpm_chip instance
+ * @buf: &tpm_buf instance
+ * @handle: a TPM object handle
+ *
+ * Add a handle to the buffer, and increase the count tracking the number of
+ * handles in the command buffer. Works only for command buffers.
+ */
+void tpm_buf_append_handle(struct tpm_chip *chip, struct tpm_buf *buf, u32 handle)
+{
+ if (buf->flags & TPM_BUF_TPM2B) {
+ dev_err(&chip->dev, "Invalid buffer type (TPM2B)\n");
+ return;
+ }
+
+ tpm_buf_append_u32(buf, handle);
+ buf->handles++;
+}
+
/**
* tpm_buf_read() - Read from a TPM buffer
* @buf: &tpm_buf instance
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 1e856259219e..dfdcbd009720 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -14,6 +14,10 @@
#include "tpm.h"
#include <crypto/hash_info.h>
+static bool disable_pcr_integrity;
+module_param(disable_pcr_integrity, bool, 0444);
+MODULE_PARM_DESC(disable_pcr_integrity, "Disable integrity protection of TPM2_PCR_Extend");
+
static struct tpm2_hash tpm2_hash_map[] = {
{HASH_ALGO_SHA1, TPM_ALG_SHA1},
{HASH_ALGO_SHA256, TPM_ALG_SHA256},
@@ -232,18 +236,26 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
int rc;
int i;
- rc = tpm2_start_auth_session(chip);
- if (rc)
- return rc;
+ if (!disable_pcr_integrity) {
+ rc = tpm2_start_auth_session(chip);
+ if (rc)
+ return rc;
+ }
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
if (rc) {
- tpm2_end_auth_session(chip);
+ if (!disable_pcr_integrity)
+ tpm2_end_auth_session(chip);
return rc;
}
- tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
- tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
+ if (!disable_pcr_integrity) {
+ tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
+ tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
+ } else {
+ tpm_buf_append_handle(chip, &buf, pcr_idx);
+ tpm_buf_append_auth(chip, &buf, 0, NULL, 0);
+ }
tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
@@ -253,9 +265,11 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
chip->allocated_banks[i].digest_size);
}
- tpm_buf_fill_hmac_session(chip, &buf);
+ if (!disable_pcr_integrity)
+ tpm_buf_fill_hmac_session(chip, &buf);
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
+ if (!disable_pcr_integrity)
+ rc = tpm_buf_check_hmac_response(chip, &buf, rc);
tpm_buf_destroy(&buf);
diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index 42df980168b6..a7c1b162251b 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -237,9 +237,7 @@ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
#endif
if (!tpm2_chip_auth(chip)) {
- tpm_buf_append_u32(buf, handle);
- /* count the number of handles in the upper bits of flags */
- buf->handles++;
+ tpm_buf_append_handle(chip, buf, handle);
return;
}
@@ -272,6 +270,31 @@ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
}
EXPORT_SYMBOL_GPL(tpm_buf_append_name);
+void tpm_buf_append_auth(struct tpm_chip *chip, struct tpm_buf *buf,
+ u8 attributes, u8 *passphrase, int passphrase_len)
+{
+ /* offset tells us where the sessions area begins */
+ int offset = buf->handles * 4 + TPM_HEADER_SIZE;
+ u32 len = 9 + passphrase_len;
+
+ if (tpm_buf_length(buf) != offset) {
+ /* not the first session so update the existing length */
+ len += get_unaligned_be32(&buf->data[offset]);
+ put_unaligned_be32(len, &buf->data[offset]);
+ } else {
+ tpm_buf_append_u32(buf, len);
+ }
+ /* auth handle */
+ tpm_buf_append_u32(buf, TPM2_RS_PW);
+ /* nonce */
+ tpm_buf_append_u16(buf, 0);
+ /* attributes */
+ tpm_buf_append_u8(buf, 0);
+ /* passphrase */
+ tpm_buf_append_u16(buf, passphrase_len);
+ tpm_buf_append(buf, passphrase, passphrase_len);
+}
+
/**
* tpm_buf_append_hmac_session() - Append a TPM session element
* @chip: the TPM chip structure
@@ -309,26 +332,8 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
#endif
if (!tpm2_chip_auth(chip)) {
- /* offset tells us where the sessions area begins */
- int offset = buf->handles * 4 + TPM_HEADER_SIZE;
- u32 len = 9 + passphrase_len;
-
- if (tpm_buf_length(buf) != offset) {
- /* not the first session so update the existing length */
- len += get_unaligned_be32(&buf->data[offset]);
- put_unaligned_be32(len, &buf->data[offset]);
- } else {
- tpm_buf_append_u32(buf, len);
- }
- /* auth handle */
- tpm_buf_append_u32(buf, TPM2_RS_PW);
- /* nonce */
- tpm_buf_append_u16(buf, 0);
- /* attributes */
- tpm_buf_append_u8(buf, 0);
- /* passphrase */
- tpm_buf_append_u16(buf, passphrase_len);
- tpm_buf_append(buf, passphrase, passphrase_len);
+ tpm_buf_append_auth(chip, buf, attributes, passphrase,
+ passphrase_len);
return;
}
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 587b96b4418e..20a40ade8030 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -421,6 +421,7 @@ void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value);
u8 tpm_buf_read_u8(struct tpm_buf *buf, off_t *offset);
u16 tpm_buf_read_u16(struct tpm_buf *buf, off_t *offset);
u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset);
+void tpm_buf_append_handle(struct tpm_chip *chip, struct tpm_buf *buf, u32 handle);
/*
* Check if TPM device is in the firmware upgrade mode.
@@ -505,6 +506,8 @@ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
u8 attributes, u8 *passphrase,
int passphraselen);
+void tpm_buf_append_auth(struct tpm_chip *chip, struct tpm_buf *buf,
+ u8 attributes, u8 *passphrase, int passphraselen);
static inline void tpm_buf_append_hmac_session_opt(struct tpm_chip *chip,
struct tpm_buf *buf,
u8 attributes,
--
2.47.0
On Wed, 2024-11-13 at 02:24 +0200, Jarkko Sakkinen wrote: > The initial HMAC session feature added TPM bus encryption and/or integrity > protection to various in-kernel TPM operations. This can cause performance > bottlenecks with IMA, as it heavily utilizes PCR extend operations. > > In order to mitigate this performance issue, introduce a kernel > command-line parameter to the TPM driver for disabling the integrity > protection for PCR extend operations (i.e. TPM2_PCR_Extend). > > Cc: James Bottomley <James.Bottomley@HansenPartnership.com> > Link: https://lore.kernel.org/linux-integrity/20241015193916.59964-1-zohar@linux.ibm.com/ > Fixes: 6519fea6fd37 ("tpm: add hmac checks to tpm2_pcr_extend()") > Co-developed-by: Roberto Sassu <roberto.sassu@huawei.com> > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> > Co-developed-by: Mimi Zohar <zohar@linux.ibm.com> > Signed-off-by: Mimi Zohar <zohar@linux.ibm.com> > Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org> The module_param variable documentation needs to be updated to reflect the actual module_param variable 'disable_pcr_integrity'. Otherwise, Tested-by: Mimi Zohar <zohar@linux.ibm.com> > --- > v3: > - Please test this too ;-) I did quick testing only. > - Fixed the reported glitches and mistakes. > v2: > - Followed Mimi's suggestions. > --- > .../admin-guide/kernel-parameters.txt | 9 ++++ > drivers/char/tpm/tpm-buf.c | 20 ++++++++ > drivers/char/tpm/tpm2-cmd.c | 30 ++++++++--- > drivers/char/tpm/tpm2-sessions.c | 51 ++++++++++--------- > include/linux/tpm.h | 3 ++ > 5 files changed, 82 insertions(+), 31 deletions(-) > > diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt > index 1666576acc0e..7107ad322b2e 100644 > --- a/Documentation/admin-guide/kernel-parameters.txt > +++ b/Documentation/admin-guide/kernel-parameters.txt > @@ -6727,6 +6727,15 @@ > torture.verbose_sleep_duration= [KNL] > Duration of each verbose-printk() sleep in jiffies. > > + tpm.disable_pcr_integrity_protection= [HW,TPM] -> tpm.disable_pcr_integrity= > + Do not protect PCR registers from unintended physical > + access, or interposers in the bus by the means of > + having an integrity protected session wrapped around > + TPM2_PCR_Extend command. Consider this in a situation > + where TPM is heavily utilized by IMA, thus protection > + causing a major performance hit, and the space where > + machines are deployed is by other means guarded. > + > tpm_suspend_pcr=[HW,TPM] > Format: integer pcr id > Specify that at suspend time, the tpm driver > diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c > index cad0048bcc3c..e49a19fea3bd 100644 > --- a/drivers/char/tpm/tpm-buf.c > +++ b/drivers/char/tpm/tpm-buf.c > @@ -146,6 +146,26 @@ void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value) > } > EXPORT_SYMBOL_GPL(tpm_buf_append_u32); > > +/** > + * tpm_buf_append_handle() - Add a handle > + * @chip: &tpm_chip instance > + * @buf: &tpm_buf instance > + * @handle: a TPM object handle > + * > + * Add a handle to the buffer, and increase the count tracking the number of > + * handles in the command buffer. Works only for command buffers. > + */ > +void tpm_buf_append_handle(struct tpm_chip *chip, struct tpm_buf *buf, u32 handle) > +{ > + if (buf->flags & TPM_BUF_TPM2B) { > + dev_err(&chip->dev, "Invalid buffer type (TPM2B)\n"); > + return; > + } > + > + tpm_buf_append_u32(buf, handle); > + buf->handles++; > +} > + > /** > * tpm_buf_read() - Read from a TPM buffer > * @buf: &tpm_buf instance > diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c > index 1e856259219e..dfdcbd009720 100644 > --- a/drivers/char/tpm/tpm2-cmd.c > +++ b/drivers/char/tpm/tpm2-cmd.c > @@ -14,6 +14,10 @@ > #include "tpm.h" > #include <crypto/hash_info.h> > > +static bool disable_pcr_integrity; > +module_param(disable_pcr_integrity, bool, 0444); > +MODULE_PARM_DESC(disable_pcr_integrity, "Disable integrity protection of TPM2_PCR_Extend"); 'disable_pcr_integrity' doesn't match the documentation. > + > static struct tpm2_hash tpm2_hash_map[] = { > {HASH_ALGO_SHA1, TPM_ALG_SHA1}, > {HASH_ALGO_SHA256, TPM_ALG_SHA256}, > @@ -232,18 +236,26 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, thanks, Mimi
On Wed Nov 13, 2024 at 6:34 AM EET, Mimi Zohar wrote: > The module_param variable documentation needs to be updated to reflect the > actual module_param variable 'disable_pcr_integrity'. > > Otherwise, > Tested-by: Mimi Zohar <zohar@linux.ibm.com> Thanks for catching that glitch. Here's updated version: https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git/commit/?id=8f22b3ed4d200ae0c575791e069316c633ed5c39 BR, Jarkko
On Wed, 2024-11-13 at 07:56 +0200, Jarkko Sakkinen wrote: > On Wed Nov 13, 2024 at 6:34 AM EET, Mimi Zohar wrote: > > The module_param variable documentation needs to be updated to reflect the > > actual module_param variable 'disable_pcr_integrity'. > > > > Otherwise, > > Tested-by: Mimi Zohar <zohar@linux.ibm.com> > > Thanks for catching that glitch. Here's updated version: > > https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git/commit/?id=8f22b3ed4d200ae0c575791e069316c633ed5c39 Looks good. thanks, Mimi
© 2016 - 2024 Red Hat, Inc.