]> www.infradead.org Git - users/hch/configfs.git/commitdiff
tpm: Address !chip->auth in tpm_buf_append_hmac_session*()
authorJarkko Sakkinen <jarkko@kernel.org>
Wed, 3 Jul 2024 15:47:46 +0000 (18:47 +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_hmac_session*().  Thus, address
!chip->auth in tpm_buf_hmac_session*() and remove the fallback
implementation for !TCG_TPM2_HMAC.

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

index b3ed35e7ec0019fbf13d31050fa52f68ada32112..2281d55df5456094476f461ace31cf115fd4c417 100644 (file)
@@ -272,6 +272,110 @@ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
 }
 EXPORT_SYMBOL_GPL(tpm_buf_append_name);
 
+/**
+ * tpm_buf_append_hmac_session() - Append a TPM session element
+ * @chip: the TPM chip structure
+ * @buf: The buffer to be appended
+ * @attributes: The session attributes
+ * @passphrase: The session authority (NULL if none)
+ * @passphrase_len: The length of the session authority (0 if none)
+ *
+ * This fills in a session structure in the TPM command buffer, except
+ * for the HMAC which cannot be computed until the command buffer is
+ * complete.  The type of session is controlled by the @attributes,
+ * the main ones of which are TPM2_SA_CONTINUE_SESSION which means the
+ * session won't terminate after tpm_buf_check_hmac_response(),
+ * TPM2_SA_DECRYPT which means this buffers first parameter should be
+ * encrypted with a session key and TPM2_SA_ENCRYPT, which means the
+ * response buffer's first parameter needs to be decrypted (confusing,
+ * but the defines are written from the point of view of the TPM).
+ *
+ * Any session appended by this command must be finalized by calling
+ * tpm_buf_fill_hmac_session() otherwise the HMAC will be incorrect
+ * and the TPM will reject the command.
+ *
+ * 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_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
+                                u8 attributes, u8 *passphrase,
+                                int passphrase_len)
+{
+#ifdef CONFIG_TCG_TPM2_HMAC
+       u8 nonce[SHA256_DIGEST_SIZE];
+       struct tpm2_auth *auth;
+       u32 len;
+#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);
+               return;
+       }
+
+#ifdef CONFIG_TCG_TPM2_HMAC
+       /*
+        * The Architecture Guide requires us to strip trailing zeros
+        * before computing the HMAC
+        */
+       while (passphrase && passphrase_len > 0 && passphrase[passphrase_len - 1] == '\0')
+               passphrase_len--;
+
+       auth = chip->auth;
+       auth->attrs = attributes;
+       auth->passphrase_len = passphrase_len;
+       if (passphrase_len)
+               memcpy(auth->passphrase, passphrase, passphrase_len);
+
+       if (auth->session != tpm_buf_length(buf)) {
+               /* we're not the first session */
+               len = get_unaligned_be32(&buf->data[auth->session]);
+               if (4 + len + auth->session != tpm_buf_length(buf)) {
+                       WARN(1, "session length mismatch, cannot append");
+                       return;
+               }
+
+               /* add our new session */
+               len += 9 + 2 * SHA256_DIGEST_SIZE;
+               put_unaligned_be32(len, &buf->data[auth->session]);
+       } else {
+               tpm_buf_append_u32(buf, 9 + 2 * SHA256_DIGEST_SIZE);
+       }
+
+       /* random number for our nonce */
+       get_random_bytes(nonce, sizeof(nonce));
+       memcpy(auth->our_nonce, nonce, sizeof(nonce));
+       tpm_buf_append_u32(buf, auth->handle);
+       /* our new nonce */
+       tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
+       tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
+       tpm_buf_append_u8(buf, auth->attrs);
+       /* and put a placeholder for the hmac */
+       tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
+       tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
+#endif
+}
+EXPORT_SYMBOL_GPL(tpm_buf_append_hmac_session);
+
 #ifdef CONFIG_TCG_TPM2_HMAC
 
 static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
@@ -457,82 +561,6 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip)
        crypto_free_kpp(kpp);
 }
 
