mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
fscrypt: new helper function - fscrypt_get_symlink()
Filesystems also have duplicate code to support ->get_link() on encrypted symlinks. Factor it out into a new function fscrypt_get_symlink(). It takes in the contents of the encrypted symlink on-disk and provides the target (decrypted or encoded) that should be returned from ->get_link(). Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
76e81d6d50
commit
3b0d8837a7
@ -200,3 +200,76 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
|
||||
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);
|
||||
|
@ -239,4 +239,12 @@ static inline int __fscrypt_encrypt_symlink(struct inode *inode,
|
||||
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 */
|
||||
|
@ -211,5 +211,8 @@ extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
|
||||
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
Block a user