Commit 438b2cdd authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt

Pull fscrypt updates from Eric Biggers:
 "This release contains some implementation changes, but no new
  features:

   - Rework the implementation of the fscrypt filesystem-level keyring
     to not be as tightly coupled to the keyrings subsystem. This
     resolves several issues.

   - Eliminate most direct uses of struct request_queue from fs/crypto/,
     since struct request_queue is considered to be a block layer
     implementation detail.

   - Stop using the PG_error flag to track decryption failures. This is
     a prerequisite for freeing up PG_error for other uses"

* tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt:
  fscrypt: work on block_devices instead of request_queues
  fscrypt: stop holding extra request_queue references
  fscrypt: stop using keyrings subsystem for fscrypt_master_key
  fscrypt: stop using PG_error to track error status
  fscrypt: remove fscrypt_set_test_dummy_encryption()
parents f4309528 0e91fc1e
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -25,21 +25,25 @@
 * then this function isn't applicable.  This function may sleep, so it must be
 * called from a workqueue rather than from the bio's bi_end_io callback.
 *
 * This function sets PG_error on any pages that contain any blocks that failed
 * to be decrypted.  The filesystem must not mark such pages uptodate.
 * Return: %true on success; %false on failure.  On failure, bio->bi_status is
 *	   also set to an error status.
 */
