All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] TPM: Let the tpm char device be openable multiple times
@ 2012-09-30 23:33 Jason Gunthorpe
  2012-10-01  9:07 ` [tpmdd-devel] " Peter.Huewe
  2012-10-10 16:33 ` Kent Yoder
  0 siblings, 2 replies; 13+ messages in thread
From: Jason Gunthorpe @ 2012-09-30 23:33 UTC (permalink / raw)
  To: linux-kernel, tpmdd-devel

How to use the TPM is really a user space policy choice, if the
environment wants to use middleware then fine, but it is possible to
make correct TPM apps without using middleware.

So, remove the kernel restriction that only one process may open the TPM.
- TPM low level functions (in kernel users) are already locked proprely
  and can run in parallel with the user space interface anyhow.
- Move the user space data buffer and related goop into a
  struct tpm_file, create one struct tpm_file per open file.

Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
---
 drivers/char/tpm/tpm.c |   97 +++++++++++++++++++++---------------------------
 drivers/char/tpm/tpm.h |   23 ++++++-----
 2 files changed, 55 insertions(+), 65 deletions(-)

This is rebase, retest, resend of a patch I sent two years ago. The
discussion on that earlier patch fizzled out. Resending incase there
is renewed interest :)

diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 60e8442..a161be9 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -33,7 +33,6 @@
 
 enum tpm_const {
 	TPM_MINOR = 224,	/* officially assigned */
-	TPM_BUFSIZE = 4096,
 	TPM_NUM_DEVICES = 256,
 };
 
@@ -333,19 +332,19 @@ static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
 
 static void user_reader_timeout(unsigned long ptr)
 {
-	struct tpm_chip *chip = (struct tpm_chip *) ptr;
+	struct tpm_file *fl = (struct tpm_file *) ptr;
 
-	schedule_work(&chip->work);
+	schedule_work(&fl->work);
 }
 
 static void timeout_work(struct work_struct *work)
 {
-	struct tpm_chip *chip = container_of(work, struct tpm_chip, work);
+	struct tpm_file *fl = container_of(work, struct tpm_file, work);
 
-	mutex_lock(&chip->buffer_mutex);
-	atomic_set(&chip->data_pending, 0);
-	memset(chip->data_buffer, 0, TPM_BUFSIZE);
-	mutex_unlock(&chip->buffer_mutex);
+	mutex_lock(&fl->buffer_mutex);
+	atomic_set(&fl->data_pending, 0);
+	memset(fl->data_bufferx, 0, sizeof(fl->data_bufferx));
+	mutex_unlock(&fl->buffer_mutex);
 }
 
 /*
@@ -384,9 +383,6 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 	u32 count, ordinal;
 	unsigned long stop;
 
-	if (bufsiz > TPM_BUFSIZE)
-		bufsiz = TPM_BUFSIZE;
-
 	count = be32_to_cpu(*((__be32 *) (buf + 2)));
 	ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
 	if (count == 0)
@@ -1161,6 +1157,7 @@ int tpm_open(struct inode *inode, struct file *file)
 {
 	int minor = iminor(inode);
 	struct tpm_chip *chip = NULL, *pos;
+	struct tpm_file *fl;
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
@@ -1175,22 +1172,19 @@ int tpm_open(struct inode *inode, struct file *file)
 	if (!chip)
 		return -ENODEV;
 
-	if (test_and_set_bit(0, &chip->is_open)) {
-		dev_dbg(chip->dev, "Another process owns this TPM\n");
-		put_device(chip->dev);
-		return -EBUSY;
-	}
-
-	chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
-	if (chip->data_buffer == NULL) {
-		clear_bit(0, &chip->is_open);
+	fl = kzalloc(sizeof(*fl), GFP_KERNEL);
+	if (fl == NULL) {
 		put_device(chip->dev);
 		return -ENOMEM;
 	}
 
-	atomic_set(&chip->data_pending, 0);
+	fl->chip = chip;
+	mutex_init(&fl->buffer_mutex);
+	setup_timer(&fl->user_read_timer, user_reader_timeout,
+			(unsigned long)fl);
+	INIT_WORK(&fl->work, timeout_work);
 
-	file->private_data = chip;
+	file->private_data = fl;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(tpm_open);
@@ -1200,14 +1194,14 @@ EXPORT_SYMBOL_GPL(tpm_open);
  */
 int tpm_release(struct inode *inode, struct file *file)
 {
-	struct tpm_chip *chip = file->private_data;
+	struct tpm_file *fl = file->private_data;
+	struct tpm_chip *chip = fl->chip;
 
-	del_singleshot_timer_sync(&chip->user_read_timer);
-	flush_work_sync(&chip->work);
+	del_singleshot_timer_sync(&fl->user_read_timer);
+	flush_work_sync(&fl->work);
+	mutex_destroy(&fl->buffer_mutex);
+	kfree(file->private_data);
 	file->private_data = NULL;
-	atomic_set(&chip->data_pending, 0);
-	kfree(chip->data_buffer);
-	clear_bit(0, &chip->is_open);
 	put_device(chip->dev);
 	return 0;
 }