-/**
- * tpm_buf_append_hmac_session() - Append a TPM session element
- * @chip: the TPM chip structure
- * @buf: The buffer to be appended
- * @attributes: The session attributes
- * @passphrase: The session authority (NULL if none)
- * @passphrase_len: The length of the session authority (0 if none)
- *
- * This fills in a session structure in the TPM command buffer, except
- * for the HMAC which cannot be computed until the command buffer is
- * complete.  The type of session is controlled by the @attributes,
- * the main ones of which are TPM2_SA_CONTINUE_SESSION which means the
- * session won't terminate after tpm_buf_check_hmac_response(),
- * TPM2_SA_DECRYPT which means this buffers first parameter should be
- * encrypted with a session key and TPM2_SA_ENCRYPT, which means the
- * response buffer's first parameter needs to be decrypted (confusing,
- * but the defines are written from the point of view of the TPM).
- *
- * Any session appended by this command must be finalized by calling
- * tpm_buf_fill_hmac_session() otherwise the HMAC will be incorrect
- * and the TPM will reject the command.
- *
- * 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_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
-                                u8 attributes, u8 *passphrase,
-                                int passphrase_len)
-{
-       u8 nonce[SHA256_DIGEST_SIZE];
-       u32 len;
-       struct tpm2_auth *auth = chip->auth;
-
-       /*
-        * The Architecture Guide requires us to strip trailing zeros
-        * before computing the HMAC
-        */
-       while (passphrase && passphrase_len > 0
-              && passphrase[passphrase_len - 1] == '\0')
-               passphrase_len--;
-
-       auth->attrs = attributes;
-       auth->passphrase_len = passphrase_len;
-       if (passphrase_len)
-               memcpy(auth->passphrase, passphrase, passphrase_len);
-
-       if (auth->session != tpm_buf_length(buf)) {
-               /* we're not the first session */
-               len = get_unaligned_be32(&buf->data[auth->session]);
-               if (4 + len + auth->session != tpm_buf_length(buf)) {
-                       WARN(1, "session length mismatch, cannot append");
-                       return;
-               }
-
-               /* add our new session */
-               len += 9 + 2 * SHA256_DIGEST_SIZE;
-               put_unaligned_be32(len, &buf->data[auth->session]);
-       } else {
-               tpm_buf_append_u32(buf, 9 + 2 * SHA256_DIGEST_SIZE);
-       }
-
-       /* random number for our nonce */
-       get_random_bytes(nonce, sizeof(nonce));
-       memcpy(auth->our_nonce, nonce, sizeof(nonce));
-       tpm_buf_append_u32(buf, auth->handle);
-       /* our new nonce */
-       tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
-       tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
-       tpm_buf_append_u8(buf, auth->attrs);
-       /* and put a placeholder for the hmac */
-       tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
-       tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
-}
-EXPORT_SYMBOL(tpm_buf_append_hmac_session);
-
 /**
  * tpm_buf_fill_hmac_session() - finalize the session HMAC
  * @chip: the TPM chip structure
@@ -563,6 +591,9 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
        u8 cphash[SHA256_DIGEST_SIZE];
        struct sha256_state sctx;
 
+       if (!auth)
+               return;
+
        /* save the command code in BE format */
        auth->ordinal = head->ordinal;
 
@@ -721,6 +752,9 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
        u32 cc = be32_to_cpu(auth->ordinal);
        int parm_len, len, i, handles;
 
+       if (!auth)
+               return rc;
+
        if (auth->session >= TPM_HEADER_SIZE) {
                WARN(1, "tpm session not filled correctly\n");
                goto out;
index 4d3071e885a0501eb62d83bc509d570aeb2d4d68..e93ee8d936a9c8508b62c29189277ea0890dcf54 100644 (file)
@@ -502,10 +502,6 @@ static inline struct tpm2_auth *tpm2_chip_auth(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);
@@ -515,9 +511,27 @@ static inline void tpm_buf_append_hmac_session_opt(struct tpm_chip *chip,
                                                   u8 *passphrase,
                                                   int passphraselen)
 {
-       tpm_buf_append_hmac_session(chip, buf, attributes, passphrase,
-                                   passphraselen);
+       struct tpm_header *head;
+       int offset;
+
+       if (tpm2_chip_auth(chip)) {
+               tpm_buf_append_hmac_session(chip, buf, attributes, passphrase, passphraselen);
+       } else  {
+               offset = buf->handles * 4 + TPM_HEADER_SIZE;
+               head = (struct tpm_header *)buf->data;
+
+               /*
+                * If the only sessions are optional, the command tag must change to
+                * TPM2_ST_NO_SESSIONS.
+                */
+               if (tpm_buf_length(buf) == offset)
+                       head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
+       }
 }
+
+#ifdef CONFIG_TCG_TPM2_HMAC
+
+int tpm2_start_auth_session(struct tpm_chip *chip);
 void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf);
 int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
                                int rc);
@@ -532,48 +546,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_hmac_session(struct tpm_chip *chip,
-                                              struct tpm_buf *buf,
-                                              u8 attributes, u8 *passphrase,
-                                              int passphraselen)
-{
-       /* offset tells us where the sessions area begins */
-       int offset = buf->handles * 4 + TPM_HEADER_SIZE;
-       u32 len = 9 + passphraselen;
-
-       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, passphraselen);
-       tpm_buf_append(buf, passphrase, passphraselen);
-}
-static inline void tpm_buf_append_hmac_session_opt(struct tpm_chip *chip,
-                                                  struct tpm_buf *buf,
-                                                  u8 attributes,
-                                                  u8 *passphrase,
-                                                  int passphraselen)
-{
-       int offset = buf->handles * 4 + TPM_HEADER_SIZE;
-       struct tpm_header *head = (struct tpm_header *) buf->data;
-
-       /*
-        * if the only sessions are optional, the command tag
-        * must change to TPM2_ST_NO_SESSIONS
-        */
-       if (tpm_buf_length(buf) == offset)
-               head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
-}
 static inline void tpm_buf_fill_hmac_session(struct tpm_chip *chip,
                                             struct tpm_buf *buf)
 {