Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/* Copyright(c) 2023 Intel Corporation. All rights reserved. */
  3
  4#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  5
  6#include <linux/tsm.h>
  7#include <linux/err.h>
  8#include <linux/slab.h>
  9#include <linux/rwsem.h>
 10#include <linux/string.h>
 11#include <linux/module.h>
 12#include <linux/cleanup.h>
 13#include <linux/configfs.h>
 14
 15static struct tsm_provider {
 16	const struct tsm_ops *ops;
 
 17	void *data;
 18} provider;
 19static DECLARE_RWSEM(tsm_rwsem);
 20
 21/**
 22 * DOC: Trusted Security Module (TSM) Attestation Report Interface
 23 *
 24 * The TSM report interface is a common provider of blobs that facilitate
 25 * attestation of a TVM (confidential computing guest) by an attestation
 26 * service. A TSM report combines a user-defined blob (likely a public-key with
 27 * a nonce for a key-exchange protocol) with a signed attestation report. That
 28 * combined blob is then used to obtain secrets provided by an agent that can
 29 * validate the attestation report. The expectation is that this interface is
 30 * invoked infrequently, however configfs allows for multiple agents to
 31 * own their own report generation instances to generate reports as
 32 * often as needed.
 33 *
 34 * The attestation report format is TSM provider specific, when / if a standard
 35 * materializes that can be published instead of the vendor layout. Until then
 36 * the 'provider' attribute indicates the format of 'outblob', and optionally
 37 * 'auxblob' and 'manifestblob'.
 38 */
 39
 40struct tsm_report_state {
 41	struct tsm_report report;
 42	unsigned long write_generation;
 43	unsigned long read_generation;
 44	struct config_item cfg;
 45};
 46
 47enum tsm_data_select {
 48	TSM_REPORT,
 49	TSM_CERTS,
 50	TSM_MANIFEST,
 51};
 52
 53static struct tsm_report *to_tsm_report(struct config_item *cfg)
 54{
 55	struct tsm_report_state *state =
 56		container_of(cfg, struct tsm_report_state, cfg);
 57
 58	return &state->report;
 59}
 60
 61static struct tsm_report_state *to_state(struct tsm_report *report)
 62{
 63	return container_of(report, struct tsm_report_state, report);
 64}
 65
 66static int try_advance_write_generation(struct tsm_report *report)
 67{
 68	struct tsm_report_state *state = to_state(report);
 69
 70	lockdep_assert_held_write(&tsm_rwsem);
 71
 72	/*
 73	 * Malicious or broken userspace has written enough times for
 74	 * read_generation == write_generation by modular arithmetic without an
 75	 * interim read. Stop accepting updates until the current report
 76	 * configuration is read.
 77	 */
 78	if (state->write_generation == state->read_generation - 1)
 79		return -EBUSY;
 80	state->write_generation++;
 81	return 0;
 82}
 83
 84static ssize_t tsm_report_privlevel_store(struct config_item *cfg,
 85					  const char *buf, size_t len)
 86{
 87	struct tsm_report *report = to_tsm_report(cfg);
 88	unsigned int val;
 89	int rc;
 90
 91	rc = kstrtouint(buf, 0, &val);
 92	if (rc)
 93		return rc;
 94
 95	/*
 96	 * The valid privilege levels that a TSM might accept, if it accepts a
 97	 * privilege level setting at all, are a max of TSM_PRIVLEVEL_MAX (see
 98	 * SEV-SNP GHCB) and a minimum of a TSM selected floor value no less
 99	 * than 0.
100	 */
101	if (provider.ops->privlevel_floor > val || val > TSM_PRIVLEVEL_MAX)
102		return -EINVAL;
103
104	guard(rwsem_write)(&tsm_rwsem);
105	rc = try_advance_write_generation(report);
106	if (rc)
107		return rc;
108	report->desc.privlevel = val;
109
110	return len;
111}
112CONFIGFS_ATTR_WO(tsm_report_, privlevel);
113
114static ssize_t tsm_report_privlevel_floor_show(struct config_item *cfg,
115					       char *buf)
116{
117	guard(rwsem_read)(&tsm_rwsem);
118	return sysfs_emit(buf, "%u\n", provider.ops->privlevel_floor);
119}
120CONFIGFS_ATTR_RO(tsm_report_, privlevel_floor);
121
122static ssize_t tsm_report_service_provider_store(struct config_item *cfg,
123						 const char *buf, size_t len)
124{
125	struct tsm_report *report = to_tsm_report(cfg);
126	size_t sp_len;
127	char *sp;
128	int rc;
129
130	guard(rwsem_write)(&tsm_rwsem);
131	rc = try_advance_write_generation(report);
132	if (rc)
133		return rc;
134
135	sp_len = (buf[len - 1] != '\n') ? len : len - 1;
136
137	sp = kstrndup(buf, sp_len, GFP_KERNEL);
138	if (!sp)
139		return -ENOMEM;
140	kfree(report->desc.service_provider);
141
142	report->desc.service_provider = sp;
143
144	return len;
145}
146CONFIGFS_ATTR_WO(tsm_report_, service_provider);
147
148static ssize_t tsm_report_service_guid_store(struct config_item *cfg,
149					     const char *buf, size_t len)
150{
151	struct tsm_report *report = to_tsm_report(cfg);
152	int rc;
153
154	guard(rwsem_write)(&tsm_rwsem);
155	rc = try_advance_write_generation(report);
156	if (rc)
157		return rc;
158
159	report->desc.service_guid = guid_null;
160
161	rc = guid_parse(buf, &report->desc.service_guid);
162	if (rc)
163		return rc;
164
165	return len;
166}
167CONFIGFS_ATTR_WO(tsm_report_, service_guid);
168
169static ssize_t tsm_report_service_manifest_version_store(struct config_item *cfg,
170							 const char *buf, size_t len)
171{
172	struct tsm_report *report = to_tsm_report(cfg);
173	unsigned int val;
174	int rc;
175
176	rc = kstrtouint(buf, 0, &val);
177	if (rc)
178		return rc;
179
180	guard(rwsem_write)(&tsm_rwsem);
181	rc = try_advance_write_generation(report);
182	if (rc)
183		return rc;
184	report->desc.service_manifest_version = val;
185
186	return len;
187}
188CONFIGFS_ATTR_WO(tsm_report_, service_manifest_version);
189
190static ssize_t tsm_report_inblob_write(struct config_item *cfg,
191				       const void *buf, size_t count)
192{
193	struct tsm_report *report = to_tsm_report(cfg);
194	int rc;
195
196	guard(rwsem_write)(&tsm_rwsem);
197	rc = try_advance_write_generation(report);
198	if (rc)
199		return rc;
200
201	report->desc.inblob_len = count;
202	memcpy(report->desc.inblob, buf, count);
203	return count;
204}
205CONFIGFS_BIN_ATTR_WO(tsm_report_, inblob, NULL, TSM_INBLOB_MAX);
206
207static ssize_t tsm_report_generation_show(struct config_item *cfg, char *buf)
208{
209	struct tsm_report *report = to_tsm_report(cfg);
210	struct tsm_report_state *state = to_state(report);
211
212	guard(rwsem_read)(&tsm_rwsem);
213	return sysfs_emit(buf, "%lu\n", state->write_generation);
214}
215CONFIGFS_ATTR_RO(tsm_report_, generation);
216
217static ssize_t tsm_report_provider_show(struct config_item *cfg, char *buf)
218{
219	guard(rwsem_read)(&tsm_rwsem);
220	return sysfs_emit(buf, "%s\n", provider.ops->name);
221}
222CONFIGFS_ATTR_RO(tsm_report_, provider);
223
224static ssize_t __read_report(struct tsm_report *report, void *buf, size_t count,
225			     enum tsm_data_select select)
226{
227	loff_t offset = 0;
228	ssize_t len;
229	u8 *out;
230
231	if (select == TSM_REPORT) {
232		out = report->outblob;
233		len = report->outblob_len;
234	} else if (select == TSM_MANIFEST) {
235		out = report->manifestblob;
236		len = report->manifestblob_len;
237	} else {
238		out = report->auxblob;
239		len = report->auxblob_len;
240	}
241
242	/*
243	 * Recall that a NULL @buf is configfs requesting the size of
244	 * the buffer.
245	 */
246	if (!buf)
247		return len;
248	return memory_read_from_buffer(buf, count, &offset, out, len);
249}
250
251static ssize_t read_cached_report(struct tsm_report *report, void *buf,
252				  size_t count, enum tsm_data_select select)
253{
254	struct tsm_report_state *state = to_state(report);
255
256	guard(rwsem_read)(&tsm_rwsem);
257	if (!report->desc.inblob_len)
258		return -EINVAL;
259
260	/*
261	 * A given TSM backend always fills in ->outblob regardless of
262	 * whether the report includes an auxblob/manifestblob or not.
263	 */
264	if (!report->outblob ||
265	    state->read_generation != state->write_generation)
266		return -EWOULDBLOCK;
267
268	return __read_report(report, buf, count, select);
269}
270
271static ssize_t tsm_report_read(struct tsm_report *report, void *buf,
272			       size_t count, enum tsm_data_select select)
273{
274	struct tsm_report_state *state = to_state(report);
275	const struct tsm_ops *ops;
276	ssize_t rc;
277
278	/* try to read from the existing report if present and valid... */
279	rc = read_cached_report(report, buf, count, select);
280	if (rc >= 0 || rc != -EWOULDBLOCK)
281		return rc;
282
283	/* slow path, report may need to be regenerated... */
284	guard(rwsem_write)(&tsm_rwsem);
285	ops = provider.ops;
286	if (!ops)
287		return -ENOTTY;
288	if (!report->desc.inblob_len)
289		return -EINVAL;
290
291	/* did another thread already generate this report? */
292	if (report->outblob &&
293	    state->read_generation == state->write_generation)
294		goto out;
295
296	kvfree(report->outblob);
297	kvfree(report->auxblob);
298	kvfree(report->manifestblob);
299	report->outblob = NULL;
300	report->auxblob = NULL;
301	report->manifestblob = NULL;
302	rc = ops->report_new(report, provider.data);
303	if (rc < 0)
304		return rc;
305	state->read_generation = state->write_generation;
306out:
307	return __read_report(report, buf, count, select);
308}
309
310static ssize_t tsm_report_outblob_read(struct config_item *cfg, void *buf,
311				       size_t count)
312{
313	struct tsm_report *report = to_tsm_report(cfg);
314
315	return tsm_report_read(report, buf, count, TSM_REPORT);
316}
317CONFIGFS_BIN_ATTR_RO(tsm_report_, outblob, NULL, TSM_OUTBLOB_MAX);
318
319static ssize_t tsm_report_auxblob_read(struct config_item *cfg, void *buf,
320				       size_t count)
321{
322	struct tsm_report *report = to_tsm_report(cfg);
323
324	return tsm_report_read(report, buf, count, TSM_CERTS);
325}
326CONFIGFS_BIN_ATTR_RO(tsm_report_, auxblob, NULL, TSM_OUTBLOB_MAX);
327
328static ssize_t tsm_report_manifestblob_read(struct config_item *cfg, void *buf,
329					    size_t count)
330{
331	struct tsm_report *report = to_tsm_report(cfg);
332
333	return tsm_report_read(report, buf, count, TSM_MANIFEST);
334}
335CONFIGFS_BIN_ATTR_RO(tsm_report_, manifestblob, NULL, TSM_OUTBLOB_MAX);
336
337static struct configfs_attribute *tsm_report_attrs[] = {
338	[TSM_REPORT_GENERATION] = &tsm_report_attr_generation,
339	[TSM_REPORT_PROVIDER] = &tsm_report_attr_provider,
340	[TSM_REPORT_PRIVLEVEL] = &tsm_report_attr_privlevel,
341	[TSM_REPORT_PRIVLEVEL_FLOOR] = &tsm_report_attr_privlevel_floor,
342	[TSM_REPORT_SERVICE_PROVIDER] = &tsm_report_attr_service_provider,
343	[TSM_REPORT_SERVICE_GUID] = &tsm_report_attr_service_guid,
344	[TSM_REPORT_SERVICE_MANIFEST_VER] = &tsm_report_attr_service_manifest_version,
345	NULL,
346};
347
 
 
 
 
 
 
 
 
 
 
 
348static struct configfs_bin_attribute *tsm_report_bin_attrs[] = {
349	[TSM_REPORT_INBLOB] = &tsm_report_attr_inblob,
350	[TSM_REPORT_OUTBLOB] = &tsm_report_attr_outblob,
351	[TSM_REPORT_AUXBLOB] = &tsm_report_attr_auxblob,
352	[TSM_REPORT_MANIFESTBLOB] = &tsm_report_attr_manifestblob,
 
 
 
353	NULL,
354};
355
356static void tsm_report_item_release(struct config_item *cfg)
357{
358	struct tsm_report *report = to_tsm_report(cfg);
359	struct tsm_report_state *state = to_state(report);
360
361	kvfree(report->manifestblob);
362	kvfree(report->auxblob);
363	kvfree(report->outblob);
364	kfree(report->desc.service_provider);
365	kfree(state);
366}
367
368static struct configfs_item_operations tsm_report_item_ops = {
369	.release = tsm_report_item_release,
370};
371
372static bool tsm_report_is_visible(struct config_item *item,
373				  struct configfs_attribute *attr, int n)
374{
375	guard(rwsem_read)(&tsm_rwsem);
376	if (!provider.ops)
377		return false;
378
379	if (!provider.ops->report_attr_visible)
380		return true;
381
382	return provider.ops->report_attr_visible(n);
383}
384
385static bool tsm_report_is_bin_visible(struct config_item *item,
386				      struct configfs_bin_attribute *attr, int n)
387{
388	guard(rwsem_read)(&tsm_rwsem);
389	if (!provider.ops)
390		return false;
391
392	if (!provider.ops->report_bin_attr_visible)
393		return true;
394
395	return provider.ops->report_bin_attr_visible(n);
396}
397
398static struct configfs_group_operations tsm_report_attr_group_ops = {
399	.is_visible = tsm_report_is_visible,
400	.is_bin_visible = tsm_report_is_bin_visible,
401};
402
403static const struct config_item_type tsm_report_type = {
404	.ct_owner = THIS_MODULE,
405	.ct_bin_attrs = tsm_report_bin_attrs,
406	.ct_attrs = tsm_report_attrs,
407	.ct_item_ops = &tsm_report_item_ops,
408	.ct_group_ops = &tsm_report_attr_group_ops,
409};
 
 
 
 
 
 
 
 
 
410
411static struct config_item *tsm_report_make_item(struct config_group *group,
412						const char *name)
413{
414	struct tsm_report_state *state;
415
416	guard(rwsem_read)(&tsm_rwsem);
417	if (!provider.ops)
418		return ERR_PTR(-ENXIO);
419
420	state = kzalloc(sizeof(*state), GFP_KERNEL);
421	if (!state)
422		return ERR_PTR(-ENOMEM);
423
424	config_item_init_type_name(&state->cfg, name, &tsm_report_type);
425	return &state->cfg;
426}
427
428static struct configfs_group_operations tsm_report_group_ops = {
429	.make_item = tsm_report_make_item,
430};
431
432static const struct config_item_type tsm_reports_type = {
433	.ct_owner = THIS_MODULE,
434	.ct_group_ops = &tsm_report_group_ops,
435};
436
437static const struct config_item_type tsm_root_group_type = {
438	.ct_owner = THIS_MODULE,
439};
440
441static struct configfs_subsystem tsm_configfs = {
442	.su_group = {
443		.cg_item = {
444			.ci_namebuf = "tsm",
445			.ci_type = &tsm_root_group_type,
446		},
447	},
448	.su_mutex = __MUTEX_INITIALIZER(tsm_configfs.su_mutex),
449};
450
451int tsm_register(const struct tsm_ops *ops, void *priv)
 
452{
453	const struct tsm_ops *conflict;
454
 
 
 
 
 
455	guard(rwsem_write)(&tsm_rwsem);
456	conflict = provider.ops;
457	if (conflict) {
458		pr_err("\"%s\" ops already registered\n", conflict->name);
459		return -EBUSY;
460	}
461
462	provider.ops = ops;
463	provider.data = priv;
 
464	return 0;
465}
466EXPORT_SYMBOL_GPL(tsm_register);
467
468int tsm_unregister(const struct tsm_ops *ops)
469{
470	guard(rwsem_write)(&tsm_rwsem);
471	if (ops != provider.ops)
472		return -EBUSY;
473	provider.ops = NULL;
474	provider.data = NULL;
 
475	return 0;
476}
477EXPORT_SYMBOL_GPL(tsm_unregister);
478
479static struct config_group *tsm_report_group;
480
481static int __init tsm_init(void)
482{
483	struct config_group *root = &tsm_configfs.su_group;
484	struct config_group *tsm;
485	int rc;
486
487	config_group_init(root);
488	rc = configfs_register_subsystem(&tsm_configfs);
489	if (rc)
490		return rc;
491
492	tsm = configfs_register_default_group(root, "report",
493					      &tsm_reports_type);
494	if (IS_ERR(tsm)) {
495		configfs_unregister_subsystem(&tsm_configfs);
496		return PTR_ERR(tsm);
497	}
498	tsm_report_group = tsm;
499
500	return 0;
501}
502module_init(tsm_init);
503
504static void __exit tsm_exit(void)
505{
506	configfs_unregister_default_group(tsm_report_group);
507	configfs_unregister_subsystem(&tsm_configfs);
508}
509module_exit(tsm_exit);
510
511MODULE_LICENSE("GPL");
512MODULE_DESCRIPTION("Provide Trusted Security Module attestation reports via configfs");
v6.8
  1// SPDX-License-Identifier: GPL-2.0-only
  2/* Copyright(c) 2023 Intel Corporation. All rights reserved. */
  3
  4#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  5
  6#include <linux/tsm.h>
  7#include <linux/err.h>
  8#include <linux/slab.h>
  9#include <linux/rwsem.h>
 10#include <linux/string.h>
 11#include <linux/module.h>
 12#include <linux/cleanup.h>
 13#include <linux/configfs.h>
 14
 15static struct tsm_provider {
 16	const struct tsm_ops *ops;
 17	const struct config_item_type *type;
 18	void *data;
 19} provider;
 20static DECLARE_RWSEM(tsm_rwsem);
 21
 22/**
 23 * DOC: Trusted Security Module (TSM) Attestation Report Interface
 24 *
 25 * The TSM report interface is a common provider of blobs that facilitate
 26 * attestation of a TVM (confidential computing guest) by an attestation
 27 * service. A TSM report combines a user-defined blob (likely a public-key with
 28 * a nonce for a key-exchange protocol) with a signed attestation report. That
 29 * combined blob is then used to obtain secrets provided by an agent that can
 30 * validate the attestation report. The expectation is that this interface is
 31 * invoked infrequently, however configfs allows for multiple agents to
 32 * own their own report generation instances to generate reports as
 33 * often as needed.
 34 *
 35 * The attestation report format is TSM provider specific, when / if a standard
 36 * materializes that can be published instead of the vendor layout. Until then
 37 * the 'provider' attribute indicates the format of 'outblob', and optionally
 38 * 'auxblob'.
 39 */
 40
 41struct tsm_report_state {
 42	struct tsm_report report;
 43	unsigned long write_generation;
 44	unsigned long read_generation;
 45	struct config_item cfg;
 46};
 47
 48enum tsm_data_select {
 49	TSM_REPORT,
 50	TSM_CERTS,
 
 51};
 52
 53static struct tsm_report *to_tsm_report(struct config_item *cfg)
 54{
 55	struct tsm_report_state *state =
 56		container_of(cfg, struct tsm_report_state, cfg);
 57
 58	return &state->report;
 59}
 60
 61static struct tsm_report_state *to_state(struct tsm_report *report)
 62{
 63	return container_of(report, struct tsm_report_state, report);
 64}
 65
 66static int try_advance_write_generation(struct tsm_report *report)
 67{
 68	struct tsm_report_state *state = to_state(report);
 69
 70	lockdep_assert_held_write(&tsm_rwsem);
 71
 72	/*
 73	 * Malicious or broken userspace has written enough times for
 74	 * read_generation == write_generation by modular arithmetic without an
 75	 * interim read. Stop accepting updates until the current report
 76	 * configuration is read.
 77	 */
 78	if (state->write_generation == state->read_generation - 1)
 79		return -EBUSY;
 80	state->write_generation++;
 81	return 0;
 82}
 83
 84static ssize_t tsm_report_privlevel_store(struct config_item *cfg,
 85					  const char *buf, size_t len)
 86{
 87	struct tsm_report *report = to_tsm_report(cfg);
 88	unsigned int val;
 89	int rc;
 90
 91	rc = kstrtouint(buf, 0, &val);
 92	if (rc)
 93		return rc;
 94
 95	/*
 96	 * The valid privilege levels that a TSM might accept, if it accepts a
 97	 * privilege level setting at all, are a max of TSM_PRIVLEVEL_MAX (see
 98	 * SEV-SNP GHCB) and a minimum of a TSM selected floor value no less
 99	 * than 0.
100	 */
101	if (provider.ops->privlevel_floor > val || val > TSM_PRIVLEVEL_MAX)
102		return -EINVAL;
103
104	guard(rwsem_write)(&tsm_rwsem);
105	rc = try_advance_write_generation(report);
106	if (rc)
107		return rc;
108	report->desc.privlevel = val;
109
110	return len;
111}
112CONFIGFS_ATTR_WO(tsm_report_, privlevel);
113
114static ssize_t tsm_report_privlevel_floor_show(struct config_item *cfg,
115					       char *buf)
116{
117	guard(rwsem_read)(&tsm_rwsem);
118	return sysfs_emit(buf, "%u\n", provider.ops->privlevel_floor);
119}
120CONFIGFS_ATTR_RO(tsm_report_, privlevel_floor);
121
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122static ssize_t tsm_report_inblob_write(struct config_item *cfg,
123				       const void *buf, size_t count)
124{
125	struct tsm_report *report = to_tsm_report(cfg);
126	int rc;
127
128	guard(rwsem_write)(&tsm_rwsem);
129	rc = try_advance_write_generation(report);
130	if (rc)
131		return rc;
132
133	report->desc.inblob_len = count;
134	memcpy(report->desc.inblob, buf, count);
135	return count;
136}
137CONFIGFS_BIN_ATTR_WO(tsm_report_, inblob, NULL, TSM_INBLOB_MAX);
138
139static ssize_t tsm_report_generation_show(struct config_item *cfg, char *buf)
140{
141	struct tsm_report *report = to_tsm_report(cfg);
142	struct tsm_report_state *state = to_state(report);
143
144	guard(rwsem_read)(&tsm_rwsem);
145	return sysfs_emit(buf, "%lu\n", state->write_generation);
146}
147CONFIGFS_ATTR_RO(tsm_report_, generation);
148
149static ssize_t tsm_report_provider_show(struct config_item *cfg, char *buf)
150{
151	guard(rwsem_read)(&tsm_rwsem);
152	return sysfs_emit(buf, "%s\n", provider.ops->name);
153}
154CONFIGFS_ATTR_RO(tsm_report_, provider);
155
156static ssize_t __read_report(struct tsm_report *report, void *buf, size_t count,
157			     enum tsm_data_select select)
158{
159	loff_t offset = 0;
160	ssize_t len;
161	u8 *out;
162
163	if (select == TSM_REPORT) {
164		out = report->outblob;
165		len = report->outblob_len;
 
 
 
166	} else {
167		out = report->auxblob;
168		len = report->auxblob_len;
169	}
170
171	/*
172	 * Recall that a NULL @buf is configfs requesting the size of
173	 * the buffer.
174	 */
175	if (!buf)
176		return len;
177	return memory_read_from_buffer(buf, count, &offset, out, len);
178}
179
180static ssize_t read_cached_report(struct tsm_report *report, void *buf,
181				  size_t count, enum tsm_data_select select)
182{
183	struct tsm_report_state *state = to_state(report);
184
185	guard(rwsem_read)(&tsm_rwsem);
186	if (!report->desc.inblob_len)
187		return -EINVAL;
188
189	/*
190	 * A given TSM backend always fills in ->outblob regardless of
191	 * whether the report includes an auxblob or not.
192	 */
193	if (!report->outblob ||
194	    state->read_generation != state->write_generation)
195		return -EWOULDBLOCK;
196
197	return __read_report(report, buf, count, select);
198}
199
200static ssize_t tsm_report_read(struct tsm_report *report, void *buf,
201			       size_t count, enum tsm_data_select select)
202{
203	struct tsm_report_state *state = to_state(report);
204	const struct tsm_ops *ops;
205	ssize_t rc;
206
207	/* try to read from the existing report if present and valid... */
208	rc = read_cached_report(report, buf, count, select);
209	if (rc >= 0 || rc != -EWOULDBLOCK)
210		return rc;
211
212	/* slow path, report may need to be regenerated... */
213	guard(rwsem_write)(&tsm_rwsem);
214	ops = provider.ops;
215	if (!ops)
216		return -ENOTTY;
217	if (!report->desc.inblob_len)
218		return -EINVAL;
219
220	/* did another thread already generate this report? */
221	if (report->outblob &&
222	    state->read_generation == state->write_generation)
223		goto out;
224
225	kvfree(report->outblob);
226	kvfree(report->auxblob);
 
227	report->outblob = NULL;
228	report->auxblob = NULL;
 
229	rc = ops->report_new(report, provider.data);
230	if (rc < 0)
231		return rc;
232	state->read_generation = state->write_generation;
233out:
234	return __read_report(report, buf, count, select);
235}
236
237static ssize_t tsm_report_outblob_read(struct config_item *cfg, void *buf,
238				       size_t count)
239{
240	struct tsm_report *report = to_tsm_report(cfg);
241
242	return tsm_report_read(report, buf, count, TSM_REPORT);
243}
244CONFIGFS_BIN_ATTR_RO(tsm_report_, outblob, NULL, TSM_OUTBLOB_MAX);
245
246static ssize_t tsm_report_auxblob_read(struct config_item *cfg, void *buf,
247				       size_t count)
248{
249	struct tsm_report *report = to_tsm_report(cfg);
250
251	return tsm_report_read(report, buf, count, TSM_CERTS);
252}
253CONFIGFS_BIN_ATTR_RO(tsm_report_, auxblob, NULL, TSM_OUTBLOB_MAX);
254
255#define TSM_DEFAULT_ATTRS() \
256	&tsm_report_attr_generation, \
257	&tsm_report_attr_provider
 
 
 
 
 
