dm ima: measure data on device resume
[linux-block.git] / drivers / md / dm-ima.c
CommitLineData
91ccbbac
TS
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2021 Microsoft Corporation
4 *
5 * Author: Tushar Sugandhi <tusharsu@linux.microsoft.com>
6 *
7 * File: dm-ima.c
8 * Enables IMA measurements for DM targets
9 */
10
11#include "dm-core.h"
12#include "dm-ima.h"
13
14#include <linux/ima.h>
15#include <crypto/hash.h>
16#include <linux/crypto.h>
17#include <crypto/hash_info.h>
18
19#define DM_MSG_PREFIX "ima"
20
21/*
22 * Internal function to prefix separator characters in input buffer with escape
23 * character, so that they don't interfere with the construction of key-value pairs,
24 * and clients can split the key1=val1,key2=val2,key3=val3; pairs properly.
25 */
26static void fix_separator_chars(char **buf)
27{
28 int l = strlen(*buf);
29 int i, j, sp = 0;
30
31 for (i = 0; i < l; i++)
32 if ((*buf)[i] == '\\' || (*buf)[i] == ';' || (*buf)[i] == '=' || (*buf)[i] == ',')
33 sp++;
34
35 if (!sp)
36 return;
37
38 for (i = l-1, j = i+sp; i >= 0; i--) {
39 (*buf)[j--] = (*buf)[i];
40 if ((*buf)[i] == '\\' || (*buf)[i] == ';' || (*buf)[i] == '=' || (*buf)[i] == ',')
41 (*buf)[j--] = '\\';
42 }
43}
44
45/*
46 * Internal function to allocate memory for IMA measurements.
47 */
48static void *dm_ima_alloc(size_t len, gfp_t flags, bool noio)
49{
50 unsigned int noio_flag;
51 void *ptr;
52
53 if (noio)
54 noio_flag = memalloc_noio_save();
55
56 ptr = kzalloc(len, flags);
57
58 if (noio)
59 memalloc_noio_restore(noio_flag);
60
61 return ptr;
62}
63
64/*
65 * Internal function to allocate and copy name and uuid for IMA measurements.
66 */
67static int dm_ima_alloc_and_copy_name_uuid(struct mapped_device *md, char **dev_name,
68 char **dev_uuid, bool noio)
69{
70 int r;
71 *dev_name = dm_ima_alloc(DM_NAME_LEN*2, GFP_KERNEL, noio);
72 if (!(*dev_name)) {
73 r = -ENOMEM;
74 goto error;
75 }
76
77 *dev_uuid = dm_ima_alloc(DM_UUID_LEN*2, GFP_KERNEL, noio);
78 if (!(*dev_uuid)) {
79 r = -ENOMEM;
80 goto error;
81 }
82
83 r = dm_copy_name_and_uuid(md, *dev_name, *dev_uuid);
84 if (r)
85 goto error;
86
87 fix_separator_chars(dev_name);
88 fix_separator_chars(dev_uuid);
89
90 return 0;
91error:
92 kfree(*dev_name);
93 kfree(*dev_uuid);
94 *dev_name = NULL;
95 *dev_uuid = NULL;
96 return r;
97}
98
99/*
100 * Internal function to allocate and copy device data for IMA measurements.
101 */
102static int dm_ima_alloc_and_copy_device_data(struct mapped_device *md, char **device_data,
103 unsigned int num_targets, bool noio)
104{
105 char *dev_name = NULL, *dev_uuid = NULL;
106 int r;
107
108 r = dm_ima_alloc_and_copy_name_uuid(md, &dev_name, &dev_uuid, noio);
109 if (r)
110 return r;
111
112 *device_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, GFP_KERNEL, noio);
113 if (!(*device_data)) {
114 r = -ENOMEM;
115 goto error;
116 }
117
118 scnprintf(*device_data, DM_IMA_DEVICE_BUF_LEN,
119 "name=%s,uuid=%s,major=%d,minor=%d,minor_count=%d,num_targets=%u;",
120 dev_name, dev_uuid, md->disk->major, md->disk->first_minor,
121 md->disk->minors, num_targets);
122error:
123 kfree(dev_name);
124 kfree(dev_uuid);
125 return r;
126}
127
128/*
129 * Internal wrapper function to call IMA to measure DM data.
130 */
131static void dm_ima_measure_data(const char *event_name, const void *buf, size_t buf_len,
132 bool noio)
133{
134 unsigned int noio_flag;
135
136 if (noio)
137 noio_flag = memalloc_noio_save();
138
139 ima_measure_critical_data(DM_NAME, event_name, buf, buf_len, false);
140
141 if (noio)
142 memalloc_noio_restore(noio_flag);
143}
144
8eb6fab4
TS
145/*
146 * Internal function to allocate and copy current device capacity for IMA measurements.
147 */
148static int dm_ima_alloc_and_copy_capacity_str(struct mapped_device *md, char **capacity_str,
149 bool noio)
150{
151 sector_t capacity;
152
153 capacity = get_capacity(md->disk);
154
155 *capacity_str = dm_ima_alloc(DM_IMA_DEVICE_CAPACITY_BUF_LEN, GFP_KERNEL, noio);
156 if (!(*capacity_str))
157 return -ENOMEM;
158
159 scnprintf(*capacity_str, DM_IMA_DEVICE_BUF_LEN, "current_device_capacity=%llu;",
160 capacity);
161
162 return 0;
163}
164
91ccbbac
TS
165/*
166 * Initialize/reset the dm ima related data structure variables.
167 */
168void dm_ima_reset_data(struct mapped_device *md)
169{
170 memset(&(md->ima), 0, sizeof(md->ima));
171}
172
173/*
174 * Build up the IMA data for each target, and finally measure.
175 */
176void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_flags)
177{
178 size_t device_data_buf_len, target_metadata_buf_len, target_data_buf_len, l = 0;
179 char *target_metadata_buf = NULL, *target_data_buf = NULL, *digest_buf = NULL;
180 char *ima_buf = NULL, *device_data_buf = NULL;
181 int digest_size, last_target_measured = -1, r;
182 status_type_t type = STATUSTYPE_IMA;
183 size_t cur_total_buf_len = 0;
184 unsigned int num_targets, i;
185 SHASH_DESC_ON_STACK(shash, NULL);
186 struct crypto_shash *tfm = NULL;
187 u8 *digest = NULL;
188 bool noio = false;
189
190 ima_buf = dm_ima_alloc(DM_IMA_MEASUREMENT_BUF_LEN, GFP_KERNEL, noio);
191 if (!ima_buf)
192 return;
193
194 target_metadata_buf = dm_ima_alloc(DM_IMA_TARGET_METADATA_BUF_LEN, GFP_KERNEL, noio);
195 if (!target_metadata_buf)
196 goto error;
197
198 target_data_buf = dm_ima_alloc(DM_IMA_TARGET_DATA_BUF_LEN, GFP_KERNEL, noio);
199 if (!target_data_buf)
200 goto error;
201
202 num_targets = dm_table_get_num_targets(table);
203
204 if (dm_ima_alloc_and_copy_device_data(table->md, &device_data_buf, num_targets, noio))
205 goto error;
206
207 tfm = crypto_alloc_shash("sha256", 0, 0);
208 if (IS_ERR(tfm))
209 goto error;
210
211 shash->tfm = tfm;
212 digest_size = crypto_shash_digestsize(tfm);
213 digest = dm_ima_alloc(digest_size, GFP_KERNEL, noio);
214 if (!digest)
215 goto error;
216
217 r = crypto_shash_init(shash);
218 if (r)
219 goto error;
220
221 device_data_buf_len = strlen(device_data_buf);
222 memcpy(ima_buf + l, device_data_buf, device_data_buf_len);
223 l += device_data_buf_len;
224
225 for (i = 0; i < num_targets; i++) {
226 struct dm_target *ti = dm_table_get_target(table, i);
227
228 if (!ti)
229 goto error;
230
231 last_target_measured = 0;
232
233 /*
234 * First retrieve the target metadata.
235 */
236 scnprintf(target_metadata_buf, DM_IMA_TARGET_METADATA_BUF_LEN,
237 "target_index=%d,target_begin=%llu,target_len=%llu,",
238 i, ti->begin, ti->len);
239 target_metadata_buf_len = strlen(target_metadata_buf);
240
241 /*
242 * Then retrieve the actual target data.
243 */
244 if (ti->type->status)
245 ti->type->status(ti, type, status_flags, target_data_buf,
246 DM_IMA_TARGET_DATA_BUF_LEN);
247 else
248 target_data_buf[0] = '\0';
249
250 target_data_buf_len = strlen(target_data_buf);
251
252 /*
253 * Check if the total data can fit into the IMA buffer.
254 */
255 cur_total_buf_len = l + target_metadata_buf_len + target_data_buf_len;
256
257 /*
258 * IMA measurements for DM targets are best-effort.
259 * If the total data buffered so far, including the current target,
260 * is too large to fit into DM_IMA_MEASUREMENT_BUF_LEN, measure what
261 * we have in the current buffer, and continue measuring the remaining
262 * targets by prefixing the device metadata again.
263 */
264 if (unlikely(cur_total_buf_len >= DM_IMA_MEASUREMENT_BUF_LEN)) {
265 dm_ima_measure_data("table_load", ima_buf, l, noio);
266 r = crypto_shash_update(shash, (const u8 *)ima_buf, l);
267 if (r < 0)
268 goto error;
269
270 memset(ima_buf, 0, DM_IMA_MEASUREMENT_BUF_LEN);
271 l = 0;
272
273 /*
274 * Each new "table_load" entry in IMA log should have device data
275 * prefix, so that multiple records from the same table_load for
276 * a given device can be linked together.
277 */
278 memcpy(ima_buf + l, device_data_buf, device_data_buf_len);
279 l += device_data_buf_len;
280
281 /*
282 * If this iteration of the for loop turns out to be the last target
283 * in the table, dm_ima_measure_data("table_load", ...) doesn't need
284 * to be called again, just the hash needs to be finalized.
285 * "last_target_measured" tracks this state.
286 */
287 last_target_measured = 1;
288 }
289
290 /*
291 * Fill-in all the target metadata, so that multiple targets for the same
292 * device can be linked together.
293 */
294 memcpy(ima_buf + l, target_metadata_buf, target_metadata_buf_len);
295 l += target_metadata_buf_len;
296
297 memcpy(ima_buf + l, target_data_buf, target_data_buf_len);
298 l += target_data_buf_len;
299 }
300
301 if (!last_target_measured) {
302 dm_ima_measure_data("table_load", ima_buf, l, noio);
303
304 r = crypto_shash_update(shash, (const u8 *)ima_buf, l);
305 if (r < 0)
306 goto error;
307 }
308
309 /*
310 * Finalize the table hash, and store it in table->md->ima.inactive_table.hash,
311 * so that the table data can be verified against the future device state change
312 * events, e.g. resume, rename, remove, table-clear etc.
313 */
314 r = crypto_shash_final(shash, digest);
315 if (r < 0)
316 goto error;
317
318 digest_buf = dm_ima_alloc((digest_size*2)+1, GFP_KERNEL, noio);
319 if (!digest_buf)
320 goto error;
321
322 for (i = 0; i < digest_size; i++)
323 snprintf((digest_buf+(i*2)), 3, "%02x", digest[i]);
324
325 if (table->md->ima.active_table.hash != table->md->ima.inactive_table.hash)
326 kfree(table->md->ima.inactive_table.hash);
327
328 table->md->ima.inactive_table.hash = digest_buf;
329 table->md->ima.inactive_table.hash_len = strlen(digest_buf);
330 table->md->ima.inactive_table.num_targets = num_targets;
331
332 if (table->md->ima.active_table.device_metadata !=
333 table->md->ima.inactive_table.device_metadata)
334 kfree(table->md->ima.inactive_table.device_metadata);
335
336 table->md->ima.inactive_table.device_metadata = device_data_buf;
337 table->md->ima.inactive_table.device_metadata_len = device_data_buf_len;
338
339 goto exit;
340error:
341 kfree(digest_buf);
342 kfree(device_data_buf);
343exit:
344 kfree(digest);
345 if (tfm)
346 crypto_free_shash(tfm);
347 kfree(ima_buf);
348 kfree(target_metadata_buf);
349 kfree(target_data_buf);
350}
8eb6fab4
TS
351
352/*
353 * Measure IMA data on device resume.
354 */
355void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap)
356{
357 char *device_table_data, *dev_name = NULL, *dev_uuid = NULL, *capacity_str = NULL;
358 char active[] = "active_table_hash=";
359 unsigned int active_len = strlen(active), capacity_len = 0;
360 unsigned int l = 0;
361 bool noio = true;
362 int r;
363
364 device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, GFP_KERNEL, noio);
365 if (!device_table_data)
366 return;
367
368 r = dm_ima_alloc_and_copy_capacity_str(md, &capacity_str, noio);
369 if (r)
370 goto error;
371
372 if (swap) {
373 if (md->ima.active_table.hash != md->ima.inactive_table.hash)
374 kfree(md->ima.active_table.hash);
375
376 md->ima.active_table.hash = NULL;
377 md->ima.active_table.hash_len = 0;
378
379 if (md->ima.active_table.device_metadata !=
380 md->ima.inactive_table.device_metadata)
381 kfree(md->ima.active_table.device_metadata);
382
383 md->ima.active_table.device_metadata = NULL;
384 md->ima.active_table.device_metadata_len = 0;
385 md->ima.active_table.num_targets = 0;
386
387 if (md->ima.inactive_table.hash) {
388 md->ima.active_table.hash = md->ima.inactive_table.hash;
389 md->ima.active_table.hash_len = md->ima.inactive_table.hash_len;
390 md->ima.inactive_table.hash = NULL;
391 md->ima.inactive_table.hash_len = 0;
392 }
393
394 if (md->ima.inactive_table.device_metadata) {
395 md->ima.active_table.device_metadata =
396 md->ima.inactive_table.device_metadata;
397 md->ima.active_table.device_metadata_len =
398 md->ima.inactive_table.device_metadata_len;
399 md->ima.active_table.num_targets = md->ima.inactive_table.num_targets;
400 md->ima.inactive_table.device_metadata = NULL;
401 md->ima.inactive_table.device_metadata_len = 0;
402 md->ima.inactive_table.num_targets = 0;
403 }
404 }
405
406 if (md->ima.active_table.device_metadata) {
407 l = md->ima.active_table.device_metadata_len;
408 memcpy(device_table_data, md->ima.active_table.device_metadata, l);
409 }
410
411 if (md->ima.active_table.hash) {
412 memcpy(device_table_data + l, active, active_len);
413 l += active_len;
414
415 memcpy(device_table_data + l, md->ima.active_table.hash,
416 md->ima.active_table.hash_len);
417 l += md->ima.active_table.hash_len;
418
419 memcpy(device_table_data + l, ";", 1);
420 l++;
421 }
422
423 if (!l) {
424 r = dm_ima_alloc_and_copy_name_uuid(md, &dev_name, &dev_uuid, noio);
425 if (r)
426 goto error;
427
428 scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN,
429 "name=%s,uuid=%s;device_resume=no_data;",
430 dev_name, dev_uuid);
431 l += strlen(device_table_data);
432
433 }
434
435 capacity_len = strlen(capacity_str);
436 memcpy(device_table_data + l, capacity_str, capacity_len);
437 l += capacity_len;
438
439 dm_ima_measure_data("device_resume", device_table_data, l, noio);
440
441 kfree(dev_name);
442 kfree(dev_uuid);
443error:
444 kfree(capacity_str);
445 kfree(device_table_data);
446}