mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 14:30:06 -04:00
Merge tag 'for-7.2/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull device mapper fixes from Mikulas Patocka: - dm-log: fix overflow on 32-bit machines - dm-era: fix out of bounds memory access; fix crashes on invalid args - dm-verity: fix buffer overflow in forward error correction - dm-thin: fix misbehavior on I/O failures - dm-pcache: fix NULL pointer dereference on invalid arguments - dm-inlinecrypt: fix memory leak on error handling - dm-integrity: fix ignoring the 'fix_hmac' option on device open - dm: don't store the keyring in memory for a long term - 12 miscellaneous fixes for bugs found by Claude Opus 4.6 * tag 'for-7.2/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: (23 commits) dm thin metadata: fix superblock refcount leak on snapshot shadow failure dm-stats: fix dm_jiffies_to_msec64 dm-stats: fix merge accounting dm-bufio: fix wrong count calculation in dm_bufio_issue_discard dm-verity: make error counter atomic dm-verity: increase sprintf buffer size dm-verity: fix a possible NULL pointer dereference dm-verity: avoid double increment of &use_bh_wq_enabled dm-ioctl: fix a possible overflow in list_version_get_info dm_early_create: fix freeing used table on dm_resume failure dm-integrity: fix a bug if the bio is out of limits dm-integrity: don't increment hash_offset twice dm-integrity: fix leaking uninitialized kernel memory dm-integrity: fix the 'fix_hmac' option dm era: fix error code propagation in era_ctr() dm era: fix NULL pointer dereference in metadata_open() dm: avoid leaking the caller's thread keyring via the table device file dm-inlinecrypt: Fix an error handling path in inlinecrypt_ctr() dm-pcache: reject option groups without values dm thin metadata: fix metadata snapshot consistency on commit failure ...
This commit is contained in:
@@ -2238,7 +2238,9 @@ int dm_bufio_issue_discard(struct dm_bufio_client *c, sector_t block, sector_t c
|
||||
struct dm_io_region io_reg = {
|
||||
.bdev = c->bdev,
|
||||
.sector = block_to_sector(c, block),
|
||||
.count = block_to_sector(c, count),
|
||||
.count = likely(c->sectors_per_block_bits >= 0) ?
|
||||
count << c->sectors_per_block_bits :
|
||||
count * (c->block_size >> SECTOR_SHIFT),
|
||||
};
|
||||
|
||||
if (WARN_ON_ONCE(dm_bufio_in_request()))
|
||||
|
||||
@@ -810,8 +810,10 @@ static struct era_metadata *metadata_open(struct block_device *bdev,
|
||||
int r;
|
||||
struct era_metadata *md = kzalloc_obj(*md);
|
||||
|
||||
if (!md)
|
||||
return NULL;
|
||||
if (!md) {
|
||||
DMERR("could not allocate metadata struct");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
md->bdev = bdev;
|
||||
md->block_size = block_size;
|
||||
@@ -1229,6 +1231,7 @@ static dm_block_t get_block(struct era *era, struct bio *bio)
|
||||
static void remap_to_origin(struct era *era, struct bio *bio)
|
||||
{
|
||||
bio_set_dev(bio, era->origin_dev->bdev);
|
||||
bio->bi_iter.bi_sector = dm_target_offset(era->ti, bio->bi_iter.bi_sector);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1486,7 +1489,7 @@ static int era_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
if (r) {
|
||||
ti->error = "Error opening metadata device";
|
||||
era_destroy(era);
|
||||
return -EINVAL;
|
||||
return r;
|
||||
}
|
||||
|
||||
r = dm_get_device(ti, argv[1], BLK_OPEN_READ | BLK_OPEN_WRITE,
|
||||
@@ -1494,7 +1497,7 @@ static int era_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
if (r) {
|
||||
ti->error = "Error opening data device";
|
||||
era_destroy(era);
|
||||
return -EINVAL;
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sscanf(argv[2], "%u%c", &era->sectors_per_block, &dummy);
|
||||
@@ -1508,7 +1511,7 @@ static int era_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
if (r) {
|
||||
ti->error = "could not set max io len";
|
||||
era_destroy(era);
|
||||
return -EINVAL;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!valid_block_size(era->sectors_per_block)) {
|
||||
@@ -1560,7 +1563,7 @@ static void era_dtr(struct dm_target *ti)
|
||||
static int era_map(struct dm_target *ti, struct bio *bio)
|
||||
{
|
||||
struct era *era = ti->private;
|
||||
dm_block_t block = get_block(era, bio);
|
||||
dm_block_t block;
|
||||
|
||||
/*
|
||||
* All bios get remapped to the origin device. We do this now, but
|
||||
@@ -1568,6 +1571,7 @@ static int era_map(struct dm_target *ti, struct bio *bio)
|
||||
* block is marked in this era.
|
||||
*/
|
||||
remap_to_origin(era, bio);
|
||||
block = get_block(era, bio);
|
||||
|
||||
/*
|
||||
* REQ_PREFLUSH bios carry no data, so we're not interested in them.
|
||||
|
||||
@@ -347,7 +347,8 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
err = get_key_size(&argv[1]);
|
||||
if (err < 0) {
|
||||
ti->error = "Cannot parse key size";
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
ctx->key_size = err;
|
||||
|
||||
@@ -398,6 +399,7 @@ static int inlinecrypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
if (ctx->iv_offset & ((ctx->sector_size >> SECTOR_SHIFT) - 1)) {
|
||||
ti->error = "Wrong alignment of iv_offset sector";
|
||||
err = -EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
ctx->max_dun = (ctx->iv_offset + ti->len - 1) >>
|
||||
|
||||
@@ -1480,9 +1480,6 @@ static int dm_integrity_rw_tag(struct dm_integrity_c *ic, unsigned char *tag, se
|
||||
*metadata_offset = 0;
|
||||
}
|
||||
|
||||
if (unlikely(!is_power_of_2(ic->tag_size)))
|
||||
hash_offset = (hash_offset + to_copy) % ic->tag_size;
|
||||
|
||||
total_size -= to_copy;
|
||||
} while (unlikely(total_size));
|
||||
|
||||
@@ -2523,6 +2520,9 @@ static int dm_integrity_map_inline(struct dm_integrity_io *dio, bool from_map)
|
||||
if (unlikely((bio->bi_opf & REQ_PREFLUSH) != 0))
|
||||
return DM_MAPIO_REMAPPED;
|
||||
|
||||
if (unlikely(!dm_integrity_check_limits(ic, bio->bi_iter.bi_sector, bio)))
|
||||
return DM_MAPIO_KILL;
|
||||
|
||||
retry:
|
||||
if (!dio->integrity_payload) {
|
||||
unsigned digest_size, extra_size;
|
||||
@@ -2587,10 +2587,6 @@ static int dm_integrity_map_inline(struct dm_integrity_io *dio, bool from_map)
|
||||
|
||||
dio->bio_details.bi_iter = bio->bi_iter;
|
||||
|
||||
if (unlikely(!dm_integrity_check_limits(ic, bio->bi_iter.bi_sector, bio))) {
|
||||
return DM_MAPIO_KILL;
|
||||
}
|
||||
|
||||
bio->bi_iter.bi_sector += ic->start + SB_SECTORS;
|
||||
|
||||
bip = bio_integrity_alloc(bio, GFP_NOIO, 1);
|
||||
@@ -2606,7 +2602,7 @@ static int dm_integrity_map_inline(struct dm_integrity_io *dio, bool from_map)
|
||||
struct bio_vec bv = bio_iter_iovec(bio, dio->bio_details.bi_iter);
|
||||
const char *mem = integrity_kmap(ic, bv.bv_page);
|
||||
if (ic->tag_size < ic->tuple_size)
|
||||
memset(dio->integrity_payload + pos + ic->tag_size, 0, ic->tuple_size - ic->tuple_size);
|
||||
memset(dio->integrity_payload + pos + ic->tag_size, 0, ic->tuple_size - ic->tag_size);
|
||||
integrity_sector_checksum(ic, &dio->ahash_req, dio->bio_details.bi_iter.bi_sector, mem, bv.bv_offset, dio->integrity_payload + pos);
|
||||
integrity_kunmap(ic, mem);
|
||||
pos += ic->tuple_size;
|
||||
@@ -5130,6 +5126,20 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
|
||||
ti->error = "Journal mac mismatch";
|
||||
goto bad;
|
||||
}
|
||||
if (ic->fix_hmac && !(ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC)) && ic->journal_mac_alg.key_string) {
|
||||
/*
|
||||
* If this happens, it may be either because someone tampered
|
||||
* with the device or it may be due to a bug in the
|
||||
* integritysetup tool.
|
||||
*
|
||||
* In the latter case, upgrade to integritysetup 2.8.7 and use
|
||||
* the argument --integrity-legacy-hmac when using the open
|
||||
* command.
|
||||
*/
|
||||
r = -EINVAL;
|
||||
ti->error = "fix_hmac is on the command line but not in the superblock";
|
||||
goto bad;
|
||||
}
|
||||
|
||||
get_provided_data_sectors(ic);
|
||||
if (!ic->provided_data_sectors) {
|
||||
|
||||
@@ -785,7 +785,7 @@ static void list_version_get_info(struct target_type *tt, void *param)
|
||||
struct vers_iter *info = param;
|
||||
|
||||
/* Check space - it might have changed since the first iteration */
|
||||
if ((char *)info->vers + sizeof(tt->version) + strlen(tt->name) + 1 > info->end) {
|
||||
if ((char *)info->vers + sizeof(struct dm_target_versions) + strlen(tt->name) + 1 > info->end) {
|
||||
info->flags = DM_BUFFER_FULL_FLAG;
|
||||
return;
|
||||
}
|
||||
@@ -2473,7 +2473,7 @@ int __init dm_early_create(struct dm_ioctl *dmi,
|
||||
/* resume device */
|
||||
r = dm_resume(md);
|
||||
if (r)
|
||||
goto err_destroy_table;
|
||||
goto err_hash_remove;
|
||||
|
||||
DMINFO("%s (%s) is ready", md->disk->disk_name, dmi->name);
|
||||
dm_put(md);
|
||||
|
||||
@@ -425,6 +425,9 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
|
||||
*/
|
||||
bitset_size = dm_round_up(region_count, BITS_PER_LONG);
|
||||
bitset_size >>= BYTE_SHIFT;
|
||||
/* Handle dm_round_up rollover on 32-bit systems */
|
||||
if (!bitset_size)
|
||||
bitset_size = 1UL << (BITS_PER_LONG - BYTE_SHIFT);
|
||||
|
||||
lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits);
|
||||
|
||||
|
||||
@@ -168,6 +168,10 @@ static int parse_cache_opts(struct dm_pcache *pcache, struct dm_arg_set *as,
|
||||
argc--;
|
||||
|
||||
if (!strcmp(arg, "cache_mode")) {
|
||||
if (!argc) {
|
||||
*error = "Missing value for cache_mode";
|
||||
return -EINVAL;
|
||||
}
|
||||
arg = dm_shift_arg(as);
|
||||
if (!strcmp(arg, "writeback")) {
|
||||
opts->cache_mode = PCACHE_CACHE_MODE_WRITEBACK;
|
||||
@@ -177,6 +181,10 @@ static int parse_cache_opts(struct dm_pcache *pcache, struct dm_arg_set *as,
|
||||
}
|
||||
argc--;
|
||||
} else if (!strcmp(arg, "data_crc")) {
|
||||
if (!argc) {
|
||||
*error = "Missing value for data_crc";
|
||||
return -EINVAL;
|
||||
}
|
||||
arg = dm_shift_arg(as);
|
||||
if (!strcmp(arg, "true")) {
|
||||
opts->data_crc = true;
|
||||
|
||||
@@ -692,10 +692,8 @@ void dm_stats_account_io(struct dm_stats *stats, unsigned long bi_rw,
|
||||
*/
|
||||
last = raw_cpu_ptr(stats->last);
|
||||
stats_aux->merged =
|
||||
(bi_sector == (READ_ONCE(last->last_sector) &&
|
||||
((bi_rw == WRITE) ==
|
||||
(READ_ONCE(last->last_rw) == WRITE))
|
||||
));
|
||||
bi_sector == READ_ONCE(last->last_sector) &&
|
||||
(bi_rw == WRITE) == (READ_ONCE(last->last_rw) == WRITE);
|
||||
WRITE_ONCE(last->last_sector, end_sector);
|
||||
WRITE_ONCE(last->last_rw, bi_rw);
|
||||
} else
|
||||
@@ -842,10 +840,10 @@ static unsigned long long dm_jiffies_to_msec64(struct dm_stat *s, unsigned long
|
||||
result = jiffies_to_msecs(j & 0x3fffff);
|
||||
if (j >= 1 << 22) {
|
||||
mult = jiffies_to_msecs(1 << 22);
|
||||
result += (unsigned long long)mult * (unsigned long long)jiffies_to_msecs((j >> 22) & 0x3fffff);
|
||||
result += (unsigned long long)mult * ((j >> 22) & 0x3fffff);
|
||||
}
|
||||
if (j >= 1ULL << 44)
|
||||
result += (unsigned long long)mult * (unsigned long long)mult * (unsigned long long)jiffies_to_msecs(j >> 44);
|
||||
result += (unsigned long long)mult * (unsigned long long)(1 << 22) * (j >> 44);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -186,6 +186,7 @@ struct dm_pool_metadata {
|
||||
uint32_t time;
|
||||
dm_block_t root;
|
||||
dm_block_t details_root;
|
||||
dm_block_t held_root;
|
||||
struct list_head thin_devices;
|
||||
uint64_t trans_id;
|
||||
unsigned long flags;
|
||||
@@ -748,6 +749,7 @@ static int __open_metadata(struct dm_pool_metadata *pmd)
|
||||
*/
|
||||
pmd->root = le64_to_cpu(disk_super->data_mapping_root);
|
||||
pmd->details_root = le64_to_cpu(disk_super->device_details_root);
|
||||
pmd->held_root = le64_to_cpu(disk_super->held_root);
|
||||
|
||||
__setup_btree_details(pmd);
|
||||
dm_bm_unlock(sblock);
|
||||
@@ -838,6 +840,7 @@ static int __begin_transaction(struct dm_pool_metadata *pmd)
|
||||
pmd->time = le32_to_cpu(disk_super->time);
|
||||
pmd->root = le64_to_cpu(disk_super->data_mapping_root);
|
||||
pmd->details_root = le64_to_cpu(disk_super->device_details_root);
|
||||
pmd->held_root = le64_to_cpu(disk_super->held_root);
|
||||
pmd->trans_id = le64_to_cpu(disk_super->trans_id);
|
||||
pmd->flags = le32_to_cpu(disk_super->flags);
|
||||
pmd->data_block_size = le32_to_cpu(disk_super->data_block_size);
|
||||
@@ -928,6 +931,7 @@ static int __commit_transaction(struct dm_pool_metadata *pmd)
|
||||
disk_super->time = cpu_to_le32(pmd->time);
|
||||
disk_super->data_mapping_root = cpu_to_le64(pmd->root);
|
||||
disk_super->device_details_root = cpu_to_le64(pmd->details_root);
|
||||
disk_super->held_root = cpu_to_le64(pmd->held_root);
|
||||
disk_super->trans_id = cpu_to_le64(pmd->trans_id);
|
||||
disk_super->flags = cpu_to_le32(pmd->flags);
|
||||
|
||||
@@ -1333,9 +1337,14 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd)
|
||||
{
|
||||
int r, inc;
|
||||
struct thin_disk_superblock *disk_super;
|
||||
struct dm_block *copy, *sblock;
|
||||
struct dm_block *copy;
|
||||
dm_block_t held_root;
|
||||
|
||||
if (pmd->held_root) {
|
||||
DMWARN("Pool metadata snapshot already exists: release this before taking another.");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* We commit to ensure the btree roots which we increment in a
|
||||
* moment are up to date.
|
||||
@@ -1353,22 +1362,16 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd)
|
||||
dm_sm_inc_block(pmd->metadata_sm, THIN_SUPERBLOCK_LOCATION);
|
||||
r = dm_tm_shadow_block(pmd->tm, THIN_SUPERBLOCK_LOCATION,
|
||||
&sb_validator, ©, &inc);
|
||||
if (r)
|
||||
if (r) {
|
||||
dm_sm_dec_block(pmd->metadata_sm, THIN_SUPERBLOCK_LOCATION);
|
||||
return r;
|
||||
}
|
||||
|
||||
BUG_ON(!inc);
|
||||
|
||||
held_root = dm_block_location(copy);
|
||||
disk_super = dm_block_data(copy);
|
||||
|
||||
if (le64_to_cpu(disk_super->held_root)) {
|
||||
DMWARN("Pool metadata snapshot already exists: release this before taking another.");
|
||||
|
||||
dm_tm_dec(pmd->tm, held_root);
|
||||
dm_tm_unlock(pmd->tm, copy);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wipe the spacemap since we're not publishing this.
|
||||
*/
|
||||
@@ -1384,18 +1387,8 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd)
|
||||
dm_tm_inc(pmd->tm, le64_to_cpu(disk_super->device_details_root));
|
||||
dm_tm_unlock(pmd->tm, copy);
|
||||
|
||||
/*
|
||||
* Write the held root into the superblock.
|
||||
*/
|
||||
r = superblock_lock(pmd, &sblock);
|
||||
if (r) {
|
||||
dm_tm_dec(pmd->tm, held_root);
|
||||
return r;
|
||||
}
|
||||
pmd->held_root = held_root;
|
||||
|
||||
disk_super = dm_block_data(sblock);
|
||||
disk_super->held_root = cpu_to_le64(held_root);
|
||||
dm_bm_unlock(sblock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1415,18 +1408,10 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd)
|
||||
{
|
||||
int r;
|
||||
struct thin_disk_superblock *disk_super;
|
||||
struct dm_block *sblock, *copy;
|
||||
struct dm_block *copy;
|
||||
dm_block_t held_root;
|
||||
|
||||
r = superblock_lock(pmd, &sblock);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
disk_super = dm_block_data(sblock);
|
||||
held_root = le64_to_cpu(disk_super->held_root);
|
||||
disk_super->held_root = cpu_to_le64(0);
|
||||
|
||||
dm_bm_unlock(sblock);
|
||||
held_root = pmd->held_root;
|
||||
|
||||
if (!held_root) {
|
||||
DMWARN("No pool metadata snapshot found: nothing to release.");
|
||||
@@ -1437,13 +1422,15 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
pmd->held_root = 0;
|
||||
|
||||
disk_super = dm_block_data(copy);
|
||||
dm_btree_del(&pmd->info, le64_to_cpu(disk_super->data_mapping_root));
|
||||
dm_btree_del(&pmd->details_info, le64_to_cpu(disk_super->device_details_root));
|
||||
dm_sm_dec_block(pmd->metadata_sm, held_root);
|
||||
|
||||
dm_tm_unlock(pmd->tm, copy);
|
||||
|
||||
dm_sm_dec_block(pmd->metadata_sm, held_root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1462,19 +1449,7 @@ int dm_pool_release_metadata_snap(struct dm_pool_metadata *pmd)
|
||||
static int __get_metadata_snap(struct dm_pool_metadata *pmd,
|
||||
dm_block_t *result)
|
||||
{
|
||||
int r;
|
||||
struct thin_disk_superblock *disk_super;
|
||||
struct dm_block *sblock;
|
||||
|
||||
r = dm_bm_read_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION,
|
||||
&sb_validator, &sblock);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
disk_super = dm_block_data(sblock);
|
||||
*result = le64_to_cpu(disk_super->held_root);
|
||||
|
||||
dm_bm_unlock(sblock);
|
||||
*result = pmd->held_root;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
|
||||
PTR_ERR(bbuf));
|
||||
|
||||
/* assume the block is corrupted */
|
||||
if (neras && *neras <= v->fec->roots)
|
||||
if (neras && *neras < v->fec->roots)
|
||||
fio->erasures[(*neras)++] = i;
|
||||
|
||||
continue;
|
||||
@@ -238,7 +238,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
|
||||
* skip if we have already found the theoretical
|
||||
* maximum number (i.e. fec->roots) of erasures
|
||||
*/
|
||||
if (neras && *neras <= v->fec->roots &&
|
||||
if (neras && *neras < v->fec->roots &&
|
||||
fec_is_erasure(v, io, want_digest, bbuf))
|
||||
fio->erasures[(*neras)++] = i;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ struct dm_verity_fec {
|
||||
/* per-bio data */
|
||||
struct dm_verity_fec_io {
|
||||
struct rs_control *rs; /* Reed-Solomon state */
|
||||
int erasures[DM_VERITY_FEC_MAX_ROOTS + 1]; /* erasures for decode_rs8 */
|
||||
int erasures[DM_VERITY_FEC_MAX_ROOTS]; /* erasures for decode_rs8 */
|
||||
u8 *output; /* buffer for corrected output */
|
||||
unsigned int level; /* recursion level */
|
||||
unsigned int nbufs; /* number of buffers allocated */
|
||||
|
||||
@@ -70,7 +70,7 @@ bool dm_verity_loadpin_is_bdev_trusted(struct block_device *bdev)
|
||||
|
||||
table = dm_get_live_table(md, &srcu_idx);
|
||||
|
||||
if (table->num_targets != 1)
|
||||
if (!table || table->num_targets != 1)
|
||||
goto out;
|
||||
|
||||
ti = dm_table_get_target(table, 0);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#define DM_MSG_PREFIX "verity"
|
||||
|
||||
#define DM_VERITY_ENV_LENGTH 42
|
||||
#define DM_VERITY_ENV_LENGTH 46
|
||||
#define DM_VERITY_ENV_VAR_NAME "DM_VERITY_ERR_BLOCK_NR"
|
||||
|
||||
#define DM_VERITY_DEFAULT_PREFETCH_SIZE 262144
|
||||
@@ -180,14 +180,16 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
|
||||
char *envp[] = { verity_env, NULL };
|
||||
const char *type_str = "";
|
||||
struct mapped_device *md = dm_table_get_md(v->ti->table);
|
||||
int ce;
|
||||
|
||||
/* Corruption should be visible in device status in all modes */
|
||||
v->hash_failed = true;
|
||||
|
||||
if (v->corrupted_errs >= DM_VERITY_MAX_CORRUPTED_ERRS)
|
||||
goto out;
|
||||
|
||||
v->corrupted_errs++;
|
||||
ce = atomic_read(&v->corrupted_errs);
|
||||
do {
|
||||
if (ce >= DM_VERITY_MAX_CORRUPTED_ERRS)
|
||||
goto out;
|
||||
} while (!atomic_try_cmpxchg(&v->corrupted_errs, &ce, ce + 1));
|
||||
|
||||
switch (type) {
|
||||
case DM_VERITY_BLOCK_TYPE_DATA:
|
||||
@@ -203,7 +205,7 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
|
||||
DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,
|
||||
type_str, block);
|
||||
|
||||
if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS) {
|
||||
if (ce + 1 == DM_VERITY_MAX_CORRUPTED_ERRS) {
|
||||
DMERR("%s: reached maximum errors", v->data_dev->name);
|
||||
dm_audit_log_target(DM_MSG_PREFIX, "max-corrupted-errors", v->ti, 0);
|
||||
}
|
||||
@@ -1262,6 +1264,8 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
|
||||
continue;
|
||||
|
||||
} else if (!strcasecmp(arg_name, DM_VERITY_OPT_TASKLET_VERIFY)) {
|
||||
if (v->use_bh_wq)
|
||||
continue;
|
||||
v->use_bh_wq = true;
|
||||
static_branch_inc(&use_bh_wq_enabled);
|
||||
continue;
|
||||
|
||||
@@ -68,7 +68,7 @@ struct dm_verity {
|
||||
unsigned int digest_size; /* digest size for the current hash algorithm */
|
||||
enum verity_mode mode; /* mode for handling verification errors */
|
||||
enum verity_mode error_mode;/* mode for handling I/O errors */
|
||||
unsigned int corrupted_errs;/* Number of errors for corrupted blocks */
|
||||
atomic_t corrupted_errs;/* Number of errors for corrupted blocks */
|
||||
|
||||
struct workqueue_struct *verify_wq;
|
||||
|
||||
|
||||
@@ -735,7 +735,16 @@ static struct table_device *open_table_device(struct mapped_device *md,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
refcount_set(&td->count, 1);
|
||||
|
||||
bdev_file = bdev_file_open_by_dev(dev, mode, _dm_claim_ptr, NULL);
|
||||
/*
|
||||
* Open the backing device with kernel rather than caller
|
||||
* credentials. Otherwise the caller's credentials would be
|
||||
* pinned in bdev_file->f_cred until the table device is closed.
|
||||
* That would keep the caller's thread keyring alive long beyond the
|
||||
* lifetime of the caller, breaking userspace expectation (e.g.
|
||||
* cryptsetup(8) leaking the LUKS volume key).
|
||||
*/
|
||||
scoped_with_kernel_creds()
|
||||
bdev_file = bdev_file_open_by_dev(dev, mode, _dm_claim_ptr, NULL);
|
||||
if (IS_ERR(bdev_file)) {
|
||||
r = PTR_ERR(bdev_file);
|
||||
goto out_free_td;
|
||||
|
||||
Reference in New Issue
Block a user