@@ -1216,33 +1210,33 @@ EXPORT_SYMBOL_GPL(tpm_release);
 ssize_t tpm_write(struct file *file, const char __user *buf,
 		  size_t size, loff_t *off)
 {
-	struct tpm_chip *chip = file->private_data;
+	struct tpm_file *fl = file->private_data;
 	size_t in_size = size, out_size;
 
 	/* cannot perform a write until the read has cleared
 	   either via tpm_read or a user_read_timer timeout */
-	while (atomic_read(&chip->data_pending) != 0)
+	while (atomic_read(&fl->data_pending) != 0)
 		msleep(TPM_TIMEOUT);
 
-	mutex_lock(&chip->buffer_mutex);
+	mutex_lock(&fl->buffer_mutex);
 
-	if (in_size > TPM_BUFSIZE)
-		in_size = TPM_BUFSIZE;
+	in_size = min(sizeof(fl->data_bufferx), in_size);
 
 	if (copy_from_user
-	    (chip->data_buffer, (void __user *) buf, in_size)) {
-		mutex_unlock(&chip->buffer_mutex);
+	    (fl->data_bufferx, (void __user *) buf, in_size)) {
+		mutex_unlock(&fl->buffer_mutex);
 		return -EFAULT;
 	}
 
 	/* atomic tpm command send and result receive */
-	out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
+	out_size = tpm_transmit(fl->chip, fl->data_bufferx,
+				sizeof(fl->data_bufferx));
 
-	atomic_set(&chip->data_pending, out_size);
-	mutex_unlock(&chip->buffer_mutex);
+	atomic_set(&fl->data_pending, out_size);
+	mutex_unlock(&fl->buffer_mutex);
 
 	/* Set a timeout by which the reader must come claim the result */
-	mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
+	mod_timer(&fl->user_read_timer, jiffies + (60 * HZ));
 
 	return in_size;
 }
