Commit fe75a218 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -177,14 +177,20 @@ bitmap_flush_interval:number
	The bitmap flush interval in milliseconds. The metadata buffers
	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
	Use a smaller padding of the tag area that is more
	space-efficient. If this option is not present, large padding is
	used - that is for compatibility with older kernels.

allow_discards
	Allow block discard requests (a.k.a. TRIM) for the integrity device.
	Discards are only allowed to devices using internal hash.
legacy_recalculate
	Allow recalculating of volumes with HMAC keys. This is disabled by
	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
allow_discards can be changed when reloading the target (load an inactive
+3 −3
Original line number Diff line number Diff line
@@ -1481,9 +1481,9 @@ static int crypt_alloc_req_skcipher(struct crypt_config *cc,
static int crypt_alloc_req_aead(struct crypt_config *cc,
				 struct convert_context *ctx)
{
	if (!ctx->r.req) {
		ctx->r.req = mempool_alloc(&cc->req_pool, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
		if (!ctx->r.req)
	if (!ctx->r.req_aead) {
		ctx->r.req_aead = mempool_alloc(&cc->req_pool, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
		if (!ctx->r.req_aead)
			return -ENOMEM;
	}

+30 −2
Original line number Diff line number Diff line
@@ -257,8 +257,9 @@ struct dm_integrity_c {
	bool journal_uptodate;
	bool just_formatted;
	bool recalculate_flag;
	bool fix_padding;
	bool discard;
	bool fix_padding;
	bool legacy_recalculate;

	struct alg_spec internal_hash_alg;
	struct alg_spec journal_crypt_alg;
@@ -386,6 +387,14 @@ static int dm_integrity_failed(struct dm_integrity_c *ic)
	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,
					  unsigned j, unsigned char seq)
{
@@ -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_mac_alg.alg_string;
		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,
		       ic->tag_size, ic->mode, arg_count);
		if (ic->meta_dev)
@@ -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)
			DMEMIT(" fix_padding");
		if (ic->legacy_recalculate)
			DMEMIT(" legacy_recalculate");

#define EMIT_ALG(a, n)							\
		do {							\
@@ -3792,7 +3804,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
	unsigned extra_args;
	struct dm_arg_set as;
	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;
	bool should_write_sb;
@@ -3940,6 +3952,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
			ic->discard = true;
		} else if (!strcmp(opt_string, "fix_padding")) {
			ic->fix_padding = true;
		} else if (!strcmp(opt_string, "legacy_recalculate")) {
			ic->legacy_recalculate = true;
		} else {
			r = -EINVAL;
			ti->error = "Invalid argument";
@@ -4235,6 +4249,20 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
			r = -ENOMEM;
			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,
+12 −3
Original line number Diff line number Diff line
@@ -363,14 +363,23 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
{
	int r;
	dev_t dev;
	unsigned int major, minor;
	char dummy;
	struct dm_dev_internal *dd;
	struct dm_table *t = ti->table;

	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);
		if (!dev)
			return -ENODEV;
	}

	dd = find_device(&t->devices, dev);
	if (!dd) {