Skip to content

Commit c183e17

Browse files
committed
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
2 parents 3725949 + 7552750 commit c183e17

File tree

14 files changed

+221
-31
lines changed

14 files changed

+221
-31
lines changed

drivers/md/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,7 @@ config DM_INTEGRITY
610610
select CRYPTO
611611
select CRYPTO_SKCIPHER
612612
select ASYNC_XOR
613+
select DM_AUDIT if AUDIT
613614
help
614615
This device-mapper target emulates a block device that has
615616
additional per-sector tags that can be used for storing
@@ -642,4 +643,13 @@ config DM_ZONED
642643

643644
If unsure, say N.
644645

646+
config DM_AUDIT
647+
bool "DM audit events"
648+
depends on AUDIT
649+
help
650+
Generate audit events for device-mapper.
651+
652+
Enables audit logging of several security relevant events in the
653+
particular device-mapper targets, especially the integrity target.
654+
645655
endif # MD

drivers/md/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,7 @@ endif
107107
ifeq ($(CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG),y)
108108
dm-verity-objs += dm-verity-verify-sig.o
109109
endif
110+
111+
ifeq ($(CONFIG_DM_AUDIT),y)
112+
dm-mod-objs += dm-audit.o
113+
endif

drivers/md/dm-audit.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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ß <[email protected]>
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);

drivers/md/dm-audit.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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ß <[email protected]>
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

drivers/md/dm-bufio.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2082,7 +2082,6 @@ static void __exit dm_bufio_exit(void)
20822082
int bug = 0;
20832083

20842084
cancel_delayed_work_sync(&dm_bufio_cleanup_old_work);
2085-
flush_workqueue(dm_bufio_wq);
20862085
destroy_workqueue(dm_bufio_wq);
20872086

