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