Loading...
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");
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");