Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a9fbcd67 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 Ted Ts'o:
 "Clean up fscrypt's dcache revalidation support, and other
  miscellaneous cleanups"

* tag 'fscrypt_for_linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt:
  fscrypt: cache decrypted symlink target in ->i_link
  vfs: use READ_ONCE() to access ->i_link
  fscrypt: fix race where ->lookup() marks plaintext dentry as ciphertext
  fscrypt: only set dentry_operations on ciphertext dentries
  fs, fscrypt: clear DCACHE_ENCRYPTED_NAME when unaliasing directory
  fscrypt: fix race allowing rename() and link() of ciphertext dentries
  fscrypt: clean up and improve dentry revalidation
  fscrypt: use READ_ONCE() to access ->i_crypt_info
  fscrypt: remove WARN_ON_ONCE() when decryption fails
  fscrypt: drop inode argument from fscrypt_get_ctx()
parents 5abe3795 2c58d548
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -36,12 +36,10 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
		int ret = fscrypt_decrypt_page(page->mapping->host, page,
				PAGE_SIZE, 0, page->index);

		if (ret) {
			WARN_ON_ONCE(1);
		if (ret)
			SetPageError(page);
		} else if (done) {
		else if (done)
			SetPageUptodate(page);
		}
		if (done)
			unlock_page(page);
	}
@@ -103,7 +101,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,

	BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE);

	ctx = fscrypt_get_ctx(inode, GFP_NOFS);
	ctx = fscrypt_get_ctx(GFP_NOFS);
	if (IS_ERR(ctx))
		return PTR_ERR(ctx);

+35 −39
Original line number Diff line number Diff line
@@ -87,23 +87,17 @@ EXPORT_SYMBOL(fscrypt_release_ctx);

/**
 * fscrypt_get_ctx() - Gets an encryption context
 * @inode:       The inode for which we are doing the crypto
 * @gfp_flags:   The gfp flag for memory allocation
 *
 * Allocates and initializes an encryption context.
 *
 * Return: An allocated and initialized encryption context on success; error
 * value or NULL otherwise.
 * Return: A new encryption context on success; an ERR_PTR() otherwise.
 */
struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags)
struct fscrypt_ctx *fscrypt_get_ctx(gfp_t gfp_flags)
{
	struct fscrypt_ctx *ctx = NULL;
	struct fscrypt_info *ci = inode->i_crypt_info;
	struct fscrypt_ctx *ctx;
	unsigned long flags;

	if (ci == NULL)
		return ERR_PTR(-ENOKEY);