@@ -1251,26 +1245,25 @@ EXPORT_SYMBOL_GPL(tpm_write);
 ssize_t tpm_read(struct file *file, char __user *buf,
 		 size_t size, loff_t *off)
 {
-	struct tpm_chip *chip = file->private_data;
+	struct tpm_file *fl = file->private_data;
 	ssize_t ret_size;
 	int rc;
 
-	del_singleshot_timer_sync(&chip->user_read_timer);
-	flush_work_sync(&chip->work);
-	ret_size = atomic_read(&chip->data_pending);
-	atomic_set(&chip->data_pending, 0);
+	del_singleshot_timer_sync(&fl->user_read_timer);
+	flush_work_sync(&fl->work);
+	ret_size = atomic_read(&fl->data_pending);
+	atomic_set(&fl->data_pending, 0);
 	if (ret_size > 0) {	/* relay data */
 		ssize_t orig_ret_size = ret_size;
 		if (size < ret_size)
 			ret_size = size;
 
-		mutex_lock(&chip->buffer_mutex);
-		rc = copy_to_user(buf, chip->data_buffer, ret_size);
-		memset(chip->data_buffer, 0, orig_ret_size);
+		mutex_lock(&fl->buffer_mutex);
+		rc = copy_to_user(buf, fl->data_bufferx, ret_size);
+		memset(fl->data_bufferx, 0, orig_ret_size);
 		if (rc)
 			ret_size = -EFAULT;
-
-		mutex_unlock(&chip->buffer_mutex);
+		mutex_unlock(&fl->buffer_mutex);
 	}
 
 	return ret_size;
@@ -1413,15 +1406,9 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
 	if (chip == NULL || devname == NULL)
 		goto out_free;
 
-	mutex_init(&chip->buffer_mutex);
 	mutex_init(&chip->tpm_mutex);
 	INIT_LIST_HEAD(&chip->list);
 
-	INIT_WORK(&chip->work, timeout_work);
-
-	setup_timer(&chip->user_read_timer, user_reader_timeout,
-			(unsigned long)chip);
-
 	memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
 
 	chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 2d583ef..58bde7c 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -106,16 +106,6 @@ struct tpm_chip {
 	struct device *dev;	/* Device stuff */
 
 	int dev_num;		/* /dev/tpm# */
-	unsigned long is_open;	/* only one allowed */
-	int time_expired;
-
-	/* Data passed to and from the tpm via the read/write calls */
-	u8 *data_buffer;
-	atomic_t data_pending;
-	struct mutex buffer_mutex;
-
-	struct timer_list user_read_timer;	/* user needs to claim result */
-	struct work_struct work;
 	struct mutex tpm_mutex;	/* tpm is processing */
 
 	struct tpm_vendor_specific vendor;
@@ -132,6 +122,19 @@ static inline void tpm_chip_put(struct tpm_chip *chip)
 {
 	module_put(chip->dev->driver->owner);
 }
+/* Private data structure for struct file */
+struct tpm_file {
+	struct tpm_chip *chip;
+
+	/* Data passed to and from the tpm via the read/write calls */
+	atomic_t data_pending;
+	struct mutex buffer_mutex;
+
+	struct timer_list user_read_timer;	/* user needs to claim result */
+	struct work_struct work;
+
+	u8 data_bufferx[2048];
+};
 
 static inline int tpm_read_index(int base, int index)
 {
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* RE: [tpmdd-devel] [PATCH] TPM: Let the tpm char device be openable multiple times
  2012-09-30 23:33 [PATCH] TPM: Let the tpm char device be openable multiple times Jason Gunthorpe
@ 2012-10-01  9:07 ` Peter.Huewe
  2012-10-01 16:09   ` Jason Gunthorpe
  2012-10-10 16:33 ` Kent Yoder
  1 sibling, 1 reply; 13+ messages in thread
From: Peter.Huewe @ 2012-10-01  9:07 UTC (permalink / raw)
  To: jgunthorpe, linux-kernel, tpmdd-devel

Hi Jason,

one quick question:
-	TPM_BUFSIZE = 4096,
[...]
+	u8 data_bufferx[2048];

Why do you half the buffer size?

Thanks,
Peter

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [tpmdd-devel] [PATCH] TPM: Let the tpm char device be openable multiple times
  2012-10-01  9:07 ` [tpmdd-devel] " Peter.Huewe
@ 2012-10-01 16:09   ` Jason Gunthorpe
  0 siblings, 0 replies; 13+ messages in thread
From: Jason Gunthorpe @ 2012-10-01 16:09 UTC (permalink / raw)
  To: Peter.Huewe; +Cc: linux-kernel, tpmdd-devel

On Mon, Oct 01, 2012 at 09:07:11AM +0000, Peter.Huewe@infineon.com wrote:
> Hi Jason,
> 
> one quick question:
> -	TPM_BUFSIZE = 4096,
> [...]
> +	u8 data_bufferx[2048];
> 
> Why do you half the buffer size?

I missed 7f366784f5c2b8fc065 when I rebased the patch, thanks!

Jason

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] TPM: Let the tpm char device be openable multiple times
  2012-09-30 23:33 [PATCH] TPM: Let the tpm char device be openable multiple times Jason Gunthorpe
  2012-10-01  9:07 ` [tpmdd-devel] " Peter.Huewe
@ 2012-10-10 16:33 ` Kent Yoder
  2012-10-12 20:56   ` Jason Gunthorpe
  1 sibling, 1 reply; 13+ messages in thread
From: Kent Yoder @ 2012-10-10 16:33 UTC (permalink / raw)
  To: Jason Gunthorpe; +Cc: linux-kernel, tpmdd-devel

On Sun, Sep 30, 2012 at 05:33:45PM -0600, Jason Gunthorpe wrote:
> How to use the TPM is really a user space policy choice, if the
> environment wants to use middleware then fine, but it is possible to
> make correct TPM apps without using middleware.

  I'm not sure how I feel about this. The single open rule doesn't
prevent replacement of the middleware, it just requires a open()/close()
around any use of the device node. That seems simple enough to me. In
places where you do want TSS to be the sole opener, it can't enforce
that rule itself, so I think we need to preserve the option of a single
open at a minimum.

Kent

> So, remove the kernel restriction that only one process may open the TPM.
> - TPM low level functions (in kernel users) are already locked proprely
>   and can run in parallel with the user space interface anyhow.
> - Move the user space data buffer and related goop into a
>   struct tpm_file, create one struct tpm_file per open file.
> 
> Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
> ---
>  drivers/char/tpm/tpm.c |   97 +++++++++++++++++++++---------------------------
>  drivers/char/tpm/tpm.h |   23 ++++++-----
>  2 files changed, 55 insertions(+), 65 deletions(-)
> 
> This is rebase, retest, resend of a patch I sent two years ago. The
> discussion on that earlier patch fizzled out. Resending incase there
> is renewed interest :)
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] TPM: Let the tpm char device be openable multiple times
  2012-10-10 16:33 ` Kent Yoder
@ 2012-10-12 20:56   ` Jason Gunthorpe
  2012-10-15  8:35     ` [tpmdd-devel] " Peter.Huewe
  2012-10-15 22:02     ` Kent Yoder
  0 siblings, 2 replies; 13+ messages in thread
From: Jason Gunthorpe @ 2012-10-12 20:56 UTC (permalink / raw)
  To: Kent Yoder; +Cc: linux-kernel, tpmdd-devel

On Wed, Oct 10, 2012 at 11:33:24AM -0500, Kent Yoder wrote:
> On Sun, Sep 30, 2012 at 05:33:45PM -0600, Jason Gunthorpe wrote:
> > How to use the TPM is really a user space policy choice, if the
> > environment wants to use middleware then fine, but it is possible to
> > make correct TPM apps without using middleware.
> 
>   I'm not sure how I feel about this. The single open rule doesn't
> prevent replacement of the middleware, it just requires a
> open()/close()

I'm not interested in replacing the middleware, our designs do not use
any middleware and several processes are required to access the TPM at
once.

Using open/close is an interesting idea, but it wouldn't work. open()
is coded to return EBUSY if another process has it open, rather than
block, and spinning on open would be unacceptable.

> around any use of the device node. That seems simple enough to me. In
> places where you do want TSS to be the sole opener, it can't enforce
> that rule itself, so I think we need to preserve the option of a single
> open at a minimum.

I agree, but I'm not sure how to expose this function? I've seen other
places abuse O_EXCL for this, but that would not be compatible with
existing implementations.

Three things come to mind
 - O_EXCL means the open only succeeds if it the only open and
   prevents others (not compatible)
 - Some other O_ flag is hijacked to mean the opposite of the above
   (yuk)
 - A sysfs flag is added to turn on the new O_EXCL behavior

What do you think?

Jason

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [tpmdd-devel] [PATCH] TPM: Let the tpm char device be openable multiple times
  2012-10-12 20:56   ` Jason Gunthorpe
@ 2012-10-15  8:35     ` Peter.Huewe
  2012-10-15 16:39       ` Jason Gunthorpe
  2012-10-15 22:02     ` Kent Yoder
  1 sibling, 1 reply; 13+ messages in thread
From: Peter.Huewe @ 2012-10-15  8:35 UTC (permalink / raw)
  To: jgunthorpe, key; +Cc: tpmdd-devel, linux-kernel

-----Original Message-----
> From: Jason Gunthorpe [mailto:jgunthorpe@obsidianresearch.com] 

> Using open/close is an interesting idea, but it wouldn't work. open()
> is coded to return EBUSY if another process has it open, rather than
> block, and spinning on open would be unacceptable.

Hmm, maybe write a small pass through program which opens /dev/tpm once and accepts its data via a socket or pipe?

Thanks,
Peter



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [tpmdd-devel] [PATCH] TPM: Let the tpm char device be openable multiple times
  2012-10-15  8:35     ` [tpmdd-devel] " Peter.Huewe
@ 2012-10-15 16:39       ` Jason Gunthorpe
  2012-10-15 16:49         ` Alan Cox
  0 siblings, 1 reply; 13+ messages in thread
From: Jason Gunthorpe @ 2012-10-15 16:39 UTC (permalink / raw)
  To: Peter.Huewe; +Cc: key, tpmdd-devel, linux-kernel

On Mon, Oct 15, 2012 at 08:35:09AM +0000, Peter.Huewe@infineon.com wrote:
> > From: Jason Gunthorpe [mailto:jgunthorpe@obsidianresearch.com] 
> 
> > Using open/close is an interesting idea, but it wouldn't work. open()
> > is coded to return EBUSY if another process has it open, rather than
> > block, and spinning on open would be unacceptable.
> 
> Hmm, maybe write a small pass through program which opens /dev/tpm
> once and accepts its data via a socket or pipe?

I believe the kernel should not be enforcing this kind of policy into
userspace. Plus, some of our embedded system are memory constrained
so an unnecessary process is not welcome..

Jason

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [tpmdd-devel] [PATCH] TPM: Let the tpm char device be openable multiple times
  2012-10-15 16:39       ` Jason Gunthorpe
@ 2012-10-15 16:49         ` Alan Cox
  2012-10-15 16:56           ` Jason Gunthorpe
  0 siblings, 1 reply; 13+ messages in thread
From: Alan Cox @ 2012-10-15 16:49 UTC (permalink / raw)
  To: Jason Gunthorpe; +Cc: Peter.Huewe, key, tpmdd-devel, linux-kernel

On Mon, 15 Oct 2012 10:39:45 -0600
Jason Gunthorpe <jgunthorpe@obsidianresearch.com> wrote:

> On Mon, Oct 15, 2012 at 08:35:09AM +0000, Peter.Huewe@infineon.com wrote:
> > > From: Jason Gunthorpe [mailto:jgunthorpe@obsidianresearch.com] 
> > 
> > > Using open/close is an interesting idea, but it wouldn't work. open()
> > > is coded to return EBUSY if another process has it open, rather than
> > > block, and spinning on open would be unacceptable.
> > 
> > Hmm, maybe write a small pass through program which opens /dev/tpm
> > once and accepts its data via a socket or pipe?
> 
> I believe the kernel should not be enforcing this kind of policy into
> userspace. Plus, some of our embedded system are memory constrained
> so an unnecessary process is not welcome..

Sane device drivers for devices where contention is meaningful block on
an open that is busy, or return an error if the O_NONBLOCK option is
specified. That's the normal case.

Alan

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [tpmdd-devel] [PATCH] TPM: Let the tpm char device be openable multiple times
  2012-10-15 16:49         ` Alan Cox
@ 2012-10-15 16:56           ` Jason Gunthorpe
  0 siblings, 0 replies; 13+ messages in thread
From: Jason Gunthorpe @ 2012-10-15 16:56 UTC (permalink / raw)
  To: Alan Cox; +Cc: Peter.Huewe, key, tpmdd-devel, linux-kernel

On Mon, Oct 15, 2012 at 05:49:22PM +0100, Alan Cox wrote:

> > > > Using open/close is an interesting idea, but it wouldn't work. open()
> > > > is coded to return EBUSY if another process has it open, rather than
> > > > block, and spinning on open would be unacceptable.
> > > 
> > > Hmm, maybe write a small pass through program which opens /dev/tpm
> > > once and accepts its data via a socket or pipe?
> > 
> > I believe the kernel should not be enforcing this kind of policy into
> > userspace. Plus, some of our embedded system are memory constrained
> > so an unnecessary process is not welcome..
> 
> Sane device drivers for devices where contention is meaningful block on
> an open that is busy, or return an error if the O_NONBLOCK option is
> specified. That's the normal case.

We have here a situation where there is no kernel or hardware
requirement for exclusivity, but the current driver enforces it, for
userspace only. Today the kernel and user space can access the TPM
device concurrently.

So, I would like to migrate the userspace interface to allow
non-exclusivity, but how do we do this?

Jason

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] TPM: Let the tpm char device be openable multiple times
  2012-10-12 20:56   ` Jason Gunthorpe
  2012-10-15  8:35     ` [tpmdd-devel] " Peter.Huewe
