Hi
Addresses a significant boot-time delay issue: https://bugzilla.kernel.org/show_bug.cgi?id=219229 BR, Jarkko -----BEGIN PGP SIGNATURE----- iIgEABYKADAWIQRE6pSOnaBC00OEHEIaerohdGur0gUCZyAhHxIcamFya2tvQGtl cm5lbC5vcmcACgkQGnq6IXRrq9IdzQEAw8uoorY2IHBLFFyvYPebfHAZq5rPci8x eu1606gzODsBAIddSR4tgzFfqm0JVeh5vBa85wIZ43rRbUcpscrgEN8B =J+AF -----END PGP SIGNATURE----- Merge tag 'tpmdd-next-6.12-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd Pull tpm fix from Jarkko Sakkinen: "Address a significant boot-time delay issue" Link: https://bugzilla.kernel.org/show_bug.cgi?id=219229 * tag 'tpmdd-next-6.12-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd: tpm: Lazily flush the auth session tpm: Rollback tpm2_load_null() tpm: Return tpm2_sessions_init() when null key creation fails
This commit is contained in:
commit
d5b2ee0fe8
@ -674,6 +674,16 @@ EXPORT_SYMBOL_GPL(tpm_chip_register);
|
||||
*/
|
||||
void tpm_chip_unregister(struct tpm_chip *chip)
|
||||
{
|
||||
#ifdef CONFIG_TCG_TPM2_HMAC
|
||||
int rc;
|
||||
|
||||
rc = tpm_try_get_ops(chip);
|
||||
if (!rc) {
|
||||
tpm2_end_auth_session(chip);
|
||||
tpm_put_ops(chip);
|
||||
}
|
||||
#endif
|
||||
|
||||
tpm_del_legacy_sysfs(chip);
|
||||
if (tpm_is_hwrng_enabled(chip))
|
||||
hwrng_unregister(&chip->hwrng);
|
||||
|
@ -27,6 +27,9 @@ static ssize_t tpm_dev_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
||||
struct tpm_header *header = (void *)buf;
|
||||
ssize_t ret, len;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
tpm2_end_auth_session(chip);
|
||||
|
||||
ret = tpm2_prepare_space(chip, space, buf, bufsiz);
|
||||
/* If the command is not implemented by the TPM, synthesize a
|
||||
* response with a TPM2_RC_COMMAND_CODE return for user-space.
|
||||
|
@ -379,10 +379,12 @@ int tpm_pm_suspend(struct device *dev)
|
||||
|
||||
rc = tpm_try_get_ops(chip);
|
||||
if (!rc) {
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
tpm2_end_auth_session(chip);
|
||||
tpm2_shutdown(chip, TPM2_SU_STATE);
|
||||
else
|
||||
} else {
|
||||
rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
|
||||
}
|
||||
|
||||
tpm_put_ops(chip);
|
||||
}
|
||||
|
@ -333,6 +333,9 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TCG_TPM2_HMAC
|
||||
/* The first write to /dev/tpm{rm0} will flush the session. */
|
||||
attributes |= TPM2_SA_CONTINUE_SESSION;
|
||||
|
||||
/*
|
||||
* The Architecture Guide requires us to strip trailing zeros
|
||||
* before computing the HMAC
|
||||
@ -484,7 +487,8 @@ static void tpm2_KDFe(u8 z[EC_PT_SZ], const char *str, u8 *pt_u, u8 *pt_v,
|
||||
sha256_final(&sctx, out);
|
||||
}
|
||||
|
||||
static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip)
|
||||
static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip,
|
||||
struct tpm2_auth *auth)
|
||||
{
|
||||
struct crypto_kpp *kpp;
|
||||
struct kpp_request *req;
|
||||
@ -543,7 +547,7 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip)
|
||||
sg_set_buf(&s[0], chip->null_ec_key_x, EC_PT_SZ);
|
||||
sg_set_buf(&s[1], chip->null_ec_key_y, EC_PT_SZ);
|
||||
kpp_request_set_input(req, s, EC_PT_SZ*2);
|
||||
sg_init_one(d, chip->auth->salt, EC_PT_SZ);
|
||||
sg_init_one(d, auth->salt, EC_PT_SZ);
|
||||
kpp_request_set_output(req, d, EC_PT_SZ);
|
||||
crypto_kpp_compute_shared_secret(req);
|
||||
kpp_request_free(req);
|
||||
@ -554,8 +558,7 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip)
|
||||
* This works because KDFe fully consumes the secret before it
|
||||
* writes the salt
|
||||
*/
|
||||
tpm2_KDFe(chip->auth->salt, "SECRET", x, chip->null_ec_key_x,
|
||||
chip->auth->salt);
|
||||
tpm2_KDFe(auth->salt, "SECRET", x, chip->null_ec_key_x, auth->salt);
|
||||
|
||||
out:
|
||||
crypto_free_kpp(kpp);
|
||||
@ -853,7 +856,9 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||
if (rc)
|
||||
/* manually close the session if it wasn't consumed */
|
||||
tpm2_flush_context(chip, auth->handle);
|
||||
memzero_explicit(auth, sizeof(*auth));
|
||||
|
||||
kfree_sensitive(auth);
|
||||
chip->auth = NULL;
|
||||
} else {
|
||||
/* reset for next use */
|
||||
auth->session = TPM_HEADER_SIZE;
|
||||
@ -881,7 +886,8 @@ void tpm2_end_auth_session(struct tpm_chip *chip)
|
||||
return;
|
||||
|
||||
tpm2_flush_context(chip, auth->handle);
|
||||
memzero_explicit(auth, sizeof(*auth));
|
||||
kfree_sensitive(auth);
|
||||
chip->auth = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(tpm2_end_auth_session);
|
||||
|
||||
@ -915,33 +921,37 @@ static int tpm2_parse_start_auth_session(struct tpm2_auth *auth,
|
||||
|
||||
static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
|
||||
{
|
||||
int rc;
|
||||
unsigned int offset = 0; /* dummy offset for null seed context */
|
||||
u8 name[SHA256_DIGEST_SIZE + 2];
|
||||
u32 tmp_null_key;
|
||||
int rc;
|
||||
|
||||
rc = tpm2_load_context(chip, chip->null_key_context, &offset,
|
||||
null_key);
|
||||
if (rc != -EINVAL)
|
||||
return rc;
|
||||
&tmp_null_key);
|
||||
if (rc != -EINVAL) {
|
||||
if (!rc)
|
||||
*null_key = tmp_null_key;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* an integrity failure may mean the TPM has been reset */
|
||||
dev_err(&chip->dev, "NULL key integrity failure!\n");
|
||||
/* check the null name against what we know */
|
||||
tpm2_create_primary(chip, TPM2_RH_NULL, NULL, name);
|
||||
if (memcmp(name, chip->null_key_name, sizeof(name)) == 0)
|
||||
/* name unchanged, assume transient integrity failure */
|
||||
return rc;
|
||||
/*
|
||||
* Fatal TPM failure: the NULL seed has actually changed, so
|
||||
* the TPM must have been illegally reset. All in-kernel TPM
|
||||
* operations will fail because the NULL primary can't be
|
||||
* loaded to salt the sessions, but disable the TPM anyway so
|
||||
* userspace programmes can't be compromised by it.
|
||||
*/
|
||||
dev_err(&chip->dev, "NULL name has changed, disabling TPM due to interference\n");
|
||||
/* Try to re-create null key, given the integrity failure: */
|
||||
rc = tpm2_create_primary(chip, TPM2_RH_NULL, &tmp_null_key, name);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
/* Return null key if the name has not been changed: */
|
||||
if (!memcmp(name, chip->null_key_name, sizeof(name))) {
|
||||
*null_key = tmp_null_key;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Deduce from the name change TPM interference: */
|
||||
dev_err(&chip->dev, "null key integrity check failed\n");
|
||||
tpm2_flush_context(chip, tmp_null_key);
|
||||
chip->flags |= TPM_CHIP_FLAG_DISABLE;
|
||||
|
||||
return rc;
|
||||
err:
|
||||
return rc ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -958,16 +968,20 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
|
||||
*/
|
||||
int tpm2_start_auth_session(struct tpm_chip *chip)
|
||||
{
|
||||
struct tpm2_auth *auth;
|
||||
struct tpm_buf buf;
|
||||
struct tpm2_auth *auth = chip->auth;
|
||||
int rc;
|
||||
u32 null_key;
|
||||
int rc;
|
||||
|
||||
if (!auth) {
|
||||
dev_warn_once(&chip->dev, "auth session is not active\n");
|
||||
if (chip->auth) {
|
||||
dev_warn_once(&chip->dev, "auth session is active\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
auth = kzalloc(sizeof(*auth), GFP_KERNEL);
|
||||
if (!auth)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = tpm2_load_null(chip, &null_key);
|
||||
if (rc)
|
||||
goto out;
|
||||
@ -988,7 +1002,7 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
|
||||
tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
|
||||
|
||||
/* append encrypted salt and squirrel away unencrypted in auth */
|
||||
tpm_buf_append_salt(&buf, chip);
|
||||
tpm_buf_append_salt(&buf, chip, auth);
|
||||
/* session type (HMAC, audit or policy) */
|
||||
tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
|
||||
|
||||
@ -1010,10 +1024,13 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
|
||||
|
||||
tpm_buf_destroy(&buf);
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
if (rc == TPM2_RC_SUCCESS) {
|
||||
chip->auth = auth;
|
||||
return 0;
|
||||
}
|
||||
|
||||
out:
|
||||
out:
|
||||
kfree_sensitive(auth);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(tpm2_start_auth_session);
|
||||
@ -1347,18 +1364,21 @@ static int tpm2_create_null_primary(struct tpm_chip *chip)
|
||||
*
|
||||
* Derive and context save the null primary and allocate memory in the
|
||||
* struct tpm_chip for the authorizations.
|
||||
*
|
||||
* Return:
|
||||
* * 0 - OK
|
||||
* * -errno - A system error
|
||||
* * TPM_RC - A TPM error
|
||||
*/
|
||||
int tpm2_sessions_init(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = tpm2_create_null_primary(chip);
|
||||
if (rc)
|
||||
dev_err(&chip->dev, "TPM: security failed (NULL seed derivation): %d\n", rc);
|
||||
|
||||
chip->auth = kmalloc(sizeof(*chip->auth), GFP_KERNEL);
|
||||
if (!chip->auth)
|
||||
return -ENOMEM;
|
||||
if (rc) {
|
||||
dev_err(&chip->dev, "null key creation failed with %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user