	/*
	 * We first try getting the ctx from a free list because in
	 * the common case the ctx will have an allocated and
@@ -258,9 +252,9 @@ struct page *fscrypt_encrypt_page(const struct inode *inode,

	BUG_ON(!PageLocked(page));

	ctx = fscrypt_get_ctx(inode, gfp_flags);
	ctx = fscrypt_get_ctx(gfp_flags);
	if (IS_ERR(ctx))
		return (struct page *)ctx;
		return ERR_CAST(ctx);

	/* The encryption operation will require a bounce page. */
	ciphertext_page = fscrypt_alloc_bounce_page(ctx, gfp_flags);
@@ -313,45 +307,47 @@ int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
EXPORT_SYMBOL(fscrypt_decrypt_page);

/*
 * Validate dentries for encrypted directories to make sure we aren't
 * potentially caching stale data after a key has been added or
 * removed.
 * Validate dentries in encrypted directories to make sure we aren't potentially
 * caching stale dentries after a key has been added.
 */
static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
{
	struct dentry *dir;
	int dir_has_key, cached_with_key;
	int err;
	int valid;

	/*
	 * Plaintext names are always valid, since fscrypt doesn't support
	 * reverting to ciphertext names without evicting the directory's inode
	 * -- which implies eviction of the dentries in the directory.
	 */
	if (!(dentry->d_flags & DCACHE_ENCRYPTED_NAME))
		return 1;

	/*
	 * Ciphertext name; valid if the directory's key is still unavailable.
	 *
	 * Although fscrypt forbids rename() on ciphertext names, we still must
	 * use dget_parent() here rather than use ->d_parent directly.  That's
	 * because a corrupted fs image may contain directory hard links, which
	 * the VFS handles by moving the directory's dentry tree in the dcache
	 * each time ->lookup() finds the directory and it already has a dentry
	 * elsewhere.  Thus ->d_parent can be changing, and we must safely grab
	 * a reference to some ->d_parent to prevent it from being freed.
	 */

	if (flags & LOOKUP_RCU)
		return -ECHILD;

	dir = dget_parent(dentry);
	if (!IS_ENCRYPTED(d_inode(dir))) {
	err = fscrypt_get_encryption_info(d_inode(dir));
	valid = !fscrypt_has_encryption_key(d_inode(dir));
	dput(dir);
		return 0;
	}

	spin_lock(&dentry->d_lock);
	cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY;
	spin_unlock(&dentry->d_lock);
	dir_has_key = (d_inode(dir)->i_crypt_info != NULL);
	dput(dir);
	if (err < 0)
		return err;

	/*
	 * If the dentry was cached without the key, and it is a
	 * negative dentry, it might be a valid name.  We can't check
	 * if the key has since been made available due to locking
	 * reasons, so we fail the validation so ext4_lookup() can do
	 * this check.
	 *
	 * We also fail the validation if the dentry was created with
	 * the key present, but we no longer have the key, or vice versa.
	 */
	if ((!cached_with_key && d_is_negative(dentry)) ||
			(!cached_with_key && dir_has_key) ||
			(cached_with_key && !dir_has_key))
		return 0;
	return 1;
	return valid;
}

const struct dentry_operations fscrypt_d_ops = {
+3 −2
Original line number Diff line number Diff line
@@ -269,7 +269,7 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
	if (iname->len < FS_CRYPTO_BLOCK_SIZE)
		return -EUCLEAN;

	if (inode->i_crypt_info)
	if (fscrypt_has_encryption_key(inode))
		return fname_decrypt(inode, iname, oname);

	if (iname->len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) {
@@ -336,7 +336,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
	if (ret)
		return ret;

	if (dir->i_crypt_info) {
	if (fscrypt_has_encryption_key(dir)) {
		if (!fscrypt_fname_encrypted_size(dir, iname->len,
						  dir->i_sb->s_cop->max_namelen,
						  &fname->crypto_buf.len))
@@ -356,6 +356,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
	}
	if (!lookup)
		return -ENOKEY;
	fname->is_ciphertext_name = true;

	/*
	 * We don't have the key and we are doing a lookup; decode the
+52 −16
Original line number Diff line number Diff line
@@ -49,7 +49,8 @@ int fscrypt_file_open(struct inode *inode, struct file *filp)
}
EXPORT_SYMBOL_GPL(fscrypt_file_open);

int __fscrypt_prepare_link(struct inode *inode, struct inode *dir)
int __fscrypt_prepare_link(struct inode *inode, struct inode *dir,
			   struct dentry *dentry)
{
	int err;

@@ -57,6 +58,10 @@ int __fscrypt_prepare_link(struct inode *inode, struct inode *dir)
	if (err)
		return err;

	/* ... in case we looked up ciphertext name before key was added */
	if (dentry->d_flags & DCACHE_ENCRYPTED_NAME)
		return -ENOKEY;

	if (!fscrypt_has_permitted_context(dir, inode))
		return -EXDEV;

@@ -78,6 +83,11 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
	if (err)
		return err;

	/* ... in case we looked up ciphertext name(s) before key was added */
	if ((old_dentry->d_flags | new_dentry->d_flags) &
	    DCACHE_ENCRYPTED_NAME)
		return -ENOKEY;

	if (old_dir != new_dir) {
		if (IS_ENCRYPTED(new_dir) &&
		    !fscrypt_has_permitted_context(new_dir,
@@ -94,21 +104,21 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
}
EXPORT_SYMBOL_GPL(__fscrypt_prepare_rename);

int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry)
int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
			     struct fscrypt_name *fname)
{
	int err = fscrypt_get_encryption_info(dir);
	int err = fscrypt_setup_filename(dir, &dentry->d_name, 1, fname);

	if (err)
	if (err && err != -ENOENT)
		return err;

	if (fscrypt_has_encryption_key(dir)) {
	if (fname->is_ciphertext_name) {
		spin_lock(&dentry->d_lock);
		dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
		dentry->d_flags |= DCACHE_ENCRYPTED_NAME;
		spin_unlock(&dentry->d_lock);
	}

		d_set_d_op(dentry, &fscrypt_d_ops);
	return 0;
	}
	return err;
}
EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);

@@ -179,11 +189,9 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
	sd->len = cpu_to_le16(ciphertext_len);

	err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len);
	if (err) {
		if (!disk_link->name)
			kfree(sd);
		return err;
	}
	if (err)
		goto err_free_sd;

	/*
	 * Null-terminating the ciphertext doesn't make sense, but we still
	 * count the null terminator in the length, so we might as well
@@ -191,9 +199,20 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
	 */
	sd->encrypted_path[ciphertext_len] = '\0';

	/* Cache the plaintext symlink target for later use by get_link() */
	err = -ENOMEM;
	inode->i_link = kmemdup(target, len + 1, GFP_NOFS);
	if (!inode->i_link)
		goto err_free_sd;

	if (!disk_link->name)
		disk_link->name = (unsigned char *)sd;
	return 0;

err_free_sd:
	if (!disk_link->name)
		kfree(sd);
	return err;
}
EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink);

