Commit 325b7640 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-5.12/dm-changes' of...

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

Pull device mapper updates from Mike Snitzer:

 - Fix DM integrity's HMAC support to provide enhanced security of
   internal_hash and journal_mac capabilities.

 - Various DM writecache fixes to address performance, fix table output
   to match what was provided at table creation, fix writing beyond end
   of device when shrinking underlying data device, and a couple other
   small cleanups.

 - Add DM crypt support for using trusted keys.

 - Fix deadlock when swapping to DM crypt device by throttling number of
   in-flight REQ_SWAP bios. Implemented in DM core so that other
   bio-based targets can opt-in by setting ti->limit_swap_bios.

 - Fix various inverted logic bugs in the .iterate_devices callout
   functions that are used to assess if specific feature or capability
   is supported across all devices being combined/stacked by DM.

 - Fix DM era target bugs that exposed users to lost writes or memory
   leaks.

 - Add DM core support for passing through inline crypto support of
   underlying devices. Includes block/keyslot-manager changes that
   enable extending this support to DM.

 - Various small fixes and cleanups (spelling fixes, front padding
   calculation cleanup, cleanup conditional zoned support in targets,
   etc).

* tag 'for-5.12/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: (31 commits)
  dm: fix deadlock when swapping to encrypted device
  dm: simplify target code conditional on CONFIG_BLK_DEV_ZONED
  dm: set DM_TARGET_PASSES_CRYPTO feature for some targets
  dm: support key eviction from keyslot managers of underlying devices
  dm: add support for passing through inline crypto support
  block/keyslot-manager: Introduce functions for device mapper support
  block/keyslot-manager: Introduce passthrough keyslot manager
  dm era: only resize metadata in preresume
  dm era: Use correct value size in equality function of writeset tree
  dm era: Fix bitset memory leaks
  dm era: Verify the data block size hasn't changed
  dm era: Reinitialize bitset cache before digesting a new writeset
  dm era: Update in-core bitset after committing the metadata
  dm era: Recover committed writeset after crash
  dm writecache: use bdev_nr_sectors() instead of open-coded equivalent
  dm writecache: fix writing beyond end of underlying device when shrinking
  dm table: remove needless request_queue NULL pointer checks
  dm table: fix zoned iterate_devices based device capability checks
  dm table: fix DAX iterate_devices based device capability checks
  dm table: fix iterate_devices based device capability checks
  ...
parents a99163e9 a666e5c0
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ Parameters::
    the value passed in <key_size>.

<key_type>
    Either 'logon', 'user' or 'encrypted' kernel key type.
    Either 'logon', 'user', 'encrypted' or 'trusted' kernel key type.

<key_description>
    The kernel keyring key description crypt target should look for
+11 −0
Original line number Diff line number Diff line
@@ -186,6 +186,17 @@ fix_padding
	space-efficient. If this option is not present, large padding is
	used - that is for compatibility with older kernels.

fix_hmac
	Improve security of internal_hash and journal_mac:

	- the section number is mixed to the mac, so that an attacker can't
	  copy sectors from one journal section to another journal section
	- the superblock is protected by journal_mac
	- a 16-byte salt stored in the superblock is mixed to the mac, so
	  that the attacker can't detect that two disks have the same hmac
	  key and also to disallow the attacker to move sectors from one
	  disk to another

legacy_recalculate
	Allow recalculating of volumes with HMAC keys. This is disabled by
	default for security reasons - an attacker could modify the volume,
+1 −0
Original line number Diff line number Diff line
@@ -409,3 +409,4 @@ int blk_crypto_evict_key(struct request_queue *q,
	 */
	return blk_crypto_fallback_evict_key(key);
}
EXPORT_SYMBOL_GPL(blk_crypto_evict_key);
+146 −0
Original line number Diff line number Diff line
@@ -63,6 +63,11 @@ static inline void blk_ksm_hw_exit(struct blk_keyslot_manager *ksm)
		pm_runtime_put_sync(ksm->dev);
}

static inline bool blk_ksm_is_passthrough(struct blk_keyslot_manager *ksm)
{
	return ksm->num_slots == 0;
}

