tpmdd-devel Archive on lore.kernel.org
 help / color / Atom feed
From: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
To: denkenz-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org,
	jejb-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org
Cc: tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org,
	linux-integrity-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	keyrings-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: [PATCH 02/23] TPM: Provide a facility for a userspace TPM emulator
Date: Tue, 21 Aug 2018 16:57:03 +0100
Message-ID: <153486702302.13066.15889029286852815542.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <153486700916.13066.12870860668352070081.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>

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 <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---

 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 (dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org)
+ *
+ * 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 <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>");
+
+#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())


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

  parent reply index

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-21 15:56 tpm: Provide a TPM access library David Howells
     [not found] ` <153486700916.13066.12870860668352070081.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2018-08-21 15:56   ` [PATCH 01/23] TPM: Add new TPMs to the tail of the list to prevent inadvertent change of dev David Howells
     [not found]     ` <153486701644.13066.13372706238885253812.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2018-08-21 18:30       ` Jason Gunthorpe
     [not found]         ` <20180821183004.GB25543-uk2M96/98Pc@public.gmane.org>
2018-08-24  6:24           ` Jarkko Sakkinen
     [not found]             ` <20180824062434.GB3584-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2018-08-24  6:25               ` Jarkko Sakkinen
     [not found]                 ` <20180824062557.GC3584-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2018-08-24 11:22                   ` Mimi Zohar
2018-08-24  6:19       ` Jarkko Sakkinen
2018-08-21 15:57   ` David Howells [this message]
     [not found]     ` <153486702302.13066.15889029286852815542.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2018-08-21 18:31       ` [PATCH 02/23] TPM: Provide a facility for a userspace TPM emulator Jason Gunthorpe
     [not found]         ` <20180821183140.GD25543-uk2M96/98Pc@public.gmane.org>
2018-08-24  6:29           ` Jarkko Sakkinen
2018-08-21 15:57   ` [PATCH 03/23] TPM: Provide a platform driver for the user emulator driver David Howells
     [not found]     ` <153486702979.13066.16900998092976336647.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2018-08-24  6:30       ` Jarkko Sakkinen
2018-08-21 15:57   ` [PATCH 04/23] TPM: Expose struct tpm_chip and related find_get and put functions David Howells
     [not found]     ` <153486703636.13066.16209594327379341518.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2018-08-21 18:31       ` Jason Gunthorpe
     [not found]     ` <20180821183108.GC25543-uk2M96/98Pc@public.gmane.org>
2018-08-21 18:35       ` David Howells
2018-08-21 15:57   ` [PATCH 05/23] TPM: Use struct tpm_chip rather than chip number as interface parameter David Howells
     [not found]     ` <153486704294.13066.8818198038331415342.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2018-08-24  7:42       ` Jarkko Sakkinen
2018-08-21 15:57   ` [PATCH 06/23] TPM: Move ordinal values from interface file to header with other ordinals David Howells
2018-08-21 15:57   ` [PATCH 07/23] TPM: Consolidate tpm_send(), transmit_cmd() and tpm_transmit() David Howells
2018-08-21 15:57   ` [PATCH 08/23] TPMLIB: Break TPM bits out of security/keys/trusted.c David Howells
     [not found]     ` <153486706322.13066.3105842100625841410.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2018-08-24  7:52       ` Jarkko Sakkinen
     [not found]         ` <20180824075227.GG3584-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2018-08-24  8:49           ` Jarkko Sakkinen
     [not found]         ` <20180824084930.GA10266-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2018-08-24  9:33           ` David Howells
     [not found]             ` <25340.1535103190-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2018-08-27  8:25               ` Jarkko Sakkinen
2018-08-21 15:57   ` [PATCH 09/23] TPMLIB: Do some source cleanups David Howells
2018-08-21 15:57   ` [PATCH 10/23] TPMLIB: Better format calls to TSS_*hmac*() David Howells
2018-08-21 15:58   ` [PATCH 11/23] TPMLIB: Put banner comments on public TPM library functions David Howells
2018-08-21 15:58   ` [PATCH 12/23] TPMLIB: Create tpm_{even, odd}_nonce structs to represent nonces David Howells
2018-08-21 15:58   ` [PATCH 13/23] TPMLIB: Rename store8() and storebytes() David Howells
2018-08-21 15:58   ` [PATCH 14/23] TPMLIB: Make store_s() take a void* data argument, not unsigned char* David Howells
2018-08-21 15:58   ` [PATCH 15/23] TPMLIB: Use __be32 rather than int32_t and use cpu_to_beX() and co David Howells
2018-08-21 15:58   ` [PATCH 16/23] TPMLIB: Put more comments into the HMAC generation functions David Howells
2018-08-21 15:58   ` [PATCH 17/23] TPMLIB: Provide a wrapper to load bytes out of the reply David Howells
2018-08-21 15:58   ` [PATCH 18/23] TPMLIB: Encapsulate XOR-based encryption with authkey derivative David Howells
2018-08-21 15:58   ` [PATCH 19/23] TPMLIB: Add some debugging code David Howells
2018-08-21 15:59   ` [PATCH 20/23] TPMLIB: Implement call to TPM_CreateWrapKey David Howells
2018-08-21 15:59   ` [PATCH 21/23] TPMLIB: Implement call to TPM_LoadKey2 David Howells
2018-08-21 15:59   ` [PATCH 22/23] TPMLIB: Provide call for TPM_FlushSpecific David Howells
2018-08-21 15:59   ` [PATCH 23/23] TPM: Add an asymmetric key subtype for handling TPM-based keys David Howells
2018-08-22 14:19   ` tpm: Provide a TPM access library Jarkko Sakkinen
     [not found] ` <20180822141956.GA28110-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2018-08-22 14:45   ` David Howells
     [not found]     ` <13611.1534949106-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2018-08-23 22:49       ` Jarkko Sakkinen

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=153486702302.13066.15889029286852815542.stgit@warthog.procyon.org.uk \
    --to=dhowells-h+wxahxf7alqt0dzr+alfa@public.gmane.org \
    --cc=denkenz-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org \
    --cc=jejb-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org \
    --cc=keyrings-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-integrity-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-security-module-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

tpmdd-devel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/tpmdd-devel/0 tpmdd-devel/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 tpmdd-devel tpmdd-devel/ https://lore.kernel.org/tpmdd-devel \
		tpmdd-devel@lists.sourceforge.net tpmdd-devel@archiver.kernel.org
	public-inbox-index tpmdd-devel


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/net.sourceforge.lists.tpmdd-devel


AGPL code for this site: git clone https://public-inbox.org/ public-inbox