Commit fe75a218 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-5.11/dm-fixes-2' of...

Merge tag 'for-5.11/dm-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

Pull device mapper fixes from Mike Snitzer:

 - Fix DM integrity crash if "recalculate" used without "internal_hash"

 - Fix DM integrity "recalculate" support to prevent recalculating
   checksums if we use internal_hash or journal_hash with a key (e.g.
   HMAC). Use of crypto as a means to prevent malicious corruption
   requires further changes and was never a design goal for
   dm-integrity's primary usecase of detecting accidental corruption.

 - Fix a benign dm-crypt copy-and-paste bug introduced as part of a fix
   that was merged for 5.11-rc4.

 - Fix DM core's dm_get_device() to avoid filesystem lookup to get block
   device (if possible).

* tag 'for-5.11/dm-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
  dm: avoid filesystem lookup in dm_get_dev_t()
  dm crypt: fix copy and paste bug in crypt_alloc_req_aead
  dm integrity: conditionally disable "recalculate" feature
  dm integrity: fix a crash if "recalculate" used without "internal_hash"
parents faba877b 809b1e49
...@@ -177,14 +177,20 @@ bitmap_flush_interval:number ...@@ -177,14 +177,20 @@ bitmap_flush_interval:number
The bitmap flush interval in milliseconds. The metadata buffers The bitmap flush interval in milliseconds. The metadata buffers
are synchronized when this interval expires. are synchronized when this interval expires.
allow_discards
Allow block discard requests (a.k.a. TRIM) for the integrity device.
Discards are only allowed to devices using internal hash.
fix_padding fix_padding
Use a smaller padding of the tag area that is more Use a smaller padding of the tag area that is more
space-efficient. If this option is not present, large padding is space-efficient. If this option is not present, large padding is
used - that is for compatibility with older kernels. used - that is for compatibility with older kernels.
allow_discards legacy_recalculate
Allow block discard requests (a.k.a. TRIM) for the integrity device. Allow recalculating of volumes with HMAC keys. This is disabled by
Discards are only allowed to devices using internal hash. default for security reasons - an attacker could modify the volume,
set recalc_sector to zero, and the kernel would not detect the
modification.
The journal mode (D/J), buffer_sectors, journal_watermark, commit_time and The journal mode (D/J), buffer_sectors, journal_watermark, commit_time and
allow_discards can be changed when reloading the target (load an inactive allow_discards can be changed when reloading the target (load an inactive
......
...@@ -1481,9 +1481,9 @@ static int crypt_alloc_req_skcipher(struct crypt_config *cc, ...@@ -1481,9 +1481,9 @@ static int crypt_alloc_req_skcipher(struct crypt_config *cc,
static int crypt_alloc_req_aead(struct crypt_config *cc, static int crypt_alloc_req_aead(struct crypt_config *cc,
struct convert_context *ctx) struct convert_context *ctx)
{ {
if (!ctx->r.req) { if (!ctx->r.req_aead) {
ctx->r.req = mempool_alloc(&cc->req_pool, in_interrupt() ? GFP_ATOMIC : GFP_NOIO); ctx->r.req_aead = mempool_alloc(&cc->req_pool, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
if (!ctx->r.req) if (!ctx->r.req_aead)
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -257,8 +257,9 @@ struct dm_integrity_c { ...@@ -257,8 +257,9 @@ struct dm_integrity_c {
bool journal_uptodate; bool journal_uptodate;
bool just_formatted; bool just_formatted;
bool recalculate_flag; bool recalculate_flag;
bool fix_padding;
bool discard; bool discard;
bool fix_padding;
bool legacy_recalculate;
struct alg_spec internal_hash_alg; struct alg_spec internal_hash_alg;
struct alg_spec journal_crypt_alg; struct alg_spec journal_crypt_alg;
...@@ -386,6 +387,14 @@ static int dm_integrity_failed(struct dm_integrity_c *ic) ...@@ -386,6 +387,14 @@ static int dm_integrity_failed(struct dm_integrity_c *ic)
return READ_ONCE(ic->failed); return READ_ONCE(ic->failed);
} }
static bool dm_integrity_disable_recalculate(struct dm_integrity_c *ic)
{
if ((ic->internal_hash_alg.key || ic->journal_mac_alg.key) &&
!ic->legacy_recalculate)
return true;
return false;
}
static commit_id_t dm_integrity_commit_id(struct dm_integrity_c *ic, unsigned i, static commit_id_t dm_integrity_commit_id(struct dm_integrity_c *ic, unsigned i,
unsigned j, unsigned char seq) unsigned j, unsigned char seq)
{ {
...@@ -3140,6 +3149,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type, ...@@ -3140,6 +3149,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
arg_count += !!ic->journal_crypt_alg.alg_string; arg_count += !!ic->journal_crypt_alg.alg_string;
arg_count += !!ic->journal_mac_alg.alg_string; arg_count += !!ic->journal_mac_alg.alg_string;
arg_count += (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0; arg_count += (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0;
arg_count += ic->legacy_recalculate;
DMEMIT("%s %llu %u %c %u", ic->dev->name, ic->start, DMEMIT("%s %llu %u %c %u", ic->dev->name, ic->start,
ic->tag_size, ic->mode, arg_count); ic->tag_size, ic->mode, arg_count);
if (ic->meta_dev) if (ic->meta_dev)
...@@ -3163,6 +3173,8 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type, ...@@ -3163,6 +3173,8 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
} }
if ((ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0) if ((ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0)
DMEMIT(" fix_padding"); DMEMIT(" fix_padding");
if (ic->legacy_recalculate)
DMEMIT(" legacy_recalculate");
#define EMIT_ALG(a, n) \ #define EMIT_ALG(a, n) \
do { \ do { \
...@@ -3792,7 +3804,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -3792,7 +3804,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
unsigned extra_args; unsigned extra_args;
struct dm_arg_set as; struct dm_arg_set as;
static const struct dm_arg _args[] = { static const struct dm_arg _args[] = {
{0, 15, "Invalid number of feature args"}, {0, 16, "Invalid number of feature args"},
}; };
unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec; unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;
bool should_write_sb; bool should_write_sb;
...@@ -3940,6 +3952,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -3940,6 +3952,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
ic->discard = true; ic->discard = true;
} else if (!strcmp(opt_string, "fix_padding")) { } else if (!strcmp(opt_string, "fix_padding")) {
ic->fix_padding = true; ic->fix_padding = true;
} else if (!strcmp(opt_string, "legacy_recalculate")) {
ic->legacy_recalculate = true;
} else { } else {
r = -EINVAL; r = -EINVAL;
ti->error = "Invalid argument"; ti->error = "Invalid argument";
...@@ -4235,6 +4249,20 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -4235,6 +4249,20 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
r = -ENOMEM; r = -ENOMEM;
goto bad; goto bad;
} }
} else {
if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
ti->error = "Recalculate can only be specified with internal_hash";
r = -EINVAL;
goto bad;
}
}
if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) &&
le64_to_cpu(ic->sb->recalc_sector) < ic->provided_data_sectors &&
dm_integrity_disable_recalculate(ic)) {
ti->error = "Recalculating with HMAC is disabled for security reasons - if you really need it, use the argument \"legacy_recalculate\"";
r = -EOPNOTSUPP;
goto bad;
} }
ic->bufio = dm_bufio_client_create(ic->meta_dev ? ic->meta_dev->bdev : ic->dev->bdev, ic->bufio = dm_bufio_client_create(ic->meta_dev ? ic->meta_dev->bdev : ic->dev->bdev,
......
...@@ -363,14 +363,23 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode, ...@@ -363,14 +363,23 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
{ {
int r; int r;
dev_t dev; dev_t dev;
unsigned int major, minor;
char dummy;
struct dm_dev_internal *dd; struct dm_dev_internal *dd;
struct dm_table *t = ti->table; struct dm_table *t = ti->table;
BUG_ON(!t); BUG_ON(!t);
if (sscanf(path, "%u:%u%c", &major, &minor, &dummy) == 2) {
/* Extract the major/minor numbers */
dev = MKDEV(major, minor);
if (MAJOR(dev) != major || MINOR(dev) != minor)
return -EOVERFLOW;
} else {
dev = dm_get_dev_t(path); dev = dm_get_dev_t(path);
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
}
dd = find_device(&t->devices, dev); dd = find_device(&t->devices, dev);
if (!dd) { if (!dd) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment