Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'for-5.16/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

Pull device mapper updates from Mike Snitzer:

- Add DM core support for emitting audit events through the audit
subsystem. Also enhance both the integrity and crypt targets to emit
events to via dm-audit.

- Various other simple code improvements and cleanups.

* tag 'for-5.16/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
dm table: log table creation error code
dm: make workqueue names device-specific
dm writecache: Make use of the helper macro kthread_run()
dm crypt: Make use of the helper macro kthread_run()
dm verity: use bvec_kmap_local in verity_for_bv_block
dm log writes: use memcpy_from_bvec in log_writes_map
dm integrity: use bvec_kmap_local in __journal_read_write
dm integrity: use bvec_kmap_local in integrity_metadata
dm: add add_disk() error handling
dm: Remove redundant flush_workqueue() calls
dm crypt: log aead integrity violations to audit subsystem
dm integrity: log audit events for dm-integrity target
dm: introduce audit event module for device mapper

+221 -31
+10
drivers/md/Kconfig
··· 610 610 select CRYPTO 611 611 select CRYPTO_SKCIPHER 612 612 select ASYNC_XOR 613 + select DM_AUDIT if AUDIT 613 614 help 614 615 This device-mapper target emulates a block device that has 615 616 additional per-sector tags that can be used for storing ··· 642 641 be called dm-zoned. 643 642 644 643 If unsure, say N. 644 + 645 + config DM_AUDIT 646 + bool "DM audit events" 647 + depends on AUDIT 648 + help 649 + Generate audit events for device-mapper. 650 + 651 + Enables audit logging of several security relevant events in the 652 + particular device-mapper targets, especially the integrity target. 645 653 646 654 endif # MD
+4
drivers/md/Makefile
··· 107 107 ifeq ($(CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG),y) 108 108 dm-verity-objs += dm-verity-verify-sig.o 109 109 endif 110 + 111 + ifeq ($(CONFIG_DM_AUDIT),y) 112 + dm-mod-objs += dm-audit.o 113 + endif
+84
drivers/md/dm-audit.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Creating audit records for mapped devices. 4 + * 5 + * Copyright (C) 2021 Fraunhofer AISEC. All rights reserved. 6 + * 7 + * Authors: Michael Weiß <michael.weiss@aisec.fraunhofer.de> 8 + */ 9 + 10 + #include <linux/audit.h> 11 + #include <linux/module.h> 12 + #include <linux/device-mapper.h> 13 + #include <linux/bio.h> 14 + #include <linux/blkdev.h> 15 + 16 + #include "dm-audit.h" 17 + #include "dm-core.h" 18 + 19 + static struct audit_buffer *dm_audit_log_start(int audit_type, 20 + const char *dm_msg_prefix, 21 + const char *op) 22 + { 23 + struct audit_buffer *ab; 24 + 25 + if (audit_enabled == AUDIT_OFF) 26 + return NULL; 27 + 28 + ab = audit_log_start(audit_context(), GFP_KERNEL, audit_type); 29 + if (unlikely(!ab)) 30 + return NULL; 31 + 32 + audit_log_format(ab, "module=%s op=%s", dm_msg_prefix, op); 33 + return ab; 34 + } 35 + 36 + void dm_audit_log_ti(int audit_type, const char *dm_msg_prefix, const char *op, 37 + struct dm_target *ti, int result) 38 + { 39 + struct audit_buffer *ab = NULL; 40 + struct mapped_device *md = dm_table_get_md(ti->table); 41 + int dev_major = dm_disk(md)->major; 42 + int dev_minor = dm_disk(md)->first_minor; 43 + 44 + switch (audit_type) { 45 + case AUDIT_DM_CTRL: 46 + ab = dm_audit_log_start(audit_type, dm_msg_prefix, op); 47 + if (unlikely(!ab)) 48 + return; 49 + audit_log_task_info(ab); 50 + audit_log_format(ab, " dev=%d:%d error_msg='%s'", dev_major, 51 + dev_minor, !result ? ti->error : "success"); 52 + break; 53 + case AUDIT_DM_EVENT: 54 + ab = dm_audit_log_start(audit_type, dm_msg_prefix, op); 55 + if (unlikely(!ab)) 56 + return; 57 + audit_log_format(ab, " dev=%d:%d sector=?", dev_major, 58 + dev_minor); 59 + break; 60 + default: /* unintended use */ 61 + return; 62 + } 63 + 64 + audit_log_format(ab, " res=%d", result); 65 + audit_log_end(ab); 66 + } 67 + EXPORT_SYMBOL_GPL(dm_audit_log_ti); 68 + 69 + void dm_audit_log_bio(const char *dm_msg_prefix, const char *op, 70 + struct bio *bio, sector_t sector, int result) 71 + { 72 + struct audit_buffer *ab; 73 + int dev_major = MAJOR(bio->bi_bdev->bd_dev); 74 + int dev_minor = MINOR(bio->bi_bdev->bd_dev); 75 + 76 + ab = dm_audit_log_start(AUDIT_DM_EVENT, dm_msg_prefix, op); 77 + if (unlikely(!ab)) 78 + return; 79 + 80 + audit_log_format(ab, " dev=%d:%d sector=%llu res=%d", 81 + dev_major, dev_minor, sector, result); 82 + audit_log_end(ab); 83 + } 84 + EXPORT_SYMBOL_GPL(dm_audit_log_bio);
+66
drivers/md/dm-audit.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Creating audit records for mapped devices. 4 + * 5 + * Copyright (C) 2021 Fraunhofer AISEC. All rights reserved. 6 + * 7 + * Authors: Michael Weiß <michael.weiss@aisec.fraunhofer.de> 8 + */ 9 + 10 + #ifndef DM_AUDIT_H 11 + #define DM_AUDIT_H 12 + 13 + #include <linux/device-mapper.h> 14 + #include <linux/audit.h> 15 + 16 + #ifdef CONFIG_DM_AUDIT 17 + void dm_audit_log_bio(const char *dm_msg_prefix, const char *op, 18 + struct bio *bio, sector_t sector, int result); 19 + 20 + /* 21 + * dm_audit_log_ti() is not intended to be used directly in dm modules, 22 + * the wrapper functions below should be called by dm modules instead. 23 + */ 24 + void dm_audit_log_ti(int audit_type, const char *dm_msg_prefix, const char *op, 25 + struct dm_target *ti, int result); 26 + 27 + static inline void dm_audit_log_ctr(const char *dm_msg_prefix, 28 + struct dm_target *ti, int result) 29 + { 30 + dm_audit_log_ti(AUDIT_DM_CTRL, dm_msg_prefix, "ctr", ti, result); 31 + } 32 + 33 + static inline void dm_audit_log_dtr(const char *dm_msg_prefix, 34 + struct dm_target *ti, int result) 35 + { 36 + dm_audit_log_ti(AUDIT_DM_CTRL, dm_msg_prefix, "dtr", ti, result); 37 + } 38 + 39 + static inline void dm_audit_log_target(const char *dm_msg_prefix, const char *op, 40 + struct dm_target *ti, int result) 41 + { 42 + dm_audit_log_ti(AUDIT_DM_EVENT, dm_msg_prefix, op, ti, result); 43 + } 44 + #else 45 + static inline void dm_audit_log_bio(const char *dm_msg_prefix, const char *op, 46 + struct bio *bio, sector_t sector, 47 + int result) 48 + { 49 + } 50 + static inline void dm_audit_log_target(const char *dm_msg_prefix, 51 + const char *op, struct dm_target *ti, 52 + int result) 53 + { 54 + } 55 + static inline void dm_audit_log_ctr(const char *dm_msg_prefix, 56 + struct dm_target *ti, int result) 57 + { 58 + } 59 + 60 + static inline void dm_audit_log_dtr(const char *dm_msg_prefix, 61 + struct dm_target *ti, int result) 62 + { 63 + } 64 + #endif 65 + 66 + #endif
-1
drivers/md/dm-bufio.c
··· 2082 2082 int bug = 0; 2083 2083 2084 2084 cancel_delayed_work_sync(&dm_bufio_cleanup_old_work); 2085 - flush_workqueue(dm_bufio_wq); 2086 2085 destroy_workqueue(dm_bufio_wq); 2087 2086 2088 2087 if (dm_bufio_client_count) {
+19 -6
drivers/md/dm-crypt.c
··· 42 42 43 43 #include <linux/device-mapper.h> 44 44 45 + #include "dm-audit.h" 46 + 45 47 #define DM_MSG_PREFIX "crypt" 46 48 47 49 /* ··· 1365 1363 1366 1364 if (r == -EBADMSG) { 1367 1365 char b[BDEVNAME_SIZE]; 1368 - DMERR_LIMIT("%s: INTEGRITY AEAD ERROR, sector %llu", bio_devname(ctx->bio_in, b), 1369 - (unsigned long long)le64_to_cpu(*sector)); 1366 + sector_t s = le64_to_cpu(*sector); 1367 + 1368 + DMERR_LIMIT("%s: INTEGRITY AEAD ERROR, sector %llu", 1369 + bio_devname(ctx->bio_in, b), s); 1370 + dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead", 1371 + ctx->bio_in, s, 0); 1370 1372 } 1371 1373 1372 1374 if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post) ··· 2180 2174 2181 2175 if (error == -EBADMSG) { 2182 2176 char b[BDEVNAME_SIZE]; 2183 - DMERR_LIMIT("%s: INTEGRITY AEAD ERROR, sector %llu", bio_devname(ctx->bio_in, b), 2184 - (unsigned long long)le64_to_cpu(*org_sector_of_dmreq(cc, dmreq))); 2177 + sector_t s = le64_to_cpu(*org_sector_of_dmreq(cc, dmreq)); 2178 + 2179 + DMERR_LIMIT("%s: INTEGRITY AEAD ERROR, sector %llu", 2180 + bio_devname(ctx->bio_in, b), s); 2181 + dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead", 2182 + ctx->bio_in, s, 0); 2185 2183 io->error = BLK_STS_PROTECTION; 2186 2184 } else if (error < 0) 2187 2185 io->error = BLK_STS_IOERR; ··· 2745 2735 dm_crypt_clients_n--; 2746 2736 crypt_calculate_pages_per_client(); 2747 2737 spin_unlock(&dm_crypt_clients_lock); 2738 + 2739 + dm_audit_log_dtr(DM_MSG_PREFIX, ti, 1); 2748 2740 } 2749 2741 2750 2742 static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode) ··· 3363 3351 spin_lock_init(&cc->write_thread_lock); 3364 3352 cc->write_tree = RB_ROOT; 3365 3353 3366 - cc->write_thread = kthread_create(dmcrypt_write, cc, "dmcrypt_write/%s", devname); 3354 + cc->write_thread = kthread_run(dmcrypt_write, cc, "dmcrypt_write/%s", devname); 3367 3355 if (IS_ERR(cc->write_thread)) { 3368 3356 ret = PTR_ERR(cc->write_thread); 3369 3357 cc->write_thread = NULL; 3370 3358 ti->error = "Couldn't spawn write thread"; 3371 3359 goto bad; 3372 3360 } 3373 - wake_up_process(cc->write_thread); 3374 3361 3375 3362 ti->num_flush_bios = 1; 3376 3363 ti->limit_swap_bios = true; 3377 3364 3365 + dm_audit_log_ctr(DM_MSG_PREFIX, ti, 1); 3378 3366 return 0; 3379 3367 3380 3368 bad: 3369 + dm_audit_log_ctr(DM_MSG_PREFIX, ti, 0); 3381 3370 crypt_dtr(ti); 3382 3371 return ret; 3383 3372 }
+26 -9
drivers/md/dm-integrity.c
··· 23 23 #include <linux/async_tx.h> 24 24 #include <linux/dm-bufio.h> 25 25 26 + #include "dm-audit.h" 27 + 26 28 #define DM_MSG_PREFIX "integrity" 27 29 28 30 #define DEFAULT_INTERLEAVE_SECTORS 32768 ··· 541 539 } 542 540 if (memcmp((__u8 *)ic->sb + (1 << SECTOR_SHIFT) - size, result, size)) { 543 541 dm_integrity_io_error(ic, "superblock mac", -EILSEQ); 542 + dm_audit_log_target(DM_MSG_PREFIX, "mac-superblock", ic->ti, 0); 544 543 return -EILSEQ; 545 544 } 546 545 } ··· 879 876 if (likely(wr)) 880 877 memcpy(&js->mac, result + (j * JOURNAL_MAC_PER_SECTOR), JOURNAL_MAC_PER_SECTOR); 881 878 else { 882 - if (memcmp(&js->mac, result + (j * JOURNAL_MAC_PER_SECTOR), JOURNAL_MAC_PER_SECTOR)) 879 + if (memcmp(&js->mac, result + (j * JOURNAL_MAC_PER_SECTOR), JOURNAL_MAC_PER_SECTOR)) { 883 880 dm_integrity_io_error(ic, "journal mac", -EILSEQ); 881 + dm_audit_log_target(DM_MSG_PREFIX, "mac-journal", ic->ti, 0); 882 + } 884 883 } 885 884 } 886 885 } ··· 1770 1765 char *mem, *checksums_ptr; 1771 1766 1772 1767 again: 1773 - mem = (char *)kmap_atomic(bv.bv_page) + bv.bv_offset; 1768 + mem = bvec_kmap_local(&bv); 1774 1769 pos = 0; 1775 1770 checksums_ptr = checksums; 1776 1771 do { ··· 1780 1775 pos += ic->sectors_per_block << SECTOR_SHIFT; 1781 1776 sector += ic->sectors_per_block; 1782 1777 } while (pos < bv.bv_len && sectors_to_process && checksums != checksums_onstack); 1783 - kunmap_atomic(mem); 1778 + kunmap_local(mem); 1784 1779 1785 1780 r = dm_integrity_rw_tag(ic, checksums, &dio->metadata_block, &dio->metadata_offset, 1786 1781 checksums_ptr - checksums, dio->op == REQ_OP_READ ? TAG_CMP : TAG_WRITE); 1787 1782 if (unlikely(r)) { 1788 1783 if (r > 0) { 1789 1784 char b[BDEVNAME_SIZE]; 1790 - DMERR_LIMIT("%s: Checksum failed at sector 0x%llx", bio_devname(bio, b), 1791 - (sector - ((r + ic->tag_size - 1) / ic->tag_size))); 1785 + sector_t s; 1786 + 1787 + s = sector - ((r + ic->tag_size - 1) / ic->tag_size); 1788 + DMERR_LIMIT("%s: Checksum failed at sector 0x%llx", 1789 + bio_devname(bio, b), s); 1792 1790 r = -EILSEQ; 1793 1791 atomic64_inc(&ic->number_of_mismatches); 1792 + dm_audit_log_bio(DM_MSG_PREFIX, "integrity-checksum", 1793 + bio, s, 0); 1794 1794 } 1795 1795 if (likely(checksums != checksums_onstack)) 1796 1796 kfree(checksums); ··· 1963 1953 n_sectors -= bv.bv_len >> SECTOR_SHIFT; 1964 1954 bio_advance_iter(bio, &bio->bi_iter, bv.bv_len); 1965 1955 retry_kmap: 1966 - mem = kmap_atomic(bv.bv_page); 1956 + mem = bvec_kmap_local(&bv); 1967 1957 if (likely(dio->op == REQ_OP_WRITE)) 1968 1958 flush_dcache_page(bv.bv_page); 1969 1959 ··· 1977 1967 1978 1968 if (unlikely(journal_entry_is_inprogress(je))) { 1979 1969 flush_dcache_page(bv.bv_page); 1980 - kunmap_atomic(mem); 1970 + kunmap_local(mem); 1981 1971 1982 1972 __io_wait_event(ic->copy_to_journal_wait, !journal_entry_is_inprogress(je)); 1983 1973 goto retry_kmap; ··· 2001 1991 if (unlikely(memcmp(checksums_onstack, journal_entry_tag(ic, je), ic->tag_size))) { 2002 1992 DMERR_LIMIT("Checksum failed when reading from journal, at sector 0x%llx", 2003 1993 logical_sector); 1994 + dm_audit_log_bio(DM_MSG_PREFIX, "journal-checksum", 1995 + bio, logical_sector, 0); 2004 1996 } 2005 1997 } 2006 1998 #endif ··· 2070 2058 2071 2059 if (unlikely(dio->op == REQ_OP_READ)) 2072 2060 flush_dcache_page(bv.bv_page); 2073 - kunmap_atomic(mem); 2061 + kunmap_local(mem); 2074 2062 } while (n_sectors); 2075 2063 2076 2064 if (likely(dio->op == REQ_OP_WRITE)) { ··· 2546 2534 2547 2535 integrity_sector_checksum(ic, sec + ((l - j) << ic->sb->log2_sectors_per_block), 2548 2536 (char *)access_journal_data(ic, i, l), test_tag); 2549 - if (unlikely(memcmp(test_tag, journal_entry_tag(ic, je2), ic->tag_size))) 2537 + if (unlikely(memcmp(test_tag, journal_entry_tag(ic, je2), ic->tag_size))) { 2550 2538 dm_integrity_io_error(ic, "tag mismatch when replaying journal", -EILSEQ); 2539 + dm_audit_log_target(DM_MSG_PREFIX, "integrity-replay-journal", ic->ti, 0); 2540 + } 2551 2541 } 2552 2542 2553 2543 journal_entry_set_unused(je2); ··· 4528 4514 if (ic->discard) 4529 4515 ti->num_discard_bios = 1; 4530 4516 4517 + dm_audit_log_ctr(DM_MSG_PREFIX, ti, 1); 4531 4518 return 0; 4532 4519 4533 4520 bad: 4521 + dm_audit_log_ctr(DM_MSG_PREFIX, ti, 0); 4534 4522 dm_integrity_dtr(ti); 4535 4523 return r; 4536 4524 } ··· 4606 4590 free_alg(&ic->journal_mac_alg); 4607 4591 4608 4592 kfree(ic); 4593 + dm_audit_log_dtr(DM_MSG_PREFIX, ti, 1); 4609 4594 } 4610 4595 4611 4596 static struct target_type integrity_target = {
+2 -4
drivers/md/dm-log-writes.c
··· 753 753 */ 754 754 bio_for_each_segment(bv, bio, iter) { 755 755 struct page *page; 756 - void *src, *dst; 756 + void *dst; 757 757 758 758 page = alloc_page(GFP_NOIO); 759 759 if (!page) { ··· 765 765 return DM_MAPIO_KILL; 766 766 } 767 767 768 - src = kmap_atomic(bv.bv_page); 769 768 dst = kmap_atomic(page); 770 - memcpy(dst, src + bv.bv_offset, bv.bv_len); 769 + memcpy_from_bvec(dst, &bv); 771 770 kunmap_atomic(dst); 772 - kunmap_atomic(src); 773 771 block->vecs[i].bv_page = page; 774 772 block->vecs[i].bv_len = bv.bv_len; 775 773 block->vec_cnt++;
+2 -2
drivers/md/dm-table.c
··· 706 706 707 707 r = dm_split_args(&argc, &argv, params); 708 708 if (r) { 709 - tgt->error = "couldn't split parameters (insufficient memory)"; 709 + tgt->error = "couldn't split parameters"; 710 710 goto bad; 711 711 } 712 712 ··· 724 724 return 0; 725 725 726 726 bad: 727 - DMERR("%s: %s: %s", dm_device_name(t->md), type, tgt->error); 727 + DMERR("%s: %s: %s (%pe)", dm_device_name(t->md), type, tgt->error, ERR_PTR(r)); 728 728 dm_put_target_type(tgt->type); 729 729 return r; 730 730 }
+3 -3
drivers/md/dm-verity-target.c
··· 428 428 unsigned len; 429 429 struct bio_vec bv = bio_iter_iovec(bio, *iter); 430 430 431 - page = kmap_atomic(bv.bv_page); 431 + page = bvec_kmap_local(&bv); 432 432 len = bv.bv_len; 433 433 434 434 if (likely(len >= todo)) 435 435 len = todo; 436 436 437 - r = process(v, io, page + bv.bv_offset, len); 438 - kunmap_atomic(page); 437 + r = process(v, io, page, len); 438 + kunmap_local(page); 439 439 440 440 if (r < 0) 441 441 return r;
+2 -4
drivers/md/dm-writecache.c
··· 2264 2264 2265 2265 raw_spin_lock_init(&wc->endio_list_lock); 2266 2266 INIT_LIST_HEAD(&wc->endio_list); 2267 - wc->endio_thread = kthread_create(writecache_endio_thread, wc, "writecache_endio"); 2267 + wc->endio_thread = kthread_run(writecache_endio_thread, wc, "writecache_endio"); 2268 2268 if (IS_ERR(wc->endio_thread)) { 2269 2269 r = PTR_ERR(wc->endio_thread); 2270 2270 wc->endio_thread = NULL; 2271 2271 ti->error = "Couldn't spawn endio thread"; 2272 2272 goto bad; 2273 2273 } 2274 - wake_up_process(wc->endio_thread); 2275 2274 2276 2275 /* 2277 2276 * Parse the mode (pmem or ssd) ··· 2492 2493 wc->memory_map_size -= (uint64_t)wc->start_sector << SECTOR_SHIFT; 2493 2494 2494 2495 bio_list_init(&wc->flush_list); 2495 - wc->flush_thread = kthread_create(writecache_flush_thread, wc, "dm_writecache_flush"); 2496 + wc->flush_thread = kthread_run(writecache_flush_thread, wc, "dm_writecache_flush"); 2496 2497 if (IS_ERR(wc->flush_thread)) { 2497 2498 r = PTR_ERR(wc->flush_thread); 2498 2499 wc->flush_thread = NULL; 2499 2500 ti->error = "Couldn't spawn flush thread"; 2500 2501 goto bad; 2501 2502 } 2502 - wake_up_process(wc->flush_thread); 2503 2503 2504 2504 r = calculate_memory_size(wc->memory_map_size, wc->block_size, 2505 2505 &n_blocks, &n_metadata_blocks);
-1
drivers/md/dm-zoned-target.c
··· 967 967 struct dmz_target *dmz = ti->private; 968 968 int i; 969 969 970 - flush_workqueue(dmz->chunk_wq); 971 970 destroy_workqueue(dmz->chunk_wq); 972 971 973 972 for (i = 0; i < dmz->nr_ddevs; i++)
+1 -1
drivers/md/dm.c
··· 1792 1792 1793 1793 format_dev_t(md->name, MKDEV(_major, minor)); 1794 1794 1795 - md->wq = alloc_workqueue("kdmflush", WQ_MEM_RECLAIM, 0); 1795 + md->wq = alloc_workqueue("kdmflush/%s", WQ_MEM_RECLAIM, 0, md->name); 1796 1796 if (!md->wq) 1797 1797 goto bad; 1798 1798
+2
include/uapi/linux/audit.h
··· 120 120 #define AUDIT_EVENT_LISTENER 1335 /* Task joined multicast read socket */ 121 121 #define AUDIT_URINGOP 1336 /* io_uring operation */ 122 122 #define AUDIT_OPENAT2 1337 /* Record showing openat2 how args */ 123 + #define AUDIT_DM_CTRL 1338 /* Device Mapper target control */ 124 + #define AUDIT_DM_EVENT 1339 /* Device Mapper events */ 123 125 124 126 #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ 125 127 #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */