Commit f2f393c3 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tpmdd-v6.5-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd

Pull tpm fixes from Jarkko Sakkinen.

Mostly interrupt storm fixes, with some other minor changes.

* tag 'tpmdd-v6.5-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
  tpm,tpm_tis: Disable interrupts after 1000 unhandled IRQs
  tpm/tpm_tis: Disable interrupts for Lenovo L590 devices
  tpm: Do not remap from ACPI resources again for Pluton TPM
  tpm/tpm_tis: Disable interrupts for Framework Laptop Intel 13th gen
  tpm/tpm_tis: Disable interrupts for Framework Laptop Intel 12th gen
  security: keys: Modify mismatched function name
  tpm: return false from tpm_amd_is_rng_defective on non-x86 platforms
  keys: Fix linking a duplicate key to a keyring's assoc_array
  tpm: tis_i2c: Limit write bursts to I2C_SMBUS_BLOCK_MAX (32) bytes
  tpm: tis_i2c: Limit read bursts to I2C_SMBUS_BLOCK_MAX (32) bytes
  tpm_tis_spi: Release chip select when flow control fails
  tpm: tpm_tis: Disable interrupts *only* for AEON UPX-i11
  tpm: tpm_vtpm_proxy: fix a race condition in /dev/vtpmx creation
parents fdf0eaf1 481c2d14
...@@ -518,6 +518,7 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip) ...@@ -518,6 +518,7 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip)
* 6.x.y.z series: 6.0.18.6 + * 6.x.y.z series: 6.0.18.6 +
* 3.x.y.z series: 3.57.y.5 + * 3.x.y.z series: 3.57.y.5 +
*/ */
#ifdef CONFIG_X86
static bool tpm_amd_is_rng_defective(struct tpm_chip *chip) static bool tpm_amd_is_rng_defective(struct tpm_chip *chip)
{ {
u32 val1, val2; u32 val1, val2;
...@@ -566,6 +567,12 @@ static bool tpm_amd_is_rng_defective(struct tpm_chip *chip) ...@@ -566,6 +567,12 @@ static bool tpm_amd_is_rng_defective(struct tpm_chip *chip)
return true; return true;
} }
#else
static inline bool tpm_amd_is_rng_defective(struct tpm_chip *chip)
{
return false;
}
#endif /* CONFIG_X86 */
static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{ {
......
...@@ -563,15 +563,18 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, ...@@ -563,15 +563,18 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
u32 rsp_size; u32 rsp_size;
int ret; int ret;
INIT_LIST_HEAD(&acpi_resource_list); /*
ret = acpi_dev_get_resources(device, &acpi_resource_list, * Pluton sometimes does not define ACPI memory regions.
crb_check_resource, iores_array); * Mapping is then done in crb_map_pluton
if (ret < 0) */
return ret;
acpi_dev_free_resource_list(&acpi_resource_list);
/* Pluton doesn't appear to define ACPI memory regions */
if (priv->sm != ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) { if (priv->sm != ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) {
INIT_LIST_HEAD(&acpi_resource_list);
ret = acpi_dev_get_resources(device, &acpi_resource_list,
crb_check_resource, iores_array);
if (ret < 0)
return ret;
acpi_dev_free_resource_list(&acpi_resource_list);
if (resource_type(iores_array) != IORESOURCE_MEM) { if (resource_type(iores_array) != IORESOURCE_MEM) {
dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n"); dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n");
return -EINVAL; return -EINVAL;
......
...@@ -114,6 +114,22 @@ static int tpm_tis_disable_irq(const struct dmi_system_id *d) ...@@ -114,6 +114,22 @@ static int tpm_tis_disable_irq(const struct dmi_system_id *d)
} }
static const struct dmi_system_id tpm_tis_dmi_table[] = { static const struct dmi_system_id tpm_tis_dmi_table[] = {
{
.callback = tpm_tis_disable_irq,
.ident = "Framework Laptop (12th Gen Intel Core)",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
DMI_MATCH(DMI_PRODUCT_NAME, "Laptop (12th Gen Intel Core)"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "Framework Laptop (13th Gen Intel Core)",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
DMI_MATCH(DMI_PRODUCT_NAME, "Laptop (13th Gen Intel Core)"),
},
},
{ {
.callback = tpm_tis_disable_irq, .callback = tpm_tis_disable_irq,
.ident = "ThinkPad T490s", .ident = "ThinkPad T490s",
...@@ -138,11 +154,20 @@ static const struct dmi_system_id tpm_tis_dmi_table[] = { ...@@ -138,11 +154,20 @@ static const struct dmi_system_id tpm_tis_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L490"), DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L490"),
}, },
}, },
{
.callback = tpm_tis_disable_irq,
.ident = "ThinkPad L590",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L590"),
},
},
{ {
.callback = tpm_tis_disable_irq, .callback = tpm_tis_disable_irq,
.ident = "UPX-TGL", .ident = "UPX-TGL",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
DMI_MATCH(DMI_PRODUCT_VERSION, "UPX-TGL"),
}, },
}, },
{} {}
......
...@@ -24,9 +24,12 @@ ...@@ -24,9 +24,12 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/dmi.h>
#include "tpm.h" #include "tpm.h"
#include "tpm_tis_core.h" #include "tpm_tis_core.h"
#define TPM_TIS_MAX_UNHANDLED_IRQS 1000
static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value); static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value);
static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
...@@ -468,25 +471,29 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len) ...@@ -468,25 +471,29 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
return rc; return rc;
} }
static void disable_interrupts(struct tpm_chip *chip) static void __tpm_tis_disable_interrupts(struct tpm_chip *chip)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
u32 int_mask = 0;
tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &int_mask);
int_mask &= ~TPM_GLOBAL_INT_ENABLE;
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), int_mask);
chip->flags &= ~TPM_CHIP_FLAG_IRQ;
}
static void tpm_tis_disable_interrupts(struct tpm_chip *chip)
{ {
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
u32 intmask;
int rc;
if (priv->irq == 0) if (priv->irq == 0)
return; return;
rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); __tpm_tis_disable_interrupts(chip);
if (rc < 0)
intmask = 0;
intmask &= ~TPM_GLOBAL_INT_ENABLE;
rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
devm_free_irq(chip->dev.parent, priv->irq, chip); devm_free_irq(chip->dev.parent, priv->irq, chip);
priv->irq = 0; priv->irq = 0;
chip->flags &= ~TPM_CHIP_FLAG_IRQ;
} }
/* /*
...@@ -552,7 +559,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -552,7 +559,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags)) if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
tpm_msleep(1); tpm_msleep(1);
if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags)) if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
disable_interrupts(chip); tpm_tis_disable_interrupts(chip);
set_bit(TPM_TIS_IRQ_TESTED, &priv->flags); set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
return rc; return rc;
} }
...@@ -752,6 +759,57 @@ static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status) ...@@ -752,6 +759,57 @@ static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
return status == TPM_STS_COMMAND_READY; return status == TPM_STS_COMMAND_READY;
} }
static irqreturn_t tpm_tis_revert_interrupts(struct tpm_chip *chip)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
const char *product;
const char *vendor;
dev_warn(&chip->dev, FW_BUG
"TPM interrupt storm detected, polling instead\n");
vendor = dmi_get_system_info(DMI_SYS_VENDOR);
product = dmi_get_system_info(DMI_PRODUCT_VERSION);
if (vendor && product) {
dev_info(&chip->dev,
"Consider adding the following entry to tpm_tis_dmi_table:\n");
dev_info(&chip->dev, "\tDMI_SYS_VENDOR: %s\n", vendor);
dev_info(&chip->dev, "\tDMI_PRODUCT_VERSION: %s\n", product);
}
if (tpm_tis_request_locality(chip, 0) != 0)
return IRQ_NONE;
__tpm_tis_disable_interrupts(chip);
tpm_tis_relinquish_locality(chip, 0);
schedule_work(&priv->free_irq_work);
return IRQ_HANDLED;
}
static irqreturn_t tpm_tis_update_unhandled_irqs(struct tpm_chip *chip)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
irqreturn_t irqret = IRQ_HANDLED;
if (!(chip->flags & TPM_CHIP_FLAG_IRQ))
return IRQ_HANDLED;
if (time_after(jiffies, priv->last_unhandled_irq + HZ/10))
priv->unhandled_irqs = 1;
else
priv->unhandled_irqs++;
priv->last_unhandled_irq = jiffies;
if (priv->unhandled_irqs > TPM_TIS_MAX_UNHANDLED_IRQS)
irqret = tpm_tis_revert_interrupts(chip);
return irqret;
}
static irqreturn_t tis_int_handler(int dummy, void *dev_id) static irqreturn_t tis_int_handler(int dummy, void *dev_id)
{ {
struct tpm_chip *chip = dev_id; struct tpm_chip *chip = dev_id;
...@@ -761,10 +819,10 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) ...@@ -761,10 +819,10 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &interrupt); rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &interrupt);
if (rc < 0) if (rc < 0)
return IRQ_NONE; goto err;
if (interrupt == 0) if (interrupt == 0)
return IRQ_NONE; goto err;
set_bit(TPM_TIS_IRQ_TESTED, &priv->flags); set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
if (interrupt & TPM_INTF_DATA_AVAIL_INT) if (interrupt & TPM_INTF_DATA_AVAIL_INT)
...@@ -780,10 +838,13 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) ...@@ -780,10 +838,13 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), interrupt); rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), interrupt);
tpm_tis_relinquish_locality(chip, 0); tpm_tis_relinquish_locality(chip, 0);
if (rc < 0) if (rc < 0)
return IRQ_NONE; goto err;
tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &interrupt); tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &interrupt);
return IRQ_HANDLED; return IRQ_HANDLED;
err:
return tpm_tis_update_unhandled_irqs(chip);
} }
static void tpm_tis_gen_interrupt(struct tpm_chip *chip) static void tpm_tis_gen_interrupt(struct tpm_chip *chip)
...@@ -804,6 +865,15 @@ static void tpm_tis_gen_interrupt(struct tpm_chip *chip) ...@@ -804,6 +865,15 @@ static void tpm_tis_gen_interrupt(struct tpm_chip *chip)
chip->flags &= ~TPM_CHIP_FLAG_IRQ; chip->flags &= ~TPM_CHIP_FLAG_IRQ;
} }
static void tpm_tis_free_irq_func(struct work_struct *work)
{
struct tpm_tis_data *priv = container_of(work, typeof(*priv), free_irq_work);
struct tpm_chip *chip = priv->chip;
devm_free_irq(chip->dev.parent, priv->irq, chip);
priv->irq = 0;
}
/* Register the IRQ and issue a command that will cause an interrupt. If an /* Register the IRQ and issue a command that will cause an interrupt. If an
* irq is seen then leave the chip setup for IRQ operation, otherwise reverse * irq is seen then leave the chip setup for IRQ operation, otherwise reverse
* everything and leave in polling mode. Returns 0 on success. * everything and leave in polling mode. Returns 0 on success.
...@@ -816,6 +886,7 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask, ...@@ -816,6 +886,7 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
int rc; int rc;
u32 int_status; u32 int_status;
INIT_WORK(&priv->free_irq_work, tpm_tis_free_irq_func);
rc = devm_request_threaded_irq(chip->dev.parent, irq, NULL, rc = devm_request_threaded_irq(chip->dev.parent, irq, NULL,
tis_int_handler, IRQF_ONESHOT | flags, tis_int_handler, IRQF_ONESHOT | flags,
...@@ -918,6 +989,7 @@ void tpm_tis_remove(struct tpm_chip *chip) ...@@ -918,6 +989,7 @@ void tpm_tis_remove(struct tpm_chip *chip)
interrupt = 0; interrupt = 0;
tpm_tis_write32(priv, reg, ~TPM_GLOBAL_INT_ENABLE & interrupt); tpm_tis_write32(priv, reg, ~TPM_GLOBAL_INT_ENABLE & interrupt);
flush_work(&priv->free_irq_work);
tpm_tis_clkrun_enable(chip, false); tpm_tis_clkrun_enable(chip, false);
...@@ -1021,6 +1093,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, ...@@ -1021,6 +1093,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
chip->timeout_b = msecs_to_jiffies(TIS_TIMEOUT_B_MAX); chip->timeout_b = msecs_to_jiffies(TIS_TIMEOUT_B_MAX);
chip->timeout_c = msecs_to_jiffies(TIS_TIMEOUT_C_MAX); chip->timeout_c = msecs_to_jiffies(TIS_TIMEOUT_C_MAX);
chip->timeout_d = msecs_to_jiffies(TIS_TIMEOUT_D_MAX); chip->timeout_d = msecs_to_jiffies(TIS_TIMEOUT_D_MAX);
priv->chip = chip;
priv->timeout_min = TPM_TIMEOUT_USECS_MIN; priv->timeout_min = TPM_TIMEOUT_USECS_MIN;
priv->timeout_max = TPM_TIMEOUT_USECS_MAX; priv->timeout_max = TPM_TIMEOUT_USECS_MAX;
priv->phy_ops = phy_ops; priv->phy_ops = phy_ops;
...@@ -1179,7 +1252,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, ...@@ -1179,7 +1252,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
rc = tpm_tis_request_locality(chip, 0); rc = tpm_tis_request_locality(chip, 0);
if (rc < 0) if (rc < 0)
goto out_err; goto out_err;
disable_interrupts(chip); tpm_tis_disable_interrupts(chip);
tpm_tis_relinquish_locality(chip, 0); tpm_tis_relinquish_locality(chip, 0);
} }
} }
......
...@@ -91,11 +91,15 @@ enum tpm_tis_flags { ...@@ -91,11 +91,15 @@ enum tpm_tis_flags {
}; };
struct tpm_tis_data { struct tpm_tis_data {
struct tpm_chip *chip;
u16 manufacturer_id; u16 manufacturer_id;
struct mutex locality_count_mutex; struct mutex locality_count_mutex;
unsigned int locality_count; unsigned int locality_count;
int locality; int locality;
int irq; int irq;
struct work_struct free_irq_work;
unsigned long last_unhandled_irq;
unsigned int unhandled_irqs;
unsigned int int_mask; unsigned int int_mask;
unsigned long flags; unsigned long flags;
void __iomem *ilb_base_addr; void __iomem *ilb_base_addr;
......
...@@ -189,21 +189,28 @@ static int tpm_tis_i2c_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len, ...@@ -189,21 +189,28 @@ static int tpm_tis_i2c_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
int ret; int ret;
for (i = 0; i < TPM_RETRY; i++) { for (i = 0; i < TPM_RETRY; i++) {
/* write register */ u16 read = 0;
msg.len = sizeof(reg);
msg.buf = &reg; while (read < len) {
msg.flags = 0; /* write register */
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg); msg.len = sizeof(reg);
if (ret < 0) msg.buf = &reg;
return ret; msg.flags = 0;
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg);
/* read data */ if (ret < 0)
msg.buf = result; return ret;
msg.len = len;
msg.flags = I2C_M_RD; /* read data */
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg); msg.buf = result + read;
if (ret < 0) msg.len = len - read;
return ret; msg.flags = I2C_M_RD;
if (msg.len > I2C_SMBUS_BLOCK_MAX)
msg.len = I2C_SMBUS_BLOCK_MAX;
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg);
if (ret < 0)
return ret;
read += msg.len;
}
ret = tpm_tis_i2c_sanity_check_read(reg, len, result); ret = tpm_tis_i2c_sanity_check_read(reg, len, result);
if (ret == 0) if (ret == 0)
...@@ -223,19 +230,27 @@ static int tpm_tis_i2c_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, ...@@ -223,19 +230,27 @@ static int tpm_tis_i2c_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
struct i2c_msg msg = { .addr = phy->i2c_client->addr }; struct i2c_msg msg = { .addr = phy->i2c_client->addr };
u8 reg = tpm_tis_i2c_address_to_register(addr); u8 reg = tpm_tis_i2c_address_to_register(addr);
int ret; int ret;
u16 wrote = 0;
if (len > TPM_BUFSIZE - 1) if (len > TPM_BUFSIZE - 1)
return -EIO; return -EIO;
/* write register and data in one go */
phy->io_buf[0] = reg; phy->io_buf[0] = reg;
memcpy(phy->io_buf + sizeof(reg), value, len);
msg.len = sizeof(reg) + len;
msg.buf = phy->io_buf; msg.buf = phy->io_buf;
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg); while (wrote < len) {
if (ret < 0) /* write register and data in one go */
return ret; msg.len = sizeof(reg) + len - wrote;
if (msg.len > I2C_SMBUS_BLOCK_MAX)
msg.len = I2C_SMBUS_BLOCK_MAX;
memcpy(phy->io_buf + sizeof(reg), value + wrote,
msg.len - sizeof(reg));
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg);
if (ret < 0)
return ret;
wrote += msg.len - sizeof(reg);
}
return 0; return 0;
} }
......
...@@ -136,6 +136,14 @@ int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, ...@@ -136,6 +136,14 @@ int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
} }
exit: exit:
if (ret < 0) {
/* Deactivate chip select */
memset(&spi_xfer, 0, sizeof(spi_xfer));
spi_message_init(&m);
spi_message_add_tail(&spi_xfer, &m);
spi_sync_locked(phy->spi_device, &m);
}
spi_bus_unlock(phy->spi_device->master); spi_bus_unlock(phy->spi_device->master);
return ret; return ret;
} }
......
...@@ -683,37 +683,21 @@ static struct miscdevice vtpmx_miscdev = { ...@@ -683,37 +683,21 @@ static struct miscdevice vtpmx_miscdev = {
.fops = &vtpmx_fops, .fops = &vtpmx_fops,
}; };
static int vtpmx_init(void)
{
return misc_register(&vtpmx_miscdev);
}
static void vtpmx_cleanup(void)
{
misc_deregister(&vtpmx_miscdev);
}
static int __init vtpm_module_init(void) static int __init vtpm_module_init(void)
{ {
int rc; int rc;
rc = vtpmx_init();
if (rc) {
pr_err("couldn't create vtpmx device\n");
return rc;
}
workqueue = create_workqueue("tpm-vtpm"); workqueue = create_workqueue("tpm-vtpm");
if (!workqueue) { if (!workqueue) {
pr_err("couldn't create workqueue\n"); pr_err("couldn't create workqueue\n");
rc = -ENOMEM; return -ENOMEM;
goto err_vtpmx_cleanup;
} }
return 0; rc = misc_register(&vtpmx_miscdev);
if (rc) {
err_vtpmx_cleanup: pr_err("couldn't create vtpmx device\n");
vtpmx_cleanup(); destroy_workqueue(workqueue);
}
return rc; return rc;
} }
...@@ -721,7 +705,7 @@ static int __init vtpm_module_init(void) ...@@ -721,7 +705,7 @@ static int __init vtpm_module_init(void)
static void __exit vtpm_module_exit(void) static void __exit vtpm_module_exit(void)
{ {
destroy_workqueue(workqueue); destroy_workqueue(workqueue);
vtpmx_cleanup(); misc_deregister(&vtpmx_miscdev);
} }
module_init(vtpm_module_init); module_init(vtpm_module_init);
......
...@@ -401,17 +401,21 @@ static int construct_alloc_key(struct keyring_search_context *ctx, ...@@ -401,17 +401,21 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
if (dest_keyring) { if (dest_keyring) {
ret = __key_link_lock(dest_keyring, &ctx->index_key); ret = __key_link_lock(dest_keyring, &key->index_key);
if (ret < 0) if (ret < 0)
goto link_lock_failed; goto link_lock_failed;
ret = __key_link_begin(dest_keyring, &ctx->index_key, &edit);
if (ret < 0)
goto link_prealloc_failed;
} }
/* attach the key to the destination keyring under lock, but we do need /*
* Attach the key to the destination keyring under lock, but we do need
* to do another check just in case someone beat us to it whilst we * to do another check just in case someone beat us to it whilst we
* waited for locks */ * waited for locks.
*
* The caller might specify a comparison function which looks for keys
* that do not exactly match but are still equivalent from the caller's
* perspective. The __key_link_begin() operation must be done only after
* an actual key is determined.
*/
mutex_lock(&key_construction_mutex); mutex_lock(&key_construction_mutex);
rcu_read_lock(); rcu_read_lock();
...@@ -420,12 +424,16 @@ static int construct_alloc_key(struct keyring_search_context *ctx, ...@@ -420,12 +424,16 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto key_already_present; goto key_already_present;
if (dest_keyring) if (dest_keyring) {
ret = __key_link_begin(dest_keyring, &key->index_key, &edit);
if (ret < 0)
goto link_alloc_failed;
__key_link(dest_keyring, key, &edit); __key_link(dest_keyring, key, &edit);
}
mutex_unlock(&key_construction_mutex); mutex_unlock(&key_construction_mutex);
if (dest_keyring) if (dest_keyring)
__key_link_end(dest_keyring, &ctx->index_key, edit); __key_link_end(dest_keyring, &key->index_key, edit);
mutex_unlock(&user->cons_lock); mutex_unlock(&user->cons_lock);
*_key = key; *_key = key;
kleave(" = 0 [%d]", key_serial(key)); kleave(" = 0 [%d]", key_serial(key));
...@@ -438,10 +446,13 @@ static int construct_alloc_key(struct keyring_search_context *ctx, ...@@ -438,10 +446,13 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
mutex_unlock(&key_construction_mutex); mutex_unlock(&key_construction_mutex);
key = key_ref_to_ptr(key_ref); key = key_ref_to_ptr(key_ref);
if (dest_keyring) { if (dest_keyring) {
ret = __key_link_begin(dest_keyring, &key->index_key, &edit);
if (ret < 0)
goto link_alloc_failed_unlocked;
ret = __key_link_check_live_key(dest_keyring, key); ret = __key_link_check_live_key(dest_keyring, key);
if (ret == 0) if (ret == 0)
__key_link(dest_keyring, key, &edit); __key_link(dest_keyring, key, &edit);
__key_link_end(dest_keyring, &ctx->index_key, edit); __key_link_end(dest_keyring, &key->index_key, edit);
if (ret < 0) if (ret < 0)
goto link_check_failed; goto link_check_failed;
} }
...@@ -456,8 +467,10 @@ static int construct_alloc_key(struct keyring_search_context *ctx, ...@@ -456,8 +467,10 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
kleave(" = %d [linkcheck]", ret); kleave(" = %d [linkcheck]", ret);
return ret; return ret;
link_prealloc_failed: link_alloc_failed:
__key_link_end(dest_keyring, &ctx->index_key, edit); mutex_unlock(&key_construction_mutex);
link_alloc_failed_unlocked:
__key_link_end(dest_keyring, &key->index_key, edit);
link_lock_failed: link_lock_failed:
mutex_unlock(&user->cons_lock); mutex_unlock(&user->cons_lock);
key_put(key); key_put(key);
......
...@@ -186,7 +186,7 @@ int tpm2_key_priv(void *context, size_t hdrlen, ...@@ -186,7 +186,7 @@ int tpm2_key_priv(void *context, size_t hdrlen,
} }
/** /**
* tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer. * tpm2_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer.
* *
* @buf: an allocated tpm_buf instance * @buf: an allocated tpm_buf instance
* @session_handle: session handle * @session_handle: session handle
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment