diff options
Diffstat (limited to 'drivers/virt/coco/tsm.c')
| -rw-r--r-- | drivers/virt/coco/tsm.c | 93 | 
1 files changed, 91 insertions, 2 deletions
diff --git a/drivers/virt/coco/tsm.c b/drivers/virt/coco/tsm.c index 7db534b63c9f..9432d4e303f1 100644 --- a/drivers/virt/coco/tsm.c +++ b/drivers/virt/coco/tsm.c @@ -34,7 +34,7 @@ static DECLARE_RWSEM(tsm_rwsem);   * The attestation report format is TSM provider specific, when / if a standard   * materializes that can be published instead of the vendor layout. Until then   * the 'provider' attribute indicates the format of 'outblob', and optionally - * 'auxblob'. + * 'auxblob' and 'manifestblob'.   */  struct tsm_report_state { @@ -47,6 +47,7 @@ struct tsm_report_state {  enum tsm_data_select {  	TSM_REPORT,  	TSM_CERTS, +	TSM_MANIFEST,  };  static struct tsm_report *to_tsm_report(struct config_item *cfg) @@ -118,6 +119,74 @@ static ssize_t tsm_report_privlevel_floor_show(struct config_item *cfg,  }  CONFIGFS_ATTR_RO(tsm_report_, privlevel_floor); +static ssize_t tsm_report_service_provider_store(struct config_item *cfg, +						 const char *buf, size_t len) +{ +	struct tsm_report *report = to_tsm_report(cfg); +	size_t sp_len; +	char *sp; +	int rc; + +	guard(rwsem_write)(&tsm_rwsem); +	rc = try_advance_write_generation(report); +	if (rc) +		return rc; + +	sp_len = (buf[len - 1] != '\n') ? len : len - 1; + +	sp = kstrndup(buf, sp_len, GFP_KERNEL); +	if (!sp) +		return -ENOMEM; +	kfree(report->desc.service_provider); + +	report->desc.service_provider = sp; + +	return len; +} +CONFIGFS_ATTR_WO(tsm_report_, service_provider); + +static ssize_t tsm_report_service_guid_store(struct config_item *cfg, +					     const char *buf, size_t len) +{ +	struct tsm_report *report = to_tsm_report(cfg); +	int rc; + +	guard(rwsem_write)(&tsm_rwsem); +	rc = try_advance_write_generation(report); +	if (rc) +		return rc; + +	report->desc.service_guid = guid_null; + +	rc = guid_parse(buf, &report->desc.service_guid); +	if (rc) +		return rc; + +	return len; +} +CONFIGFS_ATTR_WO(tsm_report_, service_guid); + +static ssize_t tsm_report_service_manifest_version_store(struct config_item *cfg, +							 const char *buf, size_t len) +{ +	struct tsm_report *report = to_tsm_report(cfg); +	unsigned int val; +	int rc; + +	rc = kstrtouint(buf, 0, &val); +	if (rc) +		return rc; + +	guard(rwsem_write)(&tsm_rwsem); +	rc = try_advance_write_generation(report); +	if (rc) +		return rc; +	report->desc.service_manifest_version = val; + +	return len; +} +CONFIGFS_ATTR_WO(tsm_report_, service_manifest_version); +  static ssize_t tsm_report_inblob_write(struct config_item *cfg,  				       const void *buf, size_t count)  { @@ -162,6 +231,9 @@ static ssize_t __read_report(struct tsm_report *report, void *buf, size_t count,  	if (select == TSM_REPORT) {  		out = report->outblob;  		len = report->outblob_len; +	} else if (select == TSM_MANIFEST) { +		out = report->manifestblob; +		len = report->manifestblob_len;  	} else {  		out = report->auxblob;  		len = report->auxblob_len; @@ -187,7 +259,7 @@ static ssize_t read_cached_report(struct tsm_report *report, void *buf,  	/*  	 * A given TSM backend always fills in ->outblob regardless of -	 * whether the report includes an auxblob or not. +	 * whether the report includes an auxblob/manifestblob or not.  	 */  	if (!report->outblob ||  	    state->read_generation != state->write_generation) @@ -223,8 +295,10 @@ static ssize_t tsm_report_read(struct tsm_report *report, void *buf,  	kvfree(report->outblob);  	kvfree(report->auxblob); +	kvfree(report->manifestblob);  	report->outblob = NULL;  	report->auxblob = NULL; +	report->manifestblob = NULL;  	rc = ops->report_new(report, provider.data);  	if (rc < 0)  		return rc; @@ -251,11 +325,23 @@ static ssize_t tsm_report_auxblob_read(struct config_item *cfg, void *buf,  }  CONFIGFS_BIN_ATTR_RO(tsm_report_, auxblob, NULL, TSM_OUTBLOB_MAX); +static ssize_t tsm_report_manifestblob_read(struct config_item *cfg, void *buf, +					    size_t count) +{ +	struct tsm_report *report = to_tsm_report(cfg); + +	return tsm_report_read(report, buf, count, TSM_MANIFEST); +} +CONFIGFS_BIN_ATTR_RO(tsm_report_, manifestblob, NULL, TSM_OUTBLOB_MAX); +  static struct configfs_attribute *tsm_report_attrs[] = {  	[TSM_REPORT_GENERATION] = &tsm_report_attr_generation,  	[TSM_REPORT_PROVIDER] = &tsm_report_attr_provider,  	[TSM_REPORT_PRIVLEVEL] = &tsm_report_attr_privlevel,  	[TSM_REPORT_PRIVLEVEL_FLOOR] = &tsm_report_attr_privlevel_floor, +	[TSM_REPORT_SERVICE_PROVIDER] = &tsm_report_attr_service_provider, +	[TSM_REPORT_SERVICE_GUID] = &tsm_report_attr_service_guid, +	[TSM_REPORT_SERVICE_MANIFEST_VER] = &tsm_report_attr_service_manifest_version,  	NULL,  }; @@ -263,6 +349,7 @@ static struct configfs_bin_attribute *tsm_report_bin_attrs[] = {  	[TSM_REPORT_INBLOB] = &tsm_report_attr_inblob,  	[TSM_REPORT_OUTBLOB] = &tsm_report_attr_outblob,  	[TSM_REPORT_AUXBLOB] = &tsm_report_attr_auxblob, +	[TSM_REPORT_MANIFESTBLOB] = &tsm_report_attr_manifestblob,  	NULL,  }; @@ -271,8 +358,10 @@ static void tsm_report_item_release(struct config_item *cfg)  	struct tsm_report *report = to_tsm_report(cfg);  	struct tsm_report_state *state = to_state(report); +	kvfree(report->manifestblob);  	kvfree(report->auxblob);  	kvfree(report->outblob); +	kfree(report->desc.service_provider);  	kfree(state);  }  | 
