@ -11,88 +11,10 @@
* This has not yet undergone a rigorous security audit .
*/
# include <linux/namei.h>
# include <linux/scatterlist.h>
# include <crypto/hash.h>
# include <crypto/sha.h>
# include <crypto/skcipher.h>
# include "fscrypt_private.h"
/**
* struct fscrypt_nokey_name - identifier for directory entry when key is absent
*
* When userspace lists an encrypted directory without access to the key , the
* filesystem must present a unique " no-key name " for each filename that allows
* it to find the directory entry again if requested . Naively , that would just
* mean using the ciphertext filenames . However , since the ciphertext filenames
* can contain illegal characters ( ' \0 ' and ' / ' ) , they must be encoded in some
* way . We use base64 . But that can cause names to exceed NAME_MAX ( 255
* bytes ) , so we also need to use a strong hash to abbreviate long names .
*
* The filesystem may also need another kind of hash , the " dirhash " , to quickly
* find the directory entry . Since filesystems normally compute the dirhash
* over the on - disk filename ( i . e . the ciphertext ) , it ' s not computable from
* no - key names that abbreviate the ciphertext using the strong hash to fit in
* NAME_MAX . It ' s also not computable if it ' s a keyed hash taken over the
* plaintext ( but it may still be available in the on - disk directory entry ) ;
* casefolded directories use this type of dirhash . At least in these cases ,
* each no - key name must include the name ' s dirhash too .
*
* To meet all these requirements , we base64 - encode the following
* variable - length structure . It contains the dirhash , or 0 ' s if the filesystem
* didn ' t provide one ; up to 149 bytes of the ciphertext name ; and for
* ciphertexts longer than 149 bytes , also the SHA - 256 of the remaining bytes .
*
* This ensures that each no - key name contains everything needed to find the
* directory entry again , contains only legal characters , doesn ' t exceed
* NAME_MAX , is unambiguous unless there ' s a SHA - 256 collision , and that we only
* take the performance hit of SHA - 256 on very long filenames ( which are rare ) .
*/
struct fscrypt_nokey_name {
u32 dirhash [ 2 ] ;
u8 bytes [ 149 ] ;
u8 sha256 [ SHA256_DIGEST_SIZE ] ;
} ; /* 189 bytes => 252 bytes base64-encoded, which is <= NAME_MAX (255) */
/*
* Decoded size of max - size nokey name , i . e . a name that was abbreviated using
* the strong hash and thus includes the ' sha256 ' field . This isn ' t simply
* sizeof ( struct fscrypt_nokey_name ) , as the padding at the end isn ' t included .
*/
# define FSCRYPT_NOKEY_NAME_MAX offsetofend(struct fscrypt_nokey_name, sha256)
static struct crypto_shash * sha256_hash_tfm ;
static int fscrypt_do_sha256 ( const u8 * data , unsigned int data_len , u8 * result )
{
struct crypto_shash * tfm = READ_ONCE ( sha256_hash_tfm ) ;
if ( unlikely ( ! tfm ) ) {
struct crypto_shash * prev_tfm ;
tfm = crypto_alloc_shash ( " sha256 " , 0 , 0 ) ;
if ( IS_ERR ( tfm ) ) {
fscrypt_err ( NULL ,
" Error allocating SHA-256 transform: %ld " ,
PTR_ERR ( tfm ) ) ;
return PTR_ERR ( tfm ) ;
}
prev_tfm = cmpxchg ( & sha256_hash_tfm , NULL , tfm ) ;
if ( prev_tfm ) {
crypto_free_shash ( tfm ) ;
tfm = prev_tfm ;
}
}
{
SHASH_DESC_ON_STACK ( desc , tfm ) ;
desc - > tfm = tfm ;
desc - > flags = 0 ;
return crypto_shash_digest ( desc , data , data_len , result ) ;
}
}
static inline bool fscrypt_is_dot_dotdot ( const struct qstr * str )
{
if ( str - > len = = 1 & & str - > name [ 0 ] = = ' . ' )
@ -105,19 +27,19 @@ static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
}
/**
* fscrypt_f name_encrypt ( ) - encrypt a filename
* fname_encrypt ( ) - encrypt a filename
*
* 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
*/
int fscrypt_f name_encrypt ( const struct inode * inode , const struct qstr * iname ,
u8 * out , unsigned int olen )
int fname_encrypt ( struct inode * inode , const struct qstr * iname ,
u8 * out , unsigned int olen )
{
struct skcipher_request * req = NULL ;
DECLARE_CRYPTO_WAIT ( wait ) ;
const struct fscrypt_info * ci = inode - > i_crypt_info ;
struct fscrypt_info * ci = inode - > i_crypt_info ;
struct crypto_skcipher * tfm = ci - > ci_key . tfm ;
union fscrypt_iv iv ;
struct scatterlist sg ;
@ -163,14 +85,14 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
*
* Return : 0 on success , - errno on failure
*/
static int fname_decrypt ( const struct inode * inode ,
const struct fscrypt_str * iname ,
struct fscrypt_str * oname )
static int fname_decrypt ( struct inode * inode ,
const struct fscrypt_str * iname ,
struct fscrypt_str * oname )
{
struct skcipher_request * req = NULL ;
DECLARE_CRYPTO_WAIT ( wait ) ;
struct scatterlist src_sg , dst_sg ;
const struct fscrypt_info * ci = inode - > i_crypt_info ;
struct fscrypt_info * ci = inode - > i_crypt_info ;
struct crypto_skcipher * tfm = ci - > ci_key . tfm ;
union fscrypt_iv iv ;
int res ;
@ -284,7 +206,9 @@ int fscrypt_fname_alloc_buffer(const struct inode *inode,
u32 max_encrypted_len ,
struct fscrypt_str * crypto_str )
{
const u32 max_encoded_len = BASE64_CHARS ( FSCRYPT_NOKEY_NAME_MAX ) ;
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 ;
max_presented_len = max ( max_encoded_len , max_encrypted_len ) ;
@ -317,21 +241,19 @@ EXPORT_SYMBOL(fscrypt_fname_free_buffer);
*
* The caller must have allocated sufficient memory for the @ oname string .
*
* If the key is available , we ' ll decrypt the disk name . O therwise, we ' ll
* encode it for presentation in fscrypt_nokey_name format .
* See struct fscrypt_nokey_name for details .
* If the key is available , we ' ll decrypt the disk name ; o therwise, we ' ll encode
* it for presentation . Short names are directly base64 - encoded , while long
* names are encoded in fscrypt_digested_name format .
*
* Return : 0 on success , - errno on failure
*/
int fscrypt_fname_disk_to_usr ( const struct inode * inode ,
u32 hash , u32 minor_hash ,
const struct fscrypt_str * iname ,
struct fscrypt_str * oname )
int fscrypt_fname_disk_to_usr ( struct inode * inode ,
u32 hash , u32 minor_hash ,
const struct fscrypt_str * iname ,
struct fscrypt_str * oname )
{
const struct qstr qname = FSTR_TO_QSTR ( iname ) ;
struct fscrypt_nokey_name nokey_name ;
u32 size ; /* size of the unencoded no-key name */
int err ;
struct fscrypt_digested_name digested_name ;
if ( fscrypt_is_dot_dotdot ( & qname ) ) {
oname - > name [ 0 ] = ' . ' ;
@ -346,37 +268,24 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
if ( fscrypt_has_encryption_key ( inode ) )
return fname_decrypt ( inode , iname , oname ) ;
/*
* Sanity check that struct fscrypt_nokey_name doesn ' t have padding
* between fields and that its encoded size never exceeds NAME_MAX .
*/
BUILD_BUG_ON ( offsetofend ( struct fscrypt_nokey_name , dirhash ) ! =
offsetof ( struct fscrypt_nokey_name , bytes ) ) ;
BUILD_BUG_ON ( offsetofend ( struct fscrypt_nokey_name , bytes ) ! =
offsetof ( struct fscrypt_nokey_name , sha256 ) ) ;
BUILD_BUG_ON ( BASE64_CHARS ( FSCRYPT_NOKEY_NAME_MAX ) > NAME_MAX ) ;
if ( hash ) {
nokey_name . dirhash [ 0 ] = hash ;
nokey_name . dirhash [ 1 ] = minor_hash ;
} else {
nokey_name . dirhash [ 0 ] = 0 ;
nokey_name . dirhash [ 1 ] = 0 ;
if ( iname - > len < = FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE ) {
oname - > len = base64_encode ( iname - > name , iname - > len ,
oname - > name ) ;
return 0 ;
}
if ( iname - > len < = sizeof ( nokey_name . bytes ) ) {
memcpy ( nokey_name . bytes , iname - > name , iname - > len ) ;
size = offsetof ( struct fscrypt_nokey_name , bytes [ iname - > len ] ) ;
if ( hash ) {
digested_name . hash = hash ;
digested_name . minor_hash = minor_hash ;
} else {
memcpy ( nokey_name . bytes , iname - > name , sizeof ( nokey_name . bytes ) ) ;
/* Compute strong hash of remaining part of name. */
err = fscrypt_do_sha256 ( & iname - > name [ sizeof ( nokey_name . bytes ) ] ,
iname - > len - sizeof ( nokey_name . bytes ) ,
nokey_name . sha256 ) ;
if ( err )
return err ;
size = FSCRYPT_NOKEY_NAME_MAX ;
digested_name . hash = 0 ;
digested_name . minor_hash = 0 ;
}
oname - > len = base64_encode ( ( const u8 * ) & nokey_name , size , oname - > name ) ;
memcpy ( digested_name . digest ,
FSCRYPT_FNAME_DIGEST ( iname - > name , iname - > len ) ,
FSCRYPT_FNAME_DIGEST_SIZE ) ;
oname - > name [ 0 ] = ' _ ' ;
oname - > len = 1 + base64_encode ( ( const u8 * ) & digested_name ,
sizeof ( digested_name ) , oname - > name + 1 ) ;
return 0 ;
}
EXPORT_SYMBOL ( fscrypt_fname_disk_to_usr ) ;
@ -397,7 +306,8 @@ EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
* get the disk_name .
*
* Else , for keyless @ lookup operations , @ iname is the presented ciphertext , so
* we decode it to get the fscrypt_nokey_name . Non - @ lookup operations will be
* we decode it to get either the ciphertext disk_name ( for short names ) or the
* fscrypt_digested_name ( for long names ) . Non - @ lookup operations will be
* impossible in this case , so we fail them with ENOKEY .
*
* If successful , fscrypt_free_filename ( ) must be called later to clean up .
@ -407,8 +317,8 @@ EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
int fscrypt_setup_filename ( struct inode * dir , const struct qstr * iname ,
int lookup , struct fscrypt_name * fname )
{
struct fscrypt_nokey_name * nokey_name ;
int ret ;
int digested ;
memset ( fname , 0 , sizeof ( struct fscrypt_name ) ) ;
fname - > usr_fname = iname ;
@ -432,8 +342,8 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
if ( ! fname - > crypto_buf . name )
return - ENOMEM ;
ret = fscrypt_f name_encrypt ( dir , iname , fname - > crypto_buf . name ,
fname - > crypto_buf . len ) ;
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 ;
@ -448,31 +358,40 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
* We don ' t have the key and we are doing a lookup ; decode the
* user - supplied name
*/
if ( iname - > name [ 0 ] = = ' _ ' ) {
if ( iname - > len ! =
1 + BASE64_CHARS ( sizeof ( struct fscrypt_digested_name ) ) )
return - ENOENT ;
digested = 1 ;
} else {
if ( iname - > len >
BASE64_CHARS ( FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE ) )
return - ENOENT ;
digested = 0 ;
}
if ( iname - > len > BASE64_CHARS ( FSCRYPT_NOKEY_NAME_MAX ) )
return - ENOENT ;
fname - > crypto_buf . name = kmalloc ( FSCRYPT_NOKEY_NAME_MAX , GFP_KERNEL ) ;
fname - > crypto_buf . name =
kmalloc ( max_t ( size_t , FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE ,
sizeof ( struct fscrypt_digested_name ) ) ,
GFP_KERNEL ) ;
if ( fname - > crypto_buf . name = = NULL )
return - ENOMEM ;
ret = base64_decode ( iname - > name , iname - > len , fname - > crypto_buf . name ) ;
if ( ret < ( int ) offsetof ( struct fscrypt_nokey_name , bytes [ 1 ] ) | |
( ret > offsetof ( struct fscrypt_nokey_name , sha256 ) & &
ret ! = FSCRYPT_NOKEY_NAME_MAX ) ) {
ret = base64_decode ( iname - > name + digested , iname - > len - digested ,
fname - > crypto_buf . name ) ;
if ( ret < 0 ) {
ret = - ENOENT ;
goto errout ;
}
fname - > crypto_buf . len = ret ;
nokey_name = ( void * ) fname - > crypto_buf . name ;
fname - > hash = nokey_name - > dirhash [ 0 ] ;
fname - > minor_hash = nokey_name - > dirhash [ 1 ] ;
if ( ret ! = FSCRYPT_NOKEY_NAME_MAX ) {
/* The full ciphertext filename is available. */
fname - > disk_name . name = nokey_name - > bytes ;
fname - > disk_name . len =
ret - offsetof ( struct fscrypt_nokey_name , bytes ) ;
if ( digested ) {
const struct fscrypt_digested_name * n =
( const void * ) fname - > crypto_buf . name ;
fname - > hash = n - > hash ;
fname - > minor_hash = n - > minor_hash ;
} else {
fname - > disk_name . name = fname - > crypto_buf . name ;
fname - > disk_name . len = fname - > crypto_buf . len ;
}
return 0 ;
@ -481,106 +400,3 @@ errout:
return ret ;
}
EXPORT_SYMBOL ( fscrypt_setup_filename ) ;
/**
* fscrypt_match_name ( ) - test whether the given name matches a directory entry
* @ fname : the name being searched for
* @ de_name : the name from the directory entry
* @ de_name_len : the length of @ de_name in bytes
*
* Normally @ fname - > disk_name will be set , and in that case we simply compare
* that to the name stored in the directory entry . The only exception is that
* if we don ' t have the key for an encrypted directory and the name we ' re
* looking for is very long , then we won ' t have the full disk_name and instead
* we ' ll need to match against a fscrypt_nokey_name that includes a strong hash .
*
* Return : % true if the name matches , otherwise % false .
*/
bool fscrypt_match_name ( const struct fscrypt_name * fname ,
const u8 * de_name , u32 de_name_len )
{
const struct fscrypt_nokey_name * nokey_name =
( const void * ) fname - > crypto_buf . name ;
u8 sha256 [ SHA256_DIGEST_SIZE ] ;
if ( likely ( fname - > disk_name . name ) ) {
if ( de_name_len ! = fname - > disk_name . len )
return false ;
return ! memcmp ( de_name , fname - > disk_name . name , de_name_len ) ;
}
if ( de_name_len < = sizeof ( nokey_name - > bytes ) )
return false ;
if ( memcmp ( de_name , nokey_name - > bytes , sizeof ( nokey_name - > bytes ) ) )
return false ;
if ( fscrypt_do_sha256 ( & de_name [ sizeof ( nokey_name - > bytes ) ] ,
de_name_len - sizeof ( nokey_name - > bytes ) , sha256 ) )
return false ;
return ! memcmp ( sha256 , nokey_name - > sha256 , sizeof ( sha256 ) ) ;
}
EXPORT_SYMBOL_GPL ( fscrypt_match_name ) ;
/**
* fscrypt_fname_siphash ( ) - calculate the SipHash of a filename
* @ dir : the parent directory
* @ name : the filename to calculate the SipHash of
*
* Given a plaintext filename @ name and a directory @ dir which uses SipHash as
* its dirhash method and has had its fscrypt key set up , this function
* calculates the SipHash of that name using the directory ' s secret dirhash key .
*
* Return : the SipHash of @ name using the hash key of @ dir
*/
u64 fscrypt_fname_siphash ( const struct inode * dir , const struct qstr * name )
{
const struct fscrypt_info * ci = dir - > i_crypt_info ;
WARN_ON ( ! ci - > ci_dirhash_key_initialized ) ;
return siphash ( name - > name , name - > len , & ci - > ci_dirhash_key ) ;
}
EXPORT_SYMBOL_GPL ( fscrypt_fname_siphash ) ;
/*
* Validate dentries in encrypted directories to make sure we aren ' t potentially
* caching stale dentries after a key has been added .
*/
int fscrypt_d_revalidate ( struct dentry * dentry , unsigned int flags )
{
struct dentry * dir ;
int err ;
int valid ;
/*
* Plaintext names are always valid , since fscrypt doesn ' t support
* reverting to ciphertext names without evicting the directory ' s inode
* - - which implies eviction of the dentries in the directory .
*/
if ( ! ( dentry - > d_flags & DCACHE_ENCRYPTED_NAME ) )
return 1 ;
/*
* Ciphertext name ; valid if the directory ' s key is still unavailable .
*
* Although fscrypt forbids rename ( ) on ciphertext names , we still must
* use dget_parent ( ) here rather than use - > d_parent directly . That ' s
* because a corrupted fs image may contain directory hard links , which
* the VFS handles by moving the directory ' s dentry tree in the dcache
* each time - > lookup ( ) finds the directory and it already has a dentry
* elsewhere . Thus - > d_parent can be changing , and we must safely grab
* a reference to some - > d_parent to prevent it from being freed .
*/
if ( flags & LOOKUP_RCU )
return - ECHILD ;
dir = dget_parent ( dentry ) ;
err = fscrypt_get_encryption_info ( d_inode ( dir ) ) ;
valid = ! fscrypt_has_encryption_key ( d_inode ( dir ) ) ;
dput ( dir ) ;
if ( err < 0 )
return err ;
return valid ;
}
EXPORT_SYMBOL ( fscrypt_d_revalidate ) ;