You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(2) |
Dec
(20) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(11) |
Feb
(11) |
Mar
|
Apr
|
May
(3) |
Jun
(19) |
Jul
(5) |
Aug
(13) |
Sep
(18) |
Oct
(8) |
Nov
(25) |
Dec
(3) |
2006 |
Jan
(16) |
Feb
|
Mar
|
Apr
(55) |
May
(23) |
Jun
(5) |
Jul
(19) |
Aug
(12) |
Sep
(12) |
Oct
(24) |
Nov
(3) |
Dec
(7) |
2007 |
Jan
|
Feb
(13) |
Mar
(12) |
Apr
(4) |
May
|
Jun
|
Jul
(6) |
Aug
(12) |
Sep
(3) |
Oct
(1) |
Nov
(16) |
Dec
(2) |
2008 |
Jan
(20) |
Feb
(6) |
Mar
(2) |
Apr
(3) |
May
(29) |
Jun
(11) |
Jul
(16) |
Aug
(7) |
Sep
(2) |
Oct
|
Nov
(9) |
Dec
(24) |
2009 |
Jan
(4) |
Feb
(1) |
Mar
|
Apr
(2) |
May
(5) |
Jun
(13) |
Jul
(25) |
Aug
|
Sep
(47) |
Oct
(5) |
Nov
(13) |
Dec
|
2010 |
Jan
(2) |
Feb
(4) |
Mar
(7) |
Apr
(6) |
May
(2) |
Jun
(14) |
Jul
(10) |
Aug
(6) |
Sep
(12) |
Oct
(6) |
Nov
(16) |
Dec
|
2011 |
Jan
(8) |
Feb
(10) |
Mar
(41) |
Apr
|
May
(5) |
Jun
(1) |
Jul
(1) |
Aug
(6) |
Sep
(8) |
Oct
(11) |
Nov
|
Dec
(15) |
2012 |
Jan
(15) |
Feb
(5) |
Mar
(7) |
Apr
(4) |
May
(19) |
Jun
(27) |
Jul
(20) |
Aug
(40) |
Sep
(19) |
Oct
(45) |
Nov
(102) |
Dec
(26) |
2013 |
Jan
(18) |
Feb
(21) |
Mar
(36) |
Apr
(46) |
May
(46) |
Jun
(10) |
Jul
(20) |
Aug
(8) |
Sep
(53) |
Oct
(109) |
Nov
(58) |
Dec
(37) |
2014 |
Jan
(37) |
Feb
(19) |
Mar
(5) |
Apr
(16) |
May
(23) |
Jun
(3) |
Jul
(30) |
Aug
(40) |
Sep
(110) |
Oct
(207) |
Nov
(84) |
Dec
(147) |
2015 |
Jan
(88) |
Feb
(40) |
Mar
(57) |
Apr
(61) |
May
(48) |
Jun
(65) |
Jul
(23) |
Aug
(15) |
Sep
(43) |
Oct
(130) |
Nov
(210) |
Dec
(177) |
2016 |
Jan
(135) |
Feb
(302) |
Mar
(288) |
Apr
(201) |
May
(65) |
Jun
(166) |
Jul
(193) |
Aug
(139) |
Sep
(211) |
Oct
(281) |
Nov
(259) |
Dec
(86) |
2017 |
Jan
(571) |
Feb
(257) |
Mar
(276) |
Apr
(138) |
May
(257) |
Jun
(145) |
Jul
(68) |
Aug
(176) |
Sep
(152) |
Oct
(72) |
Nov
(18) |
Dec
(9) |
2018 |
Jan
(5) |
Feb
|
Mar
(30) |
Apr
(1) |
May
(18) |
Jun
(2) |
Jul
|
Aug
(43) |
Sep
|
Oct
|
Nov
|
Dec
|
2019 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
(5) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2020 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2021 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
(1) |
Jun
(1) |
Jul
|
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
|
2022 |
Jan
|
Feb
(1) |
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2023 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: David H. <dho...@re...> - 2018-08-21 15:57:32
|
Use struct tpm_chip rather than chip number as interface parameter for most interface functions. This allows the client to be sure about the consistency of what device it uses. Signed-off-by: David Howells <dho...@re...> --- drivers/char/tpm/tpm-interface.c | 76 ++++++++------------------------- drivers/char/tpm/tpm-sysfs.c | 2 - include/linux/tpm.h | 16 ++++--- security/integrity/ima/ima.h | 2 - security/integrity/ima/ima_crypto.c | 4 +- security/integrity/ima/ima_init.c | 19 +++++--- security/integrity/ima/ima_queue.c | 4 +- security/keys/trusted.c | 80 ++++++++++++++++++++++------------- 8 files changed, 96 insertions(+), 107 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index b8f1df5b64fe..29c2ce5cfc69 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -678,25 +678,9 @@ static struct tpm_input_header pcrread_header = { .ordinal = TPM_ORDINAL_PCRREAD }; -int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) -{ - int rc; - struct tpm_cmd_t cmd; - - cmd.header.in = pcrread_header; - cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); - rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, - "attempting to read a pcr value"); - - if (rc == 0) - memcpy(res_buf, cmd.params.pcrread_out.pcr_result, - TPM_DIGEST_SIZE); - return rc; -} - /** * tpm_pcr_read - read a pcr value - * @chip_num: tpm idx # or ANY + * @chip: The chip to pass the request to * @pcr_idx: pcr idx to retrieve * @res_buf: TPM_PCR value * size of res_buf is 20 bytes (or NULL if you don't care) @@ -705,23 +689,26 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) * isn't, protect against the chip disappearing, by incrementing * the module usage count. */ -int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) +int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { - struct tpm_chip *chip; int rc; + struct tpm_cmd_t cmd; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) - return -ENODEV; - rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); - tpm_chip_put(chip); + cmd.header.in = pcrread_header; + cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); + rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, + "attempting to read a pcr value"); + + if (rc == 0) + memcpy(res_buf, cmd.params.pcrread_out.pcr_result, + TPM_DIGEST_SIZE); return rc; } EXPORT_SYMBOL_GPL(tpm_pcr_read); /** * tpm_pcr_extend - extend pcr value with hash - * @chip_num: tpm idx # or AN& + * @chip: The chip to pass the request to * @pcr_idx: pcr idx to extend * @hash: hash value used to extend pcr value * @@ -737,24 +724,15 @@ static struct tpm_input_header pcrextend_header = { .ordinal = TPM_ORD_PCR_EXTEND }; -int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) +int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) { struct tpm_cmd_t cmd; - int rc; - struct tpm_chip *chip; - - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) - return -ENODEV; cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); - rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, - "attempting extend a PCR value"); - - tpm_chip_put(chip); - return rc; + return transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + "attempting extend a PCR value"); } EXPORT_SYMBOL_GPL(tpm_pcr_extend); @@ -821,19 +799,9 @@ int tpm_do_selftest(struct tpm_chip *chip) } EXPORT_SYMBOL_GPL(tpm_do_selftest); -int tpm_send(u32 chip_num, void *cmd, size_t buflen) +int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) { - struct tpm_chip *chip; - int rc; - - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) - return -ENODEV; - - rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); - - tpm_chip_put(chip); - return rc; + return transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); } EXPORT_SYMBOL_GPL(tpm_send); @@ -1010,15 +978,14 @@ static struct tpm_input_header tpm_getrandom_header = { /** * tpm_get_random() - Get random bytes from the tpm's RNG - * @chip_num: A specific chip number for the request or TPM_ANY_NUM + * @chip: The chip to pass the request to * @out: destination buffer for the random bytes * @max: the max number of bytes to write to @out * * Returns < 0 on error and the number of bytes read on success */ -int tpm_get_random(u32 chip_num, u8 *out, size_t max) +int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) { - struct tpm_chip *chip; struct tpm_cmd_t tpm_cmd; u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA); int err, total = 0, retries = 5; @@ -1027,10 +994,6 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) return -EINVAL; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) - return -ENODEV; - do { tpm_cmd.header.in = tpm_getrandom_header; tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); @@ -1049,7 +1012,6 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) num_bytes -= recd; } while (retries-- && total < max); - tpm_chip_put(chip); return total ? total : -EIO; } EXPORT_SYMBOL_GPL(tpm_get_random); diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 01730a27ae07..507d8ab37ef1 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -120,7 +120,7 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, num_pcrs = be32_to_cpu(cap.num_pcrs); for (i = 0; i < num_pcrs; i++) { - rc = tpm_pcr_read_dev(chip, i, digest); + rc = tpm_pcr_read(chip, i, digest); if (rc) break; str += sprintf(str, "PCR-%02d: ", i); diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 44c8cad7132d..c213e09b7d81 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -49,10 +49,10 @@ struct tpm_class_ops { extern struct tpm_chip *tpm_chip_find_get(int chip_num); extern void tpm_chip_put(struct tpm_chip *chip); -extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); -extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); -extern int tpm_send(u32 chip_num, void *cmd, size_t buflen); -extern int tpm_get_random(u32 chip_num, u8 *data, size_t max); +extern int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); +extern int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); +extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen); +extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max); #else static inline struct tpm_chip *tpm_chip_find_get(int chip_num) { @@ -61,16 +61,16 @@ static inline struct tpm_chip *tpm_chip_find_get(int chip_num) static inline void tpm_chip_put(struct tpm_chip *chip) { } -static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { +static inline int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { return -ENODEV; } -static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) { +static inline int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) { return -ENODEV; } -static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) { +static inline int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) { return -ENODEV; } -static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) { +static inline int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max) { return -ENODEV; } #endif diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 8e4bb883fc13..8f932e53a449 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -44,8 +44,8 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; #define IMA_TEMPLATE_IMA_FMT "d|n" /* set during initialization */ +extern struct tpm_chip *ima_tpm; extern int ima_initialized; -extern int ima_used_chip; extern int ima_hash_algo; extern int ima_appraise; diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index d34e7dfc1118..c4631e5bac5a 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -556,10 +556,10 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data, static void __init ima_pcrread(int idx, u8 *pcr) { - if (!ima_used_chip) + if (!ima_tpm) return; - if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) + if (tpm_pcr_read(ima_tpm, idx, pcr) != 0) pr_err("Error Communicating to TPM chip\n"); } diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index e8f9d70a465d..bcad4da9e663 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -26,7 +26,7 @@ /* name for boot aggregate entry */ static const char *boot_aggregate_name = "boot_aggregate"; -int ima_used_chip; +struct tpm_chip *ima_tpm; /* Add the boot aggregate to the IMA measurement list and extend * the PCR register. @@ -62,7 +62,7 @@ static void __init ima_add_boot_aggregate(void) iint->ima_hash->algo = HASH_ALGO_SHA1; iint->ima_hash->length = SHA1_DIGEST_SIZE; - if (ima_used_chip) { + if (ima_tpm) { result = ima_calc_boot_aggregate(&hash.hdr); if (result < 0) { audit_cause = "hashing_error"; @@ -90,12 +90,17 @@ int __init ima_init(void) u8 pcr_i[TPM_DIGEST_SIZE]; int rc; - ima_used_chip = 0; - rc = tpm_pcr_read(TPM_ANY_NUM, 0, pcr_i); - if (rc == 0) - ima_used_chip = 1; + ima_tpm = tpm_chip_find_get(TPM_ANY_NUM); - if (!ima_used_chip) + if (ima_tpm) { + rc = tpm_pcr_read(ima_tpm, 0, pcr_i); + if (rc != 0) { + tpm_chip_put(ima_tpm); + ima_tpm = NULL; + } + } + + if (!ima_tpm) pr_info("No TPM chip found, activating TPM-bypass!\n"); rc = ima_init_crypto(); diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 552705d5a78d..83629075375c 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -93,10 +93,10 @@ static int ima_pcr_extend(const u8 *hash) { int result = 0; - if (!ima_used_chip) + if (!ima_tpm) return result; - result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); + result = tpm_pcr_extend(ima_tpm, CONFIG_IMA_MEASURE_PCR_IDX, hash); if (result != 0) pr_err("Error Communicating to TPM chip, result: %d\n", result); return result; diff --git a/security/keys/trusted.c b/security/keys/trusted.c index c0594cb07ada..adb0caa5c38d 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -354,13 +354,13 @@ out: * For key specific tpm requests, we will generate and send our * own TPM command packets using the drivers send function. */ -static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd, +static int trusted_tpm_send(struct tpm_chip *chip, unsigned char *cmd, size_t buflen) { int rc; dump_tpm_buf(cmd); - rc = tpm_send(chip_num, cmd, buflen); + rc = tpm_send(chip, cmd, buflen); dump_tpm_buf(cmd); if (rc > 0) /* Can't return positive return codes values to keyctl */ @@ -374,30 +374,31 @@ static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd, * Prevents a trusted key that is sealed to PCRs from being accessed. * This uses the tpm driver's extend function. */ -static int pcrlock(const int pcrnum) +static int pcrlock(struct tpm_chip *chip, const int pcrnum) { unsigned char hash[SHA1_DIGEST_SIZE]; int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - ret = tpm_get_random(TPM_ANY_NUM, hash, SHA1_DIGEST_SIZE); + ret = tpm_get_random(chip, hash, SHA1_DIGEST_SIZE); if (ret != SHA1_DIGEST_SIZE) return ret; - return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0; + return tpm_pcr_extend(chip, pcrnum, hash) ? -EINVAL : 0; } /* * Create an object specific authorisation protocol (OSAP) session */ -static int osap(struct tpm_buf *tb, struct osapsess *s, +static int osap(struct tpm_chip *chip, + struct tpm_buf *tb, struct osapsess *s, const unsigned char *key, uint16_t type, uint32_t handle) { unsigned char enonce[TPM_NONCE_SIZE]; unsigned char ononce[TPM_NONCE_SIZE]; int ret; - ret = tpm_get_random(TPM_ANY_NUM, ononce, TPM_NONCE_SIZE); + ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE); if (ret != TPM_NONCE_SIZE) return ret; @@ -409,7 +410,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, store32(tb, handle); storebytes(tb, ononce, TPM_NONCE_SIZE); - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); if (ret < 0) return ret; @@ -425,7 +426,8 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, /* * Create an object independent authorisation protocol (oiap) session */ -static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) +static int oiap(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t *handle, + unsigned char *nonce) { int ret; @@ -433,7 +435,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) store16(tb, TPM_TAG_RQU_COMMAND); store32(tb, TPM_OIAP_SIZE); store32(tb, TPM_ORD_OIAP); - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); if (ret < 0) return ret; @@ -455,7 +457,8 @@ struct tpm_digests { * Have the TPM seal(encrypt) the trusted key, possibly based on * Platform Configuration Registers (PCRs). AUTH1 for sealing key. */ -static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, +static int tpm_seal(struct tpm_chip *chip, + struct tpm_buf *tb, uint16_t keytype, uint32_t keyhandle, const unsigned char *keyauth, const unsigned char *data, uint32_t datalen, unsigned char *blob, uint32_t *bloblen, @@ -480,7 +483,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, return -ENOMEM; /* get session for sealing key */ - ret = osap(tb, &sess, keyauth, keytype, keyhandle); + ret = osap(chip, tb, &sess, keyauth, keytype, keyhandle); if (ret < 0) goto out; dump_sess(&sess); @@ -492,7 +495,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, if (ret < 0) goto out; - ret = tpm_get_random(TPM_ANY_NUM, td->nonceodd, TPM_NONCE_SIZE); + ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE); if (ret != TPM_NONCE_SIZE) goto out; ordinal = htonl(TPM_ORD_SEAL); @@ -541,7 +544,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, store8(tb, cont); storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); if (ret < 0) goto out; @@ -570,7 +573,7 @@ out: /* * use the AUTH2_COMMAND form of unseal, to authorize both key and blob */ -static int tpm_unseal(struct tpm_buf *tb, +static int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t keyhandle, const unsigned char *keyauth, const unsigned char *blob, int bloblen, const unsigned char *blobauth, @@ -589,12 +592,12 @@ static int tpm_unseal(struct tpm_buf *tb, int ret; /* sessions for unsealing key and data */ - ret = oiap(tb, &authhandle1, enonce1); + ret = oiap(chip, tb, &authhandle1, enonce1); if (ret < 0) { pr_info("trusted_key: oiap failed (%d)\n", ret); return ret; } - ret = oiap(tb, &authhandle2, enonce2); + ret = oiap(chip, tb, &authhandle2, enonce2); if (ret < 0) { pr_info("trusted_key: oiap failed (%d)\n", ret); return ret; @@ -602,7 +605,7 @@ static int tpm_unseal(struct tpm_buf *tb, ordinal = htonl(TPM_ORD_UNSEAL); keyhndl = htonl(SRKHANDLE); - ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE); + ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE); if (ret != TPM_NONCE_SIZE) { pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); return ret; @@ -634,7 +637,7 @@ static int tpm_unseal(struct tpm_buf *tb, store8(tb, cont); storebytes(tb, authdata2, SHA1_DIGEST_SIZE); - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); if (ret < 0) { pr_info("trusted_key: authhmac failed (%d)\n", ret); return ret; @@ -658,7 +661,8 @@ static int tpm_unseal(struct tpm_buf *tb, /* * Have the TPM seal(encrypt) the symmetric key */ -static int key_seal(struct trusted_key_payload *p, +static int key_seal(struct tpm_chip *chip, + struct trusted_key_payload *p, struct trusted_key_options *o) { struct tpm_buf *tb; @@ -671,7 +675,7 @@ static int key_seal(struct trusted_key_payload *p, /* include migratable flag at end of sealed key */ p->key[p->key_len] = p->migratable; - ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth, + ret = tpm_seal(chip, tb, o->keytype, o->keyhandle, o->keyauth, p->key, p->key_len + 1, p->blob, &p->blob_len, o->blobauth, o->pcrinfo, o->pcrinfo_len); if (ret < 0) @@ -684,7 +688,8 @@ static int key_seal(struct trusted_key_payload *p, /* * Have the TPM unseal(decrypt) the symmetric key */ -static int key_unseal(struct trusted_key_payload *p, +static int key_unseal(struct tpm_chip *chip, + struct trusted_key_payload *p, struct trusted_key_options *o) { struct tpm_buf *tb; @@ -694,7 +699,8 @@ static int key_unseal(struct trusted_key_payload *p, if (!tb) return -ENOMEM; - ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len, + ret = tpm_unseal(chip, tb, o->keyhandle, o->keyauth, + p->blob, p->blob_len, o->blobauth, p->key, &p->key_len); if (ret < 0) pr_info("trusted_key: srkunseal failed (%d)\n", ret); @@ -900,6 +906,7 @@ static int trusted_instantiate(struct key *key, { struct trusted_key_payload *payload = NULL; struct trusted_key_options *options = NULL; + struct tpm_chip *chip = NULL; size_t datalen = prep->datalen; char *datablob; int ret = 0; @@ -935,9 +942,14 @@ static int trusted_instantiate(struct key *key, dump_payload(payload); dump_options(options); + ret = -ENODEV; + chip = tpm_chip_find_get(TPM_ANY_NUM); + if (!chip) + goto out; + switch (key_cmd) { case Opt_load: - ret = key_unseal(payload, options); + ret = key_unseal(chip, payload, options); dump_payload(payload); dump_options(options); if (ret < 0) @@ -945,12 +957,12 @@ static int trusted_instantiate(struct key *key, break; case Opt_new: key_len = payload->key_len; - ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len); + ret = tpm_get_random(chip, payload->key, key_len); if (ret != key_len) { pr_info("trusted_key: key_create failed (%d)\n", ret); goto out; } - ret = key_seal(payload, options); + ret = key_seal(chip, payload, options); if (ret < 0) pr_info("trusted_key: key_seal failed (%d)\n", ret); break; @@ -958,9 +970,11 @@ static int trusted_instantiate(struct key *key, ret = -EINVAL; goto out; } + if (!ret && options->pcrlock) - ret = pcrlock(options->pcrlock); + ret = pcrlock(chip, options->pcrlock); out: + tpm_chip_put(chip); kfree(datablob); kfree(options); if (!ret) @@ -987,6 +1001,7 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) struct trusted_key_payload *p = key->payload.data; struct trusted_key_payload *new_p; struct trusted_key_options *new_o; + struct tpm_chip *chip = NULL; size_t datalen = prep->datalen; char *datablob; int ret = 0; @@ -1018,6 +1033,7 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) kfree(new_p); goto out; } + /* copy old key values, and reseal with new pcrs */ new_p->migratable = p->migratable; new_p->key_len = p->key_len; @@ -1025,14 +1041,19 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) dump_payload(p); dump_payload(new_p); - ret = key_seal(new_p, new_o); + ret = -ENODEV; + chip = tpm_chip_find_get(TPM_ANY_NUM); + if (!chip) + goto out; + + ret = key_seal(chip, new_p, new_o); if (ret < 0) { pr_info("trusted_key: key_seal failed (%d)\n", ret); kfree(new_p); goto out; } if (new_o->pcrlock) { - ret = pcrlock(new_o->pcrlock); + ret = pcrlock(chip, new_o->pcrlock); if (ret < 0) { pr_info("trusted_key: pcrlock failed (%d)\n", ret); kfree(new_p); @@ -1042,6 +1063,7 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) rcu_assign_keypointer(key, new_p); call_rcu(&p->rcu, trusted_rcu_free); out: + tpm_chip_put(chip); kfree(datablob); kfree(new_o); return ret; |
From: David H. <dho...@re...> - 2018-08-21 15:57:25
|
Expose struct tpm_chip and related find_get and put functions so that TPM-using code can make sure it uses the same TPM for any related set of operations. Signed-off-by: David Howells <dho...@re...> --- drivers/char/tpm/tpm-interface.c | 19 ++++++++++++++++--- drivers/char/tpm/tpm.h | 5 ----- include/linux/tpm.h | 10 ++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index cfb9089887bd..b8f1df5b64fe 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -636,10 +636,11 @@ static int tpm_continue_selftest(struct tpm_chip *chip) return rc; } -/* - * tpm_chip_find_get - return tpm_chip for given chip number +/** + * tpm_chip_find_get - Look up a TPM chip by device index + * @chip_num: The index number of the chip to use or TPM_ANY_NUM */ -static struct tpm_chip *tpm_chip_find_get(int chip_num) +struct tpm_chip *tpm_chip_find_get(int chip_num) { struct tpm_chip *pos, *chip = NULL; @@ -656,6 +657,18 @@ static struct tpm_chip *tpm_chip_find_get(int chip_num) rcu_read_unlock(); return chip; } +EXPORT_SYMBOL_GPL(tpm_chip_find_get); + +/** + * tpm_chip_put - Release a previously looked up TPM chip + * @chip: The chip to release + */ +void tpm_chip_put(struct tpm_chip *chip) +{ + if (chip) + module_put(chip->dev->driver->owner); +} +EXPORT_SYMBOL_GPL(tpm_chip_put); #define TPM_ORDINAL_PCRREAD cpu_to_be32(21) #define READ_PCR_RESULT_SIZE 30 diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index e4d0888d2eab..df6ffceb3429 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -115,11 +115,6 @@ struct tpm_chip { #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor) -static inline void tpm_chip_put(struct tpm_chip *chip) -{ - module_put(chip->dev->driver->owner); -} - static inline int tpm_read_index(int base, int index) { outb(index, base); diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 8350c538b486..44c8cad7132d 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -46,11 +46,21 @@ struct tpm_class_ops { #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) +extern struct tpm_chip *tpm_chip_find_get(int chip_num); +extern void tpm_chip_put(struct tpm_chip *chip); + extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); extern int tpm_send(u32 chip_num, void *cmd, size_t buflen); extern int tpm_get_random(u32 chip_num, u8 *data, size_t max); #else +static inline struct tpm_chip *tpm_chip_find_get(int chip_num) +{ + return NULL; +} +static inline void tpm_chip_put(struct tpm_chip *chip) +{ +} static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { return -ENODEV; } |
From: David H. <dho...@re...> - 2018-08-21 15:57:18
|
Provide a platform driver for the user emulator driver. This seems to be necessary to stop tpm_chip_find_get() from blowing up because it assumes unconditionally that any device will have a driver attached: if (try_module_get(pos->dev->driver->owner)) { However, this doesn't then work right because if I remove the TPM device and re-add it, the tpm ID isn't recycled (ie, /dev/tpm0 becomes unavailable and the new TPM is /dev/tpm1). Signed-off-by: David Howells <dho...@re...> --- drivers/char/tpm/tpm_user_emul.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_user_emul.c b/drivers/char/tpm/tpm_user_emul.c index b96350592bca..e5b13358c71e 100644 --- a/drivers/char/tpm/tpm_user_emul.c +++ b/drivers/char/tpm/tpm_user_emul.c @@ -656,17 +656,39 @@ static struct miscdevice tpm_user_dev = { .fops = &tpm_user_fops, }; +static struct platform_driver tpm_user_drv = { + .driver = { + .name = "tpm_user", + .owner = THIS_MODULE, + /* .pm = &tpm_user_pm, -- do we need pm since there's no h/w? */ + }, +}; + /* * Initialise a device */ static __init int tpm_user_mod_init(void) { - return misc_register(&tpm_user_dev); + int ret; + + ret = platform_driver_register(&tpm_user_drv); + if (ret < 0) + return ret; + + ret = misc_register(&tpm_user_dev); + if (ret < 0) + goto error_dev; + return 0; + +error_dev: + platform_driver_unregister(&tpm_user_drv); + return ret; } device_initcall(tpm_user_mod_init); static __exit void tpm_user_mod_exit(void) { misc_deregister(&tpm_user_dev); + platform_driver_unregister(&tpm_user_drv); } module_exit(tpm_user_mod_exit); |
From: David H. <dho...@re...> - 2018-08-21 15:57:12
|
Provide a misc device file (/dev/tpm_emul) by which a userspace TPM emulator can set up a virtual TPM device under the control of the TPM frontend. The way this works is: (1) The emulator opens /dev/tpm_emul which is provided by the tpm_user driver. (2) tpm_user registers a TPM device and the tpm driver creates a /dev/tpmN misc device for the trousers package and suchlike to access. (3) The emulator sits in read() on the emulator device waiting for a command to come through. (4) tpm_user passes requests from /dev/tpmN to the emulator's read() call. (5) The emulator processes the request. (6) The emulator either write()'s the reply or calls ioctl(fd,0,0) to cancel the command. (7) The emulator goes back to read() to wait for the next command. (8) tpm_user passes the reply back to the tpm driver which passes it back to /dev/tpmN. When the emulator closes /dev/tpm_emul, the TPM driver is unregistered and the /dev/tpmN misc device is then removed. Any outstanding requests are aborted and -EIO will be returned from then on. Multiple TPMs can be registered. Signed-off-by: David Howells <dho...@re...> --- drivers/char/tpm/Kconfig | 13 + drivers/char/tpm/Makefile | 1 drivers/char/tpm/tpm_user_emul.c | 672 ++++++++++++++++++++++++++++++++++++++ include/linux/wait.h | 11 + 4 files changed, 697 insertions(+) create mode 100644 drivers/char/tpm/tpm_user_emul.c diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index c54cac3f8bc8..c33ebd8504ec 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -122,4 +122,17 @@ config TCG_XEN To compile this driver as a module, choose M here; the module will be called xen-tpmfront. +config TCG_USER_EMUL + tristate "Userspace TPM emulation interface for development purposes" + depends on DEBUG_KERNEL + ---help--- + Provide a userspace TPM emulation interface through a misc device + interface (/dev/tpm_emul). This can be used to enable development of + TPM-based services by providing a target TPM that can be safely + trashed or for computers that don't have a physical TPM. + + This driver should _NOT_ be included in production kernels as it + might be possible to use it to fool various kernel security features + (such as IMA). + endif # TCG_TPM diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 4d85dd681b81..b179052cd81b 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o +obj-$(CONFIG_TCG_USER_EMUL) += tpm_user_emul.o diff --git a/drivers/char/tpm/tpm_user_emul.c b/drivers/char/tpm/tpm_user_emul.c new file mode 100644 index 000000000000..b96350592bca --- /dev/null +++ b/drivers/char/tpm/tpm_user_emul.c @@ -0,0 +1,672 @@ +/* TPM userspace emulation driver + * + * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dho...@re...) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#define pr_fmt(fmt) "TPM_USER: "fmt +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/miscdevice.h> +#include <linux/workqueue.h> +#include <linux/completion.h> +#include "tpm.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Howells <dho...@re...>"); + +#define TIS_SHORT_TIMEOUT 750 /* ms */ +#define TIS_LONG_TIMEOUT 2000 /* 2 sec */ + +#define kenter(FMT, ...) \ + pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) +#define kleave(FMT, ...) \ + pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) + +/* + * Packet of data going to/from the TPM. We only permit one command + * at a time, so we don't need to deal with chains of packets. + */ +struct tpm_user_packet { + unsigned size; + unsigned cancellation; + u8 buffer[]; +}; + +/* + * Emulator state. + */ +enum tpm_user_status { + TPM_USER_INITIALISING, + TPM_USER_IDLE, + TPM_USER_SENDING, + TPM_USER_AWAITING_REPLY, + TPM_USER_CANCELLING, + TPM_USER_GOT_REPLY, + TPM_USER_CANCELLED, + TPM_USER_EIO, +}; + +struct tpm_user_state { + struct work_struct initialiser_work; + struct completion initialiser_done; + struct file *file; + struct platform_device *pdev; + struct tpm_chip *chip; + wait_queue_head_t wq; + struct tpm_user_packet *to_emulator_q; + struct tpm_user_packet *from_emulator_q; + spinlock_t lock; + enum tpm_user_status status; + int initialiser_error; +}; + +/* + * Read the emulator status. + */ +static u8 tpm_user_status(struct tpm_chip *chip) +{ + struct tpm_user_state *state = chip->vendor.priv; + enum tpm_user_status status = ACCESS_ONCE(state->status); + + if (status == TPM_USER_GOT_REPLY) + return 1; + if (status == TPM_USER_CANCELLED || + status == TPM_USER_EIO) + return 2; + return 0; +} + +/* + * Find out if a request has been cancelled. + */ +static bool tpm_user_is_req_cancelled(struct tpm_chip *chip, u8 status) +{ + struct tpm_user_state *state = chip->vendor.priv; + struct tpm_user_packet *pkt = NULL; + + if (status != 2) + return false; + + spin_lock(&state->lock); + if (state->status == TPM_USER_CANCELLED) { + pkt = state->from_emulator_q; + state->from_emulator_q = NULL; + state->status = TPM_USER_IDLE; + } + spin_unlock(&state->lock); + kfree(pkt); + return true; +} + +/* + * Send data to the emulator. + */ +static int tpm_user_send(struct tpm_chip *chip, u8 *buf, size_t len) +{ + struct tpm_user_state *state = chip->vendor.priv; + struct tpm_user_packet *pkt; + int ret; + + kenter(",%*phN,%zu", min_t(int, len, 16), buf, len); + + pkt = kmalloc(sizeof(struct tpm_user_packet) + len, GFP_KERNEL); + if (!pkt) + return -ENOMEM; + pkt->size = len; + memcpy(pkt->buffer, buf, len); + + spin_lock(&state->lock); + switch (state->status) { + case TPM_USER_IDLE: + state->to_emulator_q = pkt; + state->status = TPM_USER_SENDING; + ret = 0; + break; + default: + dev_err(chip->dev, "Sending in state %u\n", state->status); + case TPM_USER_EIO: + kfree(pkt); + ret = -EIO; + break; + } + spin_unlock(&state->lock); + if (ret == 0) + wake_up(&state->wq); + return ret; +} + +/* + * Allow the TPM emulator to read requests from the driver + */ +static ssize_t tpm_user_read(struct file *file, char __user *buffer, + size_t buflen, loff_t *pos) +{ + struct tpm_user_state *state = file->private_data; + struct tpm_user_packet *pkt; + unsigned long copied; + ssize_t ret; + + kenter("{%u},,%zu,", state->status, buflen); + +again: + mutex_lock(&file_inode(file)->i_mutex); + + ret = -EAGAIN; + spin_lock(&state->lock); + if (state->status == TPM_USER_EIO) { + ret = -EIO; + goto out; + } + + if (state->status != TPM_USER_SENDING) { + if (file->f_flags & O_NONBLOCK) + goto out; + pr_devel("sleeping\n"); + wait_event_cmd_interruptible( + state->wq, + state->status == TPM_USER_SENDING || + state->status == TPM_USER_EIO, + spin_unlock(&state->lock), + spin_lock(&state->lock)); + pr_devel("woken\n"); + + ret = -ERESTARTSYS; + if (signal_pending(current)) + goto out; + ret = -EIO; + if (state->status == TPM_USER_EIO) + goto out; + } + + pkt = state->to_emulator_q; + pr_devel("dequeued send(%u)\n", pkt->size); + ret = -EMSGSIZE; + if (pkt->size > buflen) + goto out; + + /* Claim responsibility for the packet. */ + state->status = TPM_USER_AWAITING_REPLY; + state->to_emulator_q = NULL; + spin_unlock(&state->lock); + + copied = copy_to_user(buffer, pkt->buffer, pkt->size); + spin_lock(&state->lock); + + if (copied != 0) { + /* Ugh - the emulator went splat. Discard the request and + * reject all further requests. */ + kfree(pkt); + dev_err(state->chip->dev, "Emulator EFAULT in read\n"); + state->status = TPM_USER_EIO; + ret = -EFAULT; + } else if (state->status == TPM_USER_CANCELLING) { + pr_devel("cancel\n"); + state->status = TPM_USER_CANCELLED; + ret = -ECANCELED; + } else { + ret = pkt->size; + } + +out: + spin_unlock(&state->lock); + mutex_unlock(&file_inode(file)->i_mutex); + if (ret == -ECANCELED) + goto again; + kleave(" = %zd", ret); + return ret; +} + +/* + * Allow the TPM emulator to respond to requests + * + * The buffer is should contain a packet with at least TPM_HEADER_SIZE bytes of + * data in it. + */ +static ssize_t tpm_user_write(struct file *file, + const char __user *data, + size_t datalen, + loff_t *pos) +{ + struct tpm_user_state *state = file->private_data; + struct tpm_user_packet *pkt; + unsigned expected; + __be32 tmpbe; + ssize_t ret; + + kenter("{%u},,%zu,", state->status, datalen); + + /* Sanity checking the reply before we get any locks. */ + if (datalen == 0) { + dev_err(state->chip->dev, "Empty reply\n"); + return -EMSGSIZE; + } + + if (datalen < TPM_HEADER_SIZE) { + dev_err(state->chip->dev, "Data packet missing TPM header\n"); + return -EMSGSIZE; + } + + pkt = kmalloc(sizeof(struct tpm_user_packet) + datalen, GFP_KERNEL); + if (!pkt) + return -ENOMEM; + pkt->size = datalen; + ret = -EFAULT; + if (copy_from_user(pkt->buffer, data, datalen) != 0) + goto err_free; + + pr_debug("got reply %*phN\n", min_t(int, datalen, 16), pkt->buffer); + + memcpy(&tmpbe, pkt->buffer + 2, sizeof(tmpbe)); + expected = be32_to_cpu(tmpbe); + if (expected != datalen) { + dev_err(state->chip->dev, "Data packet size (%zu) != expected (%x)\n", + datalen, expected); + ret = -EMSGSIZE; + goto err_free; + } + + mutex_lock(&file_inode(file)->i_mutex); + spin_lock(&state->lock); + + switch (state->status) { + case TPM_USER_AWAITING_REPLY: + BUG_ON(state->from_emulator_q != NULL); + state->from_emulator_q = pkt; + state->status = TPM_USER_GOT_REPLY; + pkt = NULL; + ret = datalen; + break; + + case TPM_USER_CANCELLING: + state->status = TPM_USER_CANCELLED; + ret = -ECANCELED; + break; + + case TPM_USER_EIO: + ret = -EIO; + break; + + default: + dev_err(state->chip->dev, "Reply unexpected in state (%u)\n", + state->status); + ret = -EPROTO; + break; + } + + spin_unlock(&state->lock); + mutex_unlock(&file_inode(file)->i_mutex); + if (ret != -EPROTO) + wake_up(&state->wq); +err_free: + kfree(pkt); + kleave(" = %zd", ret); + return ret; +} + +/* + * Allow the TPM emulator to cancel a request with ioctl(fd,0,0). + */ +static long tpm_user_ioctl(struct file *file, unsigned cmd, unsigned long data) +{ + struct tpm_user_state *state = file->private_data; + long ret; + + kenter("{%u},%x,%lx", state->status, cmd, data); + + if (cmd != 0 && data != 0) + return -ENOIOCTLCMD; + + mutex_lock(&file_inode(file)->i_mutex); + spin_lock(&state->lock); + + switch (state->status) { + case TPM_USER_AWAITING_REPLY: + case TPM_USER_CANCELLING: + state->status = TPM_USER_CANCELLED; + ret = 0; + break; + + case TPM_USER_EIO: + ret = -EIO; + break; + + default: + dev_err(state->chip->dev, + "Cancellation unexpected in state (%u)\n", + state->status); + ret = -EPROTO; + break; + } + + spin_unlock(&state->lock); + mutex_unlock(&file_inode(file)->i_mutex); + wake_up(&state->wq); + kleave(" = %ld", ret); + return ret; +} + +/* + * Receive data from the emulator. + */ +static int tpm_user_recv(struct tpm_chip *chip, u8 *buf, size_t count) +{ + struct tpm_user_state *state = chip->vendor.priv; + struct tpm_user_packet *pkt; + int ret; + + kenter("{%u},,%zu", state->status, count); + + spin_lock(&state->lock); + + pkt = state->from_emulator_q; + state->from_emulator_q = NULL; + switch (state->status) { + case TPM_USER_GOT_REPLY: + state->status = TPM_USER_IDLE; + BUG_ON(!pkt); + ret = pkt->size; + break; + + case TPM_USER_CANCELLED: + state->status = TPM_USER_IDLE; + ret = -ECANCELED; + break; + + case TPM_USER_EIO: + ret = -EIO; + break; + + default: + dev_err(chip->dev, "TPM data recv in unexpected state (%u)\n", + state->status); + ret = -EIO; + break; + } + + spin_unlock(&state->lock); + + if (pkt) { + if (ret > 0) { + if (pkt->size > count) { + dev_err(chip->dev, "Received excess data\n"); + ret = -EIO; + } else { + memcpy(buf, pkt->buffer, pkt->size); + } + } + kfree(pkt); + } + + kleave(" = %d", ret); + return ret; +} + +/* + * Abort the current request. + */ +static void tpm_user_cancel(struct tpm_chip *chip) +{ + struct tpm_user_state *state = chip->vendor.priv; + + kenter("{%u}", state->status); + + spin_lock(&state->lock); + + switch (state->status) { + case TPM_USER_SENDING: + case TPM_USER_AWAITING_REPLY: + case TPM_USER_GOT_REPLY: + kfree(state->to_emulator_q); + state->to_emulator_q = NULL; + kfree(state->from_emulator_q); + state->from_emulator_q = NULL; + state->status = TPM_USER_CANCELLING; + break; + default: + break; + } + + if (state->status == TPM_USER_CANCELLING) { + DECLARE_WAITQUEUE(waiter, current); + + for (;;) { + prepare_to_wait(&state->wq, + &waiter, TASK_UNINTERRUPTIBLE); + if (state->status == TPM_USER_CANCELLED || + state->status == TPM_USER_EIO) + break; + spin_unlock(&state->lock); + schedule_timeout(10 * HZ); + spin_lock(&state->lock); + } + finish_wait(&state->wq, &waiter); + + if (state->status != TPM_USER_CANCELLED) + state->status = TPM_USER_EIO; + else + state->status = TPM_USER_IDLE; + } + + spin_unlock(&state->lock); +} + +/* + * Allow the TPM emulator to wait for a request + */ +static unsigned int tpm_user_poll(struct file *file, + struct poll_table_struct *poll) +{ + struct tpm_user_state *state = file->private_data; + enum tpm_user_status status = ACCESS_ONCE(state->status); + unsigned mask; + + poll_wait(file, &state->wq, poll); + mask = 0; + + switch (status) { + case TPM_USER_SENDING: + return POLLIN; + case TPM_USER_AWAITING_REPLY: + return POLLOUT; + case TPM_USER_CANCELLING: + return POLLPRI; + case TPM_USER_EIO: + return POLLERR; + default: + return 0; + } +} + +static const struct tpm_class_ops tpm_user_class = { + .status = tpm_user_status, + .recv = tpm_user_recv, + .send = tpm_user_send, + .cancel = tpm_user_cancel, + .req_complete_mask = 1, + .req_complete_val = 1, + .req_canceled = tpm_user_is_req_cancelled, +}; + +/* + * Asynchronous initialiser. We have to do it this way because we get timeouts + * and run a selftest on the TPM - which means doing reads and writes on the + * file. + */ +static void tpm_user_initialiser(struct work_struct *work) +{ + struct tpm_user_state *state = + container_of(work, struct tpm_user_state, initialiser_work); + struct platform_device *pdev; + struct tpm_chip *chip; + int ret = -ENODEV; + + kenter(""); + + pdev = platform_device_register_simple("tpm_user", -1, NULL, 0); + if (IS_ERR(pdev)) { + ret = PTR_ERR(pdev); + goto err_dev; + } + state->pdev = pdev; + + pr_devel("Registering TPM\n"); + + ret = -ENODEV; + chip = tpm_register_hardware(&pdev->dev, &tpm_user_class); + if (!chip) + goto err_reg; + + chip->vendor.priv = state; + init_waitqueue_head(&chip->vendor.read_queue); + init_waitqueue_head(&chip->vendor.int_queue); + INIT_LIST_HEAD(&chip->vendor.list); + state->chip = chip; + + /* Default timeouts */ + chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); + chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + + /* We will need to operate the communication channel */ + spin_lock(&state->lock); + ret = -EIO; + if (state->status == TPM_USER_EIO) + goto err_tpm_locked; + state->status = TPM_USER_IDLE; + spin_unlock(&state->lock); + + /* Not all variants of the emulator support getting the timeout */ + pr_devel("Getting timeouts\n"); + if (tpm_get_timeouts(chip)) + dev_err(&pdev->dev, "Could not get TPM timeouts and durations\n"); + + pr_devel("Performing selftest\n"); + ret = tpm_do_selftest(chip); + if (ret < 0) { + dev_err(&pdev->dev, "TPM self test failed\n"); + goto err_tpm; + } + + ret = 0; +out: + state->initialiser_error = ret; + kleave(" = %d", ret); + complete(&state->initialiser_done); + return; + +err_tpm: + spin_lock(&state->lock); + if (state->status != TPM_USER_EIO) + state->status = TPM_USER_EIO; +err_tpm_locked: + spin_unlock(&state->lock); + wake_up(&state->wq); + tpm_remove_hardware(chip->dev); +err_reg: + platform_device_unregister(pdev); +err_dev: + goto out; +} + +/* + * Allow the TPM emulator to create a virtual TPM. + */ +static int tpm_user_open(struct inode *inode, struct file *file) +{ + struct tpm_user_state *state; + + kenter(""); + + state = kzalloc(sizeof(struct tpm_user_state), GFP_KERNEL); + if (!state) + return -ENOMEM; + state->file = file; + state->status = TPM_USER_INITIALISING; + spin_lock_init(&state->lock); + INIT_WORK(&state->initialiser_work, tpm_user_initialiser); + init_completion(&state->initialiser_done); + init_waitqueue_head(&state->wq); + + file->private_data = state; + + /* The TPM registration must be done in another thread because the the + * process will involve self-testing the TPM and will thus need to + * communicate through this file. + */ + schedule_work(&state->initialiser_work); + kleave(" = 0"); + return 0; +} + +/* + * Release and clean up a virtual TPM. + */ +static int tpm_user_release(struct inode *inode, struct file *file) +{ + struct tpm_user_state *state = file->private_data; + int ret; + + kenter(""); + + pr_devel("forcing EIO state\n"); + spin_lock(&state->lock); + state->status = TPM_USER_EIO; + spin_unlock(&state->lock); + wake_up(&state->wq); + + wait_for_completion(&state->initialiser_done); + + ret = state->initialiser_error; + if (ret == 0) { + pr_devel("removing bits\n"); + tpm_remove_hardware(state->chip->dev); + platform_device_unregister(state->pdev); + } + kfree(state->to_emulator_q); + kfree(state->from_emulator_q); + kfree(state); + kleave(" = %d", ret); + return ret; +} + +static const struct file_operations tpm_user_fops = { + .owner = THIS_MODULE, + .open = tpm_user_open, + .release = tpm_user_release, + .read = tpm_user_read, + .write = tpm_user_write, + .unlocked_ioctl = tpm_user_ioctl, + .poll = tpm_user_poll, + .llseek = noop_llseek, +}; + +static struct miscdevice tpm_user_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "tpm_emul", + .fops = &tpm_user_fops, +}; + +/* + * Initialise a device + */ +static __init int tpm_user_mod_init(void) +{ + return misc_register(&tpm_user_dev); +} +device_initcall(tpm_user_mod_init); + +static __exit void tpm_user_mod_exit(void) +{ + misc_deregister(&tpm_user_dev); +} +module_exit(tpm_user_mod_exit); diff --git a/include/linux/wait.h b/include/linux/wait.h index bd68819f0815..8b443229997e 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -294,6 +294,10 @@ do { \ (void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0, \ cmd1; schedule(); cmd2) +#define __wait_event_cmd_interruptible(wq, condition, cmd1, cmd2) \ + (void)___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \ + cmd1; schedule(); cmd2) + /** * wait_event_cmd - sleep until a condition gets true * @wq: the waitqueue to wait on @@ -315,6 +319,13 @@ do { \ __wait_event_cmd(wq, condition, cmd1, cmd2); \ } while (0) +#define wait_event_cmd_interruptible(wq, condition, cmd1, cmd2) \ +do { \ + if (condition) \ + break; \ + __wait_event_cmd_interruptible(wq, condition, cmd1, cmd2); \ +} while (0) + #define __wait_event_interruptible(wq, condition) \ ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \ schedule()) |
From: David H. <dho...@re...> - 2018-08-21 15:57:08
|
Add newly registered TPMs to the tail of the list, not the beginning, so that things that are specifying TPM_ANY_NUM don't find that the device they're using has inadvertently changed. Adding a second device would break IMA, for instance. Signed-off-by: David Howells <dho...@re...> Reviewed-by: Jason Gunthorpe <jgu...@ob...> Signed-off-by: Peter Huewe <pet...@gm...> cc: st...@vg... --- drivers/char/tpm/tpm-interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 6af17002a115..cfb9089887bd 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1122,7 +1122,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, /* Make chip available */ spin_lock(&driver_lock); - list_add_rcu(&chip->list, &tpm_chip_list); + list_add_tail_rcu(&chip->list, &tpm_chip_list); spin_unlock(&driver_lock); return chip; |
From: David H. <dho...@re...> - 2018-08-21 15:57:00
|
Hi Denis, Jarkko, James, I managed to recover the TPM library patchset that I was working on about four years ago in the process of trying to write an asymmetric key subtype that could use the TPM. Here it is in it's original glory for reference. I ended up leaving it because Jarkko's tpm-2 stuff broke it and I had other things to work on. If it's deemed worthwhile, I can try to forward port it to current Linus/mastet. Note that one or two of the preliminary patches may be upstream. The patches can also be found here: http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=tpm-lib Thanks, David --- David Howells (23): TPM: Add new TPMs to the tail of the list to prevent inadvertent change of dev TPM: Provide a facility for a userspace TPM emulator TPM: Provide a platform driver for the user emulator driver TPM: Expose struct tpm_chip and related find_get and put functions TPM: Use struct tpm_chip rather than chip number as interface parameter TPM: Move ordinal values from interface file to header with other ordinals TPM: Consolidate tpm_send(), transmit_cmd() and tpm_transmit() TPMLIB: Break TPM bits out of security/keys/trusted.c TPMLIB: Do some source cleanups TPMLIB: Better format calls to TSS_*hmac*() TPMLIB: Put banner comments on public TPM library functions TPMLIB: Create tpm_{even,odd}_nonce structs to represent nonces TPMLIB: Rename store8() and storebytes() TPMLIB: Make store_s() take a void* data argument, not unsigned char* TPMLIB: Use __be32 rather than int32_t and use cpu_to_beX() and co. TPMLIB: Put more comments into the HMAC generation functions TPMLIB: Provide a wrapper to load bytes out of the reply TPMLIB: Encapsulate XOR-based encryption with authkey derivative TPMLIB: Add some debugging code TPMLIB: Implement call to TPM_CreateWrapKey TPMLIB: Implement call to TPM_LoadKey2 TPMLIB: Provide call for TPM_FlushSpecific TPM: Add an asymmetric key subtype for handling TPM-based keys crypto/asymmetric_keys/Kconfig | 7 crypto/asymmetric_keys/Makefile | 1 crypto/asymmetric_keys/tpm_key.c | 73 ++ crypto/asymmetric_keys/tpm_key.h | 19 crypto/asymmetric_keys/tpm_key_parser.c | 212 +++++ drivers/char/tpm/Kconfig | 13 drivers/char/tpm/Makefile | 3 drivers/char/tpm/tpm-dev.c | 17 drivers/char/tpm/tpm-interface.c | 304 ++++---- drivers/char/tpm/tpm-library.c | 1216 +++++++++++++++++++++++++++++++ drivers/char/tpm/tpm-library.h | 119 +++ drivers/char/tpm/tpm-sysfs.c | 33 - drivers/char/tpm/tpm.h | 15 drivers/char/tpm/tpm_infineon.c | 6 drivers/char/tpm/tpm_user_emul.c | 694 ++++++++++++++++++ include/linux/tpm.h | 123 +++ include/linux/tpm_command.h | 22 - include/linux/wait.h | 11 security/integrity/ima/ima.h | 2 security/integrity/ima/ima_crypto.c | 4 security/integrity/ima/ima_init.c | 19 security/integrity/ima/ima_queue.c | 4 security/keys/trusted.c | 690 +----------------- security/keys/trusted.h | 80 -- 24 files changed, 2712 insertions(+), 975 deletions(-) create mode 100644 crypto/asymmetric_keys/tpm_key.c create mode 100644 crypto/asymmetric_keys/tpm_key.h create mode 100644 crypto/asymmetric_keys/tpm_key_parser.c create mode 100644 drivers/char/tpm/tpm-library.c create mode 100644 drivers/char/tpm/tpm-library.h create mode 100644 drivers/char/tpm/tpm_user_emul.c |
From: Abbaraju M. <abb...@gm...> - 2018-08-20 05:30:20
|
Hello , I had seen your mail in linux related post related to tpm . so i am thinking your the right person to contact you regarding tpm2.0 actually main problem is we interfaced slb 9670(tpm-2.0) with 16 bit msp430 controller which does not support linux kernel or any OS. now our task is to store a 100 byes of data in NV memory, without any authorisation technique, as simple as possible. please guide me in that way. slb 9670 is interfaced with msp430 controller through SPI protocol. I able to read device id , version id of slb9670 , so spi communication is working fine with our controller . what is packet format to be send with our data , i am not able to understand the TCG documents . theoretically iam able to understand we have to do nvdefinespace , nvwrite ,nvread .. internaly what is the format i have to be send not able to understand can you please guide me , or share any code snippet . sorry if i trouble you or any irrelevant questions. Regards, Manoj, mail : abb...@gm... +91-9063249308 |
From: Jarkko S. <jar...@li...> - 2018-06-04 20:00:59
|
On Sat, Jun 02, 2018 at 03:18:58PM +0200, Greg KH wrote: > On Wed, May 30, 2018 at 11:44:38PM +0300, Jarkko Sakkinen wrote: > > Decided to add Enric's commit because it is also a bug fix instead > > of modifying Chris commit. > > Why just 4.4 and not also 4.9? I don't want to take patches that would > cause a regression for people moving from 4.4 to 4.9, so can you also > provide 4.9 backports of this? If so, I will be glad to queue up both > sets of patches. Yes, I can do this. I'll check the v4.4 change with the original author as I have to put the check in the original patch into different place before sending anything (I do not have any POWER systes available to test it myself). /Jarkko |
From: Greg KH <gr...@li...> - 2018-06-02 13:19:33
|
On Wed, May 30, 2018 at 11:44:38PM +0300, Jarkko Sakkinen wrote: > Decided to add Enric's commit because it is also a bug fix instead > of modifying Chris commit. Why just 4.4 and not also 4.9? I don't want to take patches that would cause a regression for people moving from 4.4 to 4.9, so can you also provide 4.9 backports of this? If so, I will be glad to queue up both sets of patches. thanks, greg k-h |
From: Jarkko S. <jar...@li...> - 2018-05-30 23:56:35
|
On Wed, May 30, 2018 at 11:44:39PM +0300, Jarkko Sakkinen wrote: > From: Enric Balletbo i Serra <enr...@co...> > > commit b5d0ebc99bf5d0801a5ecbe958caa3d68b8eaee8 upstream > > The suspend/resume behavior of the TPM can be controlled by setting > "powered-while-suspended" in the DTS. This is useful for the cases > when hardware does not power-off the TPM. > > Signed-off-by: Sonny Rao <son...@ch...> > Signed-off-by: Enric Balletbo i Serra <enr...@co...> > Reviewed-by: Jason Gunthorpe <jgu...@ob...> > Reviewed-by: Jarkko Sakkinen <jar...@li...> > Signed-off-by: Jarkko Sakkinen <jar...@li...> > Signed-off-by: James Morris <jam...@or...> > --- > drivers/char/tpm/tpm-chip.c | 12 ++++++++++++ > drivers/char/tpm/tpm-interface.c | 3 +++ > drivers/char/tpm/tpm.h | 1 + > 3 files changed, 16 insertions(+) > > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c > index a0d9ac6b6cc9..a8d7220f613c 100644 > --- a/drivers/char/tpm/tpm-chip.c > +++ b/drivers/char/tpm/tpm-chip.c > @@ -324,8 +324,20 @@ static void tpm1_chip_unregister(struct tpm_chip *chip) > */ > int tpm_chip_register(struct tpm_chip *chip) > { > +#ifdef CONFIG_TCG_IBMVTPM > + struct device_node *np; > +#endif > int rc; > > +#ifdef CONFIG_TCG_IBMVTPM > + np = of_find_node_by_name(NULL, "vtpm"); > + if (!np) > + return -ENODEV; > + if (of_property_read_bool(np, "powered-while-suspended")) > + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; > + of_node_put(np); > +#endif I'll have to revise this as more config flag should be CONFIG_OF and property should be conditionally read if the node is found. Then it can be relocated without interference. /Jarkko |
From: Jarkko S. <jar...@li...> - 2018-05-30 20:45:20
|
From: Chris Chiu <ch...@en...> commit 0803d7befa15cab5717d667a97a66214d2a4c083 upstream The Acer Acer Veriton X4110G has a TPM device detected as: tpm_tis 00:0b: 1.2 TPM (device-id 0xFE, rev-id 71) After the first S3 suspend, the following error appears during resume: tpm tpm0: A TPM error(38) occurred continue selftest Any following S3 suspend attempts will now fail with this error: tpm tpm0: Error (38) sending savestate before suspend PM: Device 00:0b failed to suspend: error 38 Error 38 is TPM_ERR_INVALID_POSTINIT which means the TPM is not in the correct state. This indicates that the platform BIOS is not sending the usual TPM_Startup command during S3 resume. >From this point onwards, all TPM commands will fail. The same issue was previously reported on Foxconn 6150BK8MC and Sony Vaio TX3. The platform behaviour seems broken here, but we should not break suspend/resume because of this. When the unexpected TPM state is encountered, set a flag to skip the affected TPM_SaveState command on later suspends. Cc: st...@vg... Signed-off-by: Chris Chiu <ch...@en...> Signed-off-by: Daniel Drake <dr...@en...> Link: http://lkml.kernel.org/r/CAB...@ma... Link: https://lkml.org/lkml/2011/3/28/192 Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=591031 Reviewed-by: Jarkko Sakkinen <jar...@li...> Signed-off-by: Jarkko Sakkinen <jar...@li...> --- drivers/char/tpm/tpm-interface.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 247dd2b6504a..be0547115d34 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -787,6 +787,10 @@ int tpm_do_selftest(struct tpm_chip *chip) loops = jiffies_to_msecs(duration) / delay_msec; rc = tpm_continue_selftest(chip); + if (rc == TPM_ERR_INVALID_POSTINIT) { + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + dev_info(&chip->dev, "TPM not ready (%d)\n", rc); + } /* This may fail if there was no TPM driver during a suspend/resume * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) */ -- 2.17.0 |
From: Jarkko S. <jar...@li...> - 2018-05-30 20:45:14
|
From: Enric Balletbo i Serra <enr...@co...> commit b5d0ebc99bf5d0801a5ecbe958caa3d68b8eaee8 upstream The suspend/resume behavior of the TPM can be controlled by setting "powered-while-suspended" in the DTS. This is useful for the cases when hardware does not power-off the TPM. Signed-off-by: Sonny Rao <son...@ch...> Signed-off-by: Enric Balletbo i Serra <enr...@co...> Reviewed-by: Jason Gunthorpe <jgu...@ob...> Reviewed-by: Jarkko Sakkinen <jar...@li...> Signed-off-by: Jarkko Sakkinen <jar...@li...> Signed-off-by: James Morris <jam...@or...> --- drivers/char/tpm/tpm-chip.c | 12 ++++++++++++ drivers/char/tpm/tpm-interface.c | 3 +++ drivers/char/tpm/tpm.h | 1 + 3 files changed, 16 insertions(+) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index a0d9ac6b6cc9..a8d7220f613c 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -324,8 +324,20 @@ static void tpm1_chip_unregister(struct tpm_chip *chip) */ int tpm_chip_register(struct tpm_chip *chip) { +#ifdef CONFIG_TCG_IBMVTPM + struct device_node *np; +#endif int rc; +#ifdef CONFIG_TCG_IBMVTPM + np = of_find_node_by_name(NULL, "vtpm"); + if (!np) + return -ENODEV; + if (of_property_read_bool(np, "powered-while-suspended")) + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + of_node_put(np); +#endif + rc = tpm1_chip_register(chip); if (rc) return rc; diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index aaa5fa95dede..247dd2b6504a 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -931,6 +931,9 @@ int tpm_pm_suspend(struct device *dev) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) + return 0; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { tpm2_shutdown(chip, TPM2_SU_STATE); return 0; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 772d99b3a8e4..36e1abda00f9 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -168,6 +168,7 @@ struct tpm_vendor_specific { enum tpm_chip_flags { TPM_CHIP_FLAG_REGISTERED = BIT(0), TPM_CHIP_FLAG_TPM2 = BIT(1), + TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5), }; struct tpm_chip { -- 2.17.0 |
From: Jarkko S. <jar...@li...> - 2018-05-30 20:45:13
|
Decided to add Enric's commit because it is also a bug fix instead of modifying Chris commit. Chris Chiu (1): tpm: self test failure should not cause suspend to fail Enric Balletbo i Serra (1): tpm: do not suspend/resume if power stays on drivers/char/tpm/tpm-chip.c | 12 ++++++++++++ drivers/char/tpm/tpm-interface.c | 7 +++++++ drivers/char/tpm/tpm.h | 1 + 3 files changed, 20 insertions(+) -- v2: moved the check from tpm_of.c to tpm-chip.c as in v4.4 chip is unreachable otherwise. I did compilation test now with BuildRoot for power arch. 2.17.0 |
From: Jarkko S. <jar...@li...> - 2018-05-14 10:54:37
|
On Wed, May 09, 2018 at 11:55:35AM -0700, Tadeusz Struk wrote: > If load context command returns with TPM2_RC_HANDLE or > TPM2_RC_REFERENCE_H0 then we have use after free in > line 114 and double free in 117. > > Fixes: 4d57856a21ed2 ("tpm2: add session handle context saving and restoring to the space code") > > Signed-off-by: Tadeusz Struk <tad...@in...> Thank you, appreciate this! Reviewed-by: Jarkko Sakkinen <jar...@li...> /Jarkko |
From: Tadeusz S. <tad...@in...> - 2018-05-09 18:55:50
|
If load context command returns with TPM2_RC_HANDLE or TPM2_RC_REFERENCE_H0 then we have use after free in line 114 and double free in 117. Fixes: 4d57856a21ed2 ("tpm2: add session handle context saving and restoring to the space code") Signed-off-by: Tadeusz Struk <tad...@in...> --- drivers/char/tpm/tpm2-space.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c index 4e4014eabdb9..6122d3276f72 100644 --- a/drivers/char/tpm/tpm2-space.c +++ b/drivers/char/tpm/tpm2-space.c @@ -102,8 +102,9 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, * TPM_RC_REFERENCE_H0 means the session has been * flushed outside the space */ - rc = -ENOENT; + *handle = 0; tpm_buf_destroy(&tbuf); + return -ENOENT; } else if (rc > 0) { dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n", __func__, rc); |
From: Jarkko S. <jar...@li...> - 2018-05-09 11:53:02
|
On Tue, May 08, 2018 at 01:56:14PM +0300, Jarkko Sakkinen wrote: > On Fri, May 04, 2018 at 07:27:13PM -0700, Greg KH wrote: > > On Wed, May 02, 2018 at 05:38:28PM +0300, Jarkko Sakkinen wrote: > > > From: Enric Balletbo i Serra <enr...@co...> > > > > > > commit b5d0ebc99bf5d0801a5ecbe958caa3d68b8eaee8 upstream > > > > > > The suspend/resume behavior of the TPM can be controlled by setting > > > "powered-while-suspended" in the DTS. This is useful for the cases > > > when hardware does not power-off the TPM. > > > > > > Signed-off-by: Sonny Rao <son...@ch...> > > > Signed-off-by: Enric Balletbo i Serra <enr...@co...> > > > Reviewed-by: Jason Gunthorpe <jgu...@ob...> > > > Reviewed-by: Jarkko Sakkinen <jar...@li...> > > > Signed-off-by: Jarkko Sakkinen <jar...@li...> > > > Signed-off-by: James Morris <jam...@or...> > > > --- > > > drivers/char/tpm/tpm-interface.c | 3 +++ > > > drivers/char/tpm/tpm.h | 2 ++ > > > drivers/char/tpm/tpm_of.c | 3 +++ > > > 3 files changed, 8 insertions(+) > > > > > > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c > > > index 830d7e30e508..5463b649bdf1 100644 > > > --- a/drivers/char/tpm/tpm-interface.c > > > +++ b/drivers/char/tpm/tpm-interface.c > > > @@ -969,6 +969,9 @@ int tpm_pm_suspend(struct device *dev) > > > if (chip == NULL) > > > return -ENODEV; > > > > > > + if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) > > > + return 0; > > > + > > > if (chip->flags & TPM_CHIP_FLAG_TPM2) { > > > tpm2_shutdown(chip, TPM2_SU_STATE); > > > return 0; > > > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h > > > index aa4299cf7e5a..41756a9e9ad8 100644 > > > --- a/drivers/char/tpm/tpm.h > > > +++ b/drivers/char/tpm/tpm.h > > > @@ -143,6 +143,8 @@ enum tpm_chip_flags { > > > TPM_CHIP_FLAG_TPM2 = BIT(1), > > > TPM_CHIP_FLAG_IRQ = BIT(2), > > > TPM_CHIP_FLAG_VIRTUAL = BIT(3), > > > + TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4), > > > + TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5), > > > }; > > > > > > struct tpm_chip { > > > diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c > > > index 570f30c5c5f4..669f4a046398 100644 > > > --- a/drivers/char/tpm/tpm_of.c > > > +++ b/drivers/char/tpm/tpm_of.c > > > @@ -37,6 +37,9 @@ int read_log(struct tpm_bios_log *log) > > > return -ENODEV; > > > } > > > > > > + if (of_property_read_bool(np, "powered-while-suspended")) > > > + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; > > > + > > > > This last line here blows up the build, there is no chip variable > > defined in this function :( > > > > So I have to drop both of these patches, from both 4.4.y and 4.9.y > > queues right now. Can you fix this up and resend them? > > > > thanks, > > > > greg k-h > > Yes. Sorry. I'll do that. > > /Jarkko ... obviously should have compiled PPC kernel :-/ /Jarkko |
From: Jarkko S. <jar...@li...> - 2018-05-08 10:56:28
|
On Fri, May 04, 2018 at 07:27:13PM -0700, Greg KH wrote: > On Wed, May 02, 2018 at 05:38:28PM +0300, Jarkko Sakkinen wrote: > > From: Enric Balletbo i Serra <enr...@co...> > > > > commit b5d0ebc99bf5d0801a5ecbe958caa3d68b8eaee8 upstream > > > > The suspend/resume behavior of the TPM can be controlled by setting > > "powered-while-suspended" in the DTS. This is useful for the cases > > when hardware does not power-off the TPM. > > > > Signed-off-by: Sonny Rao <son...@ch...> > > Signed-off-by: Enric Balletbo i Serra <enr...@co...> > > Reviewed-by: Jason Gunthorpe <jgu...@ob...> > > Reviewed-by: Jarkko Sakkinen <jar...@li...> > > Signed-off-by: Jarkko Sakkinen <jar...@li...> > > Signed-off-by: James Morris <jam...@or...> > > --- > > drivers/char/tpm/tpm-interface.c | 3 +++ > > drivers/char/tpm/tpm.h | 2 ++ > > drivers/char/tpm/tpm_of.c | 3 +++ > > 3 files changed, 8 insertions(+) > > > > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c > > index 830d7e30e508..5463b649bdf1 100644 > > --- a/drivers/char/tpm/tpm-interface.c > > +++ b/drivers/char/tpm/tpm-interface.c > > @@ -969,6 +969,9 @@ int tpm_pm_suspend(struct device *dev) > > if (chip == NULL) > > return -ENODEV; > > > > + if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) > > + return 0; > > + > > if (chip->flags & TPM_CHIP_FLAG_TPM2) { > > tpm2_shutdown(chip, TPM2_SU_STATE); > > return 0; > > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h > > index aa4299cf7e5a..41756a9e9ad8 100644 > > --- a/drivers/char/tpm/tpm.h > > +++ b/drivers/char/tpm/tpm.h > > @@ -143,6 +143,8 @@ enum tpm_chip_flags { > > TPM_CHIP_FLAG_TPM2 = BIT(1), > > TPM_CHIP_FLAG_IRQ = BIT(2), > > TPM_CHIP_FLAG_VIRTUAL = BIT(3), > > + TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4), > > + TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5), > > }; > > > > struct tpm_chip { > > diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c > > index 570f30c5c5f4..669f4a046398 100644 > > --- a/drivers/char/tpm/tpm_of.c > > +++ b/drivers/char/tpm/tpm_of.c > > @@ -37,6 +37,9 @@ int read_log(struct tpm_bios_log *log) > > return -ENODEV; > > } > > > > + if (of_property_read_bool(np, "powered-while-suspended")) > > + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; > > + > > This last line here blows up the build, there is no chip variable > defined in this function :( > > So I have to drop both of these patches, from both 4.4.y and 4.9.y > queues right now. Can you fix this up and resend them? > > thanks, > > greg k-h Yes. Sorry. I'll do that. /Jarkko |
From: Greg KH <gr...@li...> - 2018-05-05 02:27:36
|
On Wed, May 02, 2018 at 05:38:28PM +0300, Jarkko Sakkinen wrote: > From: Enric Balletbo i Serra <enr...@co...> > > commit b5d0ebc99bf5d0801a5ecbe958caa3d68b8eaee8 upstream > > The suspend/resume behavior of the TPM can be controlled by setting > "powered-while-suspended" in the DTS. This is useful for the cases > when hardware does not power-off the TPM. > > Signed-off-by: Sonny Rao <son...@ch...> > Signed-off-by: Enric Balletbo i Serra <enr...@co...> > Reviewed-by: Jason Gunthorpe <jgu...@ob...> > Reviewed-by: Jarkko Sakkinen <jar...@li...> > Signed-off-by: Jarkko Sakkinen <jar...@li...> > Signed-off-by: James Morris <jam...@or...> > --- > drivers/char/tpm/tpm-interface.c | 3 +++ > drivers/char/tpm/tpm.h | 2 ++ > drivers/char/tpm/tpm_of.c | 3 +++ > 3 files changed, 8 insertions(+) > > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c > index 830d7e30e508..5463b649bdf1 100644 > --- a/drivers/char/tpm/tpm-interface.c > +++ b/drivers/char/tpm/tpm-interface.c > @@ -969,6 +969,9 @@ int tpm_pm_suspend(struct device *dev) > if (chip == NULL) > return -ENODEV; > > + if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) > + return 0; > + > if (chip->flags & TPM_CHIP_FLAG_TPM2) { > tpm2_shutdown(chip, TPM2_SU_STATE); > return 0; > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h > index aa4299cf7e5a..41756a9e9ad8 100644 > --- a/drivers/char/tpm/tpm.h > +++ b/drivers/char/tpm/tpm.h > @@ -143,6 +143,8 @@ enum tpm_chip_flags { > TPM_CHIP_FLAG_TPM2 = BIT(1), > TPM_CHIP_FLAG_IRQ = BIT(2), > TPM_CHIP_FLAG_VIRTUAL = BIT(3), > + TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4), > + TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5), > }; > > struct tpm_chip { > diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c > index 570f30c5c5f4..669f4a046398 100644 > --- a/drivers/char/tpm/tpm_of.c > +++ b/drivers/char/tpm/tpm_of.c > @@ -37,6 +37,9 @@ int read_log(struct tpm_bios_log *log) > return -ENODEV; > } > > + if (of_property_read_bool(np, "powered-while-suspended")) > + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; > + This last line here blows up the build, there is no chip variable defined in this function :( So I have to drop both of these patches, from both 4.4.y and 4.9.y queues right now. Can you fix this up and resend them? thanks, greg k-h |
From: Greg KH <gr...@kr...> - 2018-05-03 18:18:09
|
On Thu, May 03, 2018 at 03:43:32PM +0300, Jarkko Sakkinen wrote: > Decided to add Enric's commit because it is also a bug fix instead > of modifying Chris commit. Now applied, thanks. greg k-h |
From: Jarkko S. <jar...@li...> - 2018-05-03 12:44:07
|
From: Chris Chiu <ch...@en...> commit 0803d7befa15cab5717d667a97a66214d2a4c083 upstream The Acer Acer Veriton X4110G has a TPM device detected as: tpm_tis 00:0b: 1.2 TPM (device-id 0xFE, rev-id 71) After the first S3 suspend, the following error appears during resume: tpm tpm0: A TPM error(38) occurred continue selftest Any following S3 suspend attempts will now fail with this error: tpm tpm0: Error (38) sending savestate before suspend PM: Device 00:0b failed to suspend: error 38 Error 38 is TPM_ERR_INVALID_POSTINIT which means the TPM is not in the correct state. This indicates that the platform BIOS is not sending the usual TPM_Startup command during S3 resume. >From this point onwards, all TPM commands will fail. The same issue was previously reported on Foxconn 6150BK8MC and Sony Vaio TX3. The platform behaviour seems broken here, but we should not break suspend/resume because of this. When the unexpected TPM state is encountered, set a flag to skip the affected TPM_SaveState command on later suspends. Cc: st...@vg... Signed-off-by: Chris Chiu <ch...@en...> Signed-off-by: Daniel Drake <dr...@en...> Link: http://lkml.kernel.org/r/CAB...@ma... Link: https://lkml.org/lkml/2011/3/28/192 Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=591031 Reviewed-by: Jarkko Sakkinen <jar...@li...> Signed-off-by: Jarkko Sakkinen <jar...@li...> --- drivers/char/tpm/tpm-interface.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 247dd2b6504a..be0547115d34 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -787,6 +787,10 @@ int tpm_do_selftest(struct tpm_chip *chip) loops = jiffies_to_msecs(duration) / delay_msec; rc = tpm_continue_selftest(chip); + if (rc == TPM_ERR_INVALID_POSTINIT) { + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + dev_info(&chip->dev, "TPM not ready (%d)\n", rc); + } /* This may fail if there was no TPM driver during a suspend/resume * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) */ -- 2.17.0 |
From: Jarkko S. <jar...@li...> - 2018-05-03 12:44:03
|
From: Enric Balletbo i Serra <enr...@co...> commit b5d0ebc99bf5d0801a5ecbe958caa3d68b8eaee8 upstream The suspend/resume behavior of the TPM can be controlled by setting "powered-while-suspended" in the DTS. This is useful for the cases when hardware does not power-off the TPM. Signed-off-by: Sonny Rao <son...@ch...> Signed-off-by: Enric Balletbo i Serra <enr...@co...> Reviewed-by: Jason Gunthorpe <jgu...@ob...> Reviewed-by: Jarkko Sakkinen <jar...@li...> Signed-off-by: Jarkko Sakkinen <jar...@li...> Signed-off-by: James Morris <jam...@or...> --- drivers/char/tpm/tpm-interface.c | 3 +++ drivers/char/tpm/tpm.h | 1 + drivers/char/tpm/tpm_of.c | 3 +++ 3 files changed, 7 insertions(+) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index aaa5fa95dede..247dd2b6504a 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -931,6 +931,9 @@ int tpm_pm_suspend(struct device *dev) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) + return 0; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { tpm2_shutdown(chip, TPM2_SU_STATE); return 0; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 772d99b3a8e4..36e1abda00f9 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -168,6 +168,7 @@ struct tpm_vendor_specific { enum tpm_chip_flags { TPM_CHIP_FLAG_REGISTERED = BIT(0), TPM_CHIP_FLAG_TPM2 = BIT(1), + TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5), }; struct tpm_chip { diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 570f30c5c5f4..669f4a046398 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -37,6 +37,9 @@ int read_log(struct tpm_bios_log *log) return -ENODEV; } + if (of_property_read_bool(np, "powered-while-suspended")) + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + sizep = of_get_property(np, "linux,sml-size", NULL); if (sizep == NULL) { pr_err("%s: ERROR - SML size not found\n", __func__); -- 2.17.0 |
From: Jarkko S. <jar...@li...> - 2018-05-03 12:43:59
|
Decided to add Enric's commit because it is also a bug fix instead of modifying Chris commit. Chris Chiu (1): tpm: self test failure should not cause suspend to fail Enric Balletbo i Serra (1): tpm: do not suspend/resume if power stays on drivers/char/tpm/tpm-interface.c | 7 +++++++ drivers/char/tpm/tpm.h | 1 + drivers/char/tpm/tpm_of.c | 3 +++ 3 files changed, 11 insertions(+) -- 2.17.0 |
From: Jarkko S. <jar...@li...> - 2018-05-03 06:37:14
|
On Wed, May 02, 2018 at 01:52:39PM -0700, Greg KH wrote: > On Wed, May 02, 2018 at 05:38:27PM +0300, Jarkko Sakkinen wrote: > > Decided to add Enric's commit because it is also a bug fix instead > > of modifying Chris commit. > > Both now applied, thanks. > > greg k-h Great, I'll send next updates to v4.4. /Jarkko |
From: Greg KH <gr...@kr...> - 2018-05-02 21:08:22
|
On Wed, May 02, 2018 at 05:38:27PM +0300, Jarkko Sakkinen wrote: > Decided to add Enric's commit because it is also a bug fix instead > of modifying Chris commit. Both now applied, thanks. greg k-h |
From: Jarkko S. <jar...@li...> - 2018-05-02 14:38:59
|
From: Chris Chiu <ch...@en...> commit 0803d7befa15cab5717d667a97a66214d2a4c083 upstream The Acer Acer Veriton X4110G has a TPM device detected as: tpm_tis 00:0b: 1.2 TPM (device-id 0xFE, rev-id 71) After the first S3 suspend, the following error appears during resume: tpm tpm0: A TPM error(38) occurred continue selftest Any following S3 suspend attempts will now fail with this error: tpm tpm0: Error (38) sending savestate before suspend PM: Device 00:0b failed to suspend: error 38 Error 38 is TPM_ERR_INVALID_POSTINIT which means the TPM is not in the correct state. This indicates that the platform BIOS is not sending the usual TPM_Startup command during S3 resume. >From this point onwards, all TPM commands will fail. The same issue was previously reported on Foxconn 6150BK8MC and Sony Vaio TX3. The platform behaviour seems broken here, but we should not break suspend/resume because of this. When the unexpected TPM state is encountered, set a flag to skip the affected TPM_SaveState command on later suspends. Cc: st...@vg... Signed-off-by: Chris Chiu <ch...@en...> Signed-off-by: Daniel Drake <dr...@en...> Link: http://lkml.kernel.org/r/CAB...@ma... Link: https://lkml.org/lkml/2011/3/28/192 Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=591031 Reviewed-by: Jarkko Sakkinen <jar...@li...> Signed-off-by: Jarkko Sakkinen <jar...@li...> --- drivers/char/tpm/tpm-interface.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 5463b649bdf1..faf2db122ab9 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -803,6 +803,10 @@ int tpm_do_selftest(struct tpm_chip *chip) loops = jiffies_to_msecs(duration) / delay_msec; rc = tpm_continue_selftest(chip); + if (rc == TPM_ERR_INVALID_POSTINIT) { + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + dev_info(&chip->dev, "TPM not ready (%d)\n", rc); + } /* This may fail if there was no TPM driver during a suspend/resume * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) */ -- 2.17.0 |