diff mbox series

[7/8] tpm: add sysfs attributes for tpm2

Message ID 20190613180931.65445-8-swboyd@chromium.org (mailing list archive)
State New, archived
Headers show
Series tpm: Add driver for cr50 | expand

Commit Message

Stephen Boyd June 13, 2019, 6:09 p.m. UTC
From: Andrey Pronin <apronin@chromium.org>

Add sysfs attributes in TPM2.0 case for:
 - TPM_PT_PERMANENT flags
 - TPM_PT_STARTUP_CLEAR flags
 - lockout-related properties

Signed-off-by: Andrey Pronin <apronin@chromium.org>
Signed-off-by: Stephen Boyd <swboyd@chromium.org>
---

This was sent before as https://lkml.kernel.org/r/1469678766-117528-1-git-send-email-apronin@chromium.org
and Jarkko asked that the commit text be filled out more. I'll work with
Andrey to do so, but I'm including it here so we can see if there are
other comments.

 drivers/char/tpm/tpm-sysfs.c | 130 ++++++++++++++++++++++++++++++++---
 drivers/char/tpm/tpm.h       |  29 +++++++-
 2 files changed, 148 insertions(+), 11 deletions(-)

Comments

Jason Gunthorpe June 13, 2019, 11:30 p.m. UTC | #1
On Thu, Jun 13, 2019 at 11:09:30AM -0700, Stephen Boyd wrote:

> +static ssize_t tpm2_prop_flag_show(struct device *dev,
> +				   struct device_attribute *attr,
> +				   char *buf)
>  {
> -	/* XXX: If you wish to remove this restriction, you must first update
> -	 * tpm_sysfs to explicitly lock chip->ops.
> -	 */
> -	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> -		return;
> +	struct tpm2_prop_flag_dev_attribute *pa =
> +		container_of(attr, struct tpm2_prop_flag_dev_attribute, attr);
> +	u32 flags;
> +	ssize_t rc;
> +
> +	rc = tpm2_get_tpm_pt(to_tpm_chip(dev), pa->property_id, &flags,
> +			     "reading property");
> +	if (rc)
> +		return 0;
> +
> +	return sprintf(buf, "%d\n", !!(flags & pa->flag_mask));
> +}
> +
> +static ssize_t tpm2_prop_u32_show(struct device *dev,
> +				  struct device_attribute *attr,
> +				  char *buf)
> +{
> +	struct tpm2_prop_u32_dev_attribute *pa =
> +		container_of(attr, struct tpm2_prop_u32_dev_attribute, attr);
> +	u32 value;
> +	ssize_t rc;
> +
> +	rc = tpm2_get_tpm_pt(to_tpm_chip(dev), pa->property_id, &value,
> +			     "reading property");
> +	if (rc)
> +		return 0;
> +
> +	return sprintf(buf, "%u\n", value);
> +}
>  
> +#define TPM2_PROP_FLAG_ATTR(_name, _property_id, _flag_mask)           \
> +	struct tpm2_prop_flag_dev_attribute attr_tpm2_prop_##_name = { \
> +		__ATTR(_name, S_IRUGO, tpm2_prop_flag_show, NULL),     \
> +		_property_id, _flag_mask                               \
> +	}
> +
> +#define TPM2_PROP_U32_ATTR(_name, _property_id)                        \
> +	struct tpm2_prop_u32_dev_attribute attr_tpm2_prop_##_name = {  \
> +		__ATTR(_name, S_IRUGO, tpm2_prop_u32_show, NULL),      \
> +		_property_id                                           \
> +	}
> +
> +TPM2_PROP_FLAG_ATTR(owner_auth_set,
> +		    TPM2_PT_PERMANENT, TPM2_ATTR_OWNER_AUTH_SET);
> +TPM2_PROP_FLAG_ATTR(endorsement_auth_set,
> +		    TPM2_PT_PERMANENT, TPM2_ATTR_ENDORSEMENT_AUTH_SET);
> +TPM2_PROP_FLAG_ATTR(lockout_auth_set,
> +		    TPM2_PT_PERMANENT, TPM2_ATTR_LOCKOUT_AUTH_SET);
> +TPM2_PROP_FLAG_ATTR(disable_clear,
> +		    TPM2_PT_PERMANENT, TPM2_ATTR_DISABLE_CLEAR);
> +TPM2_PROP_FLAG_ATTR(in_lockout,
> +		    TPM2_PT_PERMANENT, TPM2_ATTR_IN_LOCKOUT);
> +TPM2_PROP_FLAG_ATTR(tpm_generated_eps,
> +		    TPM2_PT_PERMANENT, TPM2_ATTR_TPM_GENERATED_EPS);
> +
> +TPM2_PROP_FLAG_ATTR(ph_enable,
> +		    TPM2_PT_STARTUP_CLEAR, TPM2_ATTR_PH_ENABLE);
> +TPM2_PROP_FLAG_ATTR(sh_enable,
> +		    TPM2_PT_STARTUP_CLEAR, TPM2_ATTR_SH_ENABLE);
> +TPM2_PROP_FLAG_ATTR(eh_enable,
> +		    TPM2_PT_STARTUP_CLEAR, TPM2_ATTR_EH_ENABLE);
> +TPM2_PROP_FLAG_ATTR(ph_enable_nv,
> +		    TPM2_PT_STARTUP_CLEAR, TPM2_ATTR_PH_ENABLE_NV);
> +TPM2_PROP_FLAG_ATTR(orderly,
> +		    TPM2_PT_STARTUP_CLEAR, TPM2_ATTR_ORDERLY);
> +
> +TPM2_PROP_U32_ATTR(lockout_counter, TPM2_PT_LOCKOUT_COUNTER);
> +TPM2_PROP_U32_ATTR(max_auth_fail, TPM2_PT_MAX_AUTH_FAIL);
> +TPM2_PROP_U32_ATTR(lockout_interval, TPM2_PT_LOCKOUT_INTERVAL);
> +TPM2_PROP_U32_ATTR(lockout_recovery, TPM2_PT_LOCKOUT_RECOVERY);
> +
> +#define ATTR_FOR_TPM2_PROP(_name) (&attr_tpm2_prop_##_name.attr.attr)
> +static struct attribute *tpm2_dev_attrs[] = {
> +	ATTR_FOR_TPM2_PROP(owner_auth_set),
> +	ATTR_FOR_TPM2_PROP(endorsement_auth_set),
> +	ATTR_FOR_TPM2_PROP(lockout_auth_set),
> +	ATTR_FOR_TPM2_PROP(disable_clear),
> +	ATTR_FOR_TPM2_PROP(in_lockout),
> +	ATTR_FOR_TPM2_PROP(tpm_generated_eps),
> +	ATTR_FOR_TPM2_PROP(ph_enable),
> +	ATTR_FOR_TPM2_PROP(sh_enable),
> +	ATTR_FOR_TPM2_PROP(eh_enable),
> +	ATTR_FOR_TPM2_PROP(ph_enable_nv),
> +	ATTR_FOR_TPM2_PROP(orderly),
> +	ATTR_FOR_TPM2_PROP(lockout_counter),
> +	ATTR_FOR_TPM2_PROP(max_auth_fail),
> +	ATTR_FOR_TPM2_PROP(lockout_interval),
> +	ATTR_FOR_TPM2_PROP(lockout_recovery),
> +	&dev_attr_durations.attr,
> +	&dev_attr_timeouts.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group tpm2_dev_group = {
> +	.attrs = tpm2_dev_attrs,
> +};
> +
> +void tpm_sysfs_add_device(struct tpm_chip *chip)
> +{
>  	/* The sysfs routines rely on an implicit tpm_try_get_ops, device_del
>  	 * is called before ops is null'd and the sysfs core synchronizes this
>  	 * removal so that no callbacks are running or can run again
>  	 */
> +	/* FIXME: update tpm_sysfs to explicitly lock chip->ops for TPM 2.0
> +	 */

What does the fixme mean? You cold add proper get_ops locking for the
tpm2 callbacks, it is not so hard. 

I actually think it is needed...

Oh. Jarkko, this is why you can't set ops to null in the class
shutdown, sysfs needs to be fixed first. ops can only go to null for
TPM1 after device_del until someone fixes the locking.

Jason
Jarkko Sakkinen June 14, 2019, 3:31 p.m. UTC | #2
On Thu, Jun 13, 2019 at 11:09:30AM -0700, Stephen Boyd wrote:
> From: Andrey Pronin <apronin@chromium.org>
> 
> Add sysfs attributes in TPM2.0 case for:
>  - TPM_PT_PERMANENT flags
>  - TPM_PT_STARTUP_CLEAR flags
>  - lockout-related properties
> 
> Signed-off-by: Andrey Pronin <apronin@chromium.org>
> Signed-off-by: Stephen Boyd <swboyd@chromium.org>
> ---

You can use /dev/tpm0 for this from user space.

/Jarkko
diff mbox series

Patch

diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index 533a260d744e..e9f6f7960023 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -314,7 +314,7 @@  static ssize_t timeouts_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(timeouts);
 
-static struct attribute *tpm_dev_attrs[] = {
+static struct attribute *tpm1_dev_attrs[] = {
 	&dev_attr_pubek.attr,
 	&dev_attr_pcrs.attr,
 	&dev_attr_enabled.attr,
@@ -328,22 +328,132 @@  static struct attribute *tpm_dev_attrs[] = {
 	NULL,
 };
 
-static const struct attribute_group tpm_dev_group = {
-	.attrs = tpm_dev_attrs,
+static const struct attribute_group tpm1_dev_group = {
+	.attrs = tpm1_dev_attrs,
 };
 
-void tpm_sysfs_add_device(struct tpm_chip *chip)
+struct tpm2_prop_flag_dev_attribute {
+	struct device_attribute attr;
+	u32 property_id;
+	u32 flag_mask;
+};
+
+struct tpm2_prop_u32_dev_attribute {
+	struct device_attribute attr;
+	u32 property_id;
+};
+
+static ssize_t tpm2_prop_flag_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
 {
-	/* XXX: If you wish to remove this restriction, you must first update
-	 * tpm_sysfs to explicitly lock chip->ops.
-	 */
-	if (chip->flags & TPM_CHIP_FLAG_TPM2)
-		return;
+	struct tpm2_prop_flag_dev_attribute *pa =
+		container_of(attr, struct tpm2_prop_flag_dev_attribute, attr);
+	u32 flags;
+	ssize_t rc;
+
+	rc = tpm2_get_tpm_pt(to_tpm_chip(dev), pa->property_id, &flags,
+			     "reading property");
+	if (rc)
+		return 0;
+
+	return sprintf(buf, "%d\n", !!(flags & pa->flag_mask));
+}
+
+static ssize_t tpm2_prop_u32_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	struct tpm2_prop_u32_dev_attribute *pa =
+		container_of(attr, struct tpm2_prop_u32_dev_attribute, attr);
+	u32 value;
+	ssize_t rc;
+
+	rc = tpm2_get_tpm_pt(to_tpm_chip(dev), pa->property_id, &value,
+			     "reading property");
+	if (rc)
+		return 0;
+
+	return sprintf(buf, "%u\n", value);
+}
 
+#define TPM2_PROP_FLAG_ATTR(_name, _property_id, _flag_mask)           \
+	struct tpm2_prop_flag_dev_attribute attr_tpm2_prop_##_name = { \
+		__ATTR(_name, S_IRUGO, tpm2_prop_flag_show, NULL),     \
+		_property_id, _flag_mask                               \
+	}
+
+#define TPM2_PROP_U32_ATTR(_name, _property_id)                        \
+	struct tpm2_prop_u32_dev_attribute attr_tpm2_prop_##_name = {  \
+		__ATTR(_name, S_IRUGO, tpm2_prop_u32_show, NULL),      \
+		_property_id                                           \
+	}
+
+TPM2_PROP_FLAG_ATTR(owner_auth_set,
+		    TPM2_PT_PERMANENT, TPM2_ATTR_OWNER_AUTH_SET);
+TPM2_PROP_FLAG_ATTR(endorsement_auth_set,
+		    TPM2_PT_PERMANENT, TPM2_ATTR_ENDORSEMENT_AUTH_SET);
+TPM2_PROP_FLAG_ATTR(lockout_auth_set,
+		    TPM2_PT_PERMANENT, TPM2_ATTR_LOCKOUT_AUTH_SET);
+TPM2_PROP_FLAG_ATTR(disable_clear,
+		    TPM2_PT_PERMANENT, TPM2_ATTR_DISABLE_CLEAR);
+TPM2_PROP_FLAG_ATTR(in_lockout,
+		    TPM2_PT_PERMANENT, TPM2_ATTR_IN_LOCKOUT);
+TPM2_PROP_FLAG_ATTR(tpm_generated_eps,
+		    TPM2_PT_PERMANENT, TPM2_ATTR_TPM_GENERATED_EPS);
+
+TPM2_PROP_FLAG_ATTR(ph_enable,
+		    TPM2_PT_STARTUP_CLEAR, TPM2_ATTR_PH_ENABLE);
+TPM2_PROP_FLAG_ATTR(sh_enable,
+		    TPM2_PT_STARTUP_CLEAR, TPM2_ATTR_SH_ENABLE);
+TPM2_PROP_FLAG_ATTR(eh_enable,
+		    TPM2_PT_STARTUP_CLEAR, TPM2_ATTR_EH_ENABLE);
+TPM2_PROP_FLAG_ATTR(ph_enable_nv,
+		    TPM2_PT_STARTUP_CLEAR, TPM2_ATTR_PH_ENABLE_NV);
+TPM2_PROP_FLAG_ATTR(orderly,
+		    TPM2_PT_STARTUP_CLEAR, TPM2_ATTR_ORDERLY);
+
+TPM2_PROP_U32_ATTR(lockout_counter, TPM2_PT_LOCKOUT_COUNTER);
+TPM2_PROP_U32_ATTR(max_auth_fail, TPM2_PT_MAX_AUTH_FAIL);
+TPM2_PROP_U32_ATTR(lockout_interval, TPM2_PT_LOCKOUT_INTERVAL);
+TPM2_PROP_U32_ATTR(lockout_recovery, TPM2_PT_LOCKOUT_RECOVERY);
+
+#define ATTR_FOR_TPM2_PROP(_name) (&attr_tpm2_prop_##_name.attr.attr)
+static struct attribute *tpm2_dev_attrs[] = {
+	ATTR_FOR_TPM2_PROP(owner_auth_set),
+	ATTR_FOR_TPM2_PROP(endorsement_auth_set),
+	ATTR_FOR_TPM2_PROP(lockout_auth_set),
+	ATTR_FOR_TPM2_PROP(disable_clear),
+	ATTR_FOR_TPM2_PROP(in_lockout),
+	ATTR_FOR_TPM2_PROP(tpm_generated_eps),
+	ATTR_FOR_TPM2_PROP(ph_enable),
+	ATTR_FOR_TPM2_PROP(sh_enable),
+	ATTR_FOR_TPM2_PROP(eh_enable),
+	ATTR_FOR_TPM2_PROP(ph_enable_nv),
+	ATTR_FOR_TPM2_PROP(orderly),
+	ATTR_FOR_TPM2_PROP(lockout_counter),
+	ATTR_FOR_TPM2_PROP(max_auth_fail),
+	ATTR_FOR_TPM2_PROP(lockout_interval),
+	ATTR_FOR_TPM2_PROP(lockout_recovery),
+	&dev_attr_durations.attr,
+	&dev_attr_timeouts.attr,
+	NULL,
+};
+
+static const struct attribute_group tpm2_dev_group = {
+	.attrs = tpm2_dev_attrs,
+};
+
+void tpm_sysfs_add_device(struct tpm_chip *chip)
+{
 	/* The sysfs routines rely on an implicit tpm_try_get_ops, device_del
 	 * is called before ops is null'd and the sysfs core synchronizes this
 	 * removal so that no callbacks are running or can run again
 	 */
+	/* FIXME: update tpm_sysfs to explicitly lock chip->ops for TPM 2.0
+	 */
 	WARN_ON(chip->groups_cnt != 0);
-	chip->groups[chip->groups_cnt++] = &tpm_dev_group;
+	chip->groups[chip->groups_cnt++] =
+		(chip->flags & TPM_CHIP_FLAG_TPM2) ?
+		&tpm2_dev_group : &tpm1_dev_group;
 }
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 2cce072f25b5..c58140f86839 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -144,7 +144,34 @@  enum tpm2_capabilities {
 };
 
 enum tpm2_properties {
-	TPM_PT_TOTAL_COMMANDS	= 0x0129,
+	TPM_PT_TOTAL_COMMANDS		= 0x0129,
+	TPM2_PT_NONE			= 0,
+	TPM2_PT_GROUP			= 0x100,
+	TPM2_PT_FIXED			= TPM2_PT_GROUP,
+	TPM2_PT_VAR			= TPM2_PT_GROUP * 2,
+	TPM2_PT_PERMANENT		= TPM2_PT_VAR + 0,
+	TPM2_PT_STARTUP_CLEAR		= TPM2_PT_VAR + 1,
+	TPM2_PT_LOCKOUT_COUNTER		= TPM2_PT_VAR + 14,
+	TPM2_PT_MAX_AUTH_FAIL		= TPM2_PT_VAR + 15,
+	TPM2_PT_LOCKOUT_INTERVAL	= TPM2_PT_VAR + 16,
+	TPM2_PT_LOCKOUT_RECOVERY	= TPM2_PT_VAR + 17,
+};
+
+enum tpm2_attr_permanent {
+	TPM2_ATTR_OWNER_AUTH_SET	= BIT(0),
+	TPM2_ATTR_ENDORSEMENT_AUTH_SET	= BIT(1),
+	TPM2_ATTR_LOCKOUT_AUTH_SET	= BIT(2),
+	TPM2_ATTR_DISABLE_CLEAR		= BIT(8),
+	TPM2_ATTR_IN_LOCKOUT		= BIT(9),
+	TPM2_ATTR_TPM_GENERATED_EPS	= BIT(10),
+};
+
+enum tpm2_attr_startup_clear {
+	TPM2_ATTR_PH_ENABLE		= BIT(0),
+	TPM2_ATTR_SH_ENABLE		= BIT(1),
+	TPM2_ATTR_EH_ENABLE		= BIT(2),
+	TPM2_ATTR_PH_ENABLE_NV		= BIT(3),
+	TPM2_ATTR_ORDERLY		= BIT(31),
 };
 
 enum tpm2_startup_types {