@@ -202,7 +221,7 @@ EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink);
 * @inode: the symlink inode
 * @caddr: the on-disk contents of the symlink
 * @max_size: size of @caddr buffer
 * @done: if successful, will be set up to free the returned target
 * @done: if successful, will be set up to free the returned target if needed
 *
 * If the symlink's encryption key is available, we decrypt its target.
 * Otherwise, we encode its target for presentation.
@@ -217,12 +236,18 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
{
	const struct fscrypt_symlink_data *sd;
	struct fscrypt_str cstr, pstr;
	bool has_key;
	int err;

	/* This is for encrypted symlinks only */
	if (WARN_ON(!IS_ENCRYPTED(inode)))
		return ERR_PTR(-EINVAL);

	/* If the decrypted target is already cached, just return it. */
	pstr.name = READ_ONCE(inode->i_link);
	if (pstr.name)
		return pstr.name;

	/*
	 * Try to set up the symlink's encryption key, but we can continue
	 * regardless of whether the key is available or not.
@@ -230,6 +255,7 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
	err = fscrypt_get_encryption_info(inode);
	if (err)
		return ERR_PTR(err);
	has_key = fscrypt_has_encryption_key(inode);

	/*
	 * For historical reasons, encrypted symlink targets are prefixed with
@@ -261,7 +287,17 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
		goto err_kfree;

	pstr.name[pstr.len] = '\0';

	/*
	 * Cache decrypted symlink targets in i_link for later use.  Don't cache
	 * symlink targets encoded without the key, since those become outdated
	 * once the key is added.  This pairs with the READ_ONCE() above and in
	 * the VFS path lookup code.
	 */
	if (!has_key ||
	    cmpxchg_release(&inode->i_link, NULL, pstr.name) != NULL)
		set_delayed_call(done, kfree_link, pstr.name);

	return pstr.name;

err_kfree:
+23 −2
Original line number Diff line number Diff line
@@ -508,7 +508,7 @@ int fscrypt_get_encryption_info(struct inode *inode)
	u8 *raw_key = NULL;
	int res;

	if (inode->i_crypt_info)
	if (fscrypt_has_encryption_key(inode))
		return 0;

	res = fscrypt_initialize(inode->i_sb->s_cop->flags);
@@ -572,7 +572,7 @@ int fscrypt_get_encryption_info(struct inode *inode)
	if (res)
		goto out;

	if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL)
	if (cmpxchg_release(&inode->i_crypt_info, NULL, crypt_info) == NULL)
		crypt_info = NULL;
out:
	if (res == -ENOKEY)
@@ -583,9 +583,30 @@ int fscrypt_get_encryption_info(struct inode *inode)
}
EXPORT_SYMBOL(fscrypt_get_encryption_info);

/**
 * fscrypt_put_encryption_info - free most of an inode's fscrypt data
 *
 * Free the inode's fscrypt_info.  Filesystems must call this when the inode is
 * being evicted.  An RCU grace period need not have elapsed yet.
 */
void fscrypt_put_encryption_info(struct inode *inode)
{
	put_crypt_info(inode->i_crypt_info);
	inode->i_crypt_info = NULL;
}
EXPORT_SYMBOL(fscrypt_put_encryption_info);

/**
 * fscrypt_free_inode - free an inode's fscrypt data requiring RCU delay
 *
 * Free the inode's cached decrypted symlink target, if any.  Filesystems must
 * call this after an RCU grace period, just before they free the inode.
 */
void fscrypt_free_inode(struct inode *inode)
{
	if (IS_ENCRYPTED(inode) && S_ISLNK(inode->i_mode)) {
		kfree(inode->i_link);
		inode->i_link = NULL;
	}
}
EXPORT_SYMBOL(fscrypt_free_inode);
Loading