projects/linux·blob master · refs

650 lines · 17.8 KiB

1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2021 Microsoft Corporation
4 *
5 * Author: Tushar Sugandhi <[email protected]>
6 *
7 * Enables IMA measurements for DM targets
8 */
9
10#include "dm-core.h"
11#include "dm-ima.h"
12
13#include <linux/ima.h>
14#include <linux/sched/mm.h>
15#include <crypto/sha2.h>
16
17#define DM_MSG_PREFIX "ima"
18
19/*
20 * Internal function to prefix separator characters in input buffer with escape
21 * character, so that they don't interfere with the construction of key-value pairs,
22 * and clients can split the key1=val1,key2=val2,key3=val3; pairs properly.
23 */
24static void fix_separator_chars(char *buf)
25{
26 int l = strlen(buf);
27 int i, j, sp = 0;
28
29 for (i = 0; i < l; i++)
30 if (buf[i] == '\\' || buf[i] == ';' || buf[i] == '=' || buf[i] == ',')
31 sp++;
32
33 if (!sp)
34 return;
35
36 buf[l + sp] = '\0';
37 for (i = l-1, j = i+sp; i >= 0; i--) {
38 buf[j--] = buf[i];
39 if (buf[i] == '\\' || buf[i] == ';' || buf[i] == '=' || buf[i] == ',')
40 buf[j--] = '\\';
41 }
42}
43
44static void fix_context_strings(struct dm_ima_context *context)
45{
46 fix_separator_chars(context->dev_name);
47 fix_separator_chars(context->dev_uuid);
48}
49
50/*
51 * Internal function to allocate memory for IMA measurements.
52 */
53static void *dm_ima_alloc(size_t len, bool noio)
54{
55 unsigned int noio_flag;
56 void *ptr;
57
58 if (noio)
59 noio_flag = memalloc_noio_save();
60
61 ptr = kzalloc(len, GFP_KERNEL);
62
63 if (noio)
64 memalloc_noio_restore(noio_flag);
65
66 return ptr;
67}
68
69void dm_ima_init(struct mapped_device *md)
70{
71 md->ima.update_idx = 0;
72 md->ima.measure_idx = 0;
73 init_waitqueue_head(&md->ima.ima_wq);
74 spin_lock_init(&md->ima.ima_lock);
75}
76
77void dm_ima_alloc_context(struct dm_ima_context **context, bool noio)
78{
79 *context = dm_ima_alloc(sizeof(struct dm_ima_context), noio);
80}
81
82void dm_ima_free_context(struct dm_ima_context *context)
83{
84 if (likely(context)) {
85 kfree(context->table.device_metadata);
86 kfree(context->table.hash);
87 kfree(context);
88 }
89}
90
91static void wait_to_measure(struct dm_ima_measurements *ima,
92 unsigned int update_idx)
93{
94 spin_lock_irq(&ima->ima_lock);
95 wait_event_lock_irq(ima->ima_wq,
96 ima->measure_idx == update_idx,
97 ima->ima_lock);
98 spin_unlock_irq(&ima->ima_lock);
99}
100
101static void wake_next_measure(struct dm_ima_measurements *ima)
102{
103 spin_lock_irq(&ima->ima_lock);
104 ima->measure_idx++;
105 spin_unlock_irq(&ima->ima_lock);
106 wake_up_all(&ima->ima_wq);
107}
108
109/*
110 * Helper function for swapping the table, to make sure that the
111 * correct table metadata is saved and restored.
112 */
113void dm_ima_context_table_op(struct mapped_device *md,
114 struct dm_ima_context *context,
115 enum dm_ima_table_op op)
116{
117 struct dm_ima_measurements *ima = &md->ima;
118
119 if (unlikely(!context))
120 return;
121
122 wait_to_measure(ima, context->update_idx);
123
124 if (op == DM_IMA_TABLE_SAVE) {
125 context->table = ima->inactive_table;
126 memset(&ima->inactive_table, 0, sizeof(ima->inactive_table));
127 } else {
128 ima->inactive_table = context->table;
129 memset(&context->table, 0, sizeof(context->table));
130 }
131
132 wake_next_measure(ima);
133}
134
135/*
136 * Internal function to copy device data for IMA measurements.
137 */
138static void dm_ima_copy_device_data(struct mapped_device *md, char *device_data,
139 struct dm_ima_context *context,
140 unsigned int num_targets)
141{
142 memset(device_data, 0, DM_IMA_DEVICE_BUF_LEN);
143 scnprintf(device_data, DM_IMA_DEVICE_BUF_LEN,
144 "name=%s,uuid=%s,major=%d,minor=%d,minor_count=%d,num_targets=%u;",
145 context->dev_name, context->dev_uuid, md->disk->major,
146 md->disk->first_minor, md->disk->minors, num_targets);
147
148}
149
150/*
151 * Internal wrapper function to call IMA to measure DM data.
152 */
153static void dm_ima_measure_data(const char *event_name, const void *buf, size_t buf_len,
154 bool noio)
155{
156 unsigned int noio_flag;
157
158 if (noio)
159 noio_flag = memalloc_noio_save();
160
161 ima_measure_critical_data(DM_NAME, event_name, buf, buf_len,
162 false, NULL, 0);
163
164 if (noio)
165 memalloc_noio_restore(noio_flag);
166}
167
168static sector_t dm_ima_capacity(struct mapped_device *md)
169{
170 return (md->ima.active_table.device_metadata) ?
171 md->ima.active_table.capacity : get_capacity(md->disk);
172}
173
174/*
175 * Build up the IMA data for each target, and finally measure.
176 */
177void dm_ima_measure_on_table_load(struct dm_table *table,
178 struct dm_ima_context *context)
179{
180 size_t device_data_buf_len, target_metadata_buf_len, target_data_buf_len, l = 0;
181 char *target_metadata_buf = NULL, *target_data_buf = NULL, *digest_buf = NULL;
182 char *ima_buf = NULL, *device_data_buf = NULL;
183 status_type_t type = STATUSTYPE_IMA;
184 size_t cur_total_buf_len = 0;
185 unsigned int num_targets, i;
186 struct sha256_ctx hash_ctx;
187 u8 digest[SHA256_DIGEST_SIZE];
188 bool noio = false;
189 char table_load_event_name[] = "dm_table_load";
190
191 if (unlikely(!context))
192 return;
193
194 wait_to_measure(&table->md->ima, context->update_idx);
195
196 ima_buf = dm_ima_alloc(DM_IMA_MEASUREMENT_BUF_LEN, noio);
197 if (!ima_buf)
198 goto error;
199
200 target_metadata_buf = dm_ima_alloc(DM_IMA_TARGET_METADATA_BUF_LEN, noio);
201 if (!target_metadata_buf)
202 goto error;
203
204 target_data_buf = dm_ima_alloc(DM_IMA_TARGET_DATA_BUF_LEN, noio);
205 if (!target_data_buf)
206 goto error;
207
208 num_targets = table->num_targets;
209
210 device_data_buf = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio);
211 if (!device_data_buf)
212 goto error;
213
214 fix_context_strings(context);
215 dm_ima_copy_device_data(table->md, device_data_buf, context,
216 num_targets);
217
218 sha256_init(&hash_ctx);
219
220 memcpy(ima_buf + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
221 l += strlen(DM_IMA_VERSION_STR);
222
223 device_data_buf_len = strlen(device_data_buf);
224 memcpy(ima_buf + l, device_data_buf, device_data_buf_len);
225 l += device_data_buf_len;
226
227 for (i = 0; i < num_targets; i++) {
228 struct dm_target *ti = dm_table_get_target(table, i);
229
230 /*
231 * First retrieve the target metadata.
232 */
233 target_metadata_buf_len =
234 scnprintf(target_metadata_buf,
235 DM_IMA_TARGET_METADATA_BUF_LEN,
236 "target_index=%d,target_begin=%llu,target_len=%llu,",
237 i, ti->begin, ti->len);
238
239 /*
240 * Then retrieve the actual target data.
241 */
242 if (ti->type->status)
243 ti->type->status(ti, type, 0, target_data_buf,
244 DM_IMA_TARGET_DATA_BUF_LEN);
245 else
246 target_data_buf[0] = '\0';
247
248 target_data_buf_len = strlen(target_data_buf);
249
250 /*
251 * Check if the total data can fit into the IMA buffer.
252 */
253 cur_total_buf_len = l + target_metadata_buf_len + target_data_buf_len;
254
255 /*
256 * IMA measurements for DM targets are best-effort.
257 * If the total data buffered so far, including the current target,
258 * is too large to fit into DM_IMA_MEASUREMENT_BUF_LEN, measure what
259 * we have in the current buffer, and continue measuring the remaining
260 * targets by prefixing the device metadata again.
261 */
262 if (unlikely(cur_total_buf_len >= DM_IMA_MEASUREMENT_BUF_LEN)) {
263 dm_ima_measure_data(table_load_event_name, ima_buf, l, noio);
264 sha256_update(&hash_ctx, (const u8 *)ima_buf, l);
265
266 memset(ima_buf, 0, DM_IMA_MEASUREMENT_BUF_LEN);
267 l = 0;
268
269 /*
270 * Each new "dm_table_load" entry in IMA log should have device data
271 * prefix, so that multiple records from the same "dm_table_load" for
272 * a given device can be linked together.
273 */
274 memcpy(ima_buf + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
275 l += strlen(DM_IMA_VERSION_STR);
276
277 memcpy(ima_buf + l, device_data_buf, device_data_buf_len);
278 l += device_data_buf_len;
279 }
280
281 /*
282 * Fill-in all the target metadata, so that multiple targets for the same
283 * device can be linked together.
284 */
285 memcpy(ima_buf + l, target_metadata_buf, target_metadata_buf_len);
286 l += target_metadata_buf_len;
287
288 memcpy(ima_buf + l, target_data_buf, target_data_buf_len);
289 l += target_data_buf_len;
290 }
291
292 dm_ima_measure_data(table_load_event_name, ima_buf, l, noio);
293 sha256_update(&hash_ctx, (const u8 *)ima_buf, l);
294
295 /*
296 * Finalize the table hash, and store it in table->md->ima.inactive_table.hash,
297 * so that the table data can be verified against the future device state change
298 * events, e.g. resume, rename, remove, table-clear etc.
299 */
300 sha256_final(&hash_ctx, digest);
301
302 digest_buf = kasprintf(GFP_KERNEL, "sha256:%*phN", SHA256_DIGEST_SIZE,
303 digest);
304 if (!digest_buf)
305 goto error;
306
307 kfree(table->md->ima.inactive_table.hash);
308 table->md->ima.inactive_table.hash = digest_buf;
309 table->md->ima.inactive_table.hash_len = strlen(digest_buf);
310 table->md->ima.inactive_table.num_targets = num_targets;
311 table->md->ima.inactive_table.capacity = dm_table_get_size(table);
312
313
314 kfree(table->md->ima.inactive_table.device_metadata);
315 table->md->ima.inactive_table.device_metadata = device_data_buf;
316 table->md->ima.inactive_table.device_metadata_len = device_data_buf_len;
317
318 goto exit;
319error:
320 kfree(digest_buf);
321 kfree(device_data_buf);
322exit:
323 kfree(ima_buf);
324 kfree(target_metadata_buf);
325 kfree(target_data_buf);
326
327 wake_next_measure(&table->md->ima);
328}
329
330/*
331 * Measure IMA data on device resume.
332 */
333void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap,
334 struct dm_ima_context *context)
335{
336 char *device_table_data = NULL;
337 char active[] = "active_table_hash=";
338 unsigned int active_len = strlen(active);
339 unsigned int l = 0;
340 bool noio = true;
341 bool nodata = true;
342
343 if (unlikely(!context))
344 return;
345
346 wait_to_measure(&md->ima, context->update_idx);
347
348 if (swap) {
349 kfree(md->ima.active_table.hash);
350 kfree(md->ima.active_table.device_metadata);
351 md->ima.active_table = context->table;
352 memset(&context->table, 0, sizeof(context->table));
353 if (md->ima.active_table.device_metadata) {
354 /*
355 * A rename could have happened while the swap was
356 * going on. In that case, the saved table info would
357 * still have the old name. Update the metadata to be
358 * sure that it has the current name
359 */
360 struct dm_ima_device_table_metadata *table = &md->ima.active_table;
361 fix_context_strings(context);
362 dm_ima_copy_device_data(md, table->device_metadata,
363 context, table->num_targets);
364 table->device_metadata_len = strlen(table->device_metadata);
365 }
366 }
367
368 device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio);
369 if (!device_table_data)
370 goto error;
371
372 memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
373 l += strlen(DM_IMA_VERSION_STR);
374
375 if (md->ima.active_table.device_metadata) {
376 memcpy(device_table_data + l, md->ima.active_table.device_metadata,
377 md->ima.active_table.device_metadata_len);
378 l += md->ima.active_table.device_metadata_len;
379
380 nodata = false;
381 }
382
383 if (md->ima.active_table.hash) {
384 memcpy(device_table_data + l, active, active_len);
385 l += active_len;
386
387 memcpy(device_table_data + l, md->ima.active_table.hash,
388 md->ima.active_table.hash_len);
389 l += md->ima.active_table.hash_len;
390
391 memcpy(device_table_data + l, ";", 1);
392 l++;
393
394 nodata = false;
395 }
396
397 if (nodata) {
398 fix_context_strings(context);
399 l = scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN,
400 "%sname=%s,uuid=%s;device_resume=no_data;",
401 DM_IMA_VERSION_STR, context->dev_name,
402 context->dev_uuid);
403 }
404 l += scnprintf(device_table_data + l, DM_IMA_DEVICE_BUF_LEN - l,
405 "current_device_capacity=%llu;", dm_ima_capacity(md));
406
407 dm_ima_measure_data("dm_device_resume", device_table_data, l, noio);
408
409error:
410 kfree(device_table_data);
411
412 wake_next_measure(&md->ima);
413}
414
415/*
416 * Measure IMA data on remove.
417 */
418void dm_ima_measure_on_device_remove(struct mapped_device *md, bool remove_all,
419 struct dm_ima_context *context,
420 unsigned int idx)
421{
422 char *device_table_data;
423 char active_table_str[] = "active_table_hash=";
424 char inactive_table_str[] = "inactive_table_hash=";
425 char device_active_str[] = "device_active_metadata=";
426 char device_inactive_str[] = "device_inactive_metadata=";
427 unsigned int active_table_len = strlen(active_table_str);
428 unsigned int inactive_table_len = strlen(inactive_table_str);
429 unsigned int device_active_len = strlen(device_active_str);
430 unsigned int device_inactive_len = strlen(device_inactive_str);
431 unsigned int l = 0;
432 bool noio = true;
433 bool nodata = true;
434
435 wait_to_measure(&md->ima, idx);
436
437 if (unlikely(!context))
438 goto exit;
439
440 device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN*2, noio);
441 if (!device_table_data)
442 goto exit;
443
444 memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
445 l += strlen(DM_IMA_VERSION_STR);
446
447 if (md->ima.active_table.device_metadata) {
448 memcpy(device_table_data + l, device_active_str, device_active_len);
449 l += device_active_len;
450
451 memcpy(device_table_data + l, md->ima.active_table.device_metadata,
452 md->ima.active_table.device_metadata_len);
453 l += md->ima.active_table.device_metadata_len;
454
455 nodata = false;
456 }
457
458 if (md->ima.inactive_table.device_metadata) {
459 memcpy(device_table_data + l, device_inactive_str, device_inactive_len);
460 l += device_inactive_len;
461
462 memcpy(device_table_data + l, md->ima.inactive_table.device_metadata,
463 md->ima.inactive_table.device_metadata_len);
464 l += md->ima.inactive_table.device_metadata_len;
465
466 nodata = false;
467 }
468
469 if (md->ima.active_table.hash) {
470 memcpy(device_table_data + l, active_table_str, active_table_len);
471 l += active_table_len;
472
473 memcpy(device_table_data + l, md->ima.active_table.hash,
474 md->ima.active_table.hash_len);
475 l += md->ima.active_table.hash_len;
476
477 memcpy(device_table_data + l, ",", 1);
478 l++;
479
480 nodata = false;
481 }
482
483 if (md->ima.inactive_table.hash) {
484 memcpy(device_table_data + l, inactive_table_str, inactive_table_len);
485 l += inactive_table_len;
486
487 memcpy(device_table_data + l, md->ima.inactive_table.hash,
488 md->ima.inactive_table.hash_len);
489 l += md->ima.inactive_table.hash_len;
490
491 memcpy(device_table_data + l, ",", 1);
492 l++;
493
494 nodata = false;
495 }
496 /*
497 * In case both active and inactive tables, and corresponding
498 * device metadata is cleared/missing - record the name and uuid
499 * in IMA measurements.
500 */
501 if (nodata) {
502 fix_context_strings(context);
503 l = scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN,
504 "%sname=%s,uuid=%s;device_remove=no_data;",
505 DM_IMA_VERSION_STR, context->dev_name,
506 context->dev_uuid);
507 }
508
509 l += scnprintf(device_table_data + l, (DM_IMA_DEVICE_BUF_LEN * 2) - l,
510 "remove_all=%c;current_device_capacity=%llu;",
511 remove_all ? 'y' : 'n', dm_ima_capacity(md));
512
513 dm_ima_measure_data("dm_device_remove", device_table_data, l, noio);
514
515 kfree(device_table_data);
516exit:
517 kfree(md->ima.active_table.device_metadata);
518 kfree(md->ima.inactive_table.device_metadata);
519
520 kfree(md->ima.active_table.hash);
521 kfree(md->ima.inactive_table.hash);
522
523 memset(&md->ima.active_table, 0, sizeof(md->ima.active_table));
524 memset(&md->ima.inactive_table, 0, sizeof(md->ima.inactive_table));
525
526 wake_next_measure(&md->ima);
527}
528
529/*
530 * Measure ima data on table clear.
531 */
532void dm_ima_measure_on_table_clear(struct mapped_device *md,
533 struct dm_ima_context *context)
534{
535 unsigned int l = 0;
536 char *device_table_data = NULL;
537 char inactive_str[] = "inactive_table_hash=";
538 unsigned int inactive_len = strlen(inactive_str);
539 bool noio = true;
540 bool nodata = true;
541
542 if (unlikely(!context))
543 return;
544
545 wait_to_measure(&md->ima, context->update_idx);
546
547 device_table_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN, noio);
548 if (!device_table_data)
549 goto error;
550
551 memcpy(device_table_data + l, DM_IMA_VERSION_STR, strlen(DM_IMA_VERSION_STR));
552 l += strlen(DM_IMA_VERSION_STR);
553
554 if (md->ima.inactive_table.device_metadata_len &&
555 md->ima.inactive_table.hash_len) {
556 memcpy(device_table_data + l, md->ima.inactive_table.device_metadata,
557 md->ima.inactive_table.device_metadata_len);
558 l += md->ima.inactive_table.device_metadata_len;
559
560 memcpy(device_table_data + l, inactive_str, inactive_len);
561 l += inactive_len;
562
563 memcpy(device_table_data + l, md->ima.inactive_table.hash,
564 md->ima.inactive_table.hash_len);
565
566 l += md->ima.inactive_table.hash_len;
567
568 memcpy(device_table_data + l, ";", 1);
569 l++;
570
571 nodata = false;
572 }
573
574 if (nodata) {
575 fix_context_strings(context);
576 l = scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN,
577 "%sname=%s,uuid=%s;table_clear=no_data;",
578 DM_IMA_VERSION_STR, context->dev_name,
579 context->dev_uuid);
580 }
581
582 l += scnprintf(device_table_data + l, DM_IMA_DEVICE_BUF_LEN - l,
583 "current_device_capacity=%llu;", dm_ima_capacity(md));
584
585 dm_ima_measure_data("dm_table_clear", device_table_data, l, noio);
586
587error:
588 kfree(md->ima.inactive_table.hash);
589 kfree(md->ima.inactive_table.device_metadata);
590 memset(&md->ima.inactive_table, 0, sizeof(md->ima.inactive_table));
591
592 kfree(device_table_data);
593
594 wake_next_measure(&md->ima);
595}
596
597/*
598 * Measure IMA data on device rename.
599 */
600void dm_ima_measure_on_device_rename(struct mapped_device *md,
601 struct dm_ima_context *context)
602{
603 char *old_device_data = NULL;
604 char *combined_device_data = NULL;
605 bool noio = true;
606 int len;
607 struct dm_ima_device_table_metadata *table;
608
609 if (unlikely(!context))
610 return;
611
612 wait_to_measure(&md->ima, context->update_idx);
613
614 fix_context_strings(context);
615
616 combined_device_data = dm_ima_alloc(DM_IMA_DEVICE_BUF_LEN * 2, noio);
617 if (!combined_device_data)
618 goto exit;
619
620 if (md->ima.active_table.device_metadata)
621 old_device_data = md->ima.active_table.device_metadata;
622 else if (md->ima.inactive_table.device_metadata)
623 old_device_data = md->ima.inactive_table.device_metadata;
624 else
625 old_device_data = "device_rename=no_data;";
626 len = scnprintf(combined_device_data, DM_IMA_DEVICE_BUF_LEN * 2,
627 "%s%snew_name=%s,new_uuid=%s;current_device_capacity=%llu;",
628 DM_IMA_VERSION_STR, old_device_data, context->dev_name,
629 context->dev_uuid, dm_ima_capacity(md));
630
631 dm_ima_measure_data("dm_device_rename", combined_device_data, len, noio);
632 kfree(combined_device_data);
633
634exit:
635 if (md->ima.active_table.device_metadata) {
636 table = &md->ima.active_table;
637 dm_ima_copy_device_data(md, table->device_metadata, context,
638 table->num_targets);
639 table->device_metadata_len = strlen(table->device_metadata);
640 }
641
642 if (md->ima.inactive_table.device_metadata) {
643 table = &md->ima.inactive_table;
644 dm_ima_copy_device_data(md, table->device_metadata, context,
645 table->num_targets);
646 table->device_metadata_len = strlen(table->device_metadata);
647 }
648
649 wake_next_measure(&md->ima);
650}