258
259static struct configfs_attribute *tsm_report_attrs[] = {
260	TSM_DEFAULT_ATTRS(),
 
 
 
 
 
 
261	NULL,
262};
263
264static struct configfs_attribute *tsm_report_extra_attrs[] = {
265	TSM_DEFAULT_ATTRS(),
266	&tsm_report_attr_privlevel,
267	&tsm_report_attr_privlevel_floor,
268	NULL,
269};
270
271#define TSM_DEFAULT_BIN_ATTRS() \
272	&tsm_report_attr_inblob, \
273	&tsm_report_attr_outblob
274
275static struct configfs_bin_attribute *tsm_report_bin_attrs[] = {
276	TSM_DEFAULT_BIN_ATTRS(),
277	NULL,
278};
279
280static struct configfs_bin_attribute *tsm_report_bin_extra_attrs[] = {
281	TSM_DEFAULT_BIN_ATTRS(),
282	&tsm_report_attr_auxblob,
283	NULL,
284};
285
286static void tsm_report_item_release(struct config_item *cfg)
287{
288	struct tsm_report *report = to_tsm_report(cfg);
289	struct tsm_report_state *state = to_state(report);
290
 
291	kvfree(report->auxblob);
292	kvfree(report->outblob);
 
293	kfree(state);
294}
295
296static struct configfs_item_operations tsm_report_item_ops = {
297	.release = tsm_report_item_release,
298};
299
300const struct config_item_type tsm_report_default_type = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301	.ct_owner = THIS_MODULE,
302	.ct_bin_attrs = tsm_report_bin_attrs,
303	.ct_attrs = tsm_report_attrs,
304	.ct_item_ops = &tsm_report_item_ops,
 
305};
306EXPORT_SYMBOL_GPL(tsm_report_default_type);
307
308const struct config_item_type tsm_report_extra_type = {
309	.ct_owner = THIS_MODULE,
310	.ct_bin_attrs = tsm_report_bin_extra_attrs,
311	.ct_attrs = tsm_report_extra_attrs,
312	.ct_item_ops = &tsm_report_item_ops,
313};
314EXPORT_SYMBOL_GPL(tsm_report_extra_type);
315
316static struct config_item *tsm_report_make_item(struct config_group *group,
317						const char *name)
318{
319	struct tsm_report_state *state;
320
321	guard(rwsem_read)(&tsm_rwsem);
322	if (!provider.ops)
323		return ERR_PTR(-ENXIO);
324
325	state = kzalloc(sizeof(*state), GFP_KERNEL);
326	if (!state)
327		return ERR_PTR(-ENOMEM);
328
329	config_item_init_type_name(&state->cfg, name, provider.type);
330	return &state->cfg;
331}
332
333static struct configfs_group_operations tsm_report_group_ops = {
334	.make_item = tsm_report_make_item,
335};
336
337static const struct config_item_type tsm_reports_type = {
338	.ct_owner = THIS_MODULE,
339	.ct_group_ops = &tsm_report_group_ops,
340};
341
342static const struct config_item_type tsm_root_group_type = {
343	.ct_owner = THIS_MODULE,
344};
345
346static struct configfs_subsystem tsm_configfs = {
347	.su_group = {
348		.cg_item = {
349			.ci_namebuf = "tsm",
350			.ci_type = &tsm_root_group_type,
351		},
352	},
353	.su_mutex = __MUTEX_INITIALIZER(tsm_configfs.su_mutex),
354};
355
356int tsm_register(const struct tsm_ops *ops, void *priv,
357		 const struct config_item_type *type)
358{
359	const struct tsm_ops *conflict;
360
361	if (!type)
362		type = &tsm_report_default_type;
363	if (!(type == &tsm_report_default_type || type == &tsm_report_extra_type))
364		return -EINVAL;
365
366	guard(rwsem_write)(&tsm_rwsem);
367	conflict = provider.ops;
368	if (conflict) {
369		pr_err("\"%s\" ops already registered\n", conflict->name);
370		return -EBUSY;
371	}
372
373	provider.ops = ops;
374	provider.data = priv;
375	provider.type = type;
376	return 0;
377}
378EXPORT_SYMBOL_GPL(tsm_register);
379
380int tsm_unregister(const struct tsm_ops *ops)
381{
382	guard(rwsem_write)(&tsm_rwsem);
383	if (ops != provider.ops)
384		return -EBUSY;
385	provider.ops = NULL;
386	provider.data = NULL;
387	provider.type = NULL;
388	return 0;
389}
390EXPORT_SYMBOL_GPL(tsm_unregister);
391
392static struct config_group *tsm_report_group;
393
394static int __init tsm_init(void)
395{
396	struct config_group *root = &tsm_configfs.su_group;
397	struct config_group *tsm;
398	int rc;
399
400	config_group_init(root);
401	rc = configfs_register_subsystem(&tsm_configfs);
402	if (rc)
403		return rc;
404
405	tsm = configfs_register_default_group(root, "report",
406					      &tsm_reports_type);
407	if (IS_ERR(tsm)) {
408		configfs_unregister_subsystem(&tsm_configfs);
409		return PTR_ERR(tsm);
410	}
411	tsm_report_group = tsm;
412
413	return 0;
414}
415module_init(tsm_init);
416
417static void __exit tsm_exit(void)
418{
419	configfs_unregister_default_group(tsm_report_group);
420	configfs_unregister_subsystem(&tsm_configfs);
421}
422module_exit(tsm_exit);
423
424MODULE_LICENSE("GPL");
425MODULE_DESCRIPTION("Provide Trusted Security Module attestation reports via configfs");