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
a1cdacb7ae
commit
fd457d2c4e
3 changed files with 80 additions and 0 deletions
|
@ -200,3 +200,74 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink);
|
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()
|
||||||
|
*/
|
||||||
|
void *fscrypt_get_symlink(struct inode *inode, const void *caddr,
|
||||||
|
unsigned int max_size)
|
||||||
|
{
|
||||||
|
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';
|
||||||
|
return pstr.name;
|
||||||
|
|
||||||
|
err_kfree:
|
||||||
|
kfree(pstr.name);
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(fscrypt_get_symlink);
|
||||||
|
|
|
@ -238,4 +238,11 @@ static inline int __fscrypt_encrypt_symlink(struct inode *inode,
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void *fscrypt_get_symlink(struct inode *inode,
|
||||||
|
const void *caddr,
|
||||||
|
unsigned int max_size)
|
||||||
|
{
|
||||||
|
return ERR_PTR(-EOPNOTSUPP);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _LINUX_FSCRYPT_NOTSUPP_H */
|
#endif /* _LINUX_FSCRYPT_NOTSUPP_H */
|
||||||
|
|
|
@ -210,5 +210,7 @@ extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
|
||||||
extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
|
extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
|
||||||
unsigned int len,
|
unsigned int len,
|
||||||
struct fscrypt_str *disk_link);
|
struct fscrypt_str *disk_link);
|
||||||
|
extern void *fscrypt_get_symlink(struct inode *inode, const void *caddr,
|
||||||
|
unsigned int max_size);
|
||||||
|
|
||||||
#endif /* _LINUX_FSCRYPT_SUPP_H */
|
#endif /* _LINUX_FSCRYPT_SUPP_H */
|
||||||
|
|
Loading…
Add table
Reference in a new issue