@ 2012-10-15 22:02     ` Kent Yoder
  1 sibling, 0 replies; 13+ messages in thread
From: Kent Yoder @ 2012-10-15 22:02 UTC (permalink / raw)
  To: Jason Gunthorpe; +Cc: linux-kernel, tpmdd-devel

> Using open/close is an interesting idea, but it wouldn't work. open()
> is coded to return EBUSY if another process has it open, rather than
> block, and spinning on open would be unacceptable.

  I'm trying to imagine when spinning would be unacceptable? Keygen
could take several seconds, regardless of whether you can get the
command to the chip right away or not...

> > around any use of the device node. That seems simple enough to me. In
> > places where you do want TSS to be the sole opener, it can't enforce
> > that rule itself, so I think we need to preserve the option of a single
> > open at a minimum.
> 
> I agree, but I'm not sure how to expose this function? I've seen other
> places abuse O_EXCL for this, but that would not be compatible with
> existing implementations.
> 
> Three things come to mind
>  - O_EXCL means the open only succeeds if it the only open and
>    prevents others (not compatible)
>  - Some other O_ flag is hijacked to mean the opposite of the above
>    (yuk)
>  - A sysfs flag is added to turn on the new O_EXCL behavior
> 
> What do you think?

  My first thought was a sysfs var to turn off exclusivity that
defaulted to today's behavior.

Kent

> Jason
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] TPM: Let the tpm char device be openable multiple times
  2009-11-03 10:43 ` Alan Cox
@ 2009-11-03 17:15   ` Jason Gunthorpe
  0 siblings, 0 replies; 13+ messages in thread
From: Jason Gunthorpe @ 2009-11-03 17:15 UTC (permalink / raw)
  To: Alan Cox; +Cc: tpmdd-devel, linux-kernel, srajiv

On Tue, Nov 03, 2009 at 10:43:52AM +0000, Alan Cox wrote:
> > - Move the user space data buffer and related goop into a
> >   struct tpm_file, create one struct tpm_file per open file.
> 
> Is that really sufficient ?

Yes, I think so. Basically, all I did was take the per-device locking
that was already there and make it per-file. The locking hasn't
changed. If there was a multi-threading bug in the old code, it is
still in this version - but I looked for such a thing and didn't
see anything.

> You can open a file once, dup it (or inherit it and get multiple callers
> from the same file handle. Ditto consider threated apps

Yes, I did, I think it is OK. All the operations involving the file's
buffer are atomic or protected by a per-file mutex. Do you see
something specific?

It would be dangerous to do that anyhow, the way the TPM interface
works requires matched write/read pairs. The driver has a hacky way to
halt a write until the matching write happens, but it is based on
timeouts and probably isn't 100% reliable.

Thanks,
Jason

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] TPM: Let the tpm char device be openable multiple times
  2009-11-03  0:35 Jason Gunthorpe
@ 2009-11-03 10:43 ` Alan Cox
  2009-11-03 17:15   ` Jason Gunthorpe
  0 siblings, 1 reply; 13+ messages in thread
From: Alan Cox @ 2009-11-03 10:43 UTC (permalink / raw)
  To: Jason Gunthorpe; +Cc: tpmdd-devel, linux-kernel, srajiv

> - Move the user space data buffer and related goop into a
>   struct tpm_file, create one struct tpm_file per open file.

Is that really sufficient ?

You can open a file once, dup it (or inherit it and get multiple callers
from the same file handle. Ditto consider threated apps

Alan

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH] TPM: Let the tpm char device be openable multiple times
@ 2009-11-03  0:35 Jason Gunthorpe
  2009-11-03 10:43 ` Alan Cox
  0 siblings, 1 reply; 13+ messages in thread
From: Jason Gunthorpe @ 2009-11-03  0:35 UTC (permalink / raw)
  To: tpmdd-devel, linux-kernel, srajiv

How to use the TPM is really a user space policy choice, if the
environment wants to use middleware then fine, but it is possible to
make correct TPM apps without using middleware.

So, remove the kernel restriction that only one process may open the TPM.
- TPM low level functions (in kernel users) are already locked proprely
  and can run in parallel with the user space interface anyhow.
- Move the user space data buffer and related goop into a
  struct tpm_file, create one struct tpm_file per open file.

Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
---
 drivers/char/tpm/tpm.c |   87 +++++++++++++++++++++--------------------------
 drivers/char/tpm/tpm.h |   24 ++++++++-----
 2 files changed, 53 insertions(+), 58 deletions(-)

Mainly for embedded where the middleware is perhaps not appropriate.

Tested with a winbond TPM and tpm_tis.

diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 196bc48..0625404 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -31,7 +31,6 @@
 
 enum tpm_const {
 	TPM_MINOR = 224,	/* officially assigned */
-	TPM_BUFSIZE = 2048,
 	TPM_NUM_DEVICES = 256,
 };
 
@@ -321,19 +320,19 @@ static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
 
 static void user_reader_timeout(unsigned long ptr)
 {
-	struct tpm_chip *chip = (struct tpm_chip *) ptr;
+	struct tpm_file *fl = (struct tpm_file *) ptr;
 
-	schedule_work(&chip->work);
+	schedule_work(&fl->work);
 }
 
 static void timeout_work(void *ptr)
 {
-	struct tpm_chip *chip = ptr;
+	struct tpm_file *fl = ptr;
 
-	mutex_lock(&chip->buffer_mutex);
-	atomic_set(&chip->data_pending, 0);
-	memset(chip->data_buffer, 0, TPM_BUFSIZE);
-	mutex_unlock(&chip->buffer_mutex);
+	mutex_lock(&fl->buffer_mutex);
+	atomic_set(&fl->data_pending, 0);
+	memset(fl->data_bufferx, 0, sizeof(fl->data_bufferx));
+	mutex_unlock(&fl->buffer_mutex);
 }
 
 /*
@@ -962,6 +961,7 @@ int tpm_open(struct inode *inode, struct file *file)
 {
 	int minor = iminor(inode);
 	struct tpm_chip *chip = NULL, *pos;
+	struct tpm_file *fl;
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
@@ -976,22 +976,19 @@ int tpm_open(struct inode *inode, struct file *file)
 	if (!chip)
 		return -ENODEV;
 
-	if (test_and_set_bit(0, &chip->is_open)) {
-		dev_dbg(chip->dev, "Another process owns this TPM\n");
-		put_device(chip->dev);
-		return -EBUSY;
-	}
-
-	chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
-	if (chip->data_buffer == NULL) {
-		clear_bit(0, &chip->is_open);
+	fl = kzalloc(sizeof(*fl), GFP_KERNEL);
+	if (fl == NULL) {
 		put_device(chip->dev);
 		return -ENOMEM;
 	}
 
-	atomic_set(&chip->data_pending, 0);
+	fl->chip = chip;
+	mutex_init(&fl->buffer_mutex);
+	setup_timer(&fl->user_read_timer, user_reader_timeout,
+			(unsigned long)fl);
+	INIT_WORK(&fl->work, timeout_work, fl);
 
-	file->private_data = chip;
+	file->private_data = fl;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(tpm_open);
@@ -1001,14 +998,14 @@ EXPORT_SYMBOL_GPL(tpm_open);
  */
 int tpm_release(struct inode *inode, struct file *file)
 {
-	struct tpm_chip *chip = file->private_data;
+	struct tpm_file *fl = file->private_data;
+	struct tpm_chip *chip = fl->chip;
 
-	del_singleshot_timer_sync(&chip->user_read_timer);
+	del_singleshot_timer_sync(&fl->user_read_timer);
 	flush_scheduled_work();
+	mutex_destroy(&fl->buffer_mutex);
+	kfree(file->private_data);
 	file->private_data = NULL;
-	atomic_set(&chip->data_pending, 0);
-	kfree(chip->data_buffer);
-	clear_bit(0, &chip->is_open);
 	put_device(chip->dev);
 	return 0;
 }
