Re: [tpmdd-devel] [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-02-01 Thread Jarkko Sakkinen
On Tue, Jan 31, 2017 at 03:24:44PM -0800, James Bottomley wrote:
> On Mon, 2017-01-30 at 00:02 +0200, Jarkko Sakkinen wrote:
> > On Fri, Jan 27, 2017 at 04:33:54PM -0800, James Bottomley wrote:
> > > In a TPM2, sessions can be globally exhausted once there are
> > > TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context
> > > saved).
> > > The Strategy for handling this is to keep a global count of all the
> > > sessions along with their creation time.  Then if we see the TPM
> > > run
> > > out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for
> > > one
> > > to become free, but if it doesn't, we forcibly evict an existing
> > > one.
> > > The eviction strategy waits until the current command is repeated
> > > to
> > > evict the session which should guarantee there is an available
> > > slot.
> > > 
> > > On the force eviction case, we make sure that the victim session is
> > > at
> > > least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue
> > > for
> > > session slots is a FIFO one, ensuring that once we run out of
> > > sessions, everyone will get a session in a bounded time and once
> > > they
> > > get one, they'll have SESSION_TIMEOUT to use it before it may be
> > > subject to eviction.
> > > 
> > > Signed-off-by: James Bottomley <
> > > james.bottom...@hansenpartnership.com>
> > > ---
> > >  drivers/char/tpm/tpm-chip.c   |   1 +
> > >  drivers/char/tpm/tpm.h|  39 +++-
> > >  drivers/char/tpm/tpm2-cmd.c   |  15 +++
> > >  drivers/char/tpm/tpm2-space.c | 209
> > > --
> > >  drivers/char/tpm/tpms-dev.c   |  17 +++-
> > >  5 files changed, 271 insertions(+), 10 deletions(-)
> > > 
> > > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm
> > > -chip.c
> > > index 6282ad0..150c6b8 100644
> > > --- a/drivers/char/tpm/tpm-chip.c
> > > +++ b/drivers/char/tpm/tpm-chip.c
> > > @@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device
> > > *pdev,
> > >  
> > >   mutex_init(>tpm_mutex);
> > >   init_rwsem(>ops_sem);
> > > + init_waitqueue_head(>session_wait);
> > >  
> > >   chip->ops = ops;
> > >  
> > > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> > > index 10c57b9..658e5e2 100644
> > > --- a/drivers/char/tpm/tpm.h
> > > +++ b/drivers/char/tpm/tpm.h
> > > @@ -95,7 +95,8 @@ enum tpm2_return_codes {
> > >   TPM2_RC_HANDLE  = 0x008B,
> > >   TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
> > >   TPM2_RC_DISABLED= 0x0120,
> > > - TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> > > + TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
> > > + TPM2_RC_TESTING = 0x090A,
> > >   TPM2_RC_REFERENCE_H0= 0x0910,
> > >  };
> > >  
> > > @@ -139,7 +140,8 @@ enum tpm2_capabilities {
> > >  };
> > >  
> > >  enum tpm2_properties {
> > > - TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > > + TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > > + TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
> > >  };
> > >  
> > >  enum tpm2_startup_types {
> > > @@ -163,8 +165,24 @@ struct tpm_space {
> > >   u8 *context_buf;
> > >   u32 session_tbl[3];
> > >   u8 *session_buf;
> > > + u32 reserved_handle;
> > >  };
> > >  
> > > +#define TPM2_HANDLE_FORCE_EVICT 0x
> > > +
> > > +static inline void tpm2_session_force_evict(struct tpm_space
> > > *space)
> > > +{
> > > + /* if reserved handle is not empty, we already have a
> > > +  * session for eviction, so no need to force one
> > > +  */
> > > + if (space->reserved_handle == 0)
> > > + space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
> > > +}
> > > +static inline bool tpm2_is_session_force_evict(struct tpm_space
> > > *space)
> > > +{
> > > + return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
> > > +}
> > > +
> > >  enum tpm_chip_flags {
> > >   TPM_CHIP_FLAG_TPM2  = BIT(1),
> > >   TPM_CHIP_FLAG_IRQ   = BIT(2),
> > > @@ -177,6 +195,12 @@ struct tpm_chip_seqops {
> > >   const struct seq_operations *seqops;
> > >  };
> > >  
> > > +struct tpm_sessions {
> > > + struct tpm_space *space;
> > > + u32 handle;
> > > + unsigned long created;
> > > +};
> > 
> > I would rethink this a bit. I kind of dislike this structure as it
> > 
> > I would rather have 
> > 
> > struct tpm_session {
> > u32 handle;
> > unsigned long created;
> > };
> > 
> > and in struct tpm_space:
> > 
> > struct tpm_session session_tbl[3];
> > struct list_head session_list;
> > 
> > and keep those instances that have sessions in that linked list.
> > 
> > What do you think? 
> 
> I can do ... but tpm_session will also need a struct list_head node so
> it can be placed on the list ...
> 
> If I'm listifying, I'd probably also add a hash bucket list for easy
> lookup by session.
> 
> James

I've been observing the discussion that you've been going with Ken and
I've started to think: "why this needs to be put into kernel?" We still
have quite narrow perspective of TPM 2.0 applications. It's so much more
capable than TPM 1.2 that it 

Re: [tpmdd-devel] [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-02-01 Thread Jarkko Sakkinen
On Tue, Jan 31, 2017 at 03:24:44PM -0800, James Bottomley wrote:
> On Mon, 2017-01-30 at 00:02 +0200, Jarkko Sakkinen wrote:
> > On Fri, Jan 27, 2017 at 04:33:54PM -0800, James Bottomley wrote:
> > > In a TPM2, sessions can be globally exhausted once there are
> > > TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context
> > > saved).
> > > The Strategy for handling this is to keep a global count of all the
> > > sessions along with their creation time.  Then if we see the TPM
> > > run
> > > out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for
> > > one
> > > to become free, but if it doesn't, we forcibly evict an existing
> > > one.
> > > The eviction strategy waits until the current command is repeated
> > > to
> > > evict the session which should guarantee there is an available
> > > slot.
> > > 
> > > On the force eviction case, we make sure that the victim session is
> > > at
> > > least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue
> > > for
> > > session slots is a FIFO one, ensuring that once we run out of
> > > sessions, everyone will get a session in a bounded time and once
> > > they
> > > get one, they'll have SESSION_TIMEOUT to use it before it may be
> > > subject to eviction.
> > > 
> > > Signed-off-by: James Bottomley <
> > > james.bottom...@hansenpartnership.com>
> > > ---
> > >  drivers/char/tpm/tpm-chip.c   |   1 +
> > >  drivers/char/tpm/tpm.h|  39 +++-
> > >  drivers/char/tpm/tpm2-cmd.c   |  15 +++
> > >  drivers/char/tpm/tpm2-space.c | 209
> > > --
> > >  drivers/char/tpm/tpms-dev.c   |  17 +++-
> > >  5 files changed, 271 insertions(+), 10 deletions(-)
> > > 
> > > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm
> > > -chip.c
> > > index 6282ad0..150c6b8 100644
> > > --- a/drivers/char/tpm/tpm-chip.c
> > > +++ b/drivers/char/tpm/tpm-chip.c
> > > @@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device
> > > *pdev,
> > >  
> > >   mutex_init(>tpm_mutex);
> > >   init_rwsem(>ops_sem);
> > > + init_waitqueue_head(>session_wait);
> > >  
> > >   chip->ops = ops;
> > >  
> > > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> > > index 10c57b9..658e5e2 100644
> > > --- a/drivers/char/tpm/tpm.h
> > > +++ b/drivers/char/tpm/tpm.h
> > > @@ -95,7 +95,8 @@ enum tpm2_return_codes {
> > >   TPM2_RC_HANDLE  = 0x008B,
> > >   TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
> > >   TPM2_RC_DISABLED= 0x0120,
> > > - TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> > > + TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
> > > + TPM2_RC_TESTING = 0x090A,
> > >   TPM2_RC_REFERENCE_H0= 0x0910,
> > >  };
> > >  
> > > @@ -139,7 +140,8 @@ enum tpm2_capabilities {
> > >  };
> > >  
> > >  enum tpm2_properties {
> > > - TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > > + TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > > + TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
> > >  };
> > >  
> > >  enum tpm2_startup_types {
> > > @@ -163,8 +165,24 @@ struct tpm_space {
> > >   u8 *context_buf;
> > >   u32 session_tbl[3];
> > >   u8 *session_buf;
> > > + u32 reserved_handle;
> > >  };
> > >  
> > > +#define TPM2_HANDLE_FORCE_EVICT 0x
> > > +
> > > +static inline void tpm2_session_force_evict(struct tpm_space
> > > *space)
> > > +{
> > > + /* if reserved handle is not empty, we already have a
> > > +  * session for eviction, so no need to force one
> > > +  */
> > > + if (space->reserved_handle == 0)
> > > + space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
> > > +}
> > > +static inline bool tpm2_is_session_force_evict(struct tpm_space
> > > *space)
> > > +{
> > > + return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
> > > +}
> > > +
> > >  enum tpm_chip_flags {
> > >   TPM_CHIP_FLAG_TPM2  = BIT(1),
> > >   TPM_CHIP_FLAG_IRQ   = BIT(2),
> > > @@ -177,6 +195,12 @@ struct tpm_chip_seqops {
> > >   const struct seq_operations *seqops;
> > >  };
> > >  
> > > +struct tpm_sessions {
> > > + struct tpm_space *space;
> > > + u32 handle;
> > > + unsigned long created;
> > > +};
> > 
> > I would rethink this a bit. I kind of dislike this structure as it
> > 
> > I would rather have 
> > 
> > struct tpm_session {
> > u32 handle;
> > unsigned long created;
> > };
> > 
> > and in struct tpm_space:
> > 
> > struct tpm_session session_tbl[3];
> > struct list_head session_list;
> > 
> > and keep those instances that have sessions in that linked list.
> > 
> > What do you think? 
> 
> I can do ... but tpm_session will also need a struct list_head node so
> it can be placed on the list ...
> 
> If I'm listifying, I'd probably also add a hash bucket list for easy
> lookup by session.
> 
> James

I've been observing the discussion that you've been going with Ken and
I've started to think: "why this needs to be put into kernel?" We still
have quite narrow perspective of TPM 2.0 applications. It's so much more
capable than TPM 1.2 that it 

Re: [tpmdd-devel] [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-31 Thread James Bottomley
On Mon, 2017-01-30 at 00:02 +0200, Jarkko Sakkinen wrote:
> On Fri, Jan 27, 2017 at 04:33:54PM -0800, James Bottomley wrote:
> > In a TPM2, sessions can be globally exhausted once there are
> > TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context
> > saved).
> > The Strategy for handling this is to keep a global count of all the
> > sessions along with their creation time.  Then if we see the TPM
> > run
> > out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for
> > one
> > to become free, but if it doesn't, we forcibly evict an existing
> > one.
> > The eviction strategy waits until the current command is repeated
> > to
> > evict the session which should guarantee there is an available
> > slot.
> > 
> > On the force eviction case, we make sure that the victim session is
> > at
> > least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue
> > for
> > session slots is a FIFO one, ensuring that once we run out of
> > sessions, everyone will get a session in a bounded time and once
> > they
> > get one, they'll have SESSION_TIMEOUT to use it before it may be
> > subject to eviction.
> > 
> > Signed-off-by: James Bottomley <
> > james.bottom...@hansenpartnership.com>
> > ---
> >  drivers/char/tpm/tpm-chip.c   |   1 +
> >  drivers/char/tpm/tpm.h|  39 +++-
> >  drivers/char/tpm/tpm2-cmd.c   |  15 +++
> >  drivers/char/tpm/tpm2-space.c | 209
> > --
> >  drivers/char/tpm/tpms-dev.c   |  17 +++-
> >  5 files changed, 271 insertions(+), 10 deletions(-)
> > 
> > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm
> > -chip.c
> > index 6282ad0..150c6b8 100644
> > --- a/drivers/char/tpm/tpm-chip.c
> > +++ b/drivers/char/tpm/tpm-chip.c
> > @@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device
> > *pdev,
> >  
> > mutex_init(>tpm_mutex);
> > init_rwsem(>ops_sem);
> > +   init_waitqueue_head(>session_wait);
> >  
> > chip->ops = ops;
> >  
> > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> > index 10c57b9..658e5e2 100644
> > --- a/drivers/char/tpm/tpm.h
> > +++ b/drivers/char/tpm/tpm.h
> > @@ -95,7 +95,8 @@ enum tpm2_return_codes {
> > TPM2_RC_HANDLE  = 0x008B,
> > TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
> > TPM2_RC_DISABLED= 0x0120,
> > -   TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> > +   TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
> > +   TPM2_RC_TESTING = 0x090A,
> > TPM2_RC_REFERENCE_H0= 0x0910,
> >  };
> >  
> > @@ -139,7 +140,8 @@ enum tpm2_capabilities {
> >  };
> >  
> >  enum tpm2_properties {
> > -   TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > +   TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > +   TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
> >  };
> >  
> >  enum tpm2_startup_types {
> > @@ -163,8 +165,24 @@ struct tpm_space {
> > u8 *context_buf;
> > u32 session_tbl[3];
> > u8 *session_buf;
> > +   u32 reserved_handle;
> >  };
> >  
> > +#define TPM2_HANDLE_FORCE_EVICT 0x
> > +
> > +static inline void tpm2_session_force_evict(struct tpm_space
> > *space)
> > +{
> > +   /* if reserved handle is not empty, we already have a
> > +* session for eviction, so no need to force one
> > +*/
> > +   if (space->reserved_handle == 0)
> > +   space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
> > +}
> > +static inline bool tpm2_is_session_force_evict(struct tpm_space
> > *space)
> > +{
> > +   return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
> > +}
> > +
> >  enum tpm_chip_flags {
> > TPM_CHIP_FLAG_TPM2  = BIT(1),
> > TPM_CHIP_FLAG_IRQ   = BIT(2),
> > @@ -177,6 +195,12 @@ struct tpm_chip_seqops {
> > const struct seq_operations *seqops;
> >  };
> >  
> > +struct tpm_sessions {
> > +   struct tpm_space *space;
> > +   u32 handle;
> > +   unsigned long created;
> > +};
> 
> I would rethink this a bit. I kind of dislike this structure as it
> 
> I would rather have 
> 
> struct tpm_session {
>   u32 handle;
>   unsigned long created;
> };
> 
> and in struct tpm_space:
>   
> struct tpm_session session_tbl[3];
> struct list_head session_list;
>   
> and keep those instances that have sessions in that linked list.
> 
> What do you think? 

I can do ... but tpm_session will also need a struct list_head node so
it can be placed on the list ...

If I'm listifying, I'd probably also add a hash bucket list for easy
lookup by session.

James

> I'll study the actual functionality in this patch properly later.
> 
> /Jarkko
> 
> -
> -
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, SlashDot.org! http://sdm.link/slashdot
> ___
> tpmdd-devel mailing list
> tpmdd-de...@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/tpmdd-devel
> 



Re: [tpmdd-devel] [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-31 Thread James Bottomley
On Mon, 2017-01-30 at 00:02 +0200, Jarkko Sakkinen wrote:
> On Fri, Jan 27, 2017 at 04:33:54PM -0800, James Bottomley wrote:
> > In a TPM2, sessions can be globally exhausted once there are
> > TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context
> > saved).
> > The Strategy for handling this is to keep a global count of all the
> > sessions along with their creation time.  Then if we see the TPM
> > run
> > out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for
> > one
> > to become free, but if it doesn't, we forcibly evict an existing
> > one.
> > The eviction strategy waits until the current command is repeated
> > to
> > evict the session which should guarantee there is an available
> > slot.
> > 
> > On the force eviction case, we make sure that the victim session is
> > at
> > least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue
> > for
> > session slots is a FIFO one, ensuring that once we run out of
> > sessions, everyone will get a session in a bounded time and once
> > they
> > get one, they'll have SESSION_TIMEOUT to use it before it may be
> > subject to eviction.
> > 
> > Signed-off-by: James Bottomley <
> > james.bottom...@hansenpartnership.com>
> > ---
> >  drivers/char/tpm/tpm-chip.c   |   1 +
> >  drivers/char/tpm/tpm.h|  39 +++-
> >  drivers/char/tpm/tpm2-cmd.c   |  15 +++
> >  drivers/char/tpm/tpm2-space.c | 209
> > --
> >  drivers/char/tpm/tpms-dev.c   |  17 +++-
> >  5 files changed, 271 insertions(+), 10 deletions(-)
> > 
> > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm
> > -chip.c
> > index 6282ad0..150c6b8 100644
> > --- a/drivers/char/tpm/tpm-chip.c
> > +++ b/drivers/char/tpm/tpm-chip.c
> > @@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device
> > *pdev,
> >  
> > mutex_init(>tpm_mutex);
> > init_rwsem(>ops_sem);
> > +   init_waitqueue_head(>session_wait);
> >  
> > chip->ops = ops;
> >  
> > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> > index 10c57b9..658e5e2 100644
> > --- a/drivers/char/tpm/tpm.h
> > +++ b/drivers/char/tpm/tpm.h
> > @@ -95,7 +95,8 @@ enum tpm2_return_codes {
> > TPM2_RC_HANDLE  = 0x008B,
> > TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
> > TPM2_RC_DISABLED= 0x0120,
> > -   TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> > +   TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
> > +   TPM2_RC_TESTING = 0x090A,
> > TPM2_RC_REFERENCE_H0= 0x0910,
> >  };
> >  
> > @@ -139,7 +140,8 @@ enum tpm2_capabilities {
> >  };
> >  
> >  enum tpm2_properties {
> > -   TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > +   TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > +   TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
> >  };
> >  
> >  enum tpm2_startup_types {
> > @@ -163,8 +165,24 @@ struct tpm_space {
> > u8 *context_buf;
> > u32 session_tbl[3];
> > u8 *session_buf;
> > +   u32 reserved_handle;
> >  };
> >  
> > +#define TPM2_HANDLE_FORCE_EVICT 0x
> > +
> > +static inline void tpm2_session_force_evict(struct tpm_space
> > *space)
> > +{
> > +   /* if reserved handle is not empty, we already have a
> > +* session for eviction, so no need to force one
> > +*/
> > +   if (space->reserved_handle == 0)
> > +   space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
> > +}
> > +static inline bool tpm2_is_session_force_evict(struct tpm_space
> > *space)
> > +{
> > +   return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
> > +}
> > +
> >  enum tpm_chip_flags {
> > TPM_CHIP_FLAG_TPM2  = BIT(1),
> > TPM_CHIP_FLAG_IRQ   = BIT(2),
> > @@ -177,6 +195,12 @@ struct tpm_chip_seqops {
> > const struct seq_operations *seqops;
> >  };
> >  
> > +struct tpm_sessions {
> > +   struct tpm_space *space;
> > +   u32 handle;
> > +   unsigned long created;
> > +};
> 
> I would rethink this a bit. I kind of dislike this structure as it
> 
> I would rather have 
> 
> struct tpm_session {
>   u32 handle;
>   unsigned long created;
> };
> 
> and in struct tpm_space:
>   
> struct tpm_session session_tbl[3];
> struct list_head session_list;
>   
> and keep those instances that have sessions in that linked list.
> 
> What do you think? 

I can do ... but tpm_session will also need a struct list_head node so
it can be placed on the list ...

If I'm listifying, I'd probably also add a hash bucket list for easy
lookup by session.

James

> I'll study the actual functionality in this patch properly later.
> 
> /Jarkko
> 
> -
> -
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, SlashDot.org! http://sdm.link/slashdot
> ___
> tpmdd-devel mailing list
> tpmdd-de...@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/tpmdd-devel
> 



Re: [tpmdd-devel] [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-29 Thread Jarkko Sakkinen
On Mon, Jan 30, 2017 at 12:02:19AM +0200, Jarkko Sakkinen wrote:
> On Fri, Jan 27, 2017 at 04:33:54PM -0800, James Bottomley wrote:
> > In a TPM2, sessions can be globally exhausted once there are
> > TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context saved).
> > The Strategy for handling this is to keep a global count of all the
> > sessions along with their creation time.  Then if we see the TPM run
> > out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for one
> > to become free, but if it doesn't, we forcibly evict an existing one.
> > The eviction strategy waits until the current command is repeated to
> > evict the session which should guarantee there is an available slot.
> > 
> > On the force eviction case, we make sure that the victim session is at
> > least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue for
> > session slots is a FIFO one, ensuring that once we run out of
> > sessions, everyone will get a session in a bounded time and once they
> > get one, they'll have SESSION_TIMEOUT to use it before it may be
> > subject to eviction.
> > 
> > Signed-off-by: James Bottomley 
> > ---
> >  drivers/char/tpm/tpm-chip.c   |   1 +
> >  drivers/char/tpm/tpm.h|  39 +++-
> >  drivers/char/tpm/tpm2-cmd.c   |  15 +++
> >  drivers/char/tpm/tpm2-space.c | 209 
> > --
> >  drivers/char/tpm/tpms-dev.c   |  17 +++-
> >  5 files changed, 271 insertions(+), 10 deletions(-)
> > 
> > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> > index 6282ad0..150c6b8 100644
> > --- a/drivers/char/tpm/tpm-chip.c
> > +++ b/drivers/char/tpm/tpm-chip.c
> > @@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
> >  
> > mutex_init(>tpm_mutex);
> > init_rwsem(>ops_sem);
> > +   init_waitqueue_head(>session_wait);
> >  
> > chip->ops = ops;
> >  
> > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> > index 10c57b9..658e5e2 100644
> > --- a/drivers/char/tpm/tpm.h
> > +++ b/drivers/char/tpm/tpm.h
> > @@ -95,7 +95,8 @@ enum tpm2_return_codes {
> > TPM2_RC_HANDLE  = 0x008B,
> > TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
> > TPM2_RC_DISABLED= 0x0120,
> > -   TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> > +   TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
> > +   TPM2_RC_TESTING = 0x090A,
> > TPM2_RC_REFERENCE_H0= 0x0910,
> >  };
> >  
> > @@ -139,7 +140,8 @@ enum tpm2_capabilities {
> >  };
> >  
> >  enum tpm2_properties {
> > -   TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > +   TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > +   TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
> >  };
> >  
> >  enum tpm2_startup_types {
> > @@ -163,8 +165,24 @@ struct tpm_space {
> > u8 *context_buf;
> > u32 session_tbl[3];
> > u8 *session_buf;
> > +   u32 reserved_handle;
> >  };
> >  
> > +#define TPM2_HANDLE_FORCE_EVICT 0x
> > +
> > +static inline void tpm2_session_force_evict(struct tpm_space *space)
> > +{
> > +   /* if reserved handle is not empty, we already have a
> > +* session for eviction, so no need to force one
> > +*/
> > +   if (space->reserved_handle == 0)
> > +   space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
> > +}
> > +static inline bool tpm2_is_session_force_evict(struct tpm_space *space)
> > +{
> > +   return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
> > +}
> > +
> >  enum tpm_chip_flags {
> > TPM_CHIP_FLAG_TPM2  = BIT(1),
> > TPM_CHIP_FLAG_IRQ   = BIT(2),
> > @@ -177,6 +195,12 @@ struct tpm_chip_seqops {
> > const struct seq_operations *seqops;
> >  };
> >  
> > +struct tpm_sessions {
> > +   struct tpm_space *space;
> > +   u32 handle;
> > +   unsigned long created;
> > +};
> 
> I would rethink this a bit. I kind of dislike this structure as it
adds extra layer of complexity.

/Jarkko


Re: [tpmdd-devel] [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-29 Thread Jarkko Sakkinen
On Mon, Jan 30, 2017 at 12:02:19AM +0200, Jarkko Sakkinen wrote:
> On Fri, Jan 27, 2017 at 04:33:54PM -0800, James Bottomley wrote:
> > In a TPM2, sessions can be globally exhausted once there are
> > TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context saved).
> > The Strategy for handling this is to keep a global count of all the
> > sessions along with their creation time.  Then if we see the TPM run
> > out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for one
> > to become free, but if it doesn't, we forcibly evict an existing one.
> > The eviction strategy waits until the current command is repeated to
> > evict the session which should guarantee there is an available slot.
> > 
> > On the force eviction case, we make sure that the victim session is at
> > least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue for
> > session slots is a FIFO one, ensuring that once we run out of
> > sessions, everyone will get a session in a bounded time and once they
> > get one, they'll have SESSION_TIMEOUT to use it before it may be
> > subject to eviction.
> > 
> > Signed-off-by: James Bottomley 
> > ---
> >  drivers/char/tpm/tpm-chip.c   |   1 +
> >  drivers/char/tpm/tpm.h|  39 +++-
> >  drivers/char/tpm/tpm2-cmd.c   |  15 +++
> >  drivers/char/tpm/tpm2-space.c | 209 
> > --
> >  drivers/char/tpm/tpms-dev.c   |  17 +++-
> >  5 files changed, 271 insertions(+), 10 deletions(-)
> > 
> > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> > index 6282ad0..150c6b8 100644
> > --- a/drivers/char/tpm/tpm-chip.c
> > +++ b/drivers/char/tpm/tpm-chip.c
> > @@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
> >  
> > mutex_init(>tpm_mutex);
> > init_rwsem(>ops_sem);
> > +   init_waitqueue_head(>session_wait);
> >  
> > chip->ops = ops;
> >  
> > diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> > index 10c57b9..658e5e2 100644
> > --- a/drivers/char/tpm/tpm.h
> > +++ b/drivers/char/tpm/tpm.h
> > @@ -95,7 +95,8 @@ enum tpm2_return_codes {
> > TPM2_RC_HANDLE  = 0x008B,
> > TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
> > TPM2_RC_DISABLED= 0x0120,
> > -   TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> > +   TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
> > +   TPM2_RC_TESTING = 0x090A,
> > TPM2_RC_REFERENCE_H0= 0x0910,
> >  };
> >  
> > @@ -139,7 +140,8 @@ enum tpm2_capabilities {
> >  };
> >  
> >  enum tpm2_properties {
> > -   TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > +   TPM_PT_TOTAL_COMMANDS   = 0x0129,
> > +   TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
> >  };
> >  
> >  enum tpm2_startup_types {
> > @@ -163,8 +165,24 @@ struct tpm_space {
> > u8 *context_buf;
> > u32 session_tbl[3];
> > u8 *session_buf;
> > +   u32 reserved_handle;
> >  };
> >  
> > +#define TPM2_HANDLE_FORCE_EVICT 0x
> > +
> > +static inline void tpm2_session_force_evict(struct tpm_space *space)
> > +{
> > +   /* if reserved handle is not empty, we already have a
> > +* session for eviction, so no need to force one
> > +*/
> > +   if (space->reserved_handle == 0)
> > +   space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
> > +}
> > +static inline bool tpm2_is_session_force_evict(struct tpm_space *space)
> > +{
> > +   return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
> > +}
> > +
> >  enum tpm_chip_flags {
> > TPM_CHIP_FLAG_TPM2  = BIT(1),
> > TPM_CHIP_FLAG_IRQ   = BIT(2),
> > @@ -177,6 +195,12 @@ struct tpm_chip_seqops {
> > const struct seq_operations *seqops;
> >  };
> >  
> > +struct tpm_sessions {
> > +   struct tpm_space *space;
> > +   u32 handle;
> > +   unsigned long created;
> > +};
> 
> I would rethink this a bit. I kind of dislike this structure as it
adds extra layer of complexity.

/Jarkko


Re: [tpmdd-devel] [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-29 Thread Jarkko Sakkinen
On Fri, Jan 27, 2017 at 04:33:54PM -0800, James Bottomley wrote:
> In a TPM2, sessions can be globally exhausted once there are
> TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context saved).
> The Strategy for handling this is to keep a global count of all the
> sessions along with their creation time.  Then if we see the TPM run
> out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for one
> to become free, but if it doesn't, we forcibly evict an existing one.
> The eviction strategy waits until the current command is repeated to
> evict the session which should guarantee there is an available slot.
> 
> On the force eviction case, we make sure that the victim session is at
> least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue for
> session slots is a FIFO one, ensuring that once we run out of
> sessions, everyone will get a session in a bounded time and once they
> get one, they'll have SESSION_TIMEOUT to use it before it may be
> subject to eviction.
> 
> Signed-off-by: James Bottomley 
> ---
>  drivers/char/tpm/tpm-chip.c   |   1 +
>  drivers/char/tpm/tpm.h|  39 +++-
>  drivers/char/tpm/tpm2-cmd.c   |  15 +++
>  drivers/char/tpm/tpm2-space.c | 209 
> --
>  drivers/char/tpm/tpms-dev.c   |  17 +++-
>  5 files changed, 271 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 6282ad0..150c6b8 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
>  
>   mutex_init(>tpm_mutex);
>   init_rwsem(>ops_sem);
> + init_waitqueue_head(>session_wait);
>  
>   chip->ops = ops;
>  
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 10c57b9..658e5e2 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -95,7 +95,8 @@ enum tpm2_return_codes {
>   TPM2_RC_HANDLE  = 0x008B,
>   TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
>   TPM2_RC_DISABLED= 0x0120,
> - TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> + TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
> + TPM2_RC_TESTING = 0x090A,
>   TPM2_RC_REFERENCE_H0= 0x0910,
>  };
>  
> @@ -139,7 +140,8 @@ enum tpm2_capabilities {
>  };
>  
>  enum tpm2_properties {
> - TPM_PT_TOTAL_COMMANDS   = 0x0129,
> + TPM_PT_TOTAL_COMMANDS   = 0x0129,
> + TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
>  };
>  
>  enum tpm2_startup_types {
> @@ -163,8 +165,24 @@ struct tpm_space {
>   u8 *context_buf;
>   u32 session_tbl[3];
>   u8 *session_buf;
> + u32 reserved_handle;
>  };
>  
> +#define TPM2_HANDLE_FORCE_EVICT 0x
> +
> +static inline void tpm2_session_force_evict(struct tpm_space *space)
> +{
> + /* if reserved handle is not empty, we already have a
> +  * session for eviction, so no need to force one
> +  */
> + if (space->reserved_handle == 0)
> + space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
> +}
> +static inline bool tpm2_is_session_force_evict(struct tpm_space *space)
> +{
> + return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
> +}
> +
>  enum tpm_chip_flags {
>   TPM_CHIP_FLAG_TPM2  = BIT(1),
>   TPM_CHIP_FLAG_IRQ   = BIT(2),
> @@ -177,6 +195,12 @@ struct tpm_chip_seqops {
>   const struct seq_operations *seqops;
>  };
>  
> +struct tpm_sessions {
> + struct tpm_space *space;
> + u32 handle;
> + unsigned long created;
> +};

I would rethink this a bit. I kind of dislike this structure as it

I would rather have 

struct tpm_session {
u32 handle;
unsigned long created;
};

and in struct tpm_space:

struct tpm_session session_tbl[3];
struct list_head session_list;

and keep those instances that have sessions in that linked list.

What do you think? 

I'll study the actual functionality in this patch properly later.

/Jarkko


Re: [tpmdd-devel] [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-29 Thread Jarkko Sakkinen
On Fri, Jan 27, 2017 at 04:33:54PM -0800, James Bottomley wrote:
> In a TPM2, sessions can be globally exhausted once there are
> TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context saved).
> The Strategy for handling this is to keep a global count of all the
> sessions along with their creation time.  Then if we see the TPM run
> out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for one
> to become free, but if it doesn't, we forcibly evict an existing one.
> The eviction strategy waits until the current command is repeated to
> evict the session which should guarantee there is an available slot.
> 
> On the force eviction case, we make sure that the victim session is at
> least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue for
> session slots is a FIFO one, ensuring that once we run out of
> sessions, everyone will get a session in a bounded time and once they
> get one, they'll have SESSION_TIMEOUT to use it before it may be
> subject to eviction.
> 
> Signed-off-by: James Bottomley 
> ---
>  drivers/char/tpm/tpm-chip.c   |   1 +
>  drivers/char/tpm/tpm.h|  39 +++-
>  drivers/char/tpm/tpm2-cmd.c   |  15 +++
>  drivers/char/tpm/tpm2-space.c | 209 
> --
>  drivers/char/tpm/tpms-dev.c   |  17 +++-
>  5 files changed, 271 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 6282ad0..150c6b8 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
>  
>   mutex_init(>tpm_mutex);
>   init_rwsem(>ops_sem);
> + init_waitqueue_head(>session_wait);
>  
>   chip->ops = ops;
>  
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 10c57b9..658e5e2 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -95,7 +95,8 @@ enum tpm2_return_codes {
>   TPM2_RC_HANDLE  = 0x008B,
>   TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
>   TPM2_RC_DISABLED= 0x0120,
> - TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> + TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
> + TPM2_RC_TESTING = 0x090A,
>   TPM2_RC_REFERENCE_H0= 0x0910,
>  };
>  
> @@ -139,7 +140,8 @@ enum tpm2_capabilities {
>  };
>  
>  enum tpm2_properties {
> - TPM_PT_TOTAL_COMMANDS   = 0x0129,
> + TPM_PT_TOTAL_COMMANDS   = 0x0129,
> + TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
>  };
>  
>  enum tpm2_startup_types {
> @@ -163,8 +165,24 @@ struct tpm_space {
>   u8 *context_buf;
>   u32 session_tbl[3];
>   u8 *session_buf;
> + u32 reserved_handle;
>  };
>  
> +#define TPM2_HANDLE_FORCE_EVICT 0x
> +
> +static inline void tpm2_session_force_evict(struct tpm_space *space)
> +{
> + /* if reserved handle is not empty, we already have a
> +  * session for eviction, so no need to force one
> +  */
> + if (space->reserved_handle == 0)
> + space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
> +}
> +static inline bool tpm2_is_session_force_evict(struct tpm_space *space)
> +{
> + return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
> +}
> +
>  enum tpm_chip_flags {
>   TPM_CHIP_FLAG_TPM2  = BIT(1),
>   TPM_CHIP_FLAG_IRQ   = BIT(2),
> @@ -177,6 +195,12 @@ struct tpm_chip_seqops {
>   const struct seq_operations *seqops;
>  };
>  
> +struct tpm_sessions {
> + struct tpm_space *space;
> + u32 handle;
> + unsigned long created;
> +};

I would rethink this a bit. I kind of dislike this structure as it

I would rather have 

struct tpm_session {
u32 handle;
unsigned long created;
};

and in struct tpm_space:

struct tpm_session session_tbl[3];
struct list_head session_list;

and keep those instances that have sessions in that linked list.

What do you think? 

I'll study the actual functionality in this patch properly later.

/Jarkko


[PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-27 Thread James Bottomley
In a TPM2, sessions can be globally exhausted once there are
TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context saved).
The Strategy for handling this is to keep a global count of all the
sessions along with their creation time.  Then if we see the TPM run
out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for one
to become free, but if it doesn't, we forcibly evict an existing one.
The eviction strategy waits until the current command is repeated to
evict the session which should guarantee there is an available slot.

On the force eviction case, we make sure that the victim session is at
least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue for
session slots is a FIFO one, ensuring that once we run out of
sessions, everyone will get a session in a bounded time and once they
get one, they'll have SESSION_TIMEOUT to use it before it may be
subject to eviction.

Signed-off-by: James Bottomley 
---
 drivers/char/tpm/tpm-chip.c   |   1 +
 drivers/char/tpm/tpm.h|  39 +++-
 drivers/char/tpm/tpm2-cmd.c   |  15 +++
 drivers/char/tpm/tpm2-space.c | 209 --
 drivers/char/tpm/tpms-dev.c   |  17 +++-
 5 files changed, 271 insertions(+), 10 deletions(-)

diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 6282ad0..150c6b8 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
 
mutex_init(>tpm_mutex);
init_rwsem(>ops_sem);
+   init_waitqueue_head(>session_wait);
 
chip->ops = ops;
 
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 10c57b9..658e5e2 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -95,7 +95,8 @@ enum tpm2_return_codes {
TPM2_RC_HANDLE  = 0x008B,
TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
TPM2_RC_DISABLED= 0x0120,
-   TPM2_RC_TESTING = 0x090A, /* RC_WARN */
+   TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
+   TPM2_RC_TESTING = 0x090A,
TPM2_RC_REFERENCE_H0= 0x0910,
 };
 
@@ -139,7 +140,8 @@ enum tpm2_capabilities {
 };
 
 enum tpm2_properties {
-   TPM_PT_TOTAL_COMMANDS   = 0x0129,
+   TPM_PT_TOTAL_COMMANDS   = 0x0129,
+   TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
 };
 
 enum tpm2_startup_types {
@@ -163,8 +165,24 @@ struct tpm_space {
u8 *context_buf;
u32 session_tbl[3];
u8 *session_buf;
+   u32 reserved_handle;
 };
 
+#define TPM2_HANDLE_FORCE_EVICT 0x
+
+static inline void tpm2_session_force_evict(struct tpm_space *space)
+{
+   /* if reserved handle is not empty, we already have a
+* session for eviction, so no need to force one
+*/
+   if (space->reserved_handle == 0)
+   space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
+}
+static inline bool tpm2_is_session_force_evict(struct tpm_space *space)
+{
+   return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
+}
+
 enum tpm_chip_flags {
TPM_CHIP_FLAG_TPM2  = BIT(1),
TPM_CHIP_FLAG_IRQ   = BIT(2),
@@ -177,6 +195,12 @@ struct tpm_chip_seqops {
const struct seq_operations *seqops;
 };
 
+struct tpm_sessions {
+   struct tpm_space *space;
+   u32 handle;
+   unsigned long created;
+};
+
 struct tpm_chip {
struct device dev;
struct device devs;
@@ -221,8 +245,12 @@ struct tpm_chip {
 #endif /* CONFIG_ACPI */
 
struct tpm_space work_space;
+   struct tpm_space *space;
u32 nr_commands;
u32 *cc_attrs_tbl;
+   struct tpm_sessions *sessions;
+   int max_sessions;
+   wait_queue_head_t session_wait;
 };
 
 #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
@@ -570,6 +598,13 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, 
u32 count,
 int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
 void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
unsigned int flags);
+static inline void tpm2_session_clear_reserved(struct tpm_chip *chip,
+  struct tpm_space *space)
+{
+   if (space->reserved_handle && !tpm2_is_session_force_evict(space))
+   tpm2_flush_context_cmd(chip, space->reserved_handle, 0);
+   space->reserved_handle = 0;
+}
 int tpm2_seal_trusted(struct tpm_chip *chip,
  struct trusted_key_payload *payload,
  struct trusted_key_options *options);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index db9930a..4db0918 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -1050,6 +1050,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
 {
struct tpm_buf buf;
u32 nr_commands;
+   u32 nr_sessions;
u32 *attrs;

[PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-27 Thread James Bottomley
In a TPM2, sessions can be globally exhausted once there are
TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context saved).
The Strategy for handling this is to keep a global count of all the
sessions along with their creation time.  Then if we see the TPM run
out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for one
to become free, but if it doesn't, we forcibly evict an existing one.
The eviction strategy waits until the current command is repeated to
evict the session which should guarantee there is an available slot.

On the force eviction case, we make sure that the victim session is at
least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue for
session slots is a FIFO one, ensuring that once we run out of
sessions, everyone will get a session in a bounded time and once they
get one, they'll have SESSION_TIMEOUT to use it before it may be
subject to eviction.

Signed-off-by: James Bottomley 
---
 drivers/char/tpm/tpm-chip.c   |   1 +
 drivers/char/tpm/tpm.h|  39 +++-
 drivers/char/tpm/tpm2-cmd.c   |  15 +++
 drivers/char/tpm/tpm2-space.c | 209 --
 drivers/char/tpm/tpms-dev.c   |  17 +++-
 5 files changed, 271 insertions(+), 10 deletions(-)

diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 6282ad0..150c6b8 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
 
mutex_init(>tpm_mutex);
init_rwsem(>ops_sem);
+   init_waitqueue_head(>session_wait);
 
chip->ops = ops;
 
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 10c57b9..658e5e2 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -95,7 +95,8 @@ enum tpm2_return_codes {
TPM2_RC_HANDLE  = 0x008B,
TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
TPM2_RC_DISABLED= 0x0120,
-   TPM2_RC_TESTING = 0x090A, /* RC_WARN */
+   TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
+   TPM2_RC_TESTING = 0x090A,
TPM2_RC_REFERENCE_H0= 0x0910,
 };
 
@@ -139,7 +140,8 @@ enum tpm2_capabilities {
 };
 
 enum tpm2_properties {
-   TPM_PT_TOTAL_COMMANDS   = 0x0129,
+   TPM_PT_TOTAL_COMMANDS   = 0x0129,
+   TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
 };
 
 enum tpm2_startup_types {
@@ -163,8 +165,24 @@ struct tpm_space {
u8 *context_buf;
u32 session_tbl[3];
u8 *session_buf;
+   u32 reserved_handle;
 };
 
+#define TPM2_HANDLE_FORCE_EVICT 0x
+
+static inline void tpm2_session_force_evict(struct tpm_space *space)
+{
+   /* if reserved handle is not empty, we already have a
+* session for eviction, so no need to force one
+*/
+   if (space->reserved_handle == 0)
+   space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
+}
+static inline bool tpm2_is_session_force_evict(struct tpm_space *space)
+{
+   return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
+}
+
 enum tpm_chip_flags {
TPM_CHIP_FLAG_TPM2  = BIT(1),
TPM_CHIP_FLAG_IRQ   = BIT(2),
@@ -177,6 +195,12 @@ struct tpm_chip_seqops {
const struct seq_operations *seqops;
 };
 
+struct tpm_sessions {
+   struct tpm_space *space;
+   u32 handle;
+   unsigned long created;
+};
+
 struct tpm_chip {
struct device dev;
struct device devs;
@@ -221,8 +245,12 @@ struct tpm_chip {
 #endif /* CONFIG_ACPI */
 
struct tpm_space work_space;
+   struct tpm_space *space;
u32 nr_commands;
u32 *cc_attrs_tbl;
+   struct tpm_sessions *sessions;
+   int max_sessions;
+   wait_queue_head_t session_wait;
 };
 
 #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
@@ -570,6 +598,13 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, 
u32 count,
 int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
 void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
unsigned int flags);
+static inline void tpm2_session_clear_reserved(struct tpm_chip *chip,
+  struct tpm_space *space)
+{
+   if (space->reserved_handle && !tpm2_is_session_force_evict(space))
+   tpm2_flush_context_cmd(chip, space->reserved_handle, 0);
+   space->reserved_handle = 0;
+}
 int tpm2_seal_trusted(struct tpm_chip *chip,
  struct trusted_key_payload *payload,
  struct trusted_key_options *options);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index db9930a..4db0918 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -1050,6 +1050,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
 {
struct tpm_buf buf;
u32 nr_commands;
+   u32 nr_sessions;
u32 *attrs;
int i;
int rc;
@@ -1102,6 

Re: [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-26 Thread Jarkko Sakkinen
On Thu, Jan 26, 2017 at 04:45:52PM -0800, James Bottomley wrote:
> On Thu, 2017-01-26 at 14:56 +0200, Jarkko Sakkinen wrote:
> > On Mon, Jan 23, 2017 at 09:38:33PM -0800, James Bottomley wrote:
> > > In a TPM2, sessions can be globally exhausted once there are
> > > TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context 
> > > saved). The Strategy for handling this is to keep a global count of 
> > > all the sessions along with their creation time.  Then if we see 
> > > the TPM run out of sessions (via the TPM_RC_SESSION_HANDLES) we 
> > > first wait for one to become free, but if it doesn't, we forcibly 
> > > evict an existing one. The eviction strategy waits until the 
> > > current command is repeated to evict the session which should 
> > > guarantee there is an available slot.
> > > 
> > > On the force eviction case, we make sure that the victim session is 
> > > at least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue
> > > for session slots is a FIFO one, ensuring that once we run out of
> > > sessions, everyone will get a session in a bounded time and once 
> > > they get one, they'll have SESSION_TIMEOUT to use it before it may 
> > > be subject to eviction.
> > > 
> > > Signed-off-by: James Bottomley <
> > > james.bottom...@hansenpartnership.com>
> > 
> > This is not a proper review yet. Just quick question: why do you need
> > a real time (i.e. created)? Maybe in the force eviction case it would
> > be enough to sleep lets say 500 ms and pick the victim with smallest
> > number? I.e. just have increasing u64 counter instead of real time.
> 
> So that if the oldest session has already been around for > 2s there's
> no need to wait.  In order to guarantee everyone gets a session for at
> least 2s without tracking the age of sessions, you'd have to sleep for
> 2s after you find the oldest session.
> 
> > That would simplify this patch a lot and does not prevent to refine
> > later on if workloads show need for more complex logic.
> 
> An increasing monotonic counter would actually not be much simpler: all
> you could really cut out would be the four lines and two comments at
> the bottom of the for loop in tpm2_session_wait() which check the age
> of the found session.
> 
> James

Right. Thanks for explaining this. I'll check the code with more detail
ASAP.

/Jarkko


Re: [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-26 Thread Jarkko Sakkinen
On Thu, Jan 26, 2017 at 04:45:52PM -0800, James Bottomley wrote:
> On Thu, 2017-01-26 at 14:56 +0200, Jarkko Sakkinen wrote:
> > On Mon, Jan 23, 2017 at 09:38:33PM -0800, James Bottomley wrote:
> > > In a TPM2, sessions can be globally exhausted once there are
> > > TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context 
> > > saved). The Strategy for handling this is to keep a global count of 
> > > all the sessions along with their creation time.  Then if we see 
> > > the TPM run out of sessions (via the TPM_RC_SESSION_HANDLES) we 
> > > first wait for one to become free, but if it doesn't, we forcibly 
> > > evict an existing one. The eviction strategy waits until the 
> > > current command is repeated to evict the session which should 
> > > guarantee there is an available slot.
> > > 
> > > On the force eviction case, we make sure that the victim session is 
> > > at least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue
> > > for session slots is a FIFO one, ensuring that once we run out of
> > > sessions, everyone will get a session in a bounded time and once 
> > > they get one, they'll have SESSION_TIMEOUT to use it before it may 
> > > be subject to eviction.
> > > 
> > > Signed-off-by: James Bottomley <
> > > james.bottom...@hansenpartnership.com>
> > 
> > This is not a proper review yet. Just quick question: why do you need
> > a real time (i.e. created)? Maybe in the force eviction case it would
> > be enough to sleep lets say 500 ms and pick the victim with smallest
> > number? I.e. just have increasing u64 counter instead of real time.
> 
> So that if the oldest session has already been around for > 2s there's
> no need to wait.  In order to guarantee everyone gets a session for at
> least 2s without tracking the age of sessions, you'd have to sleep for
> 2s after you find the oldest session.
> 
> > That would simplify this patch a lot and does not prevent to refine
> > later on if workloads show need for more complex logic.
> 
> An increasing monotonic counter would actually not be much simpler: all
> you could really cut out would be the four lines and two comments at
> the bottom of the for loop in tpm2_session_wait() which check the age
> of the found session.
> 
> James

Right. Thanks for explaining this. I'll check the code with more detail
ASAP.

/Jarkko


Re: [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-26 Thread James Bottomley
On Thu, 2017-01-26 at 14:56 +0200, Jarkko Sakkinen wrote:
> On Mon, Jan 23, 2017 at 09:38:33PM -0800, James Bottomley wrote:
> > In a TPM2, sessions can be globally exhausted once there are
> > TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context 
> > saved). The Strategy for handling this is to keep a global count of 
> > all the sessions along with their creation time.  Then if we see 
> > the TPM run out of sessions (via the TPM_RC_SESSION_HANDLES) we 
> > first wait for one to become free, but if it doesn't, we forcibly 
> > evict an existing one. The eviction strategy waits until the 
> > current command is repeated to evict the session which should 
> > guarantee there is an available slot.
> > 
> > On the force eviction case, we make sure that the victim session is 
> > at least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue
> > for session slots is a FIFO one, ensuring that once we run out of
> > sessions, everyone will get a session in a bounded time and once 
> > they get one, they'll have SESSION_TIMEOUT to use it before it may 
> > be subject to eviction.
> > 
> > Signed-off-by: James Bottomley <
> > james.bottom...@hansenpartnership.com>
> 
> This is not a proper review yet. Just quick question: why do you need
> a real time (i.e. created)? Maybe in the force eviction case it would
> be enough to sleep lets say 500 ms and pick the victim with smallest
> number? I.e. just have increasing u64 counter instead of real time.

So that if the oldest session has already been around for > 2s there's
no need to wait.  In order to guarantee everyone gets a session for at
least 2s without tracking the age of sessions, you'd have to sleep for
2s after you find the oldest session.

> That would simplify this patch a lot and does not prevent to refine
> later on if workloads show need for more complex logic.

An increasing monotonic counter would actually not be much simpler: all
you could really cut out would be the four lines and two comments at
the bottom of the for loop in tpm2_session_wait() which check the age
of the found session.

James



Re: [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-26 Thread James Bottomley
On Thu, 2017-01-26 at 14:56 +0200, Jarkko Sakkinen wrote:
> On Mon, Jan 23, 2017 at 09:38:33PM -0800, James Bottomley wrote:
> > In a TPM2, sessions can be globally exhausted once there are
> > TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context 
> > saved). The Strategy for handling this is to keep a global count of 
> > all the sessions along with their creation time.  Then if we see 
> > the TPM run out of sessions (via the TPM_RC_SESSION_HANDLES) we 
> > first wait for one to become free, but if it doesn't, we forcibly 
> > evict an existing one. The eviction strategy waits until the 
> > current command is repeated to evict the session which should 
> > guarantee there is an available slot.
> > 
> > On the force eviction case, we make sure that the victim session is 
> > at least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue
> > for session slots is a FIFO one, ensuring that once we run out of
> > sessions, everyone will get a session in a bounded time and once 
> > they get one, they'll have SESSION_TIMEOUT to use it before it may 
> > be subject to eviction.
> > 
> > Signed-off-by: James Bottomley <
> > james.bottom...@hansenpartnership.com>
> 
> This is not a proper review yet. Just quick question: why do you need
> a real time (i.e. created)? Maybe in the force eviction case it would
> be enough to sleep lets say 500 ms and pick the victim with smallest
> number? I.e. just have increasing u64 counter instead of real time.

So that if the oldest session has already been around for > 2s there's
no need to wait.  In order to guarantee everyone gets a session for at
least 2s without tracking the age of sessions, you'd have to sleep for
2s after you find the oldest session.

> That would simplify this patch a lot and does not prevent to refine
> later on if workloads show need for more complex logic.

An increasing monotonic counter would actually not be much simpler: all
you could really cut out would be the four lines and two comments at
the bottom of the for loop in tpm2_session_wait() which check the age
of the found session.

James



Re: [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-26 Thread Jarkko Sakkinen
On Mon, Jan 23, 2017 at 09:38:33PM -0800, James Bottomley wrote:
> In a TPM2, sessions can be globally exhausted once there are
> TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context saved).
> The Strategy for handling this is to keep a global count of all the
> sessions along with their creation time.  Then if we see the TPM run
> out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for one
> to become free, but if it doesn't, we forcibly evict an existing one.
> The eviction strategy waits until the current command is repeated to
> evict the session which should guarantee there is an available slot.
> 
> On the force eviction case, we make sure that the victim session is at
> least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue for
> session slots is a FIFO one, ensuring that once we run out of
> sessions, everyone will get a session in a bounded time and once they
> get one, they'll have SESSION_TIMEOUT to use it before it may be
> subject to eviction.
> 
> Signed-off-by: James Bottomley 

This is not a proper review yet. Just quick question: why do you need
a real time (i.e. created)? Maybe in the force eviction case it would
be enough to sleep lets say 500 ms and pick the victim with smallest
number? I.e. just have increasing u64 counter instead of real time.

That would simplify this patch a lot and does not prevent to refine
later on if workloads show need for more complex logic.

/Jarkko

> ---
>  drivers/char/tpm/tpm-chip.c   |   1 +
>  drivers/char/tpm/tpm.h|  39 +++-
>  drivers/char/tpm/tpm2-cmd.c   |  15 +++
>  drivers/char/tpm/tpm2-space.c | 213 
> +++---
>  drivers/char/tpm/tpms-dev.c   |  17 +++-
>  5 files changed, 271 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 6282ad0..150c6b8 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
>  
>   mutex_init(>tpm_mutex);
>   init_rwsem(>ops_sem);
> + init_waitqueue_head(>session_wait);
>  
>   chip->ops = ops;
>  
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index b77fc60..9fd6101 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -95,7 +95,8 @@ enum tpm2_return_codes {
>   TPM2_RC_HANDLE  = 0x008B,
>   TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
>   TPM2_RC_DISABLED= 0x0120,
> - TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> + TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
> + TPM2_RC_TESTING = 0x090A,
>   TPM2_RC_REFERENCE_H0= 0x0910,
>  };
>  
> @@ -137,7 +138,8 @@ enum tpm2_capabilities {
>  };
>  
>  enum tpm2_properties {
> - TPM_PT_TOTAL_COMMANDS   = 0x0129,
> + TPM_PT_TOTAL_COMMANDS   = 0x0129,
> + TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
>  };
>  
>  enum tpm2_startup_types {
> @@ -161,8 +163,24 @@ struct tpm_space {
>   u8 *context_buf;
>   u32 session_tbl[6];
>   u8 *session_buf;
> + u32 reserved_handle;
>  };
>  
> +#define TPM2_HANDLE_FORCE_EVICT 0x
> +
> +static inline void tpm2_session_force_evict(struct tpm_space *space)
> +{
> + /* if reserved handle is not empty, we already have a
> +  * session for eviction, so no need to force one
> +  */
> + if (space->reserved_handle == 0)
> + space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
> +}
> +static inline bool tpm2_is_session_force_evict(struct tpm_space *space)
> +{
> + return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
> +}
> +
>  enum tpm_chip_flags {
>   TPM_CHIP_FLAG_TPM2  = BIT(1),
>   TPM_CHIP_FLAG_IRQ   = BIT(2),
> @@ -175,6 +193,12 @@ struct tpm_chip_seqops {
>   const struct seq_operations *seqops;
>  };
>  
> +struct tpm_sessions {
> + struct tpm_space *space;
> + u32 handle;
> + unsigned long created;
> +};
> +
>  struct tpm_chip {
>   struct device dev;
>   struct device devs;
> @@ -217,8 +241,12 @@ struct tpm_chip {
>  #endif /* CONFIG_ACPI */
>  
>   struct tpm_space work_space;
> + struct tpm_space *space;
>   u32 nr_commands;
>   u32 *cc_attrs_tbl;
> + struct tpm_sessions *sessions;
> + int max_sessions;
> + wait_queue_head_t session_wait;
>  };
>  
>  #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
> @@ -571,6 +599,13 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, 
> const u8 *hash);
>  int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
>  void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
>   unsigned int flags);
> +static inline void tpm2_session_clear_reserved(struct tpm_chip *chip,
> +struct tpm_space *space)
> +{
> + if (space->reserved_handle && 

Re: [PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-26 Thread Jarkko Sakkinen
On Mon, Jan 23, 2017 at 09:38:33PM -0800, James Bottomley wrote:
> In a TPM2, sessions can be globally exhausted once there are
> TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context saved).
> The Strategy for handling this is to keep a global count of all the
> sessions along with their creation time.  Then if we see the TPM run
> out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for one
> to become free, but if it doesn't, we forcibly evict an existing one.
> The eviction strategy waits until the current command is repeated to
> evict the session which should guarantee there is an available slot.
> 
> On the force eviction case, we make sure that the victim session is at
> least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue for
> session slots is a FIFO one, ensuring that once we run out of
> sessions, everyone will get a session in a bounded time and once they
> get one, they'll have SESSION_TIMEOUT to use it before it may be
> subject to eviction.
> 
> Signed-off-by: James Bottomley 

This is not a proper review yet. Just quick question: why do you need
a real time (i.e. created)? Maybe in the force eviction case it would
be enough to sleep lets say 500 ms and pick the victim with smallest
number? I.e. just have increasing u64 counter instead of real time.

That would simplify this patch a lot and does not prevent to refine
later on if workloads show need for more complex logic.

/Jarkko

> ---
>  drivers/char/tpm/tpm-chip.c   |   1 +
>  drivers/char/tpm/tpm.h|  39 +++-
>  drivers/char/tpm/tpm2-cmd.c   |  15 +++
>  drivers/char/tpm/tpm2-space.c | 213 
> +++---
>  drivers/char/tpm/tpms-dev.c   |  17 +++-
>  5 files changed, 271 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 6282ad0..150c6b8 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
>  
>   mutex_init(>tpm_mutex);
>   init_rwsem(>ops_sem);
> + init_waitqueue_head(>session_wait);
>  
>   chip->ops = ops;
>  
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index b77fc60..9fd6101 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -95,7 +95,8 @@ enum tpm2_return_codes {
>   TPM2_RC_HANDLE  = 0x008B,
>   TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
>   TPM2_RC_DISABLED= 0x0120,
> - TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> + TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
> + TPM2_RC_TESTING = 0x090A,
>   TPM2_RC_REFERENCE_H0= 0x0910,
>  };
>  
> @@ -137,7 +138,8 @@ enum tpm2_capabilities {
>  };
>  
>  enum tpm2_properties {
> - TPM_PT_TOTAL_COMMANDS   = 0x0129,
> + TPM_PT_TOTAL_COMMANDS   = 0x0129,
> + TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
>  };
>  
>  enum tpm2_startup_types {
> @@ -161,8 +163,24 @@ struct tpm_space {
>   u8 *context_buf;
>   u32 session_tbl[6];
>   u8 *session_buf;
> + u32 reserved_handle;
>  };
>  
> +#define TPM2_HANDLE_FORCE_EVICT 0x
> +
> +static inline void tpm2_session_force_evict(struct tpm_space *space)
> +{
> + /* if reserved handle is not empty, we already have a
> +  * session for eviction, so no need to force one
> +  */
> + if (space->reserved_handle == 0)
> + space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
> +}
> +static inline bool tpm2_is_session_force_evict(struct tpm_space *space)
> +{
> + return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
> +}
> +
>  enum tpm_chip_flags {
>   TPM_CHIP_FLAG_TPM2  = BIT(1),
>   TPM_CHIP_FLAG_IRQ   = BIT(2),
> @@ -175,6 +193,12 @@ struct tpm_chip_seqops {
>   const struct seq_operations *seqops;
>  };
>  
> +struct tpm_sessions {
> + struct tpm_space *space;
> + u32 handle;
> + unsigned long created;
> +};
> +
>  struct tpm_chip {
>   struct device dev;
>   struct device devs;
> @@ -217,8 +241,12 @@ struct tpm_chip {
>  #endif /* CONFIG_ACPI */
>  
>   struct tpm_space work_space;
> + struct tpm_space *space;
>   u32 nr_commands;
>   u32 *cc_attrs_tbl;
> + struct tpm_sessions *sessions;
> + int max_sessions;
> + wait_queue_head_t session_wait;
>  };
>  
>  #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
> @@ -571,6 +599,13 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, 
> const u8 *hash);
>  int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
>  void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
>   unsigned int flags);
> +static inline void tpm2_session_clear_reserved(struct tpm_chip *chip,
> +struct tpm_space *space)
> +{
> + if (space->reserved_handle && !tpm2_is_session_force_evict(space))
> + 

[PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-23 Thread James Bottomley
In a TPM2, sessions can be globally exhausted once there are
TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context saved).
The Strategy for handling this is to keep a global count of all the
sessions along with their creation time.  Then if we see the TPM run
out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for one
to become free, but if it doesn't, we forcibly evict an existing one.
The eviction strategy waits until the current command is repeated to
evict the session which should guarantee there is an available slot.

On the force eviction case, we make sure that the victim session is at
least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue for
session slots is a FIFO one, ensuring that once we run out of
sessions, everyone will get a session in a bounded time and once they
get one, they'll have SESSION_TIMEOUT to use it before it may be
subject to eviction.

Signed-off-by: James Bottomley 
---
 drivers/char/tpm/tpm-chip.c   |   1 +
 drivers/char/tpm/tpm.h|  39 +++-
 drivers/char/tpm/tpm2-cmd.c   |  15 +++
 drivers/char/tpm/tpm2-space.c | 213 +++---
 drivers/char/tpm/tpms-dev.c   |  17 +++-
 5 files changed, 271 insertions(+), 14 deletions(-)

diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 6282ad0..150c6b8 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
 
mutex_init(>tpm_mutex);
init_rwsem(>ops_sem);
+   init_waitqueue_head(>session_wait);
 
chip->ops = ops;
 
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index b77fc60..9fd6101 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -95,7 +95,8 @@ enum tpm2_return_codes {
TPM2_RC_HANDLE  = 0x008B,
TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
TPM2_RC_DISABLED= 0x0120,
-   TPM2_RC_TESTING = 0x090A, /* RC_WARN */
+   TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
+   TPM2_RC_TESTING = 0x090A,
TPM2_RC_REFERENCE_H0= 0x0910,
 };
 
@@ -137,7 +138,8 @@ enum tpm2_capabilities {
 };
 
 enum tpm2_properties {
-   TPM_PT_TOTAL_COMMANDS   = 0x0129,
+   TPM_PT_TOTAL_COMMANDS   = 0x0129,
+   TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
 };
 
 enum tpm2_startup_types {
@@ -161,8 +163,24 @@ struct tpm_space {
u8 *context_buf;
u32 session_tbl[6];
u8 *session_buf;
+   u32 reserved_handle;
 };
 
+#define TPM2_HANDLE_FORCE_EVICT 0x
+
+static inline void tpm2_session_force_evict(struct tpm_space *space)
+{
+   /* if reserved handle is not empty, we already have a
+* session for eviction, so no need to force one
+*/
+   if (space->reserved_handle == 0)
+   space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
+}
+static inline bool tpm2_is_session_force_evict(struct tpm_space *space)
+{
+   return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
+}
+
 enum tpm_chip_flags {
TPM_CHIP_FLAG_TPM2  = BIT(1),
TPM_CHIP_FLAG_IRQ   = BIT(2),
@@ -175,6 +193,12 @@ struct tpm_chip_seqops {
const struct seq_operations *seqops;
 };
 
+struct tpm_sessions {
+   struct tpm_space *space;
+   u32 handle;
+   unsigned long created;
+};
+
 struct tpm_chip {
struct device dev;
struct device devs;
@@ -217,8 +241,12 @@ struct tpm_chip {
 #endif /* CONFIG_ACPI */
 
struct tpm_space work_space;
+   struct tpm_space *space;
u32 nr_commands;
u32 *cc_attrs_tbl;
+   struct tpm_sessions *sessions;
+   int max_sessions;
+   wait_queue_head_t session_wait;
 };
 
 #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
@@ -571,6 +599,13 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, 
const u8 *hash);
 int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
 void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
unsigned int flags);
+static inline void tpm2_session_clear_reserved(struct tpm_chip *chip,
+  struct tpm_space *space)
+{
+   if (space->reserved_handle && !tpm2_is_session_force_evict(space))
+   tpm2_flush_context_cmd(chip, space->reserved_handle, 0);
+   space->reserved_handle = 0;
+}
 int tpm2_seal_trusted(struct tpm_chip *chip,
  struct trusted_key_payload *payload,
  struct trusted_key_options *options);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 0178816..3a54479 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -1000,6 +1000,7 @@ int tpm2_auto_startup(struct tpm_chip *chip)
struct tpm_buf buf;
u32 nr_commands;
u32 *attrs;
+   u32 nr_sessions;
int rc;

[PATCH 2/2] tpm2-space: add handling for global session exhaustion

2017-01-23 Thread James Bottomley
In a TPM2, sessions can be globally exhausted once there are
TPM_PT_ACTIVE_SESSION_MAX of them (even if they're all context saved).
The Strategy for handling this is to keep a global count of all the
sessions along with their creation time.  Then if we see the TPM run
out of sessions (via the TPM_RC_SESSION_HANDLES) we first wait for one
to become free, but if it doesn't, we forcibly evict an existing one.
The eviction strategy waits until the current command is repeated to
evict the session which should guarantee there is an available slot.

On the force eviction case, we make sure that the victim session is at
least SESSION_TIMEOUT old (currently 2 seconds).  The wait queue for
session slots is a FIFO one, ensuring that once we run out of
sessions, everyone will get a session in a bounded time and once they
get one, they'll have SESSION_TIMEOUT to use it before it may be
subject to eviction.

Signed-off-by: James Bottomley 
---
 drivers/char/tpm/tpm-chip.c   |   1 +
 drivers/char/tpm/tpm.h|  39 +++-
 drivers/char/tpm/tpm2-cmd.c   |  15 +++
 drivers/char/tpm/tpm2-space.c | 213 +++---
 drivers/char/tpm/tpms-dev.c   |  17 +++-
 5 files changed, 271 insertions(+), 14 deletions(-)

diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 6282ad0..150c6b8 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -164,6 +164,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
 
mutex_init(>tpm_mutex);
init_rwsem(>ops_sem);
+   init_waitqueue_head(>session_wait);
 
chip->ops = ops;
 
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index b77fc60..9fd6101 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -95,7 +95,8 @@ enum tpm2_return_codes {
TPM2_RC_HANDLE  = 0x008B,
TPM2_RC_INITIALIZE  = 0x0100, /* RC_VER1 */
TPM2_RC_DISABLED= 0x0120,
-   TPM2_RC_TESTING = 0x090A, /* RC_WARN */
+   TPM2_RC_SESSION_HANDLES = 0x0905, /* RC_WARN */
+   TPM2_RC_TESTING = 0x090A,
TPM2_RC_REFERENCE_H0= 0x0910,
 };
 
@@ -137,7 +138,8 @@ enum tpm2_capabilities {
 };
 
 enum tpm2_properties {
-   TPM_PT_TOTAL_COMMANDS   = 0x0129,
+   TPM_PT_TOTAL_COMMANDS   = 0x0129,
+   TPM_PT_ACTIVE_SESSIONS_MAX  = 0x0111,
 };
 
 enum tpm2_startup_types {
@@ -161,8 +163,24 @@ struct tpm_space {
u8 *context_buf;
u32 session_tbl[6];
u8 *session_buf;
+   u32 reserved_handle;
 };
 
+#define TPM2_HANDLE_FORCE_EVICT 0x
+
+static inline void tpm2_session_force_evict(struct tpm_space *space)
+{
+   /* if reserved handle is not empty, we already have a
+* session for eviction, so no need to force one
+*/
+   if (space->reserved_handle == 0)
+   space->reserved_handle = TPM2_HANDLE_FORCE_EVICT;
+}
+static inline bool tpm2_is_session_force_evict(struct tpm_space *space)
+{
+   return space->reserved_handle == TPM2_HANDLE_FORCE_EVICT;
+}
+
 enum tpm_chip_flags {
TPM_CHIP_FLAG_TPM2  = BIT(1),
TPM_CHIP_FLAG_IRQ   = BIT(2),
@@ -175,6 +193,12 @@ struct tpm_chip_seqops {
const struct seq_operations *seqops;
 };
 
+struct tpm_sessions {
+   struct tpm_space *space;
+   u32 handle;
+   unsigned long created;
+};
+
 struct tpm_chip {
struct device dev;
struct device devs;
@@ -217,8 +241,12 @@ struct tpm_chip {
 #endif /* CONFIG_ACPI */
 
struct tpm_space work_space;
+   struct tpm_space *space;
u32 nr_commands;
u32 *cc_attrs_tbl;
+   struct tpm_sessions *sessions;
+   int max_sessions;
+   wait_queue_head_t session_wait;
 };
 
 #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
@@ -571,6 +599,13 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, 
const u8 *hash);
 int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
 void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
unsigned int flags);
+static inline void tpm2_session_clear_reserved(struct tpm_chip *chip,
+  struct tpm_space *space)
+{
+   if (space->reserved_handle && !tpm2_is_session_force_evict(space))
+   tpm2_flush_context_cmd(chip, space->reserved_handle, 0);
+   space->reserved_handle = 0;
+}
 int tpm2_seal_trusted(struct tpm_chip *chip,
  struct trusted_key_payload *payload,
  struct trusted_key_options *options);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 0178816..3a54479 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -1000,6 +1000,7 @@ int tpm2_auto_startup(struct tpm_chip *chip)
struct tpm_buf buf;
u32 nr_commands;
u32 *attrs;
+   u32 nr_sessions;
int rc;
int i;
 
@@ -1075,6 +1076,20