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)
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);
......
......@@ -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))) {
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);
err = fscrypt_get_encryption_info(d_inode(dir));
valid = !fscrypt_has_encryption_key(d_inode(dir));
dput(dir);
/*
* 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;
if (err < 0)
return err;
return valid;
}
const struct dentry_operations fscrypt_d_ops = {
......
......@@ -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
......
......@@ -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);
}
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';
set_delayed_call(done, kfree_link, pstr.name);
/*
* 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:
......
......@@ -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);
......@@ -194,8 +194,8 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
res = fscrypt_get_encryption_info(child);
if (res)
return 0;
parent_ci = parent->i_crypt_info;
child_ci = child->i_crypt_info;
parent_ci = READ_ONCE(parent->i_crypt_info);
child_ci = READ_ONCE(child->i_crypt_info);
if (parent_ci && child_ci) {
return memcmp(parent_ci->ci_master_key_descriptor,
......@@ -246,7 +246,7 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child,
if (res < 0)
return res;
ci = parent->i_crypt_info;
ci = READ_ONCE(parent->i_crypt_info);
if (ci == NULL)
return -ENOKEY;
......
......@@ -18,6 +18,7 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/fscrypt.h>
#include <linux/fsnotify.h>
#include <linux/slab.h>
#include <linux/init.h>
......@@ -2797,6 +2798,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
__d_rehash(dentry);
fsnotify_update_flags(dentry);
fscrypt_handle_d_move(dentry);
write_seqcount_end(&target->d_seq);
write_seqcount_end(&dentry->d_seq);
......
......@@ -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 *);
#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,
const struct qstr *iname,
int lookup, struct ext4_filename *fname)
const struct qstr *iname,
int lookup,
struct ext4_filename *fname)
{
struct fscrypt_name name;
int err;
memset(fname, 0, sizeof(struct ext4_filename));
err = fscrypt_setup_filename(dir, iname, lookup, &name);
if (err)
return err;
fname->usr_fname = name.usr_fname;
fname->disk_name = name.disk_name;
fname->hinfo.hash = name.hash;
fname->hinfo.minor_hash = name.minor_hash;
fname->crypto_buf = name.crypto_buf;
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;
err = fscrypt_prepare_lookup(dir, dentry, &name);
if (err)
return err;
ext4_fname_from_fscrypt_name(fname, &name);
return 0;
}
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->disk_name.name = NULL;
}
#else
#else /* !CONFIG_FS_ENCRYPTION */
static inline int ext4_fname_setup_filename(struct inode *dir,
const struct qstr *iname,
int lookup, struct ext4_filename *fname)
const struct qstr *iname,
int lookup,
struct ext4_filename *fname)
{
fname->usr_fname = iname;
fname->disk_name.name = (unsigned char *) iname->name;
fname->disk_name.len = iname->len;
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 */
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,
}
/*
* ext4_find_entry()
* __ext4_find_entry()
*
* 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
......@@ -1381,39 +1381,32 @@ 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
* to brelse() it when appropriate.
*/
static struct buffer_head * ext4_find_entry (struct inode *dir,
const struct qstr *d_name,
struct ext4_dir_entry_2 **res_dir,
int *inlined)
static struct buffer_head *__ext4_find_entry(struct inode *dir,
struct ext4_filename *fname,
struct ext4_dir_entry_2 **res_dir,
int *inlined)
{
struct super_block *sb;
struct buffer_head *bh_use[NAMEI_RA_SIZE];
struct buffer_head *bh, *ret = NULL;
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
buffer, bh_use[] */
size_t ra_ptr = 0; /* Current index into readahead
buffer */
ext4_lblk_t nblocks;
int i, namelen, retval;
struct ext4_filename fname;
*res_dir = NULL;
sb = dir->i_sb;
namelen = d_name->len;
namelen = fname->usr_fname->len;
if (namelen > EXT4_NAME_LEN)
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)) {
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);
if (has_inline_data) {
if (inlined)
......@@ -1433,7 +1426,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
goto restart;
}
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,
* return. Otherwise, fall back to doing a search the
......@@ -1497,7 +1490,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
goto cleanup_and_exit;
}
set_buffer_verified(bh);
i = search_dirblock(bh, dir, &fname,
i = search_dirblock(bh, dir, fname,
block << EXT4_BLOCK_SIZE_BITS(sb), res_dir);
if (i == 1) {
EXT4_I(dir)->i_dir_start_lookup = block;
......@@ -1528,10 +1521,50 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
/* Clean up the read-ahead blocks */
for (; ra_ptr < ra_max; ra_ptr++)
brelse(bh_use[ra_ptr]);
ext4_fname_free_filename(&fname);
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,
struct ext4_filename *fname,
struct ext4_dir_entry_2 **res_dir)
......@@ -1590,16 +1623,11 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
struct inode *inode;
struct ext4_dir_entry_2 *de;
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)
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))
return ERR_CAST(bh);
inode = NULL;
......
......@@ -244,7 +244,7 @@ int ext4_mpage_readpages(struct address_space *mapping,
struct fscrypt_ctx *ctx = NULL;
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))
goto set_error_page;
}
......
......@@ -1113,6 +1113,7 @@ static int ext4_drop_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));
}
......
......@@ -436,19 +436,23 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
nid_t ino = -1;
int err = 0;
unsigned int root_ino = F2FS_ROOT_INO(F2FS_I_SB(dir));
struct fscrypt_name fname;
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) {
err = -ENAMETOOLONG;
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 (IS_ERR(page)) {
err = PTR_ERR(page);
......@@ -488,8 +492,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
}
out_splice:
new = d_splice_alias(inode, dentry);
if (IS_ERR(new))
err = PTR_ERR(new);
err = PTR_ERR_OR_ZERO(new);
trace_f2fs_lookup_end(dir, dentry, ino, err);
return new;
out_iput:
......
......@@ -1002,6 +1002,7 @@ static void f2fs_dirty_inode(struct inode *inode, int flags)
static void f2fs_free_inode(struct inode *inode)
{
fscrypt_free_inode(inode);
kmem_cache_free(f2fs_inode_cachep, F2FS_I(inode));
}
......
......@@ -1066,7 +1066,7 @@ const char *get_link(struct nameidata *nd)
return ERR_PTR(error);
nd->last_type = LAST_BIND;
res = inode->i_link;
res = READ_ONCE(inode->i_link);
if (!res) {
const char * (*get)(struct dentry *, struct inode *,
struct delayed_call *);
......@@ -4729,7 +4729,7 @@ int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
spin_unlock(&inode->i_lock);
}
link = inode->i_link;
link = READ_ONCE(inode->i_link);
if (!link) {
link = inode->i_op->get_link(dentry, inode, &done);
if (IS_ERR(link))
......
......@@ -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);
err = fscrypt_prepare_lookup(dir, dentry, flags);
if (err)
return ERR_PTR(err);
err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
err = fscrypt_prepare_lookup(dir, dentry, &nm);
if (err == -ENOENT)
return d_splice_alias(NULL, dentry);
if (err)
return ERR_PTR(err);
......
......@@ -275,7 +275,10 @@ static struct inode *ubifs_alloc_inode(struct super_block *sb)
static void ubifs_free_inode(struct inode *inode)
{
struct ubifs_inode *ui = ubifs_inode(inode);
kfree(ui->data);
fscrypt_free_inode(inode);
kmem_cache_free(ubifs_inode_slab, ui);
}
......
......@@ -211,7 +211,7 @@ struct dentry_operations {
#define DCACHE_MAY_FREE 0x00800000
#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_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */
......
......@@ -33,6 +33,7 @@ struct fscrypt_name {
u32 hash;
u32 minor_hash;
struct fscrypt_str crypto_buf;
bool is_ciphertext_name;
};
#define FSTR_INIT(n, l) { .name = n, .len = l }
......@@ -79,7 +80,8 @@ struct fscrypt_ctx {
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)
......@@ -88,9 +90,21 @@ static inline bool fscrypt_dummy_context_enabled(struct inode *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 */
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 struct page *fscrypt_encrypt_page(const struct inode *, struct page *,
unsigned int, unsigned int,
......@@ -114,6 +128,7 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *,
/* keyinfo.c */
extern int fscrypt_get_encryption_info(struct inode *);
extern void fscrypt_put_encryption_info(struct inode *);
extern void fscrypt_free_inode(struct inode *);
/* fname.c */
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,
/* hooks.c */
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,
struct dentry *old_dentry,
struct inode *new_dir,
struct dentry *new_dentry,
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,
unsigned int max_len,
struct fscrypt_str *disk_link);
......@@ -242,13 +259,16 @@ static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
return false;
}
static inline void fscrypt_handle_d_move(struct dentry *dentry)
{
}
/* crypto.c */
static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work)
{
}
static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode,
gfp_t gfp_flags)
static inline struct fscrypt_ctx *fscrypt_get_ctx(gfp_t gfp_flags)
{
return ERR_PTR(-EOPNOTSUPP);
}
......@@ -322,6 +342,10 @@ static inline void fscrypt_put_encryption_info(struct inode *inode)
return;
}
static inline void fscrypt_free_inode(struct inode *inode)
{
}
/* fname.c */
static inline int fscrypt_setup_filename(struct inode *dir,
const struct qstr *iname,
......@@ -330,7 +354,7 @@ static inline int fscrypt_setup_filename(struct inode *dir,
if (IS_ENCRYPTED(dir))
return -EOPNOTSUPP;
memset(fname, 0, sizeof(struct fscrypt_name));
memset(fname, 0, sizeof(*fname));
fname->usr_fname = iname;
fname->disk_name.name = (unsigned char *)iname->name;
fname->disk_name.len = iname->len;
......@@ -401,8 +425,8 @@ static inline int fscrypt_file_open(struct inode *inode, struct file *filp)
return 0;
}
static inline int __fscrypt_prepare_link(struct inode *inode,
struct inode *dir)
static inline int __fscrypt_prepare_link(struct inode *inode, struct inode *dir,
struct dentry *dentry)
{
return -EOPNOTSUPP;
}
......@@ -417,7 +441,8 @@ static inline int __fscrypt_prepare_rename(struct inode *old_dir,
}
static inline int __fscrypt_prepare_lookup(struct inode *dir,
struct dentry *dentry)
struct dentry *dentry,
struct fscrypt_name *fname)
{
return -EOPNOTSUPP;
}
......@@ -497,7 +522,7 @@ static inline int fscrypt_prepare_link(struct dentry *old_dentry,
struct dentry *dentry)
{
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;
}
......@@ -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
* @dir: directory being searched
* @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
* done with or without the directory's encryption key; without the key,
* Prepare for ->lookup() in a directory which may be encrypted by determining
* 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
* 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
* added later, we also install a custom ->d_revalidate() method and use the
* DCACHE_ENCRYPTED_WITH_KEY flag to indicate whether a given dentry is a
* plaintext name (flag set) or a ciphertext name (flag cleared).
* This also installs a custom ->d_revalidate() method which will invalidate the
* dentry if it was created without the key and the key is later added.
*
* Return: 0 on success, -errno if a problem occurred while setting up the
* encryption key
* Return: 0 on success; -ENOENT if key is unavailable but the filename isn't a
* 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,
struct dentry *dentry,
unsigned int flags)
struct fscrypt_name *fname)
{
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;
}
......
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