2015-04-26 10:12:50 +03:00
/*
2015-05-16 02:26:10 +03:00
* This contains functions for filename crypto management
2015-04-26 10:12:50 +03:00
*
* Copyright ( C ) 2015 , Google , Inc .
* Copyright ( C ) 2015 , Motorola Mobility
*
* Written by Uday Savagaonkar , 2014.
2015-05-16 02:26:10 +03:00
* Modified by Jaegeuk Kim , 2015.
2015-04-26 10:12:50 +03:00
*
* This has not yet undergone a rigorous security audit .
*/
2015-05-16 02:26:10 +03:00
2015-04-26 10:12:50 +03:00
# include <linux/scatterlist.h>
# include <linux/ratelimit.h>
2015-05-16 02:26:10 +03:00
# include <linux/fscrypto.h>
2015-04-26 10:12:50 +03:00
/**
2016-09-15 23:51:01 +03:00
* fname_crypt_complete ( ) - completion callback for filename crypto
* @ req : The asynchronous cipher request context
* @ res : The result of the cipher operation
2015-04-26 10:12:50 +03:00
*/
2016-09-15 23:51:01 +03:00
static void fname_crypt_complete ( struct crypto_async_request * req , int res )
2015-04-26 10:12:50 +03:00
{
2015-05-16 02:26:10 +03:00
struct fscrypt_completion_result * ecr = req - > data ;
2015-04-26 10:12:50 +03:00
if ( res = = - EINPROGRESS )
return ;
ecr - > res = res ;
complete ( & ecr - > completion ) ;
}
/**
2016-09-16 00:25:55 +03:00
* fname_encrypt ( ) - encrypt a filename
2015-04-26 10:12:50 +03:00
*
2016-09-16 00:25:55 +03:00
* The caller must have allocated sufficient memory for the @ oname string .
*
* Return : 0 on success , - errno on failure
2015-04-26 10:12:50 +03:00
*/
2015-05-16 02:26:10 +03:00
static int fname_encrypt ( struct inode * inode ,
const struct qstr * iname , struct fscrypt_str * oname )
2015-04-26 10:12:50 +03:00
{
2016-01-24 16:17:49 +03:00
struct skcipher_request * req = NULL ;
2015-05-16 02:26:10 +03:00
DECLARE_FS_COMPLETION_RESULT ( ecr ) ;
struct fscrypt_info * ci = inode - > i_crypt_info ;
2016-01-24 16:17:49 +03:00
struct crypto_skcipher * tfm = ci - > ci_ctfm ;
2015-04-26 10:12:50 +03:00
int res = 0 ;
2015-05-16 02:26:10 +03:00
char iv [ FS_CRYPTO_BLOCK_SIZE ] ;
2016-11-14 04:35:52 +03:00
struct scatterlist sg ;
2015-05-16 02:26:10 +03:00
int padding = 4 < < ( ci - > ci_flags & FS_POLICY_FLAGS_PAD_MASK ) ;
2016-11-14 04:35:52 +03:00
unsigned int lim ;
unsigned int cryptlen ;
2015-04-26 10:12:50 +03:00
2015-05-16 02:26:10 +03:00
lim = inode - > i_sb - > s_cop - > max_namelen ( inode ) ;
2015-04-26 10:12:50 +03:00
if ( iname - > len < = 0 | | iname - > len > lim )
return - EIO ;
2016-11-14 04:35:52 +03:00
/*
* 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 ) ;
2015-04-26 10:12:50 +03:00
2016-11-14 04:35:52 +03:00
/* Initialize the IV */
memset ( iv , 0 , FS_CRYPTO_BLOCK_SIZE ) ;
2015-04-26 10:12:50 +03:00
2016-11-14 04:35:52 +03:00
/* Set up the encryption request */
2016-01-24 16:17:49 +03:00
req = skcipher_request_alloc ( tfm , GFP_NOFS ) ;
2015-04-26 10:12:50 +03:00
if ( ! req ) {
printk_ratelimited ( KERN_ERR
2016-11-14 04:35:52 +03:00
" %s: skcipher_request_alloc() failed \n " , __func__ ) ;
2015-04-26 10:12:50 +03:00
return - ENOMEM ;
}
2016-01-24 16:17:49 +03:00
skcipher_request_set_callback ( req ,
2015-04-26 10:12:50 +03:00
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP ,
2016-09-15 23:51:01 +03:00
fname_crypt_complete , & ecr ) ;
2016-11-14 04:35:52 +03:00
sg_init_one ( & sg , oname - > name , cryptlen ) ;
skcipher_request_set_crypt ( req , & sg , & sg , cryptlen , iv ) ;
2015-04-26 10:12:50 +03:00
2016-11-14 04:35:52 +03:00
/* Do the encryption */
2016-01-24 16:17:49 +03:00
res = crypto_skcipher_encrypt ( req ) ;
2015-04-26 10:12:50 +03:00
if ( res = = - EINPROGRESS | | res = = - EBUSY ) {
2016-11-14 04:35:52 +03:00
/* Request is being completed asynchronously; wait for it */
2015-04-26 10:12:50 +03:00
wait_for_completion ( & ecr . completion ) ;
res = ecr . res ;
}
2016-01-24 16:17:49 +03:00
skcipher_request_free ( req ) ;
2016-09-16 00:25:55 +03:00
if ( res < 0 ) {
2015-04-26 10:12:50 +03:00
printk_ratelimited ( KERN_ERR
" %s: Error (error code %d) \n " , __func__ , res ) ;
2016-09-16 00:25:55 +03:00
return res ;
}
2015-05-16 02:26:10 +03:00
2016-11-14 04:35:52 +03:00
oname - > len = cryptlen ;
2016-09-16 00:25:55 +03:00
return 0 ;
2015-04-26 10:12:50 +03:00
}
2016-09-16 00:25:55 +03:00
/**
* fname_decrypt ( ) - decrypt a filename
*
* The caller must have allocated sufficient memory for the @ oname string .
*
* Return : 0 on success , - errno on failure
2015-04-26 10:12:50 +03:00
*/
2015-05-16 02:26:10 +03:00
static int fname_decrypt ( struct inode * inode ,
const struct fscrypt_str * iname ,
struct fscrypt_str * oname )
2015-04-26 10:12:50 +03:00
{
2016-01-24 16:17:49 +03:00
struct skcipher_request * req = NULL ;
2015-05-16 02:26:10 +03:00
DECLARE_FS_COMPLETION_RESULT ( ecr ) ;
2015-04-26 10:12:50 +03:00
struct scatterlist src_sg , dst_sg ;
2015-05-16 02:26:10 +03:00
struct fscrypt_info * ci = inode - > i_crypt_info ;
2016-01-24 16:17:49 +03:00
struct crypto_skcipher * tfm = ci - > ci_ctfm ;
2015-04-26 10:12:50 +03:00
int res = 0 ;
2015-05-16 02:26:10 +03:00
char iv [ FS_CRYPTO_BLOCK_SIZE ] ;
unsigned lim ;
2015-04-26 10:12:50 +03:00
2015-05-16 02:26:10 +03:00
lim = inode - > i_sb - > s_cop - > max_namelen ( inode ) ;
2015-04-26 10:12:50 +03:00
if ( iname - > len < = 0 | | iname - > len > lim )
return - EIO ;
/* Allocate request */
2016-01-24 16:17:49 +03:00
req = skcipher_request_alloc ( tfm , GFP_NOFS ) ;
2015-04-26 10:12:50 +03:00
if ( ! req ) {
printk_ratelimited ( KERN_ERR
" %s: crypto_request_alloc() failed \n " , __func__ ) ;
return - ENOMEM ;
}
2016-01-24 16:17:49 +03:00
skcipher_request_set_callback ( req ,
2015-04-26 10:12:50 +03:00
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP ,
2016-09-15 23:51:01 +03:00
fname_crypt_complete , & ecr ) ;
2015-04-26 10:12:50 +03:00
/* Initialize IV */
2015-05-16 02:26:10 +03:00
memset ( iv , 0 , FS_CRYPTO_BLOCK_SIZE ) ;
2015-04-26 10:12:50 +03:00
/* Create decryption request */
sg_init_one ( & src_sg , iname - > name , iname - > len ) ;
sg_init_one ( & dst_sg , oname - > name , oname - > len ) ;
2016-01-24 16:17:49 +03:00
skcipher_request_set_crypt ( req , & src_sg , & dst_sg , iname - > len , iv ) ;
res = crypto_skcipher_decrypt ( req ) ;
2015-04-26 10:12:50 +03:00
if ( res = = - EINPROGRESS | | res = = - EBUSY ) {
wait_for_completion ( & ecr . completion ) ;
res = ecr . res ;
}
2016-01-24 16:17:49 +03:00
skcipher_request_free ( req ) ;
2015-04-26 10:12:50 +03:00
if ( res < 0 ) {
printk_ratelimited ( KERN_ERR
2015-05-16 02:26:10 +03:00
" %s: Error (error code %d) \n " , __func__ , res ) ;
2015-04-26 10:12:50 +03:00
return res ;
}
oname - > len = strnlen ( oname - > name , iname - > len ) ;
2016-09-16 00:25:55 +03:00
return 0 ;
2015-04-26 10:12:50 +03:00
}
static const char * lookup_table =
" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+, " ;
/**
2015-05-16 02:26:10 +03:00
* digest_encode ( ) -
2015-04-26 10:12:50 +03:00
*
* Encodes the input digest using characters from the set [ a - zA - Z0 - 9 _ + ] .
* The encoded string is roughly 4 / 3 times the size of the input string .
*/
static int digest_encode ( const char * src , int len , char * dst )
{
int i = 0 , bits = 0 , ac = 0 ;
char * cp = dst ;
while ( i < len ) {
ac + = ( ( ( unsigned char ) src [ i ] ) < < bits ) ;
bits + = 8 ;
do {
* cp + + = lookup_table [ ac & 0x3f ] ;
ac > > = 6 ;
bits - = 6 ;
} while ( bits > = 6 ) ;
i + + ;
}
if ( bits )
* cp + + = lookup_table [ ac & 0x3f ] ;
return cp - dst ;
}
static int digest_decode ( const char * src , int len , char * dst )
{
int i = 0 , bits = 0 , ac = 0 ;
const char * p ;
char * cp = dst ;
while ( i < len ) {
p = strchr ( lookup_table , src [ i ] ) ;
if ( p = = NULL | | src [ i ] = = 0 )
return - 2 ;
ac + = ( p - lookup_table ) < < bits ;
bits + = 6 ;
if ( bits > = 8 ) {
* cp + + = ac & 0xff ;
ac > > = 8 ;
bits - = 8 ;
}
i + + ;
}
if ( ac )
return - 1 ;
return cp - dst ;
}
2016-11-14 00:20:47 +03:00
u32 fscrypt_fname_encrypted_size ( const struct inode * inode , u32 ilen )
2015-04-26 10:12:50 +03:00
{
2016-02-15 12:54:26 +03:00
int padding = 32 ;
2015-05-16 02:26:10 +03:00
struct fscrypt_info * ci = inode - > i_crypt_info ;
2016-02-15 12:54:26 +03:00
if ( ci )
2015-05-16 02:26:10 +03:00
padding = 4 < < ( ci - > ci_flags & FS_POLICY_FLAGS_PAD_MASK ) ;
2016-09-30 08:46:18 +03:00
ilen = max ( ilen , ( u32 ) FS_CRYPTO_BLOCK_SIZE ) ;
return round_up ( ilen , padding ) ;
2015-04-26 10:12:50 +03:00
}
2015-05-16 02:26:10 +03:00
EXPORT_SYMBOL ( fscrypt_fname_encrypted_size ) ;
2015-04-26 10:12:50 +03:00
/**
2015-05-16 02:26:10 +03:00
* fscrypt_fname_crypto_alloc_obuff ( ) -
2015-04-26 10:12:50 +03:00
*
* Allocates an output buffer that is sufficient for the crypto operation
* specified by the context and the direction .
*/
2016-11-14 00:20:47 +03:00
int fscrypt_fname_alloc_buffer ( const struct inode * inode ,
2015-05-16 02:26:10 +03:00
u32 ilen , struct fscrypt_str * crypto_str )
2015-04-26 10:12:50 +03:00
{
2015-05-16 02:26:10 +03:00
unsigned int olen = fscrypt_fname_encrypted_size ( inode , ilen ) ;
2015-04-26 10:12:50 +03:00
crypto_str - > len = olen ;
2015-05-16 02:26:10 +03:00
if ( olen < FS_FNAME_CRYPTO_DIGEST_SIZE * 2 )
olen = FS_FNAME_CRYPTO_DIGEST_SIZE * 2 ;
/*
* Allocated buffer can hold one more character to null - terminate the
* string
*/
2015-04-26 10:12:50 +03:00
crypto_str - > name = kmalloc ( olen + 1 , GFP_NOFS ) ;
if ( ! ( crypto_str - > name ) )
return - ENOMEM ;
return 0 ;
}
2015-05-16 02:26:10 +03:00
EXPORT_SYMBOL ( fscrypt_fname_alloc_buffer ) ;
2015-04-26 10:12:50 +03:00
/**
2015-05-16 02:26:10 +03:00
* fscrypt_fname_crypto_free_buffer ( ) -
2015-04-26 10:12:50 +03:00
*
* Frees the buffer allocated for crypto operation .
*/
2015-05-16 02:26:10 +03:00
void fscrypt_fname_free_buffer ( struct fscrypt_str * crypto_str )
2015-04-26 10:12:50 +03:00
{
if ( ! crypto_str )
return ;
kfree ( crypto_str - > name ) ;
crypto_str - > name = NULL ;
}
2015-05-16 02:26:10 +03:00
EXPORT_SYMBOL ( fscrypt_fname_free_buffer ) ;
2015-04-26 10:12:50 +03:00
/**
2015-05-16 02:26:10 +03:00
* fscrypt_fname_disk_to_usr ( ) - converts a filename from disk space to user
* space
2016-09-16 00:25:55 +03:00
*
* The caller must have allocated sufficient memory for the @ oname string .
*
* Return : 0 on success , - errno on failure
2015-04-26 10:12:50 +03:00
*/
2015-05-16 02:26:10 +03:00
int fscrypt_fname_disk_to_usr ( struct inode * inode ,
u32 hash , u32 minor_hash ,
const struct fscrypt_str * iname ,
struct fscrypt_str * oname )
2015-04-26 10:12:50 +03:00
{
const struct qstr qname = FSTR_TO_QSTR ( iname ) ;
char buf [ 24 ] ;
2015-05-16 02:26:10 +03:00
if ( fscrypt_is_dot_dotdot ( & qname ) ) {
2015-04-26 10:12:50 +03:00
oname - > name [ 0 ] = ' . ' ;
oname - > name [ iname - > len - 1 ] = ' . ' ;
oname - > len = iname - > len ;
2016-09-16 00:25:55 +03:00
return 0 ;
2015-04-26 10:12:50 +03:00
}
2015-05-16 02:26:10 +03:00
if ( iname - > len < FS_CRYPTO_BLOCK_SIZE )
2016-02-06 06:37:27 +03:00
return - EUCLEAN ;
2015-04-26 10:12:50 +03:00
2015-05-16 02:26:10 +03:00
if ( inode - > i_crypt_info )
return fname_decrypt ( inode , iname , oname ) ;
if ( iname - > len < = FS_FNAME_CRYPTO_DIGEST_SIZE ) {
2016-09-16 00:25:55 +03:00
oname - > len = digest_encode ( iname - > name , iname - > len ,
oname - > name ) ;
return 0 ;
2015-04-26 10:12:50 +03:00
}
if ( hash ) {
2015-05-16 02:26:10 +03:00
memcpy ( buf , & hash , 4 ) ;
memcpy ( buf + 4 , & minor_hash , 4 ) ;
} else {
2015-04-26 10:12:50 +03:00
memset ( buf , 0 , 8 ) ;
2015-05-16 02:26:10 +03:00
}
2015-04-26 10:12:50 +03:00
memcpy ( buf + 8 , iname - > name + iname - > len - 16 , 16 ) ;
oname - > name [ 0 ] = ' _ ' ;
2016-09-16 00:25:55 +03:00
oname - > len = 1 + digest_encode ( buf , 24 , oname - > name + 1 ) ;
return 0 ;
2015-04-26 10:12:50 +03:00
}
2015-05-16 02:26:10 +03:00
EXPORT_SYMBOL ( fscrypt_fname_disk_to_usr ) ;
2015-04-26 10:12:50 +03:00
/**
2015-05-16 02:26:10 +03:00
* fscrypt_fname_usr_to_disk ( ) - converts a filename from user space to disk
* space
2016-09-16 00:25:55 +03:00
*
* The caller must have allocated sufficient memory for the @ oname string .
*
* Return : 0 on success , - errno on failure
2015-04-26 10:12:50 +03:00
*/
2015-05-16 02:26:10 +03:00
int fscrypt_fname_usr_to_disk ( struct inode * inode ,
2015-04-26 10:12:50 +03:00
const struct qstr * iname ,
2015-05-16 02:26:10 +03:00
struct fscrypt_str * oname )
2015-04-26 10:12:50 +03:00
{
2015-05-16 02:26:10 +03:00
if ( fscrypt_is_dot_dotdot ( iname ) ) {
2015-04-26 10:12:50 +03:00
oname - > name [ 0 ] = ' . ' ;
oname - > name [ iname - > len - 1 ] = ' . ' ;
oname - > len = iname - > len ;
2016-09-16 00:25:55 +03:00
return 0 ;
2015-04-26 10:12:50 +03:00
}
2015-05-16 02:26:10 +03:00
if ( inode - > i_crypt_info )
return fname_encrypt ( inode , iname , oname ) ;
/*
* Without a proper key , a user is not allowed to modify the filenames
2015-04-26 10:12:50 +03:00
* in a directory . Consequently , a user space name cannot be mapped to
2015-05-16 02:26:10 +03:00
* a disk - space name
*/
2015-04-26 10:12:50 +03:00
return - EACCES ;
}
2015-05-16 02:26:10 +03:00
EXPORT_SYMBOL ( fscrypt_fname_usr_to_disk ) ;
2015-04-26 10:12:50 +03:00
2015-05-16 02:26:10 +03:00
int fscrypt_setup_filename ( struct inode * dir , const struct qstr * iname ,
int lookup , struct fscrypt_name * fname )
2015-04-26 10:12:50 +03:00
{
int ret = 0 , bigname = 0 ;
2015-05-16 02:26:10 +03:00
memset ( fname , 0 , sizeof ( struct fscrypt_name ) ) ;
2015-04-26 10:12:50 +03:00
fname - > usr_fname = iname ;
2015-05-16 02:26:10 +03:00
if ( ! dir - > i_sb - > s_cop - > is_encrypted ( dir ) | |
fscrypt_is_dot_dotdot ( iname ) ) {
2015-04-26 10:12:50 +03:00
fname - > disk_name . name = ( unsigned char * ) iname - > name ;
fname - > disk_name . len = iname - > len ;
2015-05-13 13:20:54 +03:00
return 0 ;
2015-04-26 10:12:50 +03:00
}
2015-05-16 02:26:10 +03:00
ret = get_crypt_info ( dir ) ;
if ( ret & & ret ! = - EOPNOTSUPP )
2015-04-26 10:12:50 +03:00
return ret ;
2015-05-16 02:26:10 +03:00
if ( dir - > i_crypt_info ) {
ret = fscrypt_fname_alloc_buffer ( dir , iname - > len ,
& fname - > crypto_buf ) ;
2016-09-16 00:25:55 +03:00
if ( ret )
2015-05-13 13:20:54 +03:00
return ret ;
2015-05-16 02:26:10 +03:00
ret = fname_encrypt ( dir , iname , & fname - > crypto_buf ) ;
2016-09-16 00:25:55 +03:00
if ( ret )
2015-05-29 03:06:40 +03:00
goto errout ;
2015-04-26 10:12:50 +03:00
fname - > disk_name . name = fname - > crypto_buf . name ;
fname - > disk_name . len = fname - > crypto_buf . len ;
2015-05-13 13:20:54 +03:00
return 0 ;
2015-04-26 10:12:50 +03:00
}
2015-05-29 03:06:40 +03:00
if ( ! lookup )
return - EACCES ;
2015-04-26 10:12:50 +03:00
2015-05-16 02:26:10 +03:00
/*
* We don ' t have the key and we are doing a lookup ; decode the
2015-04-26 10:12:50 +03:00
* user - supplied name
*/
if ( iname - > name [ 0 ] = = ' _ ' )
bigname = 1 ;
2015-05-16 02:26:10 +03:00
if ( ( bigname & & ( iname - > len ! = 33 ) ) | | ( ! bigname & & ( iname - > len > 43 ) ) )
2015-05-29 03:06:40 +03:00
return - ENOENT ;
2015-04-26 10:12:50 +03:00
fname - > crypto_buf . name = kmalloc ( 32 , GFP_KERNEL ) ;
2015-05-29 03:06:40 +03:00
if ( fname - > crypto_buf . name = = NULL )
return - ENOMEM ;
2015-05-16 02:26:10 +03:00
2015-04-26 10:12:50 +03:00
ret = digest_decode ( iname - > name + bigname , iname - > len - bigname ,
fname - > crypto_buf . name ) ;
if ( ret < 0 ) {
ret = - ENOENT ;
2015-05-29 03:06:40 +03:00
goto errout ;
2015-04-26 10:12:50 +03:00
}
fname - > crypto_buf . len = ret ;
if ( bigname ) {
memcpy ( & fname - > hash , fname - > crypto_buf . name , 4 ) ;
2015-05-16 02:26:10 +03:00
memcpy ( & fname - > minor_hash , fname - > crypto_buf . name + 4 , 4 ) ;
2015-04-26 10:12:50 +03:00
} else {
fname - > disk_name . name = fname - > crypto_buf . name ;
fname - > disk_name . len = fname - > crypto_buf . len ;
}
2015-05-13 13:20:54 +03:00
return 0 ;
2015-05-16 02:26:10 +03:00
2015-05-29 03:06:40 +03:00
errout :
2015-05-16 02:26:10 +03:00
fscrypt_fname_free_buffer ( & fname - > crypto_buf ) ;
2015-04-26 10:12:50 +03:00
return ret ;
}
2015-05-16 02:26:10 +03:00
EXPORT_SYMBOL ( fscrypt_setup_filename ) ;
2015-04-26 10:12:50 +03:00
2015-05-16 02:26:10 +03:00
void fscrypt_free_filename ( struct fscrypt_name * fname )
2015-04-26 10:12:50 +03:00
{
kfree ( fname - > crypto_buf . name ) ;
fname - > crypto_buf . name = NULL ;
fname - > usr_fname = NULL ;
fname - > disk_name . name = NULL ;
}
2015-05-16 02:26:10 +03:00
EXPORT_SYMBOL ( fscrypt_free_filename ) ;