Refactor support for encrypted symlinks to move common code to fscrypt.
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEK2m5VNv+CHkogTfJ8vlZVpUNgaMFAlp2R3AACgkQ8vlZVpUN gaOIdAgApEdlFR2Gf93z2hMj5HxVL5rjkuPJVtVkKu0eH2HMQJyxNmjymrRfuFmM 8W1CrEvVKi5Aj6r8q4KHIdVV247Ya0SVEhLwKM0LX4CvlZUXmwgCmZ/MPDTXA1eq C4vPVuJAuSNGNVYDlDs3+NiMHINGNVnBVQQFSPBP9P+iNWPD7o486712qaF8maVn RbfbQ2rWtOIRdlAOD1U5WqgQku59lOsmHk2pc0+X4LHCZFpMoaO80JVjENPAw+BF daRt6TX+WljMyx6DRIaszqau876CJhe/tqlZcCLOkpXZP0jJS13yodp26dVQmjCh w8YdiY7uHK2D+S/8eyj7h7DIwzu3vg== =ZjQP -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
3462ac5703
|
@ -448,8 +448,14 @@ astute users may notice some differences in behavior:
|
|||
|
||||
- The st_size of an encrypted symlink will not necessarily give the
|
||||
length of the symlink target as required by POSIX. It will actually
|
||||
give the length of the ciphertext, which may be slightly longer than
|
||||
the plaintext due to the NUL-padding.
|
||||
give the length of the ciphertext, which will be slightly longer
|
||||
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
|
||||
for an encrypted file contains the plaintext, not the ciphertext.
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/dcache.h>
|
||||
#include <linux/namei.h>
|
||||
#include <crypto/aes.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
static unsigned int num_prealloc_crypto_pages = 32;
|
||||
|
|
|
@ -13,42 +13,46 @@
|
|||
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <crypto/skcipher.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
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
static int fname_encrypt(struct inode *inode,
|
||||
const struct qstr *iname, struct fscrypt_str *oname)
|
||||
int fname_encrypt(struct inode *inode, const struct qstr *iname,
|
||||
u8 *out, unsigned int olen)
|
||||
{
|
||||
struct skcipher_request *req = NULL;
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
struct crypto_skcipher *tfm = ci->ci_ctfm;
|
||||
struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm;
|
||||
int res = 0;
|
||||
char iv[FS_CRYPTO_BLOCK_SIZE];
|
||||
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
|
||||
* pad it with the needed number of NUL bytes.
|
||||
*/
|
||||
cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE);
|
||||
cryptlen = round_up(cryptlen, padding);
|
||||
cryptlen = min(cryptlen, lim);
|
||||
memcpy(oname->name, iname->name, iname->len);
|
||||
memset(oname->name + iname->len, 0, cryptlen - iname->len);
|
||||
if (WARN_ON(olen < iname->len))
|
||||
return -ENOBUFS;
|
||||
memcpy(out, iname->name, iname->len);
|
||||
memset(out + iname->len, 0, olen - iname->len);
|
||||
|
||||
/* Initialize the IV */
|
||||
memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
|
||||
|
@ -63,8 +67,8 @@ static int fname_encrypt(struct inode *inode,
|
|||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
crypto_req_done, &wait);
|
||||
sg_init_one(&sg, oname->name, cryptlen);
|
||||
skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv);
|
||||
sg_init_one(&sg, out, olen);
|
||||
skcipher_request_set_crypt(req, &sg, &sg, olen, iv);
|
||||
|
||||
/* Do the encryption */
|
||||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
|
@ -75,7 +79,6 @@ static int fname_encrypt(struct inode *inode,
|
|||
return res;
|
||||
}
|
||||
|
||||
oname->len = cryptlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -188,50 +191,52 @@ static int digest_decode(const char *src, int len, char *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;
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
int padding = 4 << (inode->i_crypt_info->ci_flags &
|
||||
FS_POLICY_FLAGS_PAD_MASK);
|
||||
u32 encrypted_len;
|
||||
|
||||
if (ci)
|
||||
padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
|
||||
ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE);
|
||||
return round_up(ilen, padding);
|
||||
if (orig_len > max_len)
|
||||
return false;
|
||||
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
|
||||
* specified by the context and the direction.
|
||||
* Allocate a buffer that is large enough to hold any decrypted or encoded
|
||||
* 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,
|
||||
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 =
|
||||
max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE),
|
||||
1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)));
|
||||
u32 max_presented_len;
|
||||
|
||||
crypto_str->len = olen;
|
||||
olen = max(olen, max_encoded_len);
|
||||
max_presented_len = max(max_encoded_len, max_encrypted_len);
|
||||
|
||||
/*
|
||||
* Allocated buffer can hold one more character to null-terminate the
|
||||
* string
|
||||
*/
|
||||
crypto_str->name = kmalloc(olen + 1, GFP_NOFS);
|
||||
if (!(crypto_str->name))
|
||||
crypto_str->name = kmalloc(max_presented_len + 1, GFP_NOFS);
|
||||
if (!crypto_str->name)
|
||||
return -ENOMEM;
|
||||
crypto_str->len = max_presented_len;
|
||||
return 0;
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
@ -297,35 +302,6 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
|
|||
}
|
||||
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
|
||||
* @dir: the directory that will be searched
|
||||
|
@ -369,11 +345,17 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
|||
return ret;
|
||||
|
||||
if (dir->i_crypt_info) {
|
||||
ret = fscrypt_fname_alloc_buffer(dir, iname->len,
|
||||
&fname->crypto_buf);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = fname_encrypt(dir, iname, &fname->crypto_buf);
|
||||
if (!fscrypt_fname_encrypted_size(dir, iname->len,
|
||||
dir->i_sb->s_cop->max_namelen(dir),
|
||||
&fname->crypto_buf.len))
|
||||
return -ENAMETOOLONG;
|
||||
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)
|
||||
goto errout;
|
||||
fname->disk_name.name = fname->crypto_buf.name;
|
||||
|
@ -425,7 +407,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
|||
return 0;
|
||||
|
||||
errout:
|
||||
fscrypt_fname_free_buffer(&fname->crypto_buf);
|
||||
kfree(fname->crypto_buf.name);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_setup_filename);
|
||||
|
|
|
@ -50,6 +50,15 @@ struct fscrypt_context {
|
|||
|
||||
#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
|
||||
* representation of an inode.
|
||||
|
@ -71,7 +80,22 @@ typedef enum {
|
|||
#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001
|
||||
#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 */
|
||||
extern struct kmem_cache *fscrypt_info_cachep;
|
||||
extern int fscrypt_initialize(unsigned int cop_flags);
|
||||
extern struct workqueue_struct *fscrypt_read_workqueue;
|
||||
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,
|
||||
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 */
|
||||
extern void __exit fscrypt_essiv_cleanup(void);
|
||||
|
||||
|
|
|
@ -110,3 +110,161 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry)
|
|||
return 0;
|
||||
}
|
||||
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 @@
|
|||
#include <linux/ratelimit.h>
|
||||
#include <crypto/aes.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
static struct crypto_shash *essiv_hash_tfm;
|
||||
|
@ -354,19 +355,9 @@ out:
|
|||
}
|
||||
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;
|
||||
|
||||
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);
|
||||
put_crypt_info(inode->i_crypt_info);
|
||||
inode->i_crypt_info = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_put_encryption_info);
|
||||
|
|
|
@ -3057,39 +3057,19 @@ static int ext4_symlink(struct inode *dir,
|
|||
struct inode *inode;
|
||||
int err, len = strlen(symname);
|
||||
int credits;
|
||||
bool encryption_required;
|
||||
struct fscrypt_str disk_link;
|
||||
struct fscrypt_symlink_data *sd = NULL;
|
||||
|
||||
if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
|
||||
return -EIO;
|
||||
|
||||
disk_link.len = len + 1;
|
||||
disk_link.name = (char *) symname;
|
||||
|
||||
encryption_required = (ext4_encrypted_inode(dir) ||
|
||||
DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)));
|
||||
if (encryption_required) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
|
||||
&disk_link);
|
||||
if (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);
|
||||
if (err)
|
||||
goto err_free_sd;
|
||||
return err;
|
||||
|
||||
if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
|
||||
/*
|
||||
|
@ -3118,27 +3098,18 @@ static int ext4_symlink(struct inode *dir,
|
|||
if (IS_ERR(inode)) {
|
||||
if (handle)
|
||||
ext4_journal_stop(handle);
|
||||
err = PTR_ERR(inode);
|
||||
goto err_free_sd;
|
||||
return PTR_ERR(inode);
|
||||
}
|
||||
|
||||
if (encryption_required) {
|
||||
struct qstr istr;
|
||||
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 (IS_ENCRYPTED(inode)) {
|
||||
err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
|
||||
if (err)
|
||||
goto err_drop_inode;
|
||||
sd->len = cpu_to_le16(ostr.len);
|
||||
disk_link.name = (char *) sd;
|
||||
inode->i_op = &ext4_encrypted_symlink_inode_operations;
|
||||
}
|
||||
|
||||
if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
|
||||
if (!encryption_required)
|
||||
if (!IS_ENCRYPTED(inode))
|
||||
inode->i_op = &ext4_symlink_inode_operations;
|
||||
inode_nohighmem(inode);
|
||||
ext4_set_aops(inode);
|
||||
|
@ -3180,7 +3151,7 @@ static int ext4_symlink(struct inode *dir,
|
|||
} else {
|
||||
/* clear the extent format for fast symlink */
|
||||
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_link = (char *)&EXT4_I(inode)->i_data;
|
||||
}
|
||||
|
@ -3195,16 +3166,17 @@ static int ext4_symlink(struct inode *dir,
|
|||
|
||||
if (handle)
|
||||
ext4_journal_stop(handle);
|
||||
kfree(sd);
|
||||
return err;
|
||||
goto out_free_encrypted_link;
|
||||
|
||||
err_drop_inode:
|
||||
if (handle)
|
||||
ext4_journal_stop(handle);
|
||||
clear_nlink(inode);
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
err_free_sd:
|
||||
kfree(sd);
|
||||
out_free_encrypted_link:
|
||||
if (disk_link.name != (unsigned char *)symname)
|
||||
kfree(disk_link.name);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -1073,9 +1073,7 @@ void ext4_clear_inode(struct inode *inode)
|
|||
jbd2_free_inode(EXT4_I(inode)->jinode);
|
||||
EXT4_I(inode)->jinode = NULL;
|
||||
}
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
fscrypt_put_encryption_info(inode, NULL);
|
||||
#endif
|
||||
fscrypt_put_encryption_info(inode);
|
||||
}
|
||||
|
||||
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,
|
|||
struct delayed_call *done)
|
||||
{
|
||||
struct page *cpage = NULL;
|
||||
char *caddr, *paddr = NULL;
|
||||
struct fscrypt_str cstr, pstr;
|
||||
struct fscrypt_symlink_data *sd;
|
||||
int res;
|
||||
u32 max_size = inode->i_sb->s_blocksize;
|
||||
const void *caddr;
|
||||
unsigned int max_size;
|
||||
const char *paddr;
|
||||
|
||||
if (!dentry)
|
||||
return ERR_PTR(-ECHILD);
|
||||
|
||||
res = fscrypt_get_encryption_info(inode);
|
||||
if (res)
|
||||
return ERR_PTR(res);
|
||||
|
||||
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);
|
||||
} else {
|
||||
cpage = read_mapping_page(inode->i_mapping, 0, NULL);
|
||||
if (IS_ERR(cpage))
|
||||
return ERR_CAST(cpage);
|
||||
caddr = page_address(cpage);
|
||||
max_size = inode->i_sb->s_blocksize;
|
||||
}
|
||||
|
||||
/* Symlink is encrypted */
|
||||
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';
|
||||
paddr = fscrypt_get_symlink(inode, caddr, max_size, done);
|
||||
if (cpage)
|
||||
put_page(cpage);
|
||||
set_delayed_call(done, kfree_link, paddr);
|
||||
return paddr;
|
||||
errout:
|
||||
if (cpage)
|
||||
put_page(cpage);
|
||||
kfree(paddr);
|
||||
return ERR_PTR(res);
|
||||
}
|
||||
|
||||
const struct inode_operations ext4_encrypted_symlink_inode_operations = {
|
||||
|
|
|
@ -585,7 +585,7 @@ no_delete:
|
|||
!exist_written_data(sbi, inode->i_ino, ORPHAN_INO));
|
||||
}
|
||||
out_clear:
|
||||
fscrypt_put_encryption_info(inode, NULL);
|
||||
fscrypt_put_encryption_info(inode);
|
||||
clear_inode(inode);
|
||||
}
|
||||
|
||||
|
|
124
fs/f2fs/namei.c
124
fs/f2fs/namei.c
|
@ -486,28 +486,17 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
|
||||
struct inode *inode;
|
||||
size_t len = strlen(symname);
|
||||
struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1);
|
||||
struct fscrypt_symlink_data *sd = NULL;
|
||||
struct fscrypt_str disk_link;
|
||||
int err;
|
||||
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
return -EIO;
|
||||
|
||||
if (f2fs_encrypted_inode(dir)) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
|
||||
&disk_link);
|
||||
if (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);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -516,7 +505,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
if (f2fs_encrypted_inode(inode))
|
||||
if (IS_ENCRYPTED(inode))
|
||||
inode->i_op = &f2fs_encrypted_symlink_inode_operations;
|
||||
else
|
||||
inode->i_op = &f2fs_symlink_inode_operations;
|
||||
|
@ -526,39 +515,14 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
f2fs_lock_op(sbi);
|
||||
err = f2fs_add_link(dentry, inode);
|
||||
if (err)
|
||||
goto out;
|
||||
goto out_handle_failed_inode;
|
||||
f2fs_unlock_op(sbi);
|
||||
alloc_nid_done(sbi, inode->i_ino);
|
||||
|
||||
if (f2fs_encrypted_inode(inode)) {
|
||||
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);
|
||||
err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
|
||||
if (err)
|
||||
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_out:
|
||||
|
@ -584,12 +548,14 @@ err_out:
|
|||
f2fs_unlink(dir, dentry);
|
||||
}
|
||||
|
||||
kfree(sd);
|
||||
|
||||
f2fs_balance_fs(sbi, true);
|
||||
return err;
|
||||
out:
|
||||
goto out_free_encrypted_link;
|
||||
|
||||
out_handle_failed_inode:
|
||||
handle_failed_inode(inode);
|
||||
out_free_encrypted_link:
|
||||
if (disk_link.name != (unsigned char *)symname)
|
||||
kfree(disk_link.name);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1148,68 +1114,20 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
|
|||
struct inode *inode,
|
||||
struct delayed_call *done)
|
||||
{
|
||||
struct page *cpage = NULL;
|
||||
char *caddr, *paddr = NULL;
|
||||
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;
|
||||
struct page *page;
|
||||
const char *target;
|
||||
|
||||
if (!dentry)
|
||||
return ERR_PTR(-ECHILD);
|
||||
|
||||
res = fscrypt_get_encryption_info(inode);
|
||||
if (res)
|
||||
return ERR_PTR(res);
|
||||
page = read_mapping_page(inode->i_mapping, 0, NULL);
|
||||
if (IS_ERR(page))
|
||||
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);
|
||||
set_delayed_call(done, kfree_link, paddr);
|
||||
return paddr;
|
||||
errout:
|
||||
fscrypt_fname_free_buffer(&pstr);
|
||||
put_page(cpage);
|
||||
return ERR_PTR(res);
|
||||
target = fscrypt_get_symlink(inode, page_address(page),
|
||||
inode->i_sb->s_blocksize, done);
|
||||
put_page(page);
|
||||
return target;
|
||||
}
|
||||
|
||||
const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
|
||||
|
|
|
@ -1138,38 +1138,24 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
struct ubifs_info *c = dir->i_sb->s_fs_info;
|
||||
int err, len = strlen(symname);
|
||||
int sz_change = CALC_DENT_SIZE(len);
|
||||
struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1);
|
||||
struct fscrypt_symlink_data *sd = NULL;
|
||||
struct fscrypt_str disk_link;
|
||||
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
|
||||
.new_ino_d = ALIGN(len, 8),
|
||||
.dirtied_ino = 1 };
|
||||
struct fscrypt_name nm;
|
||||
|
||||
if (ubifs_crypt_is_encrypted(dir)) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry,
|
||||
symname, dir->i_ino);
|
||||
|
||||
err = fscrypt_prepare_symlink(dir, symname, len, UBIFS_MAX_INO_DATA,
|
||||
&disk_link);
|
||||
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) +
|
||||
sizeof(struct fscrypt_symlink_data));
|
||||
}
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Budget request settings: new inode, new direntry and changing parent
|
||||
* 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);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -1191,38 +1177,20 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
goto out_inode;
|
||||
}
|
||||
|
||||
if (ubifs_crypt_is_encrypted(dir)) {
|
||||
struct qstr istr = QSTR_INIT(symname, len);
|
||||
struct fscrypt_str ostr;
|
||||
|
||||
sd = kzalloc(disk_link.len, GFP_NOFS);
|
||||
if (!sd) {
|
||||
err = -ENOMEM;
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
disk_link.name = ui->data; /* encrypt directly into ui->data */
|
||||
err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
|
||||
if (err)
|
||||
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;
|
||||
}
|
||||
|
||||
sd->len = cpu_to_le16(ostr.len);
|
||||
disk_link.name = (char *)sd;
|
||||
} else {
|
||||
memcpy(ui->data, disk_link.name, disk_link.len);
|
||||
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
|
||||
* 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;
|
||||
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,
|
|||
goto out_cancel;
|
||||
mutex_unlock(&dir_ui->ui_mutex);
|
||||
|
||||
ubifs_release_budget(c, &req);
|
||||
insert_inode_hash(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
fscrypt_free_filename(&nm);
|
||||
return 0;
|
||||
err = 0;
|
||||
goto out_fname;
|
||||
|
||||
out_cancel:
|
||||
dir->i_size -= sz_change;
|
||||
|
|
|
@ -1629,49 +1629,17 @@ static const char *ubifs_get_link(struct dentry *dentry,
|
|||
struct inode *inode,
|
||||
struct delayed_call *done)
|
||||
{
|
||||
int err;
|
||||
struct fscrypt_symlink_data *sd;
|
||||
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;
|
||||
|
||||
if (!dentry)
|
||||
return ERR_PTR(-ECHILD);
|
||||
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
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);
|
||||
return fscrypt_get_symlink(inode, ui->data, ui->data_len, done);
|
||||
}
|
||||
|
||||
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 = {
|
||||
.readpage = ubifs_readpage,
|
||||
.writepage = ubifs_writepage,
|
||||
|
|
|
@ -379,9 +379,7 @@ out:
|
|||
}
|
||||
done:
|
||||
clear_inode(inode);
|
||||
#ifdef CONFIG_UBIFS_FS_ENCRYPTION
|
||||
fscrypt_put_encryption_info(inode, NULL);
|
||||
#endif
|
||||
fscrypt_put_encryption_info(inode);
|
||||
}
|
||||
|
||||
static void ubifs_dirty_inode(struct inode *inode, int flags)
|
||||
|
|
|
@ -14,42 +14,13 @@
|
|||
#ifndef _LINUX_FSCRYPT_H
|
||||
#define _LINUX_FSCRYPT_H
|
||||
|
||||
#include <linux/key.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
|
||||
|
||||
struct fscrypt_ctx;
|
||||
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 {
|
||||
unsigned char *name;
|
||||
u32 len;
|
||||
|
@ -68,89 +39,14 @@ struct fscrypt_name {
|
|||
#define fname_name(p) ((p)->disk_name.name)
|
||||
#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(). */
|
||||
#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
|
||||
|
||||
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>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#else
|
||||
#include <linux/fscrypt_notsupp.h>
|
||||
#endif /* __FS_HAS_ENCRYPTION */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* fscrypt_require_key - require an inode's encryption key
|
||||
|
@ -291,4 +187,68 @@ static inline int fscrypt_prepare_setattr(struct dentry *dentry,
|
|||
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 */
|
||||
|
|
|
@ -14,6 +14,16 @@
|
|||
#ifndef _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 */
|
||||
static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode,
|
||||
gfp_t gfp_flags)
|
||||
|
@ -43,6 +53,11 @@ static inline int fscrypt_decrypt_page(const struct inode *inode,
|
|||
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)
|
||||
{
|
||||
|
@ -90,8 +105,7 @@ static inline int fscrypt_get_encryption_info(struct inode *inode)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void fscrypt_put_encryption_info(struct inode *inode,
|
||||
struct fscrypt_info *ci)
|
||||
static inline void fscrypt_put_encryption_info(struct inode *inode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -116,16 +130,8 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname)
|
|||
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,
|
||||
u32 ilen,
|
||||
u32 max_encrypted_len,
|
||||
struct fscrypt_str *crypto_str)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -144,13 +150,6 @@ static inline int fscrypt_fname_disk_to_usr(struct inode *inode,
|
|||
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,
|
||||
const u8 *de_name, u32 de_name_len)
|
||||
{
|
||||
|
@ -208,4 +207,28 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir,
|
|||
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 */
|
||||
|
|
|
@ -11,8 +11,54 @@
|
|||
#ifndef _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 */
|
||||
extern struct kmem_cache *fscrypt_info_cachep;
|
||||
extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t);
|
||||
extern void fscrypt_release_ctx(struct fscrypt_ctx *);
|
||||
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);
|
||||
extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int,
|
||||
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 const struct dentry_operations fscrypt_d_ops;
|
||||
|
@ -44,7 +96,7 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *,
|
|||
void *, bool);
|
||||
/* keyinfo.c */
|
||||
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 */
|
||||
extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
|
||||
|
@ -55,14 +107,11 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname)
|
|||
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,
|
||||
struct fscrypt_str *);
|
||||
extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
|
||||
extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
|
||||
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
|
||||
|
||||
|
@ -153,5 +202,14 @@ extern int __fscrypt_prepare_rename(struct inode *old_dir,
|
|||
struct dentry *new_dentry,
|
||||
unsigned int flags);
|
||||
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 */
|
||||
|
|
Loading…
Reference in New Issue