tpm: Address !chip->auth in tpm_buf_append_name()
authorJarkko Sakkinen <jarkko@kernel.org>
Wed, 3 Jul 2024 15:33:14 +0000 (18:33 +0300)
committerJarkko Sakkinen <jarkko.sakkinen@iki.fi>
Thu, 4 Jul 2024 23:12:27 +0000 (02:12 +0300)
Unless tpm_chip_bootstrap() was called by the driver, !chip->auth can
cause a null derefence in tpm_buf_append_name().  Thus, address
!chip->auth in tpm_buf_append_name() and remove the fallback
implementation for !TCG_TPM2_HMAC.

Cc: stable@vger.kernel.org # v6.10+
Reported-by: Stefan Berger <stefanb@linux.ibm.com>
Closes: https://lore.kernel.org/linux-integrity/20240617193408.1234365-1-stefanb@linux.ibm.com/
Fixes: d0a25bb961e6 ("tpm: Add HMAC session name/handle append")
Tested-by: Michael Ellerman <mpe@ellerman.id.au> # ppc
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
drivers/char/tpm/Makefile
drivers/char/tpm/tpm2-sessions.c
include/linux/tpm.h

index 4c695b0388f3eb204589bf372f51f6e8ac405ec5..9bb142c75243f0bae9b9620ddcc9758002d707f2 100644 (file)
@@ -16,8 +16,8 @@ tpm-y += eventlog/common.o
 tpm-y += eventlog/tpm1.o
 tpm-y += eventlog/tpm2.o
 tpm-y += tpm-buf.o
+tpm-y += tpm2-sessions.o
 
-tpm-$(CONFIG_TCG_TPM2_HMAC) += tpm2-sessions.o
 tpm-$(CONFIG_ACPI) += tpm_ppi.o eventlog/acpi.o
 tpm-$(CONFIG_EFI) += eventlog/efi.o
 tpm-$(CONFIG_OF) += eventlog/of.o
index 2f1d96a5a5a76d459780707d7ebda6871e15f4d6..b3ed35e7ec0019fbf13d31050fa52f68ada32112 100644 (file)
@@ -83,9 +83,6 @@
 #define AES_KEY_BYTES  AES_KEYSIZE_128
 #define AES_KEY_BITS   (AES_KEY_BYTES*8)
 
-static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
-                              u32 *handle, u8 *name);
-
 /*
  * This is the structure that carries all the auth information (like
  * session handle, nonces, session key and auth) from use to use it is
@@ -148,6 +145,7 @@ struct tpm2_auth {
        u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE];
 };
 
+#ifdef CONFIG_TCG_TPM2_HMAC
 /*
  * Name Size based on TPM algorithm (assumes no hash bigger than 255)
  */
@@ -163,6 +161,122 @@ static u8 name_size(const u8 *name)
        return size_map[alg] + 2;
 }
 
