Commit 3462ac57 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fscrypt_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt

Pull fscrypt updates from Ted Ts'o:
 "Refactor support for encrypted symlinks to move common code to fscrypt"

Ted also points out about the merge:
 "This makes the f2fs symlink code use the fscrypt_encrypt_symlink()
  from the fscrypt tree. This will end up dropping the kzalloc() ->
  f2fs_kzalloc() change, which means the fscrypt-specific allocation
  won't get tested by f2fs's kmalloc error injection system; which is
  fine"

* tag 'fscrypt_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt: (26 commits)
  fscrypt: fix build with pre-4.6 gcc versions
  fscrypt: remove 'ci' parameter from fscrypt_put_encryption_info()
  fscrypt: document symlink length restriction
  fscrypt: fix up fscrypt_fname_encrypted_size() for internal use
  fscrypt: define fscrypt_fname_alloc_buffer() to be for presented names
  fscrypt: calculate NUL-padding length in one place only
  fscrypt: move fscrypt_symlink_data to fscrypt_private.h
  fscrypt: remove fscrypt_fname_usr_to_disk()
  ubifs: switch to fscrypt_get_symlink()
  ubifs: switch to fscrypt ->symlink() helper functions
  ubifs: free the encrypted symlink target
  f2fs: switch to fscrypt_get_symlink()
  f2fs: switch to fscrypt ->symlink() helper functions
  ext4: switch to fscrypt_get_symlink()
  ext4: switch to fscrypt ->symlink() helper functions
  fscrypt: new helper function - fscrypt_get_symlink()
  fscrypt: new helper functions for ->symlink()
  fscrypt: trim down fscrypt.h includes
  fscrypt: move fscrypt_is_dot_dotdot() to fs/crypto/fname.c
  fscrypt: move fscrypt_valid_enc_modes() to fscrypt_private.h
  ...