/**
 * blk_ksm_init() - Initialize a keyslot manager
 * @ksm: The keyslot_manager to initialize.
@@ -234,6 +239,10 @@ blk_status_t blk_ksm_get_slot_for_key(struct blk_keyslot_manager *ksm,
	int err;

	*slot_ptr = NULL;

	if (blk_ksm_is_passthrough(ksm))
		return BLK_STS_OK;

	down_read(&ksm->lock);
	slot = blk_ksm_find_and_grab_keyslot(ksm, key);
	up_read(&ksm->lock);
@@ -354,6 +363,16 @@ int blk_ksm_evict_key(struct blk_keyslot_manager *ksm,
	struct blk_ksm_keyslot *slot;
	int err = 0;

	if (blk_ksm_is_passthrough(ksm)) {
		if (ksm->ksm_ll_ops.keyslot_evict) {
			blk_ksm_hw_enter(ksm);
			err = ksm->ksm_ll_ops.keyslot_evict(ksm, key, -1);
			blk_ksm_hw_exit(ksm);
			return err;
		}
		return 0;
	}

	blk_ksm_hw_enter(ksm);
	slot = blk_ksm_find_keyslot(ksm, key);
	if (!slot)
@@ -389,6 +408,9 @@ void blk_ksm_reprogram_all_keys(struct blk_keyslot_manager *ksm)
{
	unsigned int slot;

	if (blk_ksm_is_passthrough(ksm))
		return;

	/* This is for device initialization, so don't resume the device */
	down_write(&ksm->lock);
	for (slot = 0; slot < ksm->num_slots; slot++) {
@@ -430,3 +452,127 @@ void blk_ksm_unregister(struct request_queue *q)
{
	q->ksm = NULL;
}

/**
 * blk_ksm_intersect_modes() - restrict supported modes by child device
 * @parent: The keyslot manager for parent device
 * @child: The keyslot manager for child device, or NULL
 *
 * Clear any crypto mode support bits in @parent that aren't set in @child.
 * If @child is NULL, then all parent bits are cleared.
 *
 * Only use this when setting up the keyslot manager for a layered device,
 * before it's been exposed yet.
 */
void blk_ksm_intersect_modes(struct blk_keyslot_manager *parent,
			     const struct blk_keyslot_manager *child)
{
	if (child) {
		unsigned int i;

		parent->max_dun_bytes_supported =
			min(parent->max_dun_bytes_supported,
			    child->max_dun_bytes_supported);
		for (i = 0; i < ARRAY_SIZE(child->crypto_modes_supported);
		     i++) {
			parent->crypto_modes_supported[i] &=
				child->crypto_modes_supported[i];
		}
	} else {
		parent->max_dun_bytes_supported = 0;
		memset(parent->crypto_modes_supported, 0,
		       sizeof(parent->crypto_modes_supported));
	}
}
EXPORT_SYMBOL_GPL(blk_ksm_intersect_modes);

/**
 * blk_ksm_is_superset() - Check if a KSM supports a superset of crypto modes
 *			   and DUN bytes that another KSM supports. Here,
 *			   "superset" refers to the mathematical meaning of the
 *			   word - i.e. if two KSMs have the *same* capabilities,
 *			   they *are* considered supersets of each other.
 * @ksm_superset: The KSM that we want to verify is a superset
 * @ksm_subset: The KSM that we want to verify is a subset
 *
 * Return: True if @ksm_superset supports a superset of the crypto modes and DUN
 *	   bytes that @ksm_subset supports.
 */
bool blk_ksm_is_superset(struct blk_keyslot_manager *ksm_superset,
			 struct blk_keyslot_manager *ksm_subset)
{
	int i;

	if (!ksm_subset)
		return true;

	if (!ksm_superset)
		return false;

	for (i = 0; i < ARRAY_SIZE(ksm_superset->crypto_modes_supported); i++) {
		if (ksm_subset->crypto_modes_supported[i] &
		    (~ksm_superset->crypto_modes_supported[i])) {
			return false;
		}
	}

	if (ksm_subset->max_dun_bytes_supported >
	    ksm_superset->max_dun_bytes_supported) {
		return false;
	}

	return true;
}
EXPORT_SYMBOL_GPL(blk_ksm_is_superset);

/**
 * blk_ksm_update_capabilities() - Update the restrictions of a KSM to those of
 *				   another KSM
 * @target_ksm: The KSM whose restrictions to update.
 * @reference_ksm: The KSM to whose restrictions this function will update
 *		   @target_ksm's restrictions to.
 *
 * Blk-crypto requires that crypto capabilities that were
 * advertised when a bio was created continue to be supported by the
 * device until that bio is ended. This is turn means that a device cannot
 * shrink its advertised crypto capabilities without any explicit
 * synchronization with upper layers. So if there's no such explicit
 * synchronization, @reference_ksm must support all the crypto capabilities that
 * @target_ksm does
 * (i.e. we need blk_ksm_is_superset(@reference_ksm, @target_ksm) == true).
 *
 * Note also that as long as the crypto capabilities are being expanded, the
 * order of updates becoming visible is not important because it's alright
 * for blk-crypto to see stale values - they only cause blk-crypto to
 * believe that a crypto capability isn't supported when it actually is (which
 * might result in blk-crypto-fallback being used if available, or the bio being
 * failed).
 */
void blk_ksm_update_capabilities(struct blk_keyslot_manager *target_ksm,
				 struct blk_keyslot_manager *reference_ksm)
{
	memcpy(target_ksm->crypto_modes_supported,
	       reference_ksm->crypto_modes_supported,
	       sizeof(target_ksm->crypto_modes_supported));

	target_ksm->max_dun_bytes_supported =
				reference_ksm->max_dun_bytes_supported;
}
EXPORT_SYMBOL_GPL(blk_ksm_update_capabilities);

/**
 * blk_ksm_init_passthrough() - Init a passthrough keyslot manager
 * @ksm: The keyslot manager to init
 *
 * Initialize a passthrough keyslot manager.
 * Called by e.g. storage drivers to set up a keyslot manager in their
 * request_queue, when the storage driver wants to manage its keys by itself.
 * This is useful for inline encryption hardware that doesn't have the concept
 * of keyslots, and for layered devices.
 */
void blk_ksm_init_passthrough(struct blk_keyslot_manager *ksm)
{
	memset(ksm, 0, sizeof(*ksm));
	init_rwsem(&ksm->lock);
}
EXPORT_SYMBOL_GPL(blk_ksm_init_passthrough);
+1 −0
Original line number Diff line number Diff line
@@ -270,6 +270,7 @@ config DM_CRYPT
	tristate "Crypt target support"
	depends on BLK_DEV_DM
	depends on (ENCRYPTED_KEYS || ENCRYPTED_KEYS=n)
	depends on (TRUSTED_KEYS || TRUSTED_KEYS=n)
	select CRYPTO
	select CRYPTO_CBC
	select CRYPTO_ESSIV
Loading