+static int tpm2_parse_read_public(char *name, struct tpm_buf *buf)
+{
+       struct tpm_header *head = (struct tpm_header *)buf->data;
+       off_t offset = TPM_HEADER_SIZE;
+       u32 tot_len = be32_to_cpu(head->length);
+       u32 val;
+
+       /* we're starting after the header so adjust the length */
+       tot_len -= TPM_HEADER_SIZE;
+
+       /* skip public */
+       val = tpm_buf_read_u16(buf, &offset);
+       if (val > tot_len)
+               return -EINVAL;
+       offset += val;
+       /* name */
+       val = tpm_buf_read_u16(buf, &offset);
+       if (val != name_size(&buf->data[offset]))
+               return -EINVAL;
+       memcpy(name, &buf->data[offset], val);
+       /* forget the rest */
+       return 0;
+}
+
+static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name)
+{
+       struct tpm_buf buf;
+       int rc;
+
+       rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
+       if (rc)
+               return rc;
+
+       tpm_buf_append_u32(&buf, handle);
+       rc = tpm_transmit_cmd(chip, &buf, 0, "read public");
+       if (rc == TPM2_RC_SUCCESS)
+               rc = tpm2_parse_read_public(name, &buf);
+
+       tpm_buf_destroy(&buf);
+
+       return rc;
+}
+#endif /* CONFIG_TCG_TPM2_HMAC */
+
+/**
+ * tpm_buf_append_name() - add a handle area to the buffer
+ * @chip: the TPM chip structure
+ * @buf: The buffer to be appended
+ * @handle: The handle to be appended
+ * @name: The name of the handle (may be NULL)
+ *
+ * In order to compute session HMACs, we need to know the names of the
+ * objects pointed to by the handles.  For most objects, this is simply
+ * the actual 4 byte handle or an empty buf (in these cases @name
+ * should be NULL) but for volatile objects, permanent objects and NV
+ * areas, the name is defined as the hash (according to the name
+ * algorithm which should be set to sha256) of the public area to
+ * which the two byte algorithm id has been appended.  For these
+ * objects, the @name pointer should point to this.  If a name is
+ * required but @name is NULL, then TPM2_ReadPublic() will be called
+ * on the handle to obtain the name.
+ *
+ * As with most tpm_buf operations, success is assumed because failure
+ * will be caused by an incorrect programming model and indicated by a
+ * kernel message.
+ */
+void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
+                        u32 handle, u8 *name)
+{
+#ifdef CONFIG_TCG_TPM2_HMAC
+       enum tpm2_mso_type mso = tpm2_handle_mso(handle);
+       struct tpm2_auth *auth;
+       int slot;
+#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++;
+               return;
+       }
+
+#ifdef CONFIG_TCG_TPM2_HMAC
+       slot = (tpm_buf_length(buf) - TPM_HEADER_SIZE) / 4;
+       if (slot >= AUTH_MAX_NAMES) {
+               dev_err(&chip->dev, "TPM: too many handles\n");
+               return;
+       }
+       auth = chip->auth;
+       WARN(auth->session != tpm_buf_length(buf),
+            "name added in wrong place\n");
+       tpm_buf_append_u32(buf, handle);
+       auth->session += 4;
+
+       if (mso == TPM2_MSO_PERSISTENT ||
+           mso == TPM2_MSO_VOLATILE ||
+           mso == TPM2_MSO_NVRAM) {
+               if (!name)
+                       tpm2_read_public(chip, handle, auth->name[slot]);
+       } else {
+               if (name)
+                       dev_err(&chip->dev, "TPM: Handle does not require name but one is specified\n");
+       }
+
+       auth->name_h[slot] = handle;
+       if (name)
+               memcpy(auth->name[slot], name, name_size(name));
+#endif
+}
+EXPORT_SYMBOL_GPL(tpm_buf_append_name);
+
+#ifdef CONFIG_TCG_TPM2_HMAC
+
+static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
+                              u32 *handle, u8 *name);
+
 /*
  * It turns out the crypto hmac(sha256) is hard for us to consume
  * because it assumes a fixed key and the TPM seems to change the key
@@ -567,104 +681,6 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
 }
 EXPORT_SYMBOL(tpm_buf_fill_hmac_session);
 
-static int tpm2_parse_read_public(char *name, struct tpm_buf *buf)
-{
-       struct tpm_header *head = (struct tpm_header *)buf->data;
-       off_t offset = TPM_HEADER_SIZE;
-       u32 tot_len = be32_to_cpu(head->length);
-       u32 val;
-
-       /* we're starting after the header so adjust the length */
-       tot_len -= TPM_HEADER_SIZE;
-
-       /* skip public */
-       val = tpm_buf_read_u16(buf, &offset);
-       if (val > tot_len)
-               return -EINVAL;
-       offset += val;
-       /* name */
-       val = tpm_buf_read_u16(buf, &offset);
-       if (val != name_size(&buf->data[offset]))
-               return -EINVAL;
-       memcpy(name, &buf->data[offset], val);
-       /* forget the rest */
-       return 0;
-}
-
-static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name)
-{
-       struct tpm_buf buf;
-       int rc;
-
-       rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
-       if (rc)
-               return rc;
-
-       tpm_buf_append_u32(&buf, handle);
-       rc = tpm_transmit_cmd(chip, &buf, 0, "read public");
-       if (rc == TPM2_RC_SUCCESS)
-               rc = tpm2_parse_read_public(name, &buf);
-
-       tpm_buf_destroy(&buf);
-
-       return rc;
-}
-
-/**
- * tpm_buf_append_name() - add a handle area to the buffer
- * @chip: the TPM chip structure
- * @buf: The buffer to be appended
- * @handle: The handle to be appended
- * @name: The name of the handle (may be NULL)
- *
- * In order to compute session HMACs, we need to know the names of the
- * objects pointed to by the handles.  For most objects, this is simply
- * the actual 4 byte handle or an empty buf (in these cases @name
- * should be NULL) but for volatile objects, permanent objects and NV
- * areas, the name is defined as the hash (according to the name
- * algorithm which should be set to sha256) of the public area to
- * which the two byte algorithm id has been appended.  For these
- * objects, the @name pointer should point to this.  If a name is
- * required but @name is NULL, then TPM2_ReadPublic() will be called
- * on the handle to obtain the name.
- *
- * As with most tpm_buf operations, success is assumed because failure
- * will be caused by an incorrect programming model and indicated by a
- * kernel message.
- */
-void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
-                        u32 handle, u8 *name)
-{
-       enum tpm2_mso_type mso = tpm2_handle_mso(handle);
-       struct tpm2_auth *auth = chip->auth;
-       int slot;
-
-       slot = (tpm_buf_length(buf) - TPM_HEADER_SIZE)/4;
-       if (slot >= AUTH_MAX_NAMES) {
-               dev_err(&chip->dev, "TPM: too many handles\n");
-               return;
-       }
-       WARN(auth->session != tpm_buf_length(buf),
-            "name added in wrong place\n");
-       tpm_buf_append_u32(buf, handle);
-       auth->session += 4;
-
-       if (mso == TPM2_MSO_PERSISTENT ||
-           mso == TPM2_MSO_VOLATILE ||
-           mso == TPM2_MSO_NVRAM) {
-               if (!name)
-                       tpm2_read_public(chip, handle, auth->name[slot]);
-       } else {
-               if (name)
-                       dev_err(&chip->dev, "TPM: Handle does not require name but one is specified\n");
-       }
-
-       auth->name_h[slot] = handle;
-       if (name)
-               memcpy(auth->name[slot], name, name_size(name));
-}
-EXPORT_SYMBOL(tpm_buf_append_name);
-
 /**
  * tpm_buf_check_hmac_response() - check the TPM return HMAC for correctness
  * @chip: the TPM chip structure
@@ -1311,3 +1327,4 @@ int tpm2_sessions_init(struct tpm_chip *chip)
 
        return rc;
 }
+#endif /* CONFIG_TCG_TPM2_HMAC */
index 21a67dc9efe80b2d0dc6bc2851b2b4ab67933818..4d3071e885a0501eb62d83bc509d570aeb2d4d68 100644 (file)
@@ -490,11 +490,22 @@ static inline void tpm_buf_append_empty_auth(struct tpm_buf *buf, u32 handle)
 {
 }
 #endif
+
+static inline struct tpm2_auth *tpm2_chip_auth(struct tpm_chip *chip)
+{
 #ifdef CONFIG_TCG_TPM2_HMAC
+       return chip->auth;
+#else
+       return NULL;
+#endif
+}
 
-int tpm2_start_auth_session(struct tpm_chip *chip);
 void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
                         u32 handle, u8 *name);
+
+#ifdef CONFIG_TCG_TPM2_HMAC
+
+int tpm2_start_auth_session(struct tpm_chip *chip);
 void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
                                 u8 attributes, u8 *passphrase,
                                 int passphraselen);
@@ -521,14 +532,6 @@ static inline int tpm2_start_auth_session(struct tpm_chip *chip)
 static inline void tpm2_end_auth_session(struct tpm_chip *chip)
 {
 }
-static inline void tpm_buf_append_name(struct tpm_chip *chip,
-                                      struct tpm_buf *buf,
-                                      u32 handle, u8 *name)
-{
-       tpm_buf_append_u32(buf, handle);
-       /* count the number of handles in the upper bits of flags */
-       buf->handles++;
-}
 static inline void tpm_buf_append_hmac_session(struct tpm_chip *chip,
                                               struct tpm_buf *buf,
                                               u8 attributes, u8 *passphrase,