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 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 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 * 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 = tm_digest_read; 213 } 214 215 if (tm->mrs[i].mr_flags & TSM_MR_F_WRITABLE) { 216 bap->attr.mode |= 0200; 217 bap->write = 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 = 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 */ 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); 248 kfree(container_of(attr_grp, struct tm_context, agrp)); 249 } 250 } 251 EXPORT_SYMBOL_GPL(tsm_mr_free_attribute_group); 252