20882087
if (dm_bufio_client_count) {

drivers/md/dm-crypt.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242

4343
#include <linux/device-mapper.h>
4444

45+
#include "dm-audit.h"
46+
4547
#define DM_MSG_PREFIX "crypt"
4648

4749
/*
@@ -1363,8 +1365,12 @@ static int crypt_convert_block_aead(struct crypt_config *cc,
13631365

13641366
if (r == -EBADMSG) {
13651367
char b[BDEVNAME_SIZE];
1366-
DMERR_LIMIT("%s: INTEGRITY AEAD ERROR, sector %llu", bio_devname(ctx->bio_in, b),
1367-
(unsigned long long)le64_to_cpu(*sector));
1368+
sector_t s = le64_to_cpu(*sector);
1369+
1370+
DMERR_LIMIT("%s: INTEGRITY AEAD ERROR, sector %llu",
1371+
bio_devname(ctx->bio_in, b), s);
1372+
dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead",
1373+
ctx->bio_in, s, 0);
13681374
}
13691375

13701376
if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post)
@@ -2174,8 +2180,12 @@ static void kcryptd_async_done(struct crypto_async_request *async_req,
21742180

21752181
if (error == -EBADMSG) {
21762182
char b[BDEVNAME_SIZE];
2177-
DMERR_LIMIT("%s: INTEGRITY AEAD ERROR, sector %llu", bio_devname(ctx->bio_in, b),
2178-
(unsigned long long)le64_to_cpu(*org_sector_of_dmreq(cc, dmreq)));
2183+
sector_t s = le64_to_cpu(*org_sector_of_dmreq(cc, dmreq));
2184+
2185+
DMERR_LIMIT("%s: INTEGRITY AEAD ERROR, sector %llu",
2186+
bio_devname(ctx->bio_in, b), s);
2187+
dm_audit_log_bio(DM_MSG_PREFIX, "integrity-aead",
2188+
ctx->bio_in, s, 0);
21792189
io->error = BLK_STS_PROTECTION;
21802190
} else if (error < 0)
21812191
io->error = BLK_STS_IOERR;
@@ -2735,6 +2745,8 @@ static void crypt_dtr(struct dm_target *ti)
27352745
dm_crypt_clients_n--;
27362746
crypt_calculate_pages_per_client();
27372747
spin_unlock(&dm_crypt_clients_lock);
2748+
2749+
dm_audit_log_dtr(DM_MSG_PREFIX, ti, 1);
27382750
}
27392751

27402752
static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
@@ -3351,21 +3363,22 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
33513363
spin_lock_init(&cc->write_thread_lock);
33523364
cc->write_tree = RB_ROOT;
33533365

3354-
cc->write_thread = kthread_create(dmcrypt_write, cc, "dmcrypt_write/%s", devname);
3366+
cc->write_thread = kthread_run(dmcrypt_write, cc, "dmcrypt_write/%s", devname);
33553367
if (IS_ERR(cc->write_thread)) {
33563368
ret = PTR_ERR(cc->write_thread);
33573369
cc->write_thread = NULL;
33583370
ti->error = "Couldn't spawn write thread";
33593371
goto bad;
33603372
}
3361-
wake_up_process(cc->write_thread);
33623373

33633374
ti->num_flush_bios = 1;
33643375
ti->limit_swap_bios = true;
33653376

3377+
dm_audit_log_ctr(DM_MSG_PREFIX, ti, 1);
33663378
return 0;
33673379

33683380
bad:
3381+
dm_audit_log_ctr(DM_MSG_PREFIX, ti, 0);
33693382
crypt_dtr(ti);
33703383
return ret;
33713384
}

drivers/md/dm-integrity.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <linux/async_tx.h>
2424
#include <linux/dm-bufio.h>
2525

26+
#include "dm-audit.h"
27+
2628
#define DM_MSG_PREFIX "integrity"
2729

2830
#define DEFAULT_INTERLEAVE_SECTORS 32768
@@ -539,6 +541,7 @@ static int sb_mac(struct dm_integrity_c *ic, bool wr)
539541
}
540542
if (memcmp((__u8 *)ic->sb + (1 << SECTOR_SHIFT) - size, result, size)) {
541543
dm_integrity_io_error(ic, "superblock mac", -EILSEQ);
544+
dm_audit_log_target(DM_MSG_PREFIX, "mac-superblock", ic->ti, 0);
542545
return -EILSEQ;
543546
}
544547
}
@@ -876,8 +879,10 @@ static void rw_section_mac(struct dm_integrity_c *ic, unsigned section, bool wr)
876879
if (likely(wr))
877880
memcpy(&js->mac, result + (j * JOURNAL_MAC_PER_SECTOR), JOURNAL_MAC_PER_SECTOR);
878881
else {
879-
if (memcmp(&js->mac, result + (j * JOURNAL_MAC_PER_SECTOR), JOURNAL_MAC_PER_SECTOR))
882+
if (memcmp(&js->mac, result + (j * JOURNAL_MAC_PER_SECTOR), JOURNAL_MAC_PER_SECTOR)) {
880883
dm_integrity_io_error(ic, "journal mac", -EILSEQ);
884+
dm_audit_log_target(DM_MSG_PREFIX, "mac-journal", ic->ti, 0);
885+
}
881886
}
882887
}
883888
}
@@ -1765,7 +1770,7 @@ static void integrity_metadata(struct work_struct *w)
17651770
char *mem, *checksums_ptr;
17661771

17671772
again:
1768-
mem = (char *)kmap_atomic(bv.bv_page) + bv.bv_offset;
1773+
mem = bvec_kmap_local(&bv);
17691774
pos = 0;
17701775
checksums_ptr = checksums;
17711776
do {
@@ -1775,17 +1780,22 @@ static void integrity_metadata(struct work_struct *w)
17751780
pos += ic->sectors_per_block << SECTOR_SHIFT;
17761781
sector += ic->sectors_per_block;
17771782
} while (pos < bv.bv_len && sectors_to_process && checksums != checksums_onstack);
1778-
kunmap_atomic(mem);
1783+
kunmap_local(mem);
17791784

17801785
r = dm_integrity_rw_tag(ic, checksums, &dio->metadata_block, &dio->metadata_offset,
17811786
checksums_ptr - checksums, dio->op == REQ_OP_READ ? TAG_CMP : TAG_WRITE);
17821787
if (unlikely(r)) {
17831788
if (r > 0) {
17841789
char b[BDEVNAME_SIZE];
1785-
DMERR_LIMIT("%s: Checksum failed at sector 0x%llx", bio_devname(bio, b),
1786-
(sector - ((r + ic->tag_size - 1) / ic->tag_size)));
1790+
sector_t s;
1791+
1792+
s = sector - ((r + ic->tag_size - 1) / ic->tag_size);
1793+
DMERR_LIMIT("%s: Checksum failed at sector 0x%llx",
1794+
bio_devname(bio, b), s);
17871795
r = -EILSEQ;
17881796
atomic64_inc(&ic->number_of_mismatches);
1797+
dm_audit_log_bio(DM_MSG_PREFIX, "integrity-checksum",
1798+
bio, s, 0);
17891799
}
17901800
if (likely(checksums != checksums_onstack))
17911801
kfree(checksums);
@@ -1953,7 +1963,7 @@ static bool __journal_read_write(struct dm_integrity_io *dio, struct bio *bio,
19531963
n_sectors -= bv.bv_len >> SECTOR_SHIFT;
19541964
bio_advance_iter(bio, &bio->bi_iter, bv.bv_len);
19551965
retry_kmap:
1956-
mem = kmap_atomic(bv.bv_page);
1966+
mem = bvec_kmap_local(&bv);
19571967
if (likely(dio->op == REQ_OP_WRITE))
19581968
flush_dcache_page(bv.bv_page);
19591969

@@ -1967,7 +1977,7 @@ static bool __journal_read_write(struct dm_integrity_io *dio, struct bio *bio,
19671977

19681978
if (unlikely(journal_entry_is_inprogress(je))) {
19691979
flush_dcache_page(bv.bv_page);
1970-
kunmap_atomic(mem);
1980+
kunmap_local(mem);
19711981

19721982
__io_wait_event(ic->copy_to_journal_wait, !journal_entry_is_inprogress(je));
19731983
goto retry_kmap;
@@ -1991,6 +2001,8 @@ static bool __journal_read_write(struct dm_integrity_io *dio, struct bio *bio,
19912001
if (unlikely(memcmp(checksums_onstack, journal_entry_tag(ic, je), ic->tag_size))) {
19922002
DMERR_LIMIT("Checksum failed when reading from journal, at sector 0x%llx",
19932003
logical_sector);
2004+
dm_audit_log_bio(DM_MSG_PREFIX, "journal-checksum",
2005+
bio, logical_sector, 0);
19942006
}
19952007
}
19962008
#endif
@@ -2058,7 +2070,7 @@ static bool __journal_read_write(struct dm_integrity_io *dio, struct bio *bio,
20582070

20592071
if (unlikely(dio->op == REQ_OP_READ))
20602072
flush_dcache_page(bv.bv_page);
2061-
kunmap_atomic(mem);
2073+
kunmap_local(mem);
20622074
} while (n_sectors);
20632075

20642076
if (likely(dio->op == REQ_OP_WRITE)) {
@@ -2534,8 +2546,10 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
25342546

25352547
integrity_sector_checksum(ic, sec + ((l - j) << ic->sb->log2_sectors_per_block),
25362548
(char *)access_journal_data(ic, i, l), test_tag);
2537-
if (unlikely(memcmp(test_tag, journal_entry_tag(ic, je2), ic->tag_size)))
2549+
if (unlikely(memcmp(test_tag, journal_entry_tag(ic, je2), ic->tag_size))) {
25382550
dm_integrity_io_error(ic, "tag mismatch when replaying journal", -EILSEQ);
2551+
dm_audit_log_target(DM_MSG_PREFIX, "integrity-replay-journal", ic->ti, 0);
2552+
}
25392553
}
25402554

25412555
journal_entry_set_unused(je2);
@@ -4514,9 +4528,11 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
45144528
if (ic->discard)
45154529
ti->num_discard_bios = 1;
45164530

4531+
dm_audit_log_ctr(DM_MSG_PREFIX, ti, 1);
45174532
return 0;
45184533

45194534
bad:
4535+
dm_audit_log_ctr(DM_MSG_PREFIX, ti, 0);
45204536
dm_integrity_dtr(ti);
45214537
return r;
45224538
}
@@ -4590,6 +4606,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
45904606
free_alg(&ic->journal_mac_alg);
45914607

45924608
kfree(ic);
4609+
dm_audit_log_dtr(DM_MSG_PREFIX, ti, 1);
45934610
}
45944611

45954612
static struct target_type integrity_target = {

0 commit comments

Comments
 (0)