@@ -1017,33 +1014,33 @@ EXPORT_SYMBOL_GPL(tpm_release);
 ssize_t tpm_write(struct file *file, const char __user *buf,
 		  size_t size, loff_t *off)
 {
-	struct tpm_chip *chip = file->private_data;
+	struct tpm_file *fl = file->private_data;
 	size_t in_size = size, out_size;
 
 	/* cannot perform a write until the read has cleared
 	   either via tpm_read or a user_read_timer timeout */
-	while (atomic_read(&chip->data_pending) != 0)
+	while (atomic_read(&fl->data_pending) != 0)
 		msleep(TPM_TIMEOUT);
 
-	mutex_lock(&chip->buffer_mutex);
+	mutex_lock(&fl->buffer_mutex);
 
-	if (in_size > TPM_BUFSIZE)
-		in_size = TPM_BUFSIZE;
+	in_size = min(sizeof(fl->data_bufferx), in_size);
 
 	if (copy_from_user
-	    (chip->data_buffer, (void __user *) buf, in_size)) {
-		mutex_unlock(&chip->buffer_mutex);
+	    (fl->data_bufferx, (void __user *) buf, in_size)) {
+		mutex_unlock(&fl->buffer_mutex);
 		return -EFAULT;
 	}
 
 	/* atomic tpm command send and result receive */
-	out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
+	out_size = tpm_transmit(fl->chip, fl->data_bufferx,
+				sizeof(fl->data_bufferx));
 
-	atomic_set(&chip->data_pending, out_size);
-	mutex_unlock(&chip->buffer_mutex);
+	atomic_set(&fl->data_pending, out_size);
+	mutex_unlock(&fl->buffer_mutex);
 
 	/* Set a timeout by which the reader must come claim the result */
-	mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
+	mod_timer(&fl->user_read_timer, jiffies + (60 * HZ));
 
 	return in_size;
 }
@@ -1052,21 +1049,21 @@ EXPORT_SYMBOL_GPL(tpm_write);
 ssize_t tpm_read(struct file *file, char __user *buf,
 		 size_t size, loff_t *off)
 {
-	struct tpm_chip *chip = file->private_data;
+	struct tpm_file *fl = file->private_data;
 	ssize_t ret_size;
 
-	del_singleshot_timer_sync(&chip->user_read_timer);
+	del_singleshot_timer_sync(&fl->user_read_timer);
 	flush_scheduled_work();
-	ret_size = atomic_read(&chip->data_pending);
-	atomic_set(&chip->data_pending, 0);
+	ret_size = atomic_read(&fl->data_pending);
+	atomic_set(&fl->data_pending, 0);
 	if (ret_size > 0) {	/* relay data */
 		if (size < ret_size)
 			ret_size = size;
 
-		mutex_lock(&chip->buffer_mutex);
-		if (copy_to_user(buf, chip->data_buffer, ret_size))
+		mutex_lock(&fl->buffer_mutex);
+		if (copy_to_user(buf, fl->data_bufferx, ret_size))
 			ret_size = -EFAULT;
-		mutex_unlock(&chip->buffer_mutex);
+		mutex_unlock(&fl->buffer_mutex);
 	}
 
 	return ret_size;
@@ -1182,15 +1179,9 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
 	if (chip == NULL || devname == NULL)
 		goto out_free;
 
-	mutex_init(&chip->buffer_mutex);
 	mutex_init(&chip->tpm_mutex);
 	INIT_LIST_HEAD(&chip->list);
 
-	INIT_WORK(&chip->work, timeout_work, chip);
-
-	setup_timer(&chip->user_read_timer, user_reader_timeout,
-			(unsigned long)chip);
-
 	memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
 
 	chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 8e00b4d..0fa262d 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -91,16 +91,6 @@ struct tpm_chip {
 	struct device *dev;	/* Device stuff */
 
 	int dev_num;		/* /dev/tpm# */
-	unsigned long is_open;	/* only one allowed */
-	int time_expired;
-
-	/* Data passed to and from the tpm via the read/write calls */
-	u8 *data_buffer;
-	atomic_t data_pending;
-	struct mutex buffer_mutex;
-
-	struct timer_list user_read_timer;	/* user needs to claim result */
-	struct work_struct work;
 	struct mutex tpm_mutex;	/* tpm is processing */
 
 	struct tpm_vendor_specific vendor;
@@ -113,6 +103,20 @@ struct tpm_chip {
 
 #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
 
+/* Private data structure for struct file */
+struct tpm_file {
+	struct tpm_chip *chip;
+
+	/* Data passed to and from the tpm via the read/write calls */
+	atomic_t data_pending;
+	struct mutex buffer_mutex;
+
+	struct timer_list user_read_timer;	/* user needs to claim result */
+	struct work_struct work;
+
+	u8 data_bufferx[2048];
+};
+
 static inline int tpm_read_index(int base, int index)
 {
 	outb(index, base);
-- 
1.5.4.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2012-10-15 22:02 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-30 23:33 [PATCH] TPM: Let the tpm char device be openable multiple times Jason Gunthorpe
2012-10-01  9:07 ` [tpmdd-devel] " Peter.Huewe
2012-10-01 16:09   ` Jason Gunthorpe
2012-10-10 16:33 ` Kent Yoder
2012-10-12 20:56   ` Jason Gunthorpe
2012-10-15  8:35     ` [tpmdd-devel] " Peter.Huewe
2012-10-15 16:39       ` Jason Gunthorpe
2012-10-15 16:49         ` Alan Cox
2012-10-15 16:56           ` Jason Gunthorpe
2012-10-15 22:02     ` Kent Yoder
  -- strict thread matches above, loose matches on Subject: below --
2009-11-03  0:35 Jason Gunthorpe
2009-11-03 10:43 ` Alan Cox
2009-11-03 17:15   ` Jason Gunthorpe

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.