Commit a9fbcd67 authored by Linus Torvalds's avatar Linus Torvalds

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
...@@ -36,12 +36,10 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done) ...@@ -36,12 +36,10 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
int ret = fscrypt_decrypt_page(page->mapping->host, page, int ret = fscrypt_decrypt_page(page->mapping->host, page,
PAGE_SIZE, 0, page->index); PAGE_SIZE, 0, page->index);
if (ret) { if (ret)
WARN_ON_ONCE(1);
SetPageError(page); SetPageError(page);
} else if (done) { else if (done)
SetPageUptodate(page); SetPageUptodate(page);
}
if (done) if (done)
unlock_page(page); unlock_page(page);
} }
...@@ -103,7 +101,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, ...@@ -103,7 +101,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE); 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)) if (IS_ERR(ctx))
return PTR_ERR(ctx); return PTR_ERR(ctx);
......
...@@ -87,23 +87,17 @@ EXPORT_SYMBOL(fscrypt_release_ctx); ...@@ -87,23 +87,17 @@ EXPORT_SYMBOL(fscrypt_release_ctx);
/** /**
* fscrypt_get_ctx() - Gets an encryption context * 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 * @gfp_flags: The gfp flag for memory allocation
* *
* Allocates and initializes an encryption context. * Allocates and initializes an encryption context.
* *
* Return: An allocated and initialized encryption context on success; error * Return: A new encryption context on success; an ERR_PTR() otherwise.
* value or NULL 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_ctx *ctx;
struct fscrypt_info *ci = inode->i_crypt_info;
unsigned long flags; unsigned long flags;
if (ci == NULL)
return ERR_PTR(-ENOKEY);
/* /*
* We first try getting the ctx from a free list because in * We first try getting the ctx from a free list because in
* the common case the ctx will have an allocated and * the common case the ctx will have an allocated and
...@@ -258,9 +252,9 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, ...@@ -258,9 +252,9 @@ struct page *fscrypt_encrypt_page(const struct inode *inode,
BUG_ON(!PageLocked(page)); BUG_ON(!PageLocked(page));
ctx = fscrypt_get_ctx(inode, gfp_flags); ctx = fscrypt_get_ctx(gfp_flags);
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return (struct page *)ctx; return ERR_CAST(ctx);
/* The encryption operation will require a bounce page. */ /* The encryption operation will require a bounce page. */
ciphertext_page = fscrypt_alloc_bounce_page(ctx, gfp_flags); ciphertext_page = fscrypt_alloc_bounce_page(ctx, gfp_flags);
...@@ -313,45 +307,47 @@ int fscrypt_decrypt_page(const struct inode *inode, struct page *page, ...@@ -313,45 +307,47 @@ int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
EXPORT_SYMBOL(fscrypt_decrypt_page); EXPORT_SYMBOL(fscrypt_decrypt_page);
/* /*
* Validate dentries for encrypted directories to make sure we aren't * Validate dentries in encrypted directories to make sure we aren't potentially
* potentially caching stale data after a key has been added or * caching stale dentries after a key has been added.
* removed.
*/ */
static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
{ {
struct dentry *dir; 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) if (flags & LOOKUP_RCU)
return -ECHILD; return -ECHILD;
dir = dget_parent(dentry); 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); dput(dir);
return 0;
}
spin_lock(&dentry->d_lock); if (err < 0)
cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY; return err;
spin_unlock(&dentry->d_lock);
dir_has_key = (d_inode(dir)->i_crypt_info != NULL);
dput(dir);
/* return valid;
* 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;
} }
const struct dentry_operations fscrypt_d_ops = { const struct dentry_operations fscrypt_d_ops = {
......
...@@ -269,7 +269,7 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, ...@@ -269,7 +269,7 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
if (iname->len < FS_CRYPTO_BLOCK_SIZE) if (iname->len < FS_CRYPTO_BLOCK_SIZE)
return -EUCLEAN; return -EUCLEAN;
if (inode->i_crypt_info) if (fscrypt_has_encryption_key(inode))
return fname_decrypt(inode, iname, oname); return fname_decrypt(inode, iname, oname);
if (iname->len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) { if (iname->len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) {
...@@ -336,7 +336,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, ...@@ -336,7 +336,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
if (ret) if (ret)
return ret; return ret;
if (dir->i_crypt_info) { if (fscrypt_has_encryption_key(dir)) {
if (!fscrypt_fname_encrypted_size(dir, iname->len, if (!fscrypt_fname_encrypted_size(dir, iname->len,
dir->i_sb->s_cop->max_namelen, dir->i_sb->s_cop->max_namelen,
&fname->crypto_buf.len)) &fname->crypto_buf.len))
...@@ -356,6 +356,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, ...@@ -356,6 +356,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
} }
if (!lookup) if (!lookup)
return -ENOKEY; return -ENOKEY;
fname->is_ciphertext_name = true;
/* /*
* We don't have the key and we are doing a lookup; decode the * We don't have the key and we are doing a lookup; decode the
......
...@@ -49,7 +49,8 @@ int fscrypt_file_open(struct inode *inode, struct file *filp) ...@@ -49,7 +49,8 @@ int fscrypt_file_open(struct inode *inode, struct file *filp)
} }
EXPORT_SYMBOL_GPL(fscrypt_file_open); 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; int err;
...@@ -57,6 +58,10 @@ int __fscrypt_prepare_link(struct inode *inode, struct inode *dir) ...@@ -57,6 +58,10 @@ int __fscrypt_prepare_link(struct inode *inode, struct inode *dir)
if (err) if (err)
return 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)) if (!fscrypt_has_permitted_context(dir, inode))
return -EXDEV; return -EXDEV;
...@@ -78,6 +83,11 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -78,6 +83,11 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
if (err) if (err)
return 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 (old_dir != new_dir) {
if (IS_ENCRYPTED(new_dir) && if (IS_ENCRYPTED(new_dir) &&
!fscrypt_has_permitted_context(new_dir, !fscrypt_has_permitted_context(new_dir,
...@@ -94,21 +104,21 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -94,21 +104,21 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,
} }
EXPORT_SYMBOL_GPL(__fscrypt_prepare_rename); 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; return err;
if (fscrypt_has_encryption_key(dir)) { if (fname->is_ciphertext_name) {
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY; dentry->d_flags |= DCACHE_ENCRYPTED_NAME;
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
}
d_set_d_op(dentry, &fscrypt_d_ops); d_set_d_op(dentry, &fscrypt_d_ops);
return 0; }
return err;
} }
EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup); EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
...@@ -179,11 +189,9 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, ...@@ -179,11 +189,9 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
sd->len = cpu_to_le16(ciphertext_len); sd->len = cpu_to_le16(ciphertext_len);
err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len); err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len);
if (err) { if (err)
if (!disk_link->name) goto err_free_sd;
kfree(sd);
return err;
}
/* /*
* Null-terminating the ciphertext doesn't make sense, but we still * Null-terminating the ciphertext doesn't make sense, but we still
* count the null terminator in the length, so we might as well * 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, ...@@ -191,9 +199,20 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
*/ */
sd->encrypted_path[ciphertext_len] = '\0'; 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) if (!disk_link->name)
disk_link->name = (unsigned char *)sd; disk_link->name = (unsigned char *)sd;
return 0; return 0;
err_free_sd:
if (!disk_link->name)
kfree(sd);
return err;
} }
EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink); EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink);
...@@ -202,7 +221,7 @@ EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink); ...@@ -202,7 +221,7 @@ EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink);
* @inode: the symlink inode * @inode: the symlink inode
* @caddr: the on-disk contents of the symlink * @caddr: the on-disk contents of the symlink
* @max_size: size of @caddr buffer * @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. * If the symlink's encryption key is available, we decrypt its target.
* Otherwise, we encode its target for presentation. * Otherwise, we encode its target for presentation.
...@@ -217,12 +236,18 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, ...@@ -217,12 +236,18 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
{ {
const struct fscrypt_symlink_data *sd; const struct fscrypt_symlink_data *sd;
struct fscrypt_str cstr, pstr; struct fscrypt_str cstr, pstr;
bool has_key;
int err; int err;
/* This is for encrypted symlinks only */ /* This is for encrypted symlinks only */
if (WARN_ON(!IS_ENCRYPTED(inode))) if (WARN_ON(!IS_ENCRYPTED(inode)))
return ERR_PTR(-EINVAL); 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 * Try to set up the symlink's encryption key, but we can continue
* regardless of whether the key is available or not. * regardless of whether the key is available or not.
...@@ -230,6 +255,7 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, ...@@ -230,6 +255,7 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
err = fscrypt_get_encryption_info(inode); err = fscrypt_get_encryption_info(inode);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
has_key = fscrypt_has_encryption_key(inode);
/* /*
* For historical reasons, encrypted symlink targets are prefixed with * For historical reasons, encrypted symlink targets are prefixed with
...@@ -261,7 +287,17 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, ...@@ -261,7 +287,17 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
goto err_kfree; goto err_kfree;
pstr.name[pstr.len] = '\0'; 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); set_delayed_call(done, kfree_link, pstr.name);
return pstr.name; return pstr.name;
err_kfree: err_kfree:
......
...@@ -508,7 +508,7 @@ int fscrypt_get_encryption_info(struct inode *inode) ...@@ -508,7 +508,7 @@ int fscrypt_get_encryption_info(struct inode *inode)
u8 *raw_key = NULL; u8 *raw_key = NULL;
int res; int res;
if (inode->i_crypt_info) if (fscrypt_has_encryption_key(inode))
return 0; return 0;
res = fscrypt_initialize(inode->i_sb->s_cop->flags); res = fscrypt_initialize(inode->i_sb->s_cop->flags);
...@@ -572,7 +572,7 @@ int fscrypt_get_encryption_info(struct inode *inode) ...@@ -572,7 +572,7 @@ int fscrypt_get_encryption_info(struct inode *inode)
if (res) if (res)
goto out; 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; crypt_info = NULL;
out: out:
if (res == -ENOKEY) if (res == -ENOKEY)
...@@ -583,9 +583,30 @@ int fscrypt_get_encryption_info(struct inode *inode) ...@@ -583,9 +583,30 @@ int fscrypt_get_encryption_info(struct inode *inode)
} }
EXPORT_SYMBOL(fscrypt_get_encryption_info); 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) void fscrypt_put_encryption_info(struct inode *inode)
{ {
put_crypt_info(inode->i_crypt_info); put_crypt_info(inode->i_crypt_info);
inode->i_crypt_info = NULL; inode->i_crypt_info = NULL;
} }
EXPORT_SYMBOL(fscrypt_put_encryption_info); 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);
...@@ -194,8 +194,8 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child) ...@@ -194,8 +194,8 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
res = fscrypt_get_encryption_info(child); res = fscrypt_get_encryption_info(child);
if (res) if (res)
return 0; return 0;
parent_ci = parent->i_crypt_info; parent_ci = READ_ONCE(parent->i_crypt_info);
child_ci = child->i_crypt_info; child_ci = READ_ONCE(child->i_crypt_info);
if (parent_ci && child_ci) { if (parent_ci && child_ci) {
return memcmp(parent_ci->ci_master_key_descriptor, return memcmp(parent_ci->ci_master_key_descriptor,
...@@ -246,7 +246,7 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child, ...@@ -246,7 +246,7 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child,
if (res < 0) if (res < 0)
return res; return res;
ci = parent->i_crypt_info; ci = READ_ONCE(parent->i_crypt_info);
if (ci == NULL) if (ci == NULL)
return -ENOKEY; return -ENOKEY;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/fscrypt.h>
#include <linux/fsnotify.h> #include <linux/fsnotify.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -2797,6 +2798,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target, ...@@ -2797,6 +2798,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
list_move(&dentry->d_child, &dentry->d_parent->d_subdirs); list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
__d_rehash(dentry); __d_rehash(dentry);
fsnotify_update_flags(dentry); fsnotify_update_flags(dentry);
fscrypt_handle_d_move(dentry);
write_seqcount_end(&target->d_seq); write_seqcount_end(&target->d_seq);
write_seqcount_end(&dentry->d_seq); write_seqcount_end(&dentry->d_seq);
......
...@@ -2303,23 +2303,47 @@ extern unsigned ext4_free_clusters_after_init(struct super_block *sb, ...@@ -2303,23 +2303,47 @@ extern unsigned ext4_free_clusters_after_init(struct super_block *sb,
ext4_fsblk_t ext4_inode_to_goal_block(struct inode *); ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
#ifdef CONFIG_FS_ENCRYPTION #ifdef CONFIG_FS_ENCRYPTION
static inline void ext4_fname_from_fscrypt_name(struct ext4_filename *dst,
const struct fscrypt_name *src)
{
memset(dst, 0, sizeof(*dst));
dst->usr_fname = src->usr_fname;
dst->disk_name = src->disk_name;
dst->hinfo.hash = src->hash;
dst->hinfo.minor_hash = src->minor_hash;
dst->crypto_buf = src->crypto_buf;
}
static inline int ext4_fname_setup_filename(struct inode *dir, static inline int ext4_fname_setup_filename(struct inode *dir,
const struct qstr *iname, const struct qstr *iname,
int lookup, struct ext4_filename *fname) int lookup,
struct ext4_filename *fname)
{ {
struct fscrypt_name name; struct fscrypt_name name;
int err; int err;
memset(fname, 0, sizeof(struct ext4_filename));
err = fscrypt_setup_filename(dir, iname, lookup, &name); err = fscrypt_setup_filename(dir, iname, lookup, &name);
if (err)
return err;
ext4_fname_from_fscrypt_name(fname, &name);
return 0;
}
static inline int ext4_fname_prepare_lookup(struct inode *dir,
struct dentry *dentry,
struct ext4_filename *fname)
{
struct fscrypt_name name;
int err;
fname->usr_fname = name.usr_fname; err = fscrypt_prepare_lookup(dir, dentry, &name);
fname->disk_name = name.disk_name; if (err)
fname->hinfo.hash = name.hash;
fname->hinfo.minor_hash = name.minor_hash;
fname->crypto_buf = name.crypto_buf;
return err; return err;
ext4_fname_from_fscrypt_name(fname, &name);
return 0;
} }
static inline void ext4_fname_free_filename(struct ext4_filename *fname) static inline void ext4_fname_free_filename(struct ext4_filename *fname)
...@@ -2333,19 +2357,27 @@ static inline void ext4_fname_free_filename(struct ext4_filename *fname) ...@@ -2333,19 +2357,27 @@ static inline void ext4_fname_free_filename(struct ext4_filename *fname)
fname->usr_fname = NULL; fname->usr_fname = NULL;
fname->disk_name.name = NULL; fname->disk_name.name = NULL;
} }
#else #else /* !CONFIG_FS_ENCRYPTION */
static inline int ext4_fname_setup_filename(struct inode *dir, static inline int ext4_fname_setup_filename(struct inode *dir,
const struct qstr *iname, const struct qstr *iname,
int lookup, struct ext4_filename *fname) int lookup,
struct ext4_filename *fname)
{ {
fname->usr_fname = iname; fname->usr_fname = iname;
fname->disk_name.name = (unsigned char *) iname->name; fname->disk_name.name = (unsigned char *) iname->name;
fname->disk_name.len = iname->len; fname->disk_name.len = iname->len;
return 0; return 0;
} }
static inline void ext4_fname_free_filename(struct ext4_filename *fname) { }
#endif static inline int ext4_fname_prepare_lookup(struct inode *dir,
struct dentry *dentry,
struct ext4_filename *fname)
{
return ext4_fname_setup_filename(dir, &dentry->d_name, 1, fname);
}
static inline void ext4_fname_free_filename(struct ext4_filename *fname) { }
#endif /* !CONFIG_FS_ENCRYPTION */
/* dir.c */ /* dir.c */
extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
......
...@@ -1371,7 +1371,7 @@ static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block, ...@@ -1371,7 +1371,7 @@ static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block,
} }
/* /*
* ext4_find_entry() * __ext4_find_entry()
* *
* finds an entry in the specified directory with the wanted name. It * finds an entry in the specified directory with the wanted name. It
* returns the cache buffer in which the entry was found, and the entry * returns the cache buffer in which the entry was found, and the entry
...@@ -1381,8 +1381,8 @@ static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block, ...@@ -1381,8 +1381,8 @@ static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block,
* The returned buffer_head has ->b_count elevated. The caller is expected * The returned buffer_head has ->b_count elevated. The caller is expected
* to brelse() it when appropriate. * to brelse() it when appropriate.
*/ */
static struct buffer_head * ext4_find_entry (struct inode *dir, static struct buffer_head *__ext4_find_entry(struct inode *dir,
const struct qstr *d_name, struct ext4_filename *fname,
struct ext4_dir_entry_2 **res_dir, struct ext4_dir_entry_2 **res_dir,
int *inlined) int *inlined)
{ {
...@@ -1390,30 +1390,23 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, ...@@ -1390,30 +1390,23 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
struct buffer_head *bh_use[NAMEI_RA_SIZE]; struct buffer_head *bh_use[NAMEI_RA_SIZE];
struct buffer_head *bh, *ret = NULL; struct buffer_head *bh, *ret = NULL;
ext4_lblk_t start, block; ext4_lblk_t start, block;
const u8 *name = d_name->name; const u8 *name = fname->usr_fname->name;
size_t ra_max = 0; /* Number of bh's in the readahead size_t ra_max = 0; /* Number of bh's in the readahead
buffer, bh_use[] */ buffer, bh_use[] */
size_t ra_ptr = 0; /* Current index into readahead size_t ra_ptr = 0; /* Current index into readahead
buffer */ buffer */
ext4_lblk_t nblocks; ext4_lblk_t nblocks;
int i, namelen, retval; int i, namelen, retval;
struct ext4_filename fname;
*res_dir = NULL; *res_dir = NULL;
sb = dir->i_sb; sb = dir->i_sb;
namelen = d_name->len; namelen = fname->usr_fname->len;
if (namelen > EXT4_NAME_LEN) if (namelen > EXT4_NAME_LEN)
return NULL; return NULL;
retval = ext4_fname_setup_filename(dir, d_name, 1, &fname);
if (retval == -ENOENT)
return NULL;
if (retval)
return ERR_PTR(retval);
if (ext4_has_inline_data(dir)) { if (ext4_has_inline_data(dir)) {
int has_inline_data = 1; int has_inline_data = 1;
ret = ext4_find_inline_entry(dir, &fname, res_dir, ret = ext4_find_inline_entry(dir, fname, res_dir,
&has_inline_data); &has_inline_data);
if (has_inline_data) { if (has_inline_data) {
if (inlined) if (inlined)
...@@ -1433,7 +1426,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, ...@@ -1433,7 +1426,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
goto restart; goto restart;
} }
if (is_dx(dir)) { if (is_dx(dir)) {
ret = ext4_dx_find_entry(dir, &fname, res_dir); ret = ext4_dx_find_entry(dir, fname, res_dir);
/* /*
* On success, or if the error was file not found, * On success, or if the error was file not found,
* return. Otherwise, fall back to doing a search the * return. Otherwise, fall back to doing a search the
...@@ -1497,7 +1490,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, ...@@ -1497,7 +1490,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
goto cleanup_and_exit; goto cleanup_and_exit;
} }
set_buffer_verified(bh); set_buffer_verified(bh);
i = search_dirblock(bh, dir, &fname, i = search_dirblock(bh, dir, fname,
block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); block << EXT4_BLOCK_SIZE_BITS(sb), res_dir);
if (i == 1) { if (i == 1) {
EXT4_I(dir)->i_dir_start_lookup = block; EXT4_I(dir)->i_dir_start_lookup = block;
...@@ -1528,10 +1521,50 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, ...@@ -1528,10 +1521,50 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
/* Clean up the read-ahead blocks */ /* Clean up the read-ahead blocks */
for (; ra_ptr < ra_max; ra_ptr++) for (; ra_ptr < ra_max; ra_ptr++)
brelse(bh_use[ra_ptr]); brelse(bh_use[ra_ptr]);
ext4_fname_free_filename(&fname);
return ret; return ret;
} }
static struct buffer_head *ext4_find_entry(struct inode *dir,
const struct qstr *d_name,
struct ext4_dir_entry_2 **res_dir,
int *inlined)
{
int err;
struct ext4_filename fname;
struct buffer_head *bh;
err = ext4_fname_setup_filename(dir, d_name, 1, &fname);
if (err == -ENOENT)
return NULL;
if (err)
return ERR_PTR(err);
bh = __ext4_find_entry(dir, &fname, res_dir, inlined);
ext4_fname_free_filename(&fname);
return bh;
}
static struct buffer_head *ext4_lookup_entry(struct inode *dir,
struct dentry *dentry,
struct ext4_dir_entry_2 **res_dir)
{
int err;
struct ext4_filename fname;
struct buffer_head *bh;
err = ext4_fname_prepare_lookup(dir, dentry, &fname);
if (err == -ENOENT)
return NULL;
if (err)
return ERR_PTR(err);
bh = __ext4_find_entry(dir, &fname, res_dir, NULL);
ext4_fname_free_filename(&fname);
return bh;
}
static struct buffer_head * ext4_dx_find_entry(struct inode *dir, static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
struct ext4_filename *fname, struct ext4_filename *fname,
struct ext4_dir_entry_2 **res_dir) struct ext4_dir_entry_2 **res_dir)
...@@ -1590,16 +1623,11 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi ...@@ -1590,16 +1623,11 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
struct inode *inode; struct inode *inode;
struct ext4_dir_entry_2 *de; struct ext4_dir_entry_2 *de;
struct buffer_head *bh; struct buffer_head *bh;
int err;
err = fscrypt_prepare_lookup(dir, dentry, flags);
if (err)
return ERR_PTR(err);
if (dentry->d_name.len > EXT4_NAME_LEN) if (dentry->d_name.len > EXT4_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); bh = ext4_lookup_entry(dir, dentry, &de);
if (IS_ERR(bh)) if (IS_ERR(bh))
return ERR_CAST(bh); return ERR_CAST(bh);
inode = NULL; inode = NULL;
......
...@@ -244,7 +244,7 @@ int ext4_mpage_readpages(struct address_space *mapping, ...@@ -244,7 +244,7 @@ int ext4_mpage_readpages(struct address_space *mapping,
struct fscrypt_ctx *ctx = NULL; struct fscrypt_ctx *ctx = NULL;
if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) { if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) {
ctx = fscrypt_get_ctx(inode, GFP_NOFS); ctx = fscrypt_get_ctx(GFP_NOFS);
if (IS_ERR(ctx)) if (IS_ERR(ctx))
goto set_error_page; goto set_error_page;
} }
......
...@@ -1113,6 +1113,7 @@ static int ext4_drop_inode(struct inode *inode) ...@@ -1113,6 +1113,7 @@ static int ext4_drop_inode(struct inode *inode)
static void ext4_free_in_core_inode(struct inode *inode) static void ext4_free_in_core_inode(struct inode *inode)
{ {
fscrypt_free_inode(inode);
kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); kmem_cache_free(ext4_inode_cachep, EXT4_I(inode));
} }
......
...@@ -436,19 +436,23 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -436,19 +436,23 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
nid_t ino = -1; nid_t ino = -1;
int err = 0; int err = 0;
unsigned int root_ino = F2FS_ROOT_INO(F2FS_I_SB(dir)); unsigned int root_ino = F2FS_ROOT_INO(F2FS_I_SB(dir));
struct fscrypt_name fname;
trace_f2fs_lookup_start(dir, dentry, flags); trace_f2fs_lookup_start(dir, dentry, flags);
err = fscrypt_prepare_lookup(dir, dentry, flags);
if (err)
goto out;
if (dentry->d_name.len > F2FS_NAME_LEN) { if (dentry->d_name.len > F2FS_NAME_LEN) {
err = -ENAMETOOLONG; err = -ENAMETOOLONG;
goto out; goto out;
} }
de = f2fs_find_entry(dir, &dentry->d_name, &page); err = fscrypt_prepare_lookup(dir, dentry, &fname);
if (err == -ENOENT)
goto out_splice;
if (err)
goto out;
de = __f2fs_find_entry(dir, &fname, &page);
fscrypt_free_filename(&fname);
if (!de) { if (!de) {
if (IS_ERR(page)) { if (IS_ERR(page)) {
err = PTR_ERR(page); err = PTR_ERR(page);
...@@ -488,8 +492,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -488,8 +492,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
} }
out_splice: out_splice:
new = d_splice_alias(inode, dentry); new = d_splice_alias(inode, dentry);
if (IS_ERR(new)) err = PTR_ERR_OR_ZERO(new);
err = PTR_ERR(new);
trace_f2fs_lookup_end(dir, dentry, ino, err); trace_f2fs_lookup_end(dir, dentry, ino, err);
return new; return new;
out_iput: out_iput:
......
...@@ -1002,6 +1002,7 @@ static void f2fs_dirty_inode(struct inode *inode, int flags) ...@@ -1002,6 +1002,7 @@ static void f2fs_dirty_inode(struct inode *inode, int flags)
static void f2fs_free_inode(struct inode *inode) static void f2fs_free_inode(struct inode *inode)
{ {
fscrypt_free_inode(inode);
kmem_cache_free(f2fs_inode_cachep, F2FS_I(inode)); kmem_cache_free(f2fs_inode_cachep, F2FS_I(inode));
} }
......
...@@ -1066,7 +1066,7 @@ const char *get_link(struct nameidata *nd) ...@@ -1066,7 +1066,7 @@ const char *get_link(struct nameidata *nd)
return ERR_PTR(error); return ERR_PTR(error);
nd->last_type = LAST_BIND; nd->last_type = LAST_BIND;
res = inode->i_link; res = READ_ONCE(inode->i_link);
if (!res) { if (!res) {
const char * (*get)(struct dentry *, struct inode *, const char * (*get)(struct dentry *, struct inode *,
struct delayed_call *); struct delayed_call *);
...@@ -4729,7 +4729,7 @@ int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen) ...@@ -4729,7 +4729,7 @@ int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
link = inode->i_link; link = READ_ONCE(inode->i_link);
if (!link) { if (!link) {
link = inode->i_op->get_link(dentry, inode, &done); link = inode->i_op->get_link(dentry, inode, &done);
if (IS_ERR(link)) if (IS_ERR(link))
......
...@@ -220,11 +220,9 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -220,11 +220,9 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino); dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
err = fscrypt_prepare_lookup(dir, dentry, flags); err = fscrypt_prepare_lookup(dir, dentry, &nm);
if (err) if (err == -ENOENT)
return ERR_PTR(err); return d_splice_alias(NULL, dentry);
err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
......
...@@ -275,7 +275,10 @@ static struct inode *ubifs_alloc_inode(struct super_block *sb) ...@@ -275,7 +275,10 @@ static struct inode *ubifs_alloc_inode(struct super_block *sb)
static void ubifs_free_inode(struct inode *inode) static void ubifs_free_inode(struct inode *inode)
{ {
struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *ui = ubifs_inode(inode);
kfree(ui->data); kfree(ui->data);
fscrypt_free_inode(inode);
kmem_cache_free(ubifs_inode_slab, ui); kmem_cache_free(ubifs_inode_slab, ui);
} }
......
...@@ -211,7 +211,7 @@ struct dentry_operations { ...@@ -211,7 +211,7 @@ struct dentry_operations {
#define DCACHE_MAY_FREE 0x00800000 #define DCACHE_MAY_FREE 0x00800000
#define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */ #define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */
#define DCACHE_ENCRYPTED_WITH_KEY 0x02000000 /* dir is encrypted with a valid key */ #define DCACHE_ENCRYPTED_NAME 0x02000000 /* Encrypted name (dir key was unavailable) */
#define DCACHE_OP_REAL 0x04000000 #define DCACHE_OP_REAL 0x04000000
#define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */ #define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */
......
...@@ -33,6 +33,7 @@ struct fscrypt_name { ...@@ -33,6 +33,7 @@ struct fscrypt_name {
u32 hash; u32 hash;
u32 minor_hash; u32 minor_hash;
struct fscrypt_str crypto_buf; struct fscrypt_str crypto_buf;
bool is_ciphertext_name;
}; };
#define FSTR_INIT(n, l) { .name = n, .len = l } #define FSTR_INIT(n, l) { .name = n, .len = l }
...@@ -79,7 +80,8 @@ struct fscrypt_ctx { ...@@ -79,7 +80,8 @@ struct fscrypt_ctx {
static inline bool fscrypt_has_encryption_key(const struct inode *inode) static inline bool fscrypt_has_encryption_key(const struct inode *inode)
{ {
return (inode->i_crypt_info != NULL); /* pairs with cmpxchg_release() in fscrypt_get_encryption_info() */
return READ_ONCE(inode->i_crypt_info) != NULL;
} }
static inline bool fscrypt_dummy_context_enabled(struct inode *inode) static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
...@@ -88,9 +90,21 @@ static inline bool fscrypt_dummy_context_enabled(struct inode *inode) ...@@ -88,9 +90,21 @@ static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
inode->i_sb->s_cop->dummy_context(inode); inode->i_sb->s_cop->dummy_context(inode);
} }
/*
* When d_splice_alias() moves a directory's encrypted alias to its decrypted
* alias as a result of the encryption key being added, DCACHE_ENCRYPTED_NAME
* must be cleared. Note that we don't have to support arbitrary moves of this
* flag because fscrypt doesn't allow encrypted aliases to be the source or
* target of a rename().
*/
static inline void fscrypt_handle_d_move(struct dentry *dentry)
{
dentry->d_flags &= ~DCACHE_ENCRYPTED_NAME;
}
/* crypto.c */ /* crypto.c */
extern void fscrypt_enqueue_decrypt_work(struct work_struct *); extern void fscrypt_enqueue_decrypt_work(struct work_struct *);
extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t); extern struct fscrypt_ctx *fscrypt_get_ctx(gfp_t);
extern void fscrypt_release_ctx(struct fscrypt_ctx *); extern void fscrypt_release_ctx(struct fscrypt_ctx *);
extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *,
unsigned int, unsigned int, unsigned int, unsigned int,
...@@ -114,6 +128,7 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *, ...@@ -114,6 +128,7 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *,
/* keyinfo.c */ /* keyinfo.c */
extern int fscrypt_get_encryption_info(struct inode *); extern int fscrypt_get_encryption_info(struct inode *);
extern void fscrypt_put_encryption_info(struct inode *); extern void fscrypt_put_encryption_info(struct inode *);
extern void fscrypt_free_inode(struct inode *);
/* fname.c */ /* fname.c */
extern int fscrypt_setup_filename(struct inode *, const struct qstr *, extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
...@@ -214,13 +229,15 @@ extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, ...@@ -214,13 +229,15 @@ extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t,
/* hooks.c */ /* hooks.c */
extern int fscrypt_file_open(struct inode *inode, struct file *filp); extern int fscrypt_file_open(struct inode *inode, struct file *filp);
extern int __fscrypt_prepare_link(struct inode *inode, struct inode *dir); extern int __fscrypt_prepare_link(struct inode *inode, struct inode *dir,
struct dentry *dentry);
extern int __fscrypt_prepare_rename(struct inode *old_dir, extern int __fscrypt_prepare_rename(struct inode *old_dir,
struct dentry *old_dentry, struct dentry *old_dentry,
struct inode *new_dir, struct inode *new_dir,
struct dentry *new_dentry, struct dentry *new_dentry,
unsigned int flags); unsigned int flags);
extern int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry); extern int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
struct fscrypt_name *fname);
extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len, extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
unsigned int max_len, unsigned int max_len,
struct fscrypt_str *disk_link); struct fscrypt_str *disk_link);
...@@ -242,13 +259,16 @@ static inline bool fscrypt_dummy_context_enabled(struct inode *inode) ...@@ -242,13 +259,16 @@ static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
return false; return false;
} }
static inline void fscrypt_handle_d_move(struct dentry *dentry)
{
}
/* crypto.c */ /* crypto.c */
static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work) static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work)
{ {
} }
static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, static inline struct fscrypt_ctx *fscrypt_get_ctx(gfp_t gfp_flags)
gfp_t gfp_flags)
{ {
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
...@@ -322,6 +342,10 @@ static inline void fscrypt_put_encryption_info(struct inode *inode) ...@@ -322,6 +342,10 @@ static inline void fscrypt_put_encryption_info(struct inode *inode)
return; return;
} }
static inline void fscrypt_free_inode(struct inode *inode)
{
}
/* fname.c */ /* fname.c */
static inline int fscrypt_setup_filename(struct inode *dir, static inline int fscrypt_setup_filename(struct inode *dir,
const struct qstr *iname, const struct qstr *iname,
...@@ -330,7 +354,7 @@ static inline int fscrypt_setup_filename(struct inode *dir, ...@@ -330,7 +354,7 @@ static inline int fscrypt_setup_filename(struct inode *dir,
if (IS_ENCRYPTED(dir)) if (IS_ENCRYPTED(dir))
return -EOPNOTSUPP; return -EOPNOTSUPP;
memset(fname, 0, sizeof(struct fscrypt_name)); memset(fname, 0, sizeof(*fname));
fname->usr_fname = iname; fname->usr_fname = iname;
fname->disk_name.name = (unsigned char *)iname->name; fname->disk_name.name = (unsigned char *)iname->name;
fname->disk_name.len = iname->len; fname->disk_name.len = iname->len;
...@@ -401,8 +425,8 @@ static inline int fscrypt_file_open(struct inode *inode, struct file *filp) ...@@ -401,8 +425,8 @@ static inline int fscrypt_file_open(struct inode *inode, struct file *filp)
return 0; return 0;
} }
static inline int __fscrypt_prepare_link(struct inode *inode, static inline int __fscrypt_prepare_link(struct inode *inode, struct inode *dir,
struct inode *dir) struct dentry *dentry)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -417,7 +441,8 @@ static inline int __fscrypt_prepare_rename(struct inode *old_dir, ...@@ -417,7 +441,8 @@ static inline int __fscrypt_prepare_rename(struct inode *old_dir,
} }
static inline int __fscrypt_prepare_lookup(struct inode *dir, static inline int __fscrypt_prepare_lookup(struct inode *dir,
struct dentry *dentry) struct dentry *dentry,
struct fscrypt_name *fname)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -497,7 +522,7 @@ static inline int fscrypt_prepare_link(struct dentry *old_dentry, ...@@ -497,7 +522,7 @@ static inline int fscrypt_prepare_link(struct dentry *old_dentry,
struct dentry *dentry) struct dentry *dentry)
{ {
if (IS_ENCRYPTED(dir)) if (IS_ENCRYPTED(dir))
return __fscrypt_prepare_link(d_inode(old_dentry), dir); return __fscrypt_prepare_link(d_inode(old_dentry), dir, dentry);
return 0; return 0;
} }
...@@ -538,27 +563,32 @@ static inline int fscrypt_prepare_rename(struct inode *old_dir, ...@@ -538,27 +563,32 @@ static inline int fscrypt_prepare_rename(struct inode *old_dir,
* fscrypt_prepare_lookup - prepare to lookup a name in a possibly-encrypted directory * fscrypt_prepare_lookup - prepare to lookup a name in a possibly-encrypted directory
* @dir: directory being searched * @dir: directory being searched
* @dentry: filename being looked up * @dentry: filename being looked up
* @flags: lookup flags * @fname: (output) the name to use to search the on-disk directory
* *
* Prepare for ->lookup() in a directory which may be encrypted. Lookups can be * Prepare for ->lookup() in a directory which may be encrypted by determining
* done with or without the directory's encryption key; without the key, * the name that will actually be used to search the directory on-disk. Lookups
* can be done with or without the directory's encryption key; without the key,
* filenames are presented in encrypted form. Therefore, we'll try to set up * filenames are presented in encrypted form. Therefore, we'll try to set up
* the directory's encryption key, but even without it the lookup can continue. * the directory's encryption key, but even without it the lookup can continue.
* *
* To allow invalidating stale dentries if the directory's encryption key is * This also installs a custom ->d_revalidate() method which will invalidate the
* added later, we also install a custom ->d_revalidate() method and use the * dentry if it was created without the key and the key is later added.
* DCACHE_ENCRYPTED_WITH_KEY flag to indicate whether a given dentry is a
* plaintext name (flag set) or a ciphertext name (flag cleared).
* *
* Return: 0 on success, -errno if a problem occurred while setting up the * Return: 0 on success; -ENOENT if key is unavailable but the filename isn't a
* encryption key * correctly formed encoded ciphertext name, so a negative dentry should be
* created; or another -errno code.
*/ */
static inline int fscrypt_prepare_lookup(struct inode *dir, static inline int fscrypt_prepare_lookup(struct inode *dir,
struct dentry *dentry, struct dentry *dentry,
unsigned int flags) struct fscrypt_name *fname)
{ {
if (IS_ENCRYPTED(dir)) if (IS_ENCRYPTED(dir))
return __fscrypt_prepare_lookup(dir, dentry); return __fscrypt_prepare_lookup(dir, dentry, fname);
memset(fname, 0, sizeof(*fname));
fname->usr_fname = &dentry->d_name;
fname->disk_name.name = (unsigned char *)dentry->d_name.name;
fname->disk_name.len = dentry->d_name.len;
return 0; return 0;
} }
......
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