parents 617aebe6 0b1dfa4c
...@@ -448,8 +448,14 @@ astute users may notice some differences in behavior: ...@@ -448,8 +448,14 @@ astute users may notice some differences in behavior:
- The st_size of an encrypted symlink will not necessarily give the - The st_size of an encrypted symlink will not necessarily give the
length of the symlink target as required by POSIX. It will actually length of the symlink target as required by POSIX. It will actually
give the length of the ciphertext, which may be slightly longer than give the length of the ciphertext, which will be slightly longer
the plaintext due to the NUL-padding. than the plaintext due to NUL-padding and an extra 2-byte overhead.
- The maximum length of an encrypted symlink is 2 bytes shorter than
the maximum length of an unencrypted symlink. For example, on an
EXT4 filesystem with a 4K block size, unencrypted symlinks can be up
to 4095 bytes long, while encrypted symlinks can only be up to 4093
bytes long (both lengths excluding the terminating null).
Note that mmap *is* supported. This is possible because the pagecache Note that mmap *is* supported. This is possible because the pagecache
for an encrypted file contains the plaintext, not the ciphertext. for an encrypted file contains the plaintext, not the ciphertext.
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/dcache.h> #include <linux/dcache.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <crypto/aes.h> #include <crypto/aes.h>
#include <crypto/skcipher.h>
#include "fscrypt_private.h" #include "fscrypt_private.h"
static unsigned int num_prealloc_crypto_pages = 32; static unsigned int num_prealloc_crypto_pages = 32;
......
...@@ -13,42 +13,46 @@ ...@@ -13,42 +13,46 @@
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <crypto/skcipher.h>
#include "fscrypt_private.h" #include "fscrypt_private.h"
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
{
if (str->len == 1 && str->name[0] == '.')
return true;
if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
return true;
return false;
}
/** /**
* fname_encrypt() - encrypt a filename * fname_encrypt() - encrypt a filename
* *
* The caller must have allocated sufficient memory for the @oname string. * The output buffer must be at least as large as the input buffer.
* Any extra space is filled with NUL padding before encryption.
* *
* Return: 0 on success, -errno on failure * Return: 0 on success, -errno on failure
*/ */
static int fname_encrypt(struct inode *inode, int fname_encrypt(struct inode *inode, const struct qstr *iname,
const struct qstr *iname, struct fscrypt_str *oname) u8 *out, unsigned int olen)
{ {
struct skcipher_request *req = NULL; struct skcipher_request *req = NULL;
DECLARE_CRYPTO_WAIT(wait); DECLARE_CRYPTO_WAIT(wait);
struct fscrypt_info *ci = inode->i_crypt_info; struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm;
struct crypto_skcipher *tfm = ci->ci_ctfm;
int res = 0; int res = 0;
char iv[FS_CRYPTO_BLOCK_SIZE]; char iv[FS_CRYPTO_BLOCK_SIZE];
struct scatterlist sg; struct scatterlist sg;
int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
unsigned int lim;
unsigned int cryptlen;
lim = inode->i_sb->s_cop->max_namelen(inode);
if (iname->len <= 0 || iname->len > lim)
return -EIO;
/* /*
* Copy the filename to the output buffer for encrypting in-place and * Copy the filename to the output buffer for encrypting in-place and
* pad it with the needed number of NUL bytes. * pad it with the needed number of NUL bytes.
*/ */
cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE); if (WARN_ON(olen < iname->len))
cryptlen = round_up(cryptlen, padding); return -ENOBUFS;
cryptlen = min(cryptlen, lim); memcpy(out, iname->name, iname->len);
memcpy(oname->name, iname->name, iname->len); memset(out + iname->len, 0, olen - iname->len);
memset(oname->name + iname->len, 0, cryptlen - iname->len);
/* Initialize the IV */ /* Initialize the IV */
memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
...@@ -63,8 +67,8 @@ static int fname_encrypt(struct inode *inode, ...@@ -63,8 +67,8 @@ static int fname_encrypt(struct inode *inode,
skcipher_request_set_callback(req, skcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &wait); crypto_req_done, &wait);
sg_init_one(&sg, oname->name, cryptlen); sg_init_one(&sg, out, olen);
skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv); skcipher_request_set_crypt(req, &sg, &sg, olen, iv);
/* Do the encryption */ /* Do the encryption */
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
...@@ -75,7 +79,6 @@ static int fname_encrypt(struct inode *inode, ...@@ -75,7 +79,6 @@ static int fname_encrypt(struct inode *inode,
return res; return res;
} }
oname->len = cryptlen;
return 0; return 0;
} }
...@@ -188,50 +191,52 @@ static int digest_decode(const char *src, int len, char *dst) ...@@ -188,50 +191,52 @@ static int digest_decode(const char *src, int len, char *dst)
return cp - dst; return cp - dst;
} }
u32 fscrypt_fname_encrypted_size(const struct inode *inode, u32 ilen) bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
u32 max_len, u32 *encrypted_len_ret)
{ {
int padding = 32; int padding = 4 << (inode->i_crypt_info->ci_flags &
struct fscrypt_info *ci = inode->i_crypt_info; FS_POLICY_FLAGS_PAD_MASK);
u32 encrypted_len;
if (ci)
padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); if (orig_len > max_len)
ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE); return false;
return round_up(ilen, padding); encrypted_len = max(orig_len, (u32)FS_CRYPTO_BLOCK_SIZE);
encrypted_len = round_up(encrypted_len, padding);
*encrypted_len_ret = min(encrypted_len, max_len);
return true;
} }
EXPORT_SYMBOL(fscrypt_fname_encrypted_size);
/** /**
* fscrypt_fname_crypto_alloc_obuff() - * fscrypt_fname_alloc_buffer - allocate a buffer for presented filenames
* *
* Allocates an output buffer that is sufficient for the crypto operation * Allocate a buffer that is large enough to hold any decrypted or encoded
* specified by the context and the direction. * filename (null-terminated), for the given maximum encrypted filename length.
*
* Return: 0 on success, -errno on failure
*/ */
int fscrypt_fname_alloc_buffer(const struct inode *inode, int fscrypt_fname_alloc_buffer(const struct inode *inode,
u32 ilen, struct fscrypt_str *crypto_str) u32 max_encrypted_len,
struct fscrypt_str *crypto_str)
{ {
u32 olen = fscrypt_fname_encrypted_size(inode, ilen);
const u32 max_encoded_len = const u32 max_encoded_len =
max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE), max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE),
1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name))); 1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)));
u32 max_presented_len;
crypto_str->len = olen; max_presented_len = max(max_encoded_len, max_encrypted_len);
olen = max(olen, max_encoded_len);
/* crypto_str->name = kmalloc(max_presented_len + 1, GFP_NOFS);
* Allocated buffer can hold one more character to null-terminate the if (!crypto_str->name)
* string
*/
crypto_str->name = kmalloc(olen + 1, GFP_NOFS);
if (!(crypto_str->name))
return -ENOMEM; return -ENOMEM;
crypto_str->len = max_presented_len;
return 0; return 0;
} }
EXPORT_SYMBOL(fscrypt_fname_alloc_buffer); EXPORT_SYMBOL(fscrypt_fname_alloc_buffer);
/** /**
* fscrypt_fname_crypto_free_buffer() - * fscrypt_fname_free_buffer - free the buffer for presented filenames
* *
* Frees the buffer allocated for crypto operation. * Free the buffer allocated by fscrypt_fname_alloc_buffer().
*/ */
void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str) void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
{ {
...@@ -297,35 +302,6 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, ...@@ -297,35 +302,6 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
} }
EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
/**
* fscrypt_fname_usr_to_disk() - converts a filename from user space to disk
* space
*
* The caller must have allocated sufficient memory for the @oname string.
*
* Return: 0 on success, -errno on failure
*/
int fscrypt_fname_usr_to_disk(struct inode *inode,
const struct qstr *iname,
struct fscrypt_str *oname)
{
if (fscrypt_is_dot_dotdot(iname)) {
oname->name[0] = '.';
oname->name[iname->len - 1] = '.';
oname->len = iname->len;
return 0;
}
if (inode->i_crypt_info)
return fname_encrypt(inode, iname, oname);
/*
* Without a proper key, a user is not allowed to modify the filenames
* in a directory. Consequently, a user space name cannot be mapped to
* a disk-space name
*/
return -ENOKEY;
}
EXPORT_SYMBOL(fscrypt_fname_usr_to_disk);
/** /**
* fscrypt_setup_filename() - prepare to search a possibly encrypted directory * fscrypt_setup_filename() - prepare to search a possibly encrypted directory
* @dir: the directory that will be searched * @dir: the directory that will be searched
...@@ -369,11 +345,17 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, ...@@ -369,11 +345,17 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
return ret; return ret;
if (dir->i_crypt_info) { if (dir->i_crypt_info) {
ret = fscrypt_fname_alloc_buffer(dir, iname->len, if (!fscrypt_fname_encrypted_size(dir, iname->len,
&fname->crypto_buf); dir->i_sb->s_cop->max_namelen(dir),
if (ret) &fname->crypto_buf.len))
return ret; return -ENAMETOOLONG;
ret = fname_encrypt(dir, iname, &fname->crypto_buf); fname->crypto_buf.name = kmalloc(fname->crypto_buf.len,
GFP_NOFS);
if (!fname->crypto_buf.name)
return -ENOMEM;
ret = fname_encrypt(dir, iname, fname->crypto_buf.name,
fname->crypto_buf.len);
if (ret) if (ret)
goto errout; goto errout;
fname->disk_name.name = fname->crypto_buf.name; fname->disk_name.name = fname->crypto_buf.name;
...@@ -425,7 +407,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, ...@@ -425,7 +407,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
return 0; return 0;
errout: errout:
fscrypt_fname_free_buffer(&fname->crypto_buf); kfree(fname->crypto_buf.name);
return ret; return ret;
} }
EXPORT_SYMBOL(fscrypt_setup_filename); EXPORT_SYMBOL(fscrypt_setup_filename);
...@@ -50,6 +50,15 @@ struct fscrypt_context { ...@@ -50,6 +50,15 @@ struct fscrypt_context {
#define FS_ENCRYPTION_CONTEXT_FORMAT_V1 1 #define FS_ENCRYPTION_CONTEXT_FORMAT_V1 1
/**
* For encrypted symlinks, the ciphertext length is stored at the beginning
* of the string in little-endian format.
*/
struct fscrypt_symlink_data {
__le16 len;
char encrypted_path[1];
} __packed;
/* /*
* A pointer to this structure is stored in the file system's in-core * A pointer to this structure is stored in the file system's in-core
* representation of an inode. * representation of an inode.
...@@ -71,7 +80,22 @@ typedef enum { ...@@ -71,7 +80,22 @@ typedef enum {
#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 #define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001
#define FS_CTX_HAS_BOUNCE_BUFFER_FL 0x00000002 #define FS_CTX_HAS_BOUNCE_BUFFER_FL 0x00000002
static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
u32 filenames_mode)
{
if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC &&
filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS)
return true;
if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS &&
filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
return true;
return false;
}
/* crypto.c */ /* crypto.c */
extern struct kmem_cache *fscrypt_info_cachep;
extern int fscrypt_initialize(unsigned int cop_flags); extern int fscrypt_initialize(unsigned int cop_flags);
extern struct workqueue_struct *fscrypt_read_workqueue; extern struct workqueue_struct *fscrypt_read_workqueue;
extern int fscrypt_do_page_crypto(const struct inode *inode, extern int fscrypt_do_page_crypto(const struct inode *inode,
...@@ -83,6 +107,13 @@ extern int fscrypt_do_page_crypto(const struct inode *inode, ...@@ -83,6 +107,13 @@ extern int fscrypt_do_page_crypto(const struct inode *inode,
extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx, extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
gfp_t gfp_flags); gfp_t gfp_flags);
/* fname.c */
extern int fname_encrypt(struct inode *inode, const struct qstr *iname,
u8 *out, unsigned int olen);
extern bool fscrypt_fname_encrypted_size(const struct inode *inode,
u32 orig_len, u32 max_len,
u32 *encrypted_len_ret);
/* keyinfo.c */ /* keyinfo.c */
extern void __exit fscrypt_essiv_cleanup(void); extern void __exit fscrypt_essiv_cleanup(void);
......
...@@ -110,3 +110,161 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry) ...@@ -110,3 +110,161 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup); EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
unsigned int max_len,
struct fscrypt_str *disk_link)
{
int err;
/*
* To calculate the size of the encrypted symlink target we need to know
* the amount of NUL padding, which is determined by the flags set in
* the encryption policy which will be inherited from the directory.
* The easiest way to get access to this is to just load the directory's
* fscrypt_info, since we'll need it to create the dir_entry anyway.
*
* Note: in test_dummy_encryption mode, @dir may be unencrypted.
*/
err = fscrypt_get_encryption_info(dir);
if (err)
return err;
if (!fscrypt_has_encryption_key(dir))
return -ENOKEY;
/*
* Calculate the size of the encrypted symlink and verify it won't
* exceed max_len. Note that for historical reasons, encrypted symlink
* targets are prefixed with the ciphertext length, despite this
* actually being redundant with i_size. This decreases by 2 bytes the
* longest symlink target we can accept.
*
* We could recover 1 byte by not counting a null terminator, but
* counting it (even though it is meaningless for ciphertext) is simpler
* for now since filesystems will assume it is there and subtract it.
*/
if (!fscrypt_fname_encrypted_size(dir, len,
max_len - sizeof(struct fscrypt_symlink_data),
&disk_link->len))
return -ENAMETOOLONG;
disk_link->len += sizeof(struct fscrypt_symlink_data);
disk_link->name = NULL;
return 0;
}
EXPORT_SYMBOL_GPL(__fscrypt_prepare_symlink);
int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
unsigned int len, struct fscrypt_str *disk_link)
{
int err;
struct qstr iname = QSTR_INIT(target, len);
struct fscrypt_symlink_data *sd;
unsigned int ciphertext_len;
err = fscrypt_require_key(inode);
if (err)
return err;
if (disk_link->name) {
/* filesystem-provided buffer */
sd = (struct fscrypt_symlink_data *)disk_link->name;
} else {
sd = kmalloc(disk_link->len, GFP_NOFS);
if (!sd)
return -ENOMEM;
}
ciphertext_len = disk_link->len - sizeof(*sd);
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;
}
/*
* Null-terminating the ciphertext doesn't make sense, but we still
* count the null terminator in the length, so we might as well
* initialize it just in case the filesystem writes it out.
*/
sd->encrypted_path[ciphertext_len] = '\0';
if (!disk_link->name)
disk_link->name = (unsigned char *)sd;
return 0;
}
EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink);
/**
* fscrypt_get_symlink - get the target of an encrypted 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
*
* If the symlink's encryption key is available, we decrypt its target.
* Otherwise, we encode its target for presentation.
*
* This may sleep, so the filesystem must have dropped out of RCU mode already.
*
* Return: the presentable symlink target or an ERR_PTR()
*/
const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
unsigned int max_size,
struct delayed_call *done)
{
const struct fscrypt_symlink_data *sd;
struct fscrypt_str cstr, pstr;
int err;
/* This is for encrypted symlinks only */
if (WARN_ON(!IS_ENCRYPTED(inode)))
return ERR_PTR(-EINVAL);
/*
* Try to set up the symlink's encryption key, but we can continue
* regardless of whether the key is available or not.
*/
err = fscrypt_get_encryption_info(inode);
if (err)
return ERR_PTR(err);
/*
* For historical reasons, encrypted symlink targets are prefixed with
* the ciphertext length, even though this is redundant with i_size.
*/
if (max_size < sizeof(*sd))
return ERR_PTR(-EUCLEAN);
sd = caddr;
cstr.name = (unsigned char *)sd->encrypted_path;
cstr.len = le16_to_cpu(sd->len);
if (cstr.len == 0)
return ERR_PTR(-EUCLEAN);
if (cstr.len + sizeof(*sd) - 1 > max_size)
return ERR_PTR(-EUCLEAN);
err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
if (err)
return ERR_PTR(err);
err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
if (err)
goto err_kfree;
err = -EUCLEAN;
if (pstr.name[0] == '\0')
goto err_kfree;
pstr.name[pstr.len] = '\0';
set_delayed_call(done, kfree_link, pstr.name);
return pstr.name;
err_kfree:
kfree(pstr.name);
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(fscrypt_get_symlink);
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <crypto/aes.h> #include <crypto/aes.h>
#include <crypto/sha.h> #include <crypto/sha.h>
#include <crypto/skcipher.h>
#include "fscrypt_private.h" #include "fscrypt_private.h"
static struct crypto_shash *essiv_hash_tfm; static struct crypto_shash *essiv_hash_tfm;
...@@ -354,19 +355,9 @@ int fscrypt_get_encryption_info(struct inode *inode) ...@@ -354,19 +355,9 @@ int fscrypt_get_encryption_info(struct inode *inode)
} }
EXPORT_SYMBOL(fscrypt_get_encryption_info); EXPORT_SYMBOL(fscrypt_get_encryption_info);
void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci) void fscrypt_put_encryption_info(struct inode *inode)
{ {
struct fscrypt_info *prev; put_crypt_info(inode->i_crypt_info);
inode->i_crypt_info = NULL;
if (ci == NULL)
ci = READ_ONCE(inode->i_crypt_info);
if (ci == NULL)
return;
prev = cmpxchg(&inode->i_crypt_info, ci, NULL);
if (prev != ci)
return;
put_crypt_info(ci);
} }
EXPORT_SYMBOL(fscrypt_put_encryption_info); EXPORT_SYMBOL(fscrypt_put_encryption_info);
...@@ -3057,39 +3057,19 @@ static int ext4_symlink(struct inode *dir, ...@@ -3057,39 +3057,19 @@ static int ext4_symlink(struct inode *dir,
struct inode *inode; struct inode *inode;
int err, len = strlen(symname); int err, len = strlen(symname);
int credits; int credits;
bool encryption_required;
struct fscrypt_str disk_link; struct fscrypt_str disk_link;
struct fscrypt_symlink_data *sd = NULL;
if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb)))) if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
return -EIO; return -EIO;
disk_link.len = len + 1; err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
disk_link.name = (char *) symname; &disk_link);
encryption_required = (ext4_encrypted_inode(dir) ||
DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)));
if (encryption_required) {
err = fscrypt_get_encryption_info(dir);
if (err) if (err)
return err; return err;
if (!fscrypt_has_encryption_key(dir))
return -ENOKEY;
disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
sizeof(struct fscrypt_symlink_data));
sd = kzalloc(disk_link.len, GFP_KERNEL);
if (!sd)
return -ENOMEM;
}
if (disk_link.len > dir->i_sb->s_blocksize) {
err = -ENAMETOOLONG;
goto err_free_sd;
}
err = dquot_initialize(dir); err = dquot_initialize(dir);
if (err) if (err)
goto err_free_sd; return err;
if ((disk_link.len > EXT4_N_BLOCKS * 4)) { if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
/* /*
...@@ -3118,27 +3098,18 @@ static int ext4_symlink(struct inode *dir, ...@@ -3118,27 +3098,18 @@ static int ext4_symlink(struct inode *dir,
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
if (handle) if (handle)
ext4_journal_stop(handle); ext4_journal_stop(handle);
err = PTR_ERR(inode); return PTR_ERR(inode);
goto err_free_sd;
} }
if (encryption_required) { if (IS_ENCRYPTED(inode)) {
struct qstr istr; err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
struct fscrypt_str ostr =
FSTR_INIT(sd->encrypted_path, disk_link.len);
istr.name = (const unsigned char *) symname;
istr.len = len;
err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
if (err) if (err)
goto err_drop_inode; goto err_drop_inode;
sd->len = cpu_to_le16(ostr.len);
disk_link.name = (char *) sd;
inode->i_op = &ext4_encrypted_symlink_inode_operations; inode->i_op = &ext4_encrypted_symlink_inode_operations;
} }
if ((disk_link.len > EXT4_N_BLOCKS * 4)) { if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
if (!encryption_required) if (!IS_ENCRYPTED(inode))
inode->i_op = &ext4_symlink_inode_operations; inode->i_op = &ext4_symlink_inode_operations;
inode_nohighmem(inode); inode_nohighmem(inode);
ext4_set_aops(inode); ext4_set_aops(inode);
...@@ -3180,7 +3151,7 @@ static int ext4_symlink(struct inode *dir, ...@@ -3180,7 +3151,7 @@ static int ext4_symlink(struct inode *dir,
} else { } else {
/* clear the extent format for fast symlink */ /* clear the extent format for fast symlink */
ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
if (!encryption_required) { if (!IS_ENCRYPTED(inode)) {
inode->i_op = &ext4_fast_symlink_inode_operations; inode->i_op = &ext4_fast_symlink_inode_operations;
inode->i_link = (char *)&EXT4_I(inode)->i_data; inode->i_link = (char *)&EXT4_I(inode)->i_data;
} }
...@@ -3195,16 +3166,17 @@ static int ext4_symlink(struct inode *dir, ...@@ -3195,16 +3166,17 @@ static int ext4_symlink(struct inode *dir,
if (handle) if (handle)
ext4_journal_stop(handle); ext4_journal_stop(handle);
kfree(sd); goto out_free_encrypted_link;
return err;
err_drop_inode: err_drop_inode:
if (handle) if (handle)
ext4_journal_stop(handle); ext4_journal_stop(handle);
clear_nlink(inode); clear_nlink(inode);
unlock_new_inode(inode); unlock_new_inode(inode);
iput(inode); iput(inode);
err_free_sd: out_free_encrypted_link:
kfree(sd); if (disk_link.name != (unsigned char *)symname)
kfree(disk_link.name);
return err; return err;
} }
......
...@@ -1073,9 +1073,7 @@ void ext4_clear_inode(struct inode *inode) ...@@ -1073,9 +1073,7 @@ void ext4_clear_inode(struct inode *inode)
jbd2_free_inode(EXT4_I(inode)->jinode); jbd2_free_inode(EXT4_I(inode)->jinode);
EXT4_I(inode)->jinode = NULL; EXT4_I(inode)->jinode = NULL;
} }
#ifdef CONFIG_EXT4_FS_ENCRYPTION fscrypt_put_encryption_info(inode);
fscrypt_put_encryption_info(inode, NULL);
#endif
} }
static struct inode *ext4_nfs_get_inode(struct super_block *sb, static struct inode *ext4_nfs_get_inode(struct super_block *sb,
......
...@@ -28,59 +28,28 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry, ...@@ -28,59 +28,28 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry,
struct delayed_call *done) struct delayed_call *done)
{ {
struct page *cpage = NULL; struct page *cpage = NULL;
char *caddr, *paddr = NULL; const void *caddr;
struct fscrypt_str cstr, pstr; unsigned int max_size;
struct fscrypt_symlink_data *sd; const char *paddr;
int res;
u32 max_size = inode->i_sb->s_blocksize;
if (!dentry) if (!dentry)
return ERR_PTR(-ECHILD); return ERR_PTR(-ECHILD);
res = fscrypt_get_encryption_info(inode);
if (res)
return ERR_PTR(res);
if (ext4_inode_is_fast_symlink(inode)) { if (ext4_inode_is_fast_symlink(inode)) {
caddr = (char *) EXT4_I(inode)->i_data; caddr = EXT4_I(inode)->i_data;
max_size = sizeof(EXT4_I(inode)->i_data); max_size = sizeof(EXT4_I(inode)->i_data);
} else { } else {
cpage = read_mapping_page(inode->i_mapping, 0, NULL); cpage = read_mapping_page(inode->i_mapping, 0, NULL);
if (IS_ERR(cpage)) if (IS_ERR(cpage))
return ERR_CAST(cpage); return ERR_CAST(cpage);
caddr = page_address(cpage); caddr = page_address(cpage);
max_size = inode->i_sb->s_blocksize;
} }
/* Symlink is encrypted */ paddr = fscrypt_get_symlink(inode, caddr, max_size, done);
sd = (struct fscrypt_symlink_data *)caddr;
cstr.name = sd->encrypted_path;
cstr.len = le16_to_cpu(sd->len);
if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) {
/* Symlink data on the disk is corrupted */
res = -EFSCORRUPTED;
goto errout;
}
res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
if (res)
goto errout;
paddr = pstr.name;
res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
if (res)
goto errout;
/* Null-terminate the name */
paddr[pstr.len] = '\0';
if (cpage) if (cpage)
put_page(cpage); put_page(cpage);
set_delayed_call(done, kfree_link, paddr);
return paddr; return paddr;
errout:
if (cpage)
put_page(cpage);
kfree(paddr);
return ERR_PTR(res);
} }
const struct inode_operations ext4_encrypted_symlink_inode_operations = { const struct inode_operations ext4_encrypted_symlink_inode_operations = {
......
...@@ -585,7 +585,7 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -585,7 +585,7 @@ void f2fs_evict_inode(struct inode *inode)
!exist_written_data(sbi, inode->i_ino, ORPHAN_INO)); !exist_written_data(sbi, inode->i_ino, ORPHAN_INO));
} }
out_clear: out_clear:
fscrypt_put_encryption_info(inode, NULL); fscrypt_put_encryption_info(inode);
clear_inode(inode); clear_inode(inode);
} }
......
...@@ -486,28 +486,17 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -486,28 +486,17 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
struct inode *inode; struct inode *inode;
size_t len = strlen(symname); size_t len = strlen(symname);
struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1); struct fscrypt_str disk_link;
struct fscrypt_symlink_data *sd = NULL;
int err; int err;
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return -EIO; return -EIO;
if (f2fs_encrypted_inode(dir)) { err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
err = fscrypt_get_encryption_info(dir); &disk_link);
if (err) if (err)
return err; return err;
if (!fscrypt_has_encryption_key(dir))
return -ENOKEY;
disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
sizeof(struct fscrypt_symlink_data));
}
if (disk_link.len > dir->i_sb->s_blocksize)
return -ENAMETOOLONG;
err = dquot_initialize(dir); err = dquot_initialize(dir);
if (err) if (err)
return err; return err;
...@@ -516,7 +505,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -516,7 +505,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
if (f2fs_encrypted_inode(inode)) if (IS_ENCRYPTED(inode))
inode->i_op = &f2fs_encrypted_symlink_inode_operations; inode->i_op = &f2fs_encrypted_symlink_inode_operations;
else else
inode->i_op = &f2fs_symlink_inode_operations; inode->i_op = &f2fs_symlink_inode_operations;
...@@ -526,39 +515,14 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -526,39 +515,14 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode); err = f2fs_add_link(dentry, inode);
if (err) if (err)
goto out; goto out_handle_failed_inode;
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
alloc_nid_done(sbi, inode->i_ino); alloc_nid_done(sbi, inode->i_ino);
if (f2fs_encrypted_inode(inode)) { err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
struct qstr istr = QSTR_INIT(symname, len);
struct fscrypt_str ostr;
sd = f2fs_kzalloc(sbi, disk_link.len, GFP_NOFS);
if (!sd) {
err = -ENOMEM;
goto err_out;
}
err = fscrypt_get_encryption_info(inode);
if (err) if (err)
goto err_out; goto err_out;
if (!fscrypt_has_encryption_key(inode)) {
err = -ENOKEY;
goto err_out;
}
ostr.name = sd->encrypted_path;
ostr.len = disk_link.len;
err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
if (err)
goto err_out;
sd->len = cpu_to_le16(ostr.len);
disk_link.name = (char *)sd;
}
err = page_symlink(inode, disk_link.name, disk_link.len); err = page_symlink(inode, disk_link.name, disk_link.len);
err_out: err_out:
...@@ -584,12 +548,14 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -584,12 +548,14 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
f2fs_unlink(dir, dentry); f2fs_unlink(dir, dentry);
} }
kfree(sd);
f2fs_balance_fs(sbi, true); f2fs_balance_fs(sbi, true);
return err; goto out_free_encrypted_link;
out:
out_handle_failed_inode:
handle_failed_inode(inode); handle_failed_inode(inode);
out_free_encrypted_link:
if (disk_link.name != (unsigned char *)symname)
kfree(disk_link.name);
return err; return err;
} }
...@@ -1148,68 +1114,20 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, ...@@ -1148,68 +1114,20 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
struct inode *inode, struct inode *inode,
struct delayed_call *done) struct delayed_call *done)
{ {
struct page *cpage = NULL; struct page *page;
char *caddr, *paddr = NULL; const char *target;
struct fscrypt_str cstr = FSTR_INIT(NULL, 0);
struct fscrypt_str pstr = FSTR_INIT(NULL, 0);
struct fscrypt_symlink_data *sd;
u32 max_size = inode->i_sb->s_blocksize;
int res;
if (!dentry) if (!dentry)
return ERR_PTR(-ECHILD); return ERR_PTR(-ECHILD);
res = fscrypt_get_encryption_info(inode); page = read_mapping_page(inode->i_mapping, 0, NULL);
if (res) if (IS_ERR(page))
return ERR_PTR(res); return ERR_CAST(page);
cpage = read_mapping_page(inode->i_mapping, 0, NULL);
if (IS_ERR(cpage))
return ERR_CAST(cpage);
caddr = page_address(cpage);
/* Symlink is encrypted */
sd = (struct fscrypt_symlink_data *)caddr;
cstr.name = sd->encrypted_path;
cstr.len = le16_to_cpu(sd->len);
/* this is broken symlink case */
if (unlikely(cstr.len == 0)) {
res = -ENOENT;
goto errout;
}
if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) {
/* Symlink data on the disk is corrupted */
res = -EIO;
goto errout;
}
res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
if (res)
goto errout;
res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
if (res)
goto errout;
/* this is broken symlink case */
if (unlikely(pstr.name[0] == 0)) {
res = -ENOENT;
goto errout;
}
paddr = pstr.name;
/* Null-terminate the name */
paddr[pstr.len] = '\0';
put_page(cpage); target = fscrypt_get_symlink(inode, page_address(page),
set_delayed_call(done, kfree_link, paddr); inode->i_sb->s_blocksize, done);
return paddr; put_page(page);
errout: return target;
fscrypt_fname_free_buffer(&pstr);
put_page(cpage);
return ERR_PTR(res);
} }
const struct inode_operations f2fs_encrypted_symlink_inode_operations = { const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
......
...@@ -1138,38 +1138,24 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1138,38 +1138,24 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
int err, len = strlen(symname); int err, len = strlen(symname);
int sz_change = CALC_DENT_SIZE(len); int sz_change = CALC_DENT_SIZE(len);
struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1); struct fscrypt_str disk_link;
struct fscrypt_symlink_data *sd = NULL;
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
.new_ino_d = ALIGN(len, 8), .new_ino_d = ALIGN(len, 8),
.dirtied_ino = 1 }; .dirtied_ino = 1 };
struct fscrypt_name nm; struct fscrypt_name nm;
if (ubifs_crypt_is_encrypted(dir)) { dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry,
err = fscrypt_get_encryption_info(dir); symname, dir->i_ino);
if (err)
goto out_budg;
if (!fscrypt_has_encryption_key(dir)) {
err = -EPERM;
goto out_budg;
}
disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + err = fscrypt_prepare_symlink(dir, symname, len, UBIFS_MAX_INO_DATA,
sizeof(struct fscrypt_symlink_data)); &disk_link);
} if (err)
return err;
/* /*
* Budget request settings: new inode, new direntry and changing parent * Budget request settings: new inode, new direntry and changing parent
* directory inode. * directory inode.
*/ */
dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry,
symname, dir->i_ino);
if (disk_link.len > UBIFS_MAX_INO_DATA)
return -ENAMETOOLONG;
err = ubifs_budget_space(c, &req); err = ubifs_budget_space(c, &req);
if (err) if (err)
return err; return err;
...@@ -1191,38 +1177,20 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1191,38 +1177,20 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
goto out_inode; goto out_inode;
} }
if (ubifs_crypt_is_encrypted(dir)) { if (IS_ENCRYPTED(inode)) {
struct qstr istr = QSTR_INIT(symname, len); disk_link.name = ui->data; /* encrypt directly into ui->data */
struct fscrypt_str ostr; err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
if (err)
sd = kzalloc(disk_link.len, GFP_NOFS);
if (!sd) {
err = -ENOMEM;
goto out_inode;
}
ostr.name = sd->encrypted_path;
ostr.len = disk_link.len;
err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
if (err) {
kfree(sd);
goto out_inode; goto out_inode;
}
sd->len = cpu_to_le16(ostr.len);
disk_link.name = (char *)sd;
} else { } else {
memcpy(ui->data, disk_link.name, disk_link.len);
inode->i_link = ui->data; inode->i_link = ui->data;
} }
memcpy(ui->data, disk_link.name, disk_link.len);
((char *)ui->data)[disk_link.len - 1] = '\0';
/* /*
* The terminating zero byte is not written to the flash media and it * The terminating zero byte is not written to the flash media and it
* is put just to make later in-memory string processing simpler. Thus, * is put just to make later in-memory string processing simpler. Thus,
* data length is @len, not @len + %1. * data length is @disk_link.len - 1, not @disk_link.len.
*/ */
ui->data_len = disk_link.len - 1; ui->data_len = disk_link.len - 1;
inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1; inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1;
...@@ -1240,11 +1208,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1240,11 +1208,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
goto out_cancel; goto out_cancel;
mutex_unlock(&dir_ui->ui_mutex); mutex_unlock(&dir_ui->ui_mutex);
ubifs_release_budget(c, &req);
insert_inode_hash(inode); insert_inode_hash(inode);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
fscrypt_free_filename(&nm); err = 0;
return 0; goto out_fname;
out_cancel: out_cancel:
dir->i_size -= sz_change; dir->i_size -= sz_change;
......
...@@ -1629,49 +1629,17 @@ static const char *ubifs_get_link(struct dentry *dentry, ...@@ -1629,49 +1629,17 @@ static const char *ubifs_get_link(struct dentry *dentry,
struct inode *inode, struct inode *inode,
struct delayed_call *done) struct delayed_call *done)
{ {
int err;
struct fscrypt_symlink_data *sd;
struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *ui = ubifs_inode(inode);
struct fscrypt_str cstr;
struct fscrypt_str pstr;
if (!ubifs_crypt_is_encrypted(inode)) if (!IS_ENCRYPTED(inode))
return ui->data; return ui->data;
if (!dentry) if (!dentry)
return ERR_PTR(-ECHILD); return ERR_PTR(-ECHILD);
err = fscrypt_get_encryption_info(inode); return fscrypt_get_symlink(inode, ui->data, ui->data_len, done);
if (err)
return ERR_PTR(err);
sd = (struct fscrypt_symlink_data *)ui->data;
cstr.name = sd->encrypted_path;
cstr.len = le16_to_cpu(sd->len);
if (cstr.len == 0)
return ERR_PTR(-ENOENT);
if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > ui->data_len)
return ERR_PTR(-EIO);
err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
if (err)
return ERR_PTR(err);
err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
if (err) {
fscrypt_fname_free_buffer(&pstr);
return ERR_PTR(err);
}
pstr.name[pstr.len] = '\0';
set_delayed_call(done, kfree_link, pstr.name);
return pstr.name;
} }
const struct address_space_operations ubifs_file_address_operations = { const struct address_space_operations ubifs_file_address_operations = {
.readpage = ubifs_readpage, .readpage = ubifs_readpage,
.writepage = ubifs_writepage, .writepage = ubifs_writepage,
......
...@@ -379,9 +379,7 @@ static void ubifs_evict_inode(struct inode *inode) ...@@ -379,9 +379,7 @@ static void ubifs_evict_inode(struct inode *inode)
} }
done: done:
clear_inode(inode); clear_inode(inode);
#ifdef CONFIG_UBIFS_FS_ENCRYPTION fscrypt_put_encryption_info(inode);
fscrypt_put_encryption_info(inode, NULL);
#endif
} }
static void ubifs_dirty_inode(struct inode *inode, int flags) static void ubifs_dirty_inode(struct inode *inode, int flags)
......
...@@ -14,42 +14,13 @@ ...@@ -14,42 +14,13 @@
#ifndef _LINUX_FSCRYPT_H #ifndef _LINUX_FSCRYPT_H
#define _LINUX_FSCRYPT_H #define _LINUX_FSCRYPT_H
#include <linux/key.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/mm.h>
#include <linux/bio.h>
#include <linux/dcache.h>
#include <crypto/skcipher.h>
#include <uapi/linux/fs.h>
#define FS_CRYPTO_BLOCK_SIZE 16 #define FS_CRYPTO_BLOCK_SIZE 16
struct fscrypt_ctx;
struct fscrypt_info; struct fscrypt_info;
struct fscrypt_ctx {
union {
struct {
struct page *bounce_page; /* Ciphertext page */
struct page *control_page; /* Original page */
} w;
struct {
struct bio *bio;
struct work_struct work;
} r;
struct list_head free_list; /* Free list */
};
u8 flags; /* Flags */
};
/**
* For encrypted symlinks, the ciphertext length is stored at the beginning
* of the string in little-endian format.
*/
struct fscrypt_symlink_data {
__le16 len;
char encrypted_path[1];
} __packed;
struct fscrypt_str { struct fscrypt_str {
unsigned char *name; unsigned char *name;
u32 len; u32 len;
...@@ -68,89 +39,14 @@ struct fscrypt_name { ...@@ -68,89 +39,14 @@ struct fscrypt_name {
#define fname_name(p) ((p)->disk_name.name) #define fname_name(p) ((p)->disk_name.name)
#define fname_len(p) ((p)->disk_name.len) #define fname_len(p) ((p)->disk_name.len)
/*
* fscrypt superblock flags
*/
#define FS_CFLG_OWN_PAGES (1U << 1)
/*
* crypto opertions for filesystems
*/
struct fscrypt_operations {
unsigned int flags;
const char *key_prefix;
int (*get_context)(struct inode *, void *, size_t);
int (*set_context)(struct inode *, const void *, size_t, void *);
bool (*dummy_context)(struct inode *);
bool (*empty_dir)(struct inode *);
unsigned (*max_namelen)(struct inode *);
};
/* Maximum value for the third parameter of fscrypt_operations.set_context(). */ /* Maximum value for the third parameter of fscrypt_operations.set_context(). */
#define FSCRYPT_SET_CONTEXT_MAX_SIZE 28 #define FSCRYPT_SET_CONTEXT_MAX_SIZE 28
static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
{
if (inode->i_sb->s_cop->dummy_context &&
inode->i_sb->s_cop->dummy_context(inode))
return true;
return false;
}
static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
u32 filenames_mode)
{
if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC &&
filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS)
return true;
if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS &&
filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
return true;
return false;
}
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
{
if (str->len == 1 && str->name[0] == '.')
return true;
if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
return true;
return false;
}
#if __FS_HAS_ENCRYPTION #if __FS_HAS_ENCRYPTION
static inline struct page *fscrypt_control_page(struct page *page)
{
return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
}
static inline bool fscrypt_has_encryption_key(const struct inode *inode)
{
return (inode->i_crypt_info != NULL);
}
#include <linux/fscrypt_supp.h> #include <linux/fscrypt_supp.h>
#else
#else /* !__FS_HAS_ENCRYPTION */
static inline struct page *fscrypt_control_page(struct page *page)
{
WARN_ON_ONCE(1);
return ERR_PTR(-EINVAL);
}
static inline bool fscrypt_has_encryption_key(const struct inode *inode)
{
return 0;
}
#include <linux/fscrypt_notsupp.h> #include <linux/fscrypt_notsupp.h>
#endif /* __FS_HAS_ENCRYPTION */ #endif
/** /**
* fscrypt_require_key - require an inode's encryption key * fscrypt_require_key - require an inode's encryption key
...@@ -291,4 +187,68 @@ static inline int fscrypt_prepare_setattr(struct dentry *dentry, ...@@ -291,4 +187,68 @@ static inline int fscrypt_prepare_setattr(struct dentry *dentry,
return 0; return 0;
} }
/**
* fscrypt_prepare_symlink - prepare to create a possibly-encrypted symlink
* @dir: directory in which the symlink is being created
* @target: plaintext symlink target
* @len: length of @target excluding null terminator
* @max_len: space the filesystem has available to store the symlink target
* @disk_link: (out) the on-disk symlink target being prepared
*
* This function computes the size the symlink target will require on-disk,
* stores it in @disk_link->len, and validates it against @max_len. An
* encrypted symlink may be longer than the original.
*
* Additionally, @disk_link->name is set to @target if the symlink will be
* unencrypted, but left NULL if the symlink will be encrypted. For encrypted
* symlinks, the filesystem must call fscrypt_encrypt_symlink() to create the
* on-disk target later. (The reason for the two-step process is that some
* filesystems need to know the size of the symlink target before creating the
* inode, e.g. to determine whether it will be a "fast" or "slow" symlink.)
*
* Return: 0 on success, -ENAMETOOLONG if the symlink target is too long,
* -ENOKEY if the encryption key is missing, or another -errno code if a problem
* occurred while setting up the encryption key.
*/
static inline int fscrypt_prepare_symlink(struct inode *dir,
const char *target,
unsigned int len,
unsigned int max_len,
struct fscrypt_str *disk_link)
{
if (IS_ENCRYPTED(dir) || fscrypt_dummy_context_enabled(dir))
return __fscrypt_prepare_symlink(dir, len, max_len, disk_link);
disk_link->name = (unsigned char *)target;
disk_link->len = len + 1;
if (disk_link->len > max_len)
return -ENAMETOOLONG;
return 0;
}
/**
* fscrypt_encrypt_symlink - encrypt the symlink target if needed
* @inode: symlink inode
* @target: plaintext symlink target
* @len: length of @target excluding null terminator
* @disk_link: (in/out) the on-disk symlink target being prepared
*
* If the symlink target needs to be encrypted, then this function encrypts it
* into @disk_link->name. fscrypt_prepare_symlink() must have been called
* previously to compute @disk_link->len. If the filesystem did not allocate a
* buffer for @disk_link->name after calling fscrypt_prepare_link(), then one
* will be kmalloc()'ed and the filesystem will be responsible for freeing it.
*
* Return: 0 on success, -errno on failure
*/
static inline int fscrypt_encrypt_symlink(struct inode *inode,
const char *target,
unsigned int len,
struct fscrypt_str *disk_link)
{
if (IS_ENCRYPTED(inode))
return __fscrypt_encrypt_symlink(inode, target, len, disk_link);
return 0;
}
#endif /* _LINUX_FSCRYPT_H */ #endif /* _LINUX_FSCRYPT_H */
...@@ -14,6 +14,16 @@ ...@@ -14,6 +14,16 @@
#ifndef _LINUX_FSCRYPT_NOTSUPP_H #ifndef _LINUX_FSCRYPT_NOTSUPP_H
#define _LINUX_FSCRYPT_NOTSUPP_H #define _LINUX_FSCRYPT_NOTSUPP_H
static inline bool fscrypt_has_encryption_key(const struct inode *inode)
{
return false;
}
static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
{
return false;
}
/* crypto.c */ /* crypto.c */
static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode,
gfp_t gfp_flags) gfp_t gfp_flags)
...@@ -43,6 +53,11 @@ static inline int fscrypt_decrypt_page(const struct inode *inode, ...@@ -43,6 +53,11 @@ static inline int fscrypt_decrypt_page(const struct inode *inode,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline struct page *fscrypt_control_page(struct page *page)
{
WARN_ON_ONCE(1);
return ERR_PTR(-EINVAL);
}
static inline void fscrypt_restore_control_page(struct page *page) static inline void fscrypt_restore_control_page(struct page *page)
{ {
...@@ -90,8 +105,7 @@ static inline int fscrypt_get_encryption_info(struct inode *inode) ...@@ -90,8 +105,7 @@ static inline int fscrypt_get_encryption_info(struct inode *inode)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline void fscrypt_put_encryption_info(struct inode *inode, static inline void fscrypt_put_encryption_info(struct inode *inode)
struct fscrypt_info *ci)
{ {
return; return;
} }
...@@ -116,16 +130,8 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname) ...@@ -116,16 +130,8 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname)
return; return;
} }
static inline u32 fscrypt_fname_encrypted_size(const struct inode *inode,
u32 ilen)
{
/* never happens */
WARN_ON(1);
return 0;
}
static inline int fscrypt_fname_alloc_buffer(const struct inode *inode, static inline int fscrypt_fname_alloc_buffer(const struct inode *inode,
u32 ilen, u32 max_encrypted_len,
struct fscrypt_str *crypto_str) struct fscrypt_str *crypto_str)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -144,13 +150,6 @@ static inline int fscrypt_fname_disk_to_usr(struct inode *inode, ...@@ -144,13 +150,6 @@ static inline int fscrypt_fname_disk_to_usr(struct inode *inode,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline int fscrypt_fname_usr_to_disk(struct inode *inode,
const struct qstr *iname,
struct fscrypt_str *oname)
{
return -EOPNOTSUPP;
}
static inline bool fscrypt_match_name(const struct fscrypt_name *fname, static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
const u8 *de_name, u32 de_name_len) const u8 *de_name, u32 de_name_len)
{ {
...@@ -208,4 +207,28 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir, ...@@ -208,4 +207,28 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline int __fscrypt_prepare_symlink(struct inode *dir,
unsigned int len,
unsigned int max_len,
struct fscrypt_str *disk_link)
{
return -EOPNOTSUPP;
}
static inline int __fscrypt_encrypt_symlink(struct inode *inode,
const char *target,
unsigned int len,
struct fscrypt_str *disk_link)
{
return -EOPNOTSUPP;
}
static inline const char *fscrypt_get_symlink(struct inode *inode,
const void *caddr,
unsigned int max_size,
struct delayed_call *done)
{
return ERR_PTR(-EOPNOTSUPP);
}
#endif /* _LINUX_FSCRYPT_NOTSUPP_H */ #endif /* _LINUX_FSCRYPT_NOTSUPP_H */
...@@ -11,8 +11,54 @@ ...@@ -11,8 +11,54 @@
#ifndef _LINUX_FSCRYPT_SUPP_H #ifndef _LINUX_FSCRYPT_SUPP_H
#define _LINUX_FSCRYPT_SUPP_H #define _LINUX_FSCRYPT_SUPP_H
#include <linux/mm.h>
#include <linux/slab.h>
/*
* fscrypt superblock flags
*/
#define FS_CFLG_OWN_PAGES (1U << 1)
/*
* crypto operations for filesystems
*/
struct fscrypt_operations {
unsigned int flags;
const char *key_prefix;
int (*get_context)(struct inode *, void *, size_t);
int (*set_context)(struct inode *, const void *, size_t, void *);
bool (*dummy_context)(struct inode *);
bool (*empty_dir)(struct inode *);
unsigned (*max_namelen)(struct inode *);
};
struct fscrypt_ctx {
union {
struct {
struct page *bounce_page; /* Ciphertext page */
struct page *control_page; /* Original page */
} w;
struct {
struct bio *bio;
struct work_struct work;
} r;
struct list_head free_list; /* Free list */
};
u8 flags; /* Flags */
};
static inline bool fscrypt_has_encryption_key(const struct inode *inode)
{
return (inode->i_crypt_info != NULL);
}
static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
{
return inode->i_sb->s_cop->dummy_context &&
inode->i_sb->s_cop->dummy_context(inode);
}
/* crypto.c */ /* crypto.c */
extern struct kmem_cache *fscrypt_info_cachep;
extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t); extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, 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 *,
...@@ -20,6 +66,12 @@ extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, ...@@ -20,6 +66,12 @@ extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *,
u64, gfp_t); u64, gfp_t);
extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int, extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int,
unsigned int, u64); unsigned int, u64);
static inline struct page *fscrypt_control_page(struct page *page)
{
return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
}
extern void fscrypt_restore_control_page(struct page *); extern void fscrypt_restore_control_page(struct page *);
extern const struct dentry_operations fscrypt_d_ops; extern const struct dentry_operations fscrypt_d_ops;
...@@ -44,7 +96,7 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *, ...@@ -44,7 +96,7 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *,
void *, bool); void *, bool);
/* 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 *, struct fscrypt_info *); extern void fscrypt_put_encryption_info(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 *,
...@@ -55,14 +107,11 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname) ...@@ -55,14 +107,11 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname)
kfree(fname->crypto_buf.name); kfree(fname->crypto_buf.name);
} }
extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32);
extern int fscrypt_fname_alloc_buffer(const struct inode *, u32, extern int fscrypt_fname_alloc_buffer(const struct inode *, u32,
struct fscrypt_str *); struct fscrypt_str *);
extern void fscrypt_fname_free_buffer(struct fscrypt_str *); extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32, extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
const struct fscrypt_str *, struct fscrypt_str *); const struct fscrypt_str *, struct fscrypt_str *);
extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
struct fscrypt_str *);
#define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE 32 #define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE 32
...@@ -153,5 +202,14 @@ extern int __fscrypt_prepare_rename(struct inode *old_dir, ...@@ -153,5 +202,14 @@ extern int __fscrypt_prepare_rename(struct inode *old_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);
extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
unsigned int max_len,
struct fscrypt_str *disk_link);
extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
unsigned int len,
struct fscrypt_str *disk_link);
extern const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
unsigned int max_size,
struct delayed_call *done);
#endif /* _LINUX_FSCRYPT_SUPP_H */ #endif /* _LINUX_FSCRYPT_SUPP_H */
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