void fscrypt_decrypt_bio(struct bio *bio)
bool fscrypt_decrypt_bio(struct bio *bio)
{
	struct bio_vec *bv;
	struct bvec_iter_all iter_all;

	bio_for_each_segment_all(bv, bio, iter_all) {
		struct page *page = bv->bv_page;
		int ret = fscrypt_decrypt_pagecache_blocks(page, bv->bv_len,
		int err = fscrypt_decrypt_pagecache_blocks(page, bv->bv_len,
							   bv->bv_offset);
		if (ret)
			SetPageError(page);

		if (err) {
			bio->bi_status = errno_to_blk_status(err);
			return false;
		}
	}
	return true;
}
EXPORT_SYMBOL(fscrypt_decrypt_bio);

+58 −24
Original line number Diff line number Diff line
@@ -184,7 +184,7 @@ struct fscrypt_symlink_data {
struct fscrypt_prepared_key {
	struct crypto_skcipher *tfm;
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
	struct fscrypt_blk_crypto_key *blk_key;
	struct blk_crypto_key *blk_key;
#endif
};

@@ -225,7 +225,7 @@ struct fscrypt_info {
	 * will be NULL if the master key was found in a process-subscribed
	 * keyring rather than in the filesystem-level keyring.
	 */
	struct key *ci_master_key;
	struct fscrypt_master_key *ci_master_key;

	/*
	 * Link in list of inodes that were unlocked with the master key.
@@ -344,7 +344,8 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
				     const u8 *raw_key,
				     const struct fscrypt_info *ci);

void fscrypt_destroy_inline_crypt_key(struct fscrypt_prepared_key *prep_key);
void fscrypt_destroy_inline_crypt_key(struct super_block *sb,
				      struct fscrypt_prepared_key *prep_key);

/*
 * Check whether the crypto transform or blk-crypto key has been allocated in
@@ -390,7 +391,8 @@ fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
}

static inline void
fscrypt_destroy_inline_crypt_key(struct fscrypt_prepared_key *prep_key)
fscrypt_destroy_inline_crypt_key(struct super_block *sb,
				 struct fscrypt_prepared_key *prep_key)
{
}

@@ -436,6 +438,40 @@ struct fscrypt_master_key_secret {
 */
struct fscrypt_master_key {

	/*
	 * Back-pointer to the super_block of the filesystem to which this
	 * master key has been added.  Only valid if ->mk_active_refs > 0.
	 */
	struct super_block			*mk_sb;

	/*
	 * Link in ->mk_sb->s_master_keys->key_hashtable.
	 * Only valid if ->mk_active_refs > 0.
	 */
	struct hlist_node			mk_node;

	/* Semaphore that protects ->mk_secret and ->mk_users */
	struct rw_semaphore			mk_sem;

	/*
	 * Active and structural reference counts.  An active ref guarantees
	 * that the struct continues to exist, continues to be in the keyring
	 * ->mk_sb->s_master_keys, and that any embedded subkeys (e.g.
	 * ->mk_direct_keys) that have been prepared continue to exist.
	 * A structural ref only guarantees that the struct continues to exist.
	 *
	 * There is one active ref associated with ->mk_secret being present,
	 * and one active ref for each inode in ->mk_decrypted_inodes.
	 *
	 * There is one structural ref associated with the active refcount being
	 * nonzero.  Finding a key in the keyring also takes a structural ref,
	 * which is then held temporarily while the key is operated on.
	 */
	refcount_t				mk_active_refs;
	refcount_t				mk_struct_refs;

	struct rcu_head				mk_rcu_head;

	/*
	 * The secret key material.  After FS_IOC_REMOVE_ENCRYPTION_KEY is
	 * executed, this is wiped and no new inodes can be unlocked with this
@@ -444,7 +480,10 @@ struct fscrypt_master_key {
	 * FS_IOC_REMOVE_ENCRYPTION_KEY can be retried, or
	 * FS_IOC_ADD_ENCRYPTION_KEY can add the secret again.
	 *
	 * Locking: protected by this master key's key->sem.
	 * While ->mk_secret is present, one ref in ->mk_active_refs is held.
	 *
	 * Locking: protected by ->mk_sem.  The manipulation of ->mk_active_refs
	 *	    associated with this field is protected by ->mk_sem as well.
	 */
	struct fscrypt_master_key_secret	mk_secret;

@@ -465,22 +504,12 @@ struct fscrypt_master_key {
	 *
	 * This is NULL for v1 policy keys; those can only be added by root.
	 *
	 * Locking: in addition to this keyring's own semaphore, this is
	 * protected by this master key's key->sem, so we can do atomic
	 * search+insert.  It can also be searched without taking any locks, but
	 * in that case the returned key may have already been removed.
	 * Locking: protected by ->mk_sem.  (We don't just rely on the keyrings
	 * subsystem semaphore ->mk_users->sem, as we need support for atomic
	 * search+insert along with proper synchronization with ->mk_secret.)
	 */
	struct key		*mk_users;

	/*
	 * Length of ->mk_decrypted_inodes, plus one if mk_secret is present.
	 * Once this goes to 0, the master key is removed from ->s_master_keys.
	 * The 'struct fscrypt_master_key' will continue to live as long as the
	 * 'struct key' whose payload it is, but we won't let this reference
	 * count rise again.
	 */
	refcount_t		mk_refcount;

	/*
	 * List of inodes that were unlocked using this key.  This allows the
	 * inodes to be evicted efficiently if the key is removed.
@@ -506,10 +535,10 @@ static inline bool
is_master_key_secret_present(const struct fscrypt_master_key_secret *secret)
{
	/*
	 * The READ_ONCE() is only necessary for fscrypt_drop_inode() and
	 * fscrypt_key_describe().  These run in atomic context, so they can't
	 * take the key semaphore and thus 'secret' can change concurrently
	 * which would be a data race.  But they only need to know whether the
	 * The READ_ONCE() is only necessary for fscrypt_drop_inode().
	 * fscrypt_drop_inode() runs in atomic context, so it can't take the key
	 * semaphore and thus 'secret' can change concurrently which would be a
	 * data race.  But fscrypt_drop_inode() only need to know whether the
	 * secret *was* present at the time of check, so READ_ONCE() suffices.
	 */
	return READ_ONCE(secret->size) != 0;
@@ -538,7 +567,11 @@ static inline int master_key_spec_len(const struct fscrypt_key_specifier *spec)
	return 0;
}

struct key *
void fscrypt_put_master_key(struct fscrypt_master_key *mk);

void fscrypt_put_master_key_activeref(struct fscrypt_master_key *mk);

struct fscrypt_master_key *
fscrypt_find_master_key(struct super_block *sb,
			const struct fscrypt_key_specifier *mk_spec);

@@ -569,7 +602,8 @@ extern struct fscrypt_mode fscrypt_modes[];
int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
			const u8 *raw_key, const struct fscrypt_info *ci);

void fscrypt_destroy_prepared_key(struct fscrypt_prepared_key *prep_key);
void fscrypt_destroy_prepared_key(struct super_block *sb,
				  struct fscrypt_prepared_key *prep_key);

int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key);

+3 −7
Original line number Diff line number Diff line
@@ -5,8 +5,6 @@
 * Encryption hooks for higher-level filesystem operations.
 */

#include <linux/key.h>

#include "fscrypt_private.h"

/**
@@ -142,7 +140,6 @@ int fscrypt_prepare_setflags(struct inode *inode,
			     unsigned int oldflags, unsigned int flags)
{
	struct fscrypt_info *ci;
	struct key *key;
	struct fscrypt_master_key *mk;
	int err;

@@ -158,14 +155,13 @@ int fscrypt_prepare_setflags(struct inode *inode,
		ci = inode->i_crypt_info;
		if (ci->ci_policy.version != FSCRYPT_POLICY_V2)
			return -EINVAL;
		key = ci->ci_master_key;
		mk = key->payload.data[0];
		down_read(&key->sem);
		mk = ci->ci_master_key;
		down_read(&mk->mk_sem);
		if (is_master_key_secret_present(&mk->mk_secret))
			err = fscrypt_derive_dirhash_key(ci, mk);
		else
			err = -ENOKEY;
		up_read(&key->sem);
		up_read(&mk->mk_sem);
		return err;
	}
	return 0;
+71 −76
Original line number Diff line number Diff line
@@ -21,26 +21,22 @@

#include "fscrypt_private.h"

struct fscrypt_blk_crypto_key {
	struct blk_crypto_key base;
	int num_devs;
	struct request_queue *devs[];
};

static int fscrypt_get_num_devices(struct super_block *sb)
static struct block_device **fscrypt_get_devices(struct super_block *sb,
						 unsigned int *num_devs)
{
	if (sb->s_cop->get_num_devices)
		return sb->s_cop->get_num_devices(sb);
	return 1;
}
	struct block_device **devs;

static void fscrypt_get_devices(struct super_block *sb, int num_devs,
				struct request_queue **devs)
{
	if (num_devs == 1)
		devs[0] = bdev_get_queue(sb->s_bdev);
	else
		sb->s_cop->get_devices(sb, devs);
	if (sb->s_cop->get_devices) {
		devs = sb->s_cop->get_devices(sb, num_devs);
		if (devs)
			return devs;
	}
	devs = kmalloc(sizeof(*devs), GFP_KERNEL);
	if (!devs)
		return ERR_PTR(-ENOMEM);
	devs[0] = sb->s_bdev;
	*num_devs = 1;
	return devs;
}

static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_info *ci)
@@ -74,15 +70,17 @@ static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_info *ci)
 * helpful for debugging problems where the "wrong" implementation is used.
 */
static void fscrypt_log_blk_crypto_impl(struct fscrypt_mode *mode,
					struct request_queue **devs,
					int num_devs,
					struct block_device **devs,
					unsigned int num_devs,
					const struct blk_crypto_config *cfg)
{
	int i;
	unsigned int i;

	for (i = 0; i < num_devs; i++) {
		struct request_queue *q = bdev_get_queue(devs[i]);

		if (!IS_ENABLED(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) ||
		    __blk_crypto_cfg_supported(devs[i]->crypto_profile, cfg)) {
		    __blk_crypto_cfg_supported(q->crypto_profile, cfg)) {
			if (!xchg(&mode->logged_blk_crypto_native, 1))
				pr_info("fscrypt: %s using blk-crypto (native)\n",
					mode->friendly_name);
@@ -99,9 +97,9 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci)
	const struct inode *inode = ci->ci_inode;
	struct super_block *sb = inode->i_sb;
	struct blk_crypto_config crypto_cfg;
	int num_devs;
	struct request_queue **devs;
	int i;
	struct block_device **devs;
	unsigned int num_devs;
	unsigned int i;

	/* The file must need contents encryption, not filenames encryption */
	if (!S_ISREG(inode->i_mode))
@@ -129,20 +127,20 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci)
		return 0;

	/*
	 * On all the filesystem's devices, blk-crypto must support the crypto
	 * configuration that the file would use.
	 * On all the filesystem's block devices, blk-crypto must support the
	 * crypto configuration that the file would use.
	 */
	crypto_cfg.crypto_mode = ci->ci_mode->blk_crypto_mode;
	crypto_cfg.data_unit_size = sb->s_blocksize;
	crypto_cfg.dun_bytes = fscrypt_get_dun_bytes(ci);
	num_devs = fscrypt_get_num_devices(sb);
	devs = kmalloc_array(num_devs, sizeof(*devs), GFP_KERNEL);
	if (!devs)
		return -ENOMEM;
	fscrypt_get_devices(sb, num_devs, devs);

	devs = fscrypt_get_devices(sb, &num_devs);
	if (IS_ERR(devs))
		return PTR_ERR(devs);

	for (i = 0; i < num_devs; i++) {
		if (!blk_crypto_config_supported(devs[i], &crypto_cfg))
		if (!blk_crypto_config_supported(bdev_get_queue(devs[i]),
						 &crypto_cfg))
			goto out_free_devs;
	}

@@ -162,49 +160,41 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
	const struct inode *inode = ci->ci_inode;
	struct super_block *sb = inode->i_sb;
	enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode;
	int num_devs = fscrypt_get_num_devices(sb);
	int queue_refs = 0;
	struct fscrypt_blk_crypto_key *blk_key;
	struct blk_crypto_key *blk_key;
	struct block_device **devs;
	unsigned int num_devs;
	unsigned int i;
	int err;
	int i;

	blk_key = kzalloc(struct_size(blk_key, devs, num_devs), GFP_KERNEL);
	blk_key = kmalloc(sizeof(*blk_key), GFP_KERNEL);
	if (!blk_key)
		return -ENOMEM;

	blk_key->num_devs = num_devs;
	fscrypt_get_devices(sb, num_devs, blk_key->devs);

	err = blk_crypto_init_key(&blk_key->base, raw_key, crypto_mode,
	err = blk_crypto_init_key(blk_key, raw_key, crypto_mode,
				  fscrypt_get_dun_bytes(ci), sb->s_blocksize);
	if (err) {
		fscrypt_err(inode, "error %d initializing blk-crypto key", err);
		goto fail;
	}

	/*
	 * We have to start using blk-crypto on all the filesystem's devices.
	 * We also have to save all the request_queue's for later so that the
	 * key can be evicted from them.  This is needed because some keys
	 * aren't destroyed until after the filesystem was already unmounted
	 * (namely, the per-mode keys in struct fscrypt_master_key).
	 */
	for (i = 0; i < num_devs; i++) {
		if (!blk_get_queue(blk_key->devs[i])) {
			fscrypt_err(inode, "couldn't get request_queue");
			err = -EAGAIN;
	/* Start using blk-crypto on all the filesystem's block devices. */
	devs = fscrypt_get_devices(sb, &num_devs);
	if (IS_ERR(devs)) {
		err = PTR_ERR(devs);
		goto fail;
	}
		queue_refs++;

		err = blk_crypto_start_using_key(&blk_key->base,
						 blk_key->devs[i]);
	for (i = 0; i < num_devs; i++) {
		err = blk_crypto_start_using_key(blk_key,
						 bdev_get_queue(devs[i]));
		if (err)
			break;
	}
	kfree(devs);
	if (err) {
			fscrypt_err(inode,
				    "error %d starting to use blk-crypto", err);
		fscrypt_err(inode, "error %d starting to use blk-crypto", err);
		goto fail;
	}
	}

	/*
	 * Pairs with the smp_load_acquire() in fscrypt_is_key_prepared().
	 * I.e., here we publish ->blk_key with a RELEASE barrier so that
@@ -215,25 +205,30 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
	return 0;

fail:
	for (i = 0; i < queue_refs; i++)
		blk_put_queue(blk_key->devs[i]);
	kfree_sensitive(blk_key);
	return err;
}

void fscrypt_destroy_inline_crypt_key(struct fscrypt_prepared_key *prep_key)
void fscrypt_destroy_inline_crypt_key(struct super_block *sb,
				      struct fscrypt_prepared_key *prep_key)
{
	struct fscrypt_blk_crypto_key *blk_key = prep_key->blk_key;
	int i;
	struct blk_crypto_key *blk_key = prep_key->blk_key;
	struct block_device **devs;
	unsigned int num_devs;
	unsigned int i;

	if (blk_key) {
		for (i = 0; i < blk_key->num_devs; i++) {
			blk_crypto_evict_key(blk_key->devs[i], &blk_key->base);
			blk_put_queue(blk_key->devs[i]);
	if (!blk_key)
		return;

	/* Evict the key from all the filesystem's block devices. */
	devs = fscrypt_get_devices(sb, &num_devs);
	if (!IS_ERR(devs)) {
		for (i = 0; i < num_devs; i++)
			blk_crypto_evict_key(bdev_get_queue(devs[i]), blk_key);
		kfree(devs);
	}
	kfree_sensitive(blk_key);
}
}

bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode)
{
@@ -282,7 +277,7 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode,
	ci = inode->i_crypt_info;

	fscrypt_generate_dun(ci, first_lblk, dun);
	bio_crypt_set_ctx(bio, &ci->ci_enc_key.blk_key->base, dun, gfp_mask);
	bio_crypt_set_ctx(bio, ci->ci_enc_key.blk_key, dun, gfp_mask);
}
EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx);

@@ -369,7 +364,7 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
	 * uses the same pointer.  I.e., there's currently no need to support
	 * merging requests where the keys are the same but the pointers differ.
	 */
	if (bc->bc_key != &inode->i_crypt_info->ci_enc_key.blk_key->base)
	if (bc->bc_key != inode->i_crypt_info->ci_enc_key.blk_key)
		return false;

	fscrypt_generate_dun(inode->i_crypt_info, next_lblk, next_dun);
+267 −228

File changed.

Preview size limit exceeded, changes collapsed.

Loading