xref: /linux/drivers/virt/coco/guest/tsm-mr.c (revision ae5ec8adb8ec9c2aa916f853737c101faa87e5ba)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2024-2025 Intel Corporation. All rights reserved. */
3 
4 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5 
6 #include <linux/module.h>
7 #include <linux/slab.h>
8 #include <linux/sysfs.h>
9 
10 #define CREATE_TRACE_POINTS
11 #include <trace/events/tsm_mr.h>
12 
13 /*
14  * struct tm_context - contains everything necessary to implement sysfs
15  * attributes for MRs.
16  * @rwsem: protects the MR cache from concurrent access.
17  * @agrp: contains all MR attributes created by tsm_mr_create_attribute_group().
18  * @tm: input to tsm_mr_create_attribute_group() containing MR definitions/ops.
19  * @in_sync: %true if MR cache is up-to-date.
20  * @mrs: array of &struct bin_attribute, one for each MR.
21  *
22  * This internal structure contains everything needed to implement
23  * tm_digest_read() and tm_digest_write().
24  *
25  * Given tm->refresh() is potentially expensive, tm_digest_read() caches MR
26  * values and calls tm->refresh() only when necessary. Only live MRs (i.e., with
27  * %TSM_MR_F_LIVE set) can trigger tm->refresh(), while others are assumed to
28  * retain their values from the last tm->write(). @in_sync tracks if there have
29  * been tm->write() calls since the last tm->refresh(). That is, tm->refresh()
30  * will be called only when a live MR is being read and the cache is stale
31  * (@in_sync is %false).
32  *
33  * tm_digest_write() sets @in_sync to %false and calls tm->write(), whose
34  * semantics is arch and MR specific. Most (if not all) writable MRs support the
35  * extension semantics (i.e., tm->write() extends the input buffer into the MR).
36  */
37 struct tm_context {
38 	struct rw_semaphore rwsem;
39 	struct attribute_group agrp;
40 	const struct tsm_measurements *tm;
41 	bool in_sync;
42 	struct bin_attribute mrs[];
43 };
44 
tm_digest_read(struct file * filp,struct kobject * kobj,const struct bin_attribute * attr,char * buffer,loff_t off,size_t count)45 static ssize_t tm_digest_read(struct file *filp, struct kobject *kobj,
46 			      const struct bin_attribute *attr, char *buffer,
47 			      loff_t off, size_t count)
48 {
49 	struct tm_context *ctx;
50 	const struct tsm_measurement_register *mr;
51 	int rc;
52 
53 	ctx = attr->private;
54 	rc = down_read_interruptible(&ctx->rwsem);
55 	if (rc)
56 		return rc;
57 
58 	mr = &ctx->tm->mrs[attr - ctx->mrs];
59 
60 	/*
61 	 * @ctx->in_sync indicates if the MR cache is stale. It is a global
62 	 * instead of a per-MR flag for simplicity, as most (if not all) archs
63 	 * allow reading all MRs in oneshot.
64 	 *
65 	 * ctx->refresh() is necessary only for LIVE MRs, while others retain
66 	 * their values from their respective last ctx->write().
67 	 */
68 	if ((mr->mr_flags & TSM_MR_F_LIVE) && !ctx->in_sync) {
69 		up_read(&ctx->rwsem);
70 
71 		rc = down_write_killable(&ctx->rwsem);
72 		if (rc)
73 			return rc;
74 
75 		if (!ctx->in_sync) {
76 			rc = ctx->tm->refresh(ctx->tm);
77 			ctx->in_sync = !rc;
78 			trace_tsm_mr_refresh(mr, rc);
79 		}
80 
81 		downgrade_write(&ctx->rwsem);
82 	}
83 
84 	memcpy(buffer, mr->mr_value + off, count);
85 	trace_tsm_mr_read(mr);
86 
87 	up_read(&ctx->rwsem);
88 	return rc ?: count;
89 }
90 
tm_digest_write(struct file * filp,struct kobject * kobj,const struct bin_attribute * attr,char * buffer,loff_t off,size_t count)91 static ssize_t tm_digest_write(struct file *filp, struct kobject *kobj,
92 			       const struct bin_attribute *attr, char *buffer,
93 			       loff_t off, size_t count)
94 {
95 	struct tm_context *ctx;
96 	const struct tsm_measurement_register *mr;
97 	ssize_t rc;
98 
99 	/* partial writes are not supported */
100 	if (off != 0 || count != attr->size)
101 		return -EINVAL;
102 
103 	ctx = attr->private;
104 	mr = &ctx->tm->mrs[attr - ctx->mrs];
105 
106 	rc = down_write_killable(&ctx->rwsem);
107 	if (rc)
108 		return rc;
109 
110 	rc = ctx->tm->write(ctx->tm, mr, buffer);
111 
112 	/* mark MR cache stale */
113 	if (!rc) {
114 		ctx->in_sync = false;
115 		trace_tsm_mr_write(mr, buffer);
116 	}
117 
118 	up_write(&ctx->rwsem);
119 	return rc ?: count;
120 }
121 
122 /**
123  * tsm_mr_create_attribute_group() - creates an attribute group for measurement
124  * registers (MRs)
125  * @tm: pointer to &struct tsm_measurements containing the MR definitions.
126  *
127  * This function creates attributes corresponding to the MR definitions
128  * provided by @tm->mrs.
129  *
130  * The created attributes will reference @tm and its members. The caller must
131  * not free @tm until after tsm_mr_free_attribute_group() is called.
132  *
133  * Context: Process context. May sleep due to memory allocation.
134  *
135  * Return:
136  * * On success, the pointer to a an attribute group is returned; otherwise
137  * * %-EINVAL - Invalid MR definitions.
138  * * %-ENOMEM - Out of memory.
139  */
140 const struct attribute_group *
tsm_mr_create_attribute_group(const struct tsm_measurements * tm)141 tsm_mr_create_attribute_group(const struct tsm_measurements *tm)
142 {
143 	size_t nlen;
144 
145 	if (!tm || !tm->mrs)
146 		return ERR_PTR(-EINVAL);
147 
148 	/* aggregated length of all MR names */
149 	nlen = 0;
150 	for (size_t i = 0; i < tm->nr_mrs; ++i) {
151 		if ((tm->mrs[i].mr_flags & TSM_MR_F_LIVE) && !tm->refresh)
152 			return ERR_PTR(-EINVAL);
153 
154 		if ((tm->mrs[i].mr_flags & TSM_MR_F_WRITABLE) && !tm->write)
155 			return ERR_PTR(-EINVAL);
156 
157 		if (!tm->mrs[i].mr_name)
158 			return ERR_PTR(-EINVAL);
159 
160 		if (tm->mrs[i].mr_flags & TSM_MR_F_NOHASH)
161 			continue;
162 
163 		if (tm->mrs[i].mr_hash >= HASH_ALGO__LAST)
164 			return ERR_PTR(-EINVAL);
165 
166 		/* MR sysfs attribute names have the form of MRNAME:HASH */
167 		nlen += strlen(tm->mrs[i].mr_name) + 1 +
168 			strlen(hash_algo_name[tm->mrs[i].mr_hash]) + 1;
169 	}
170 
171 	/*
172 	 * @attrs and the MR name strings are combined into a single allocation
173 	 * so that we don't have to free MR names one-by-one in
174 	 * tsm_mr_free_attribute_group()
175 	 */
176 	const struct bin_attribute **attrs __free(kfree) =
177 		kzalloc(sizeof(*attrs) * (tm->nr_mrs + 1) + nlen, GFP_KERNEL);
178 	struct tm_context *ctx __free(kfree) =
179 		kzalloc(struct_size(ctx, mrs, tm->nr_mrs), GFP_KERNEL);
180 	char *name, *end;
181 
182 	if (!ctx || !attrs)
183 		return ERR_PTR(-ENOMEM);
184 
185 	/* @attrs is followed immediately by MR name strings */
186 	name = (char *)&attrs[tm->nr_mrs + 1];
187 	end = name + nlen;
188 
189 	for (size_t i = 0; i < tm->nr_mrs; ++i) {
190 		struct bin_attribute *bap = &ctx->mrs[i];
191 
192 		sysfs_bin_attr_init(bap);
193 
194 		if (tm->mrs[i].mr_flags & TSM_MR_F_NOHASH)
195 			bap->attr.name = tm->mrs[i].mr_name;
196 		else if (name < end) {
197 			bap->attr.name = name;
198 			name += snprintf(name, end - name, "%s:%s",
199 					 tm->mrs[i].mr_name,
200 					 hash_algo_name[tm->mrs[i].mr_hash]);
201 			++name;
202 		} else
203 			return ERR_PTR(-EINVAL);
204 
205 		/* check for duplicated MR definitions */
206 		for (size_t j = 0; j < i; ++j)
207 			if (!strcmp(bap->attr.name, attrs[j]->attr.name))
208 				return ERR_PTR(-EINVAL);
209 
210 		if (tm->mrs[i].mr_flags & TSM_MR_F_READABLE) {
211 			bap->attr.mode |= 0444;
212 			bap->read_new = tm_digest_read;
213 		}
214 
215 		if (tm->mrs[i].mr_flags & TSM_MR_F_WRITABLE) {
216 			bap->attr.mode |= 0200;
217 			bap->write_new = tm_digest_write;
218 		}
219 
220 		bap->size = tm->mrs[i].mr_size;
221 		bap->private = ctx;
222 
223 		attrs[i] = bap;
224 	}
225 
226 	if (name != end)
227 		return ERR_PTR(-EINVAL);
228 
229 	init_rwsem(&ctx->rwsem);
230 	ctx->agrp.name = "measurements";
231 	ctx->agrp.bin_attrs_new = no_free_ptr(attrs);
232 	ctx->tm = tm;
233 	return &no_free_ptr(ctx)->agrp;
234 }
235 EXPORT_SYMBOL_GPL(tsm_mr_create_attribute_group);
236 
237 /**
238  * tsm_mr_free_attribute_group() - frees the attribute group returned by
239  * tsm_mr_create_attribute_group()
240  * @attr_grp: attribute group returned by tsm_mr_create_attribute_group()
241  *
242  * Context: Process context.
243  */
tsm_mr_free_attribute_group(const struct attribute_group * attr_grp)244 void tsm_mr_free_attribute_group(const struct attribute_group *attr_grp)
245 {
246 	if (!IS_ERR_OR_NULL(attr_grp)) {
247 		kfree(attr_grp->bin_attrs_new);
248 		kfree(container_of(attr_grp, struct tm_context, agrp));
249 	}
250 }
251 EXPORT_SYMBOL_GPL(tsm_mr_free_attribute_group);
252