2015-04-20 15:19:06 -07:00
/*
* copied from linux / fs / ext4 / crypto_policy . c
*
* Copyright ( C ) 2015 , Google , Inc .
* Copyright ( C ) 2015 , Motorola Mobility .
*
* This contains encryption policy functions for f2fs with some modifications
* to support f2fs - specific xattr APIs .
*
* Written by Michael Halcrow , 2015.
* Modified by Jaegeuk Kim , 2015.
*/
# include <linux/random.h>
# include <linux/string.h>
# include <linux/types.h>
# include <linux/f2fs_fs.h>
# include "f2fs.h"
# include "xattr.h"
static int f2fs_inode_has_encryption_context ( struct inode * inode )
{
int res = f2fs_getxattr ( inode , F2FS_XATTR_INDEX_ENCRYPTION ,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT , NULL , 0 , NULL ) ;
return ( res > 0 ) ;
}
/*
* check whether the policy is consistent with the encryption context
* for the inode
*/
static int f2fs_is_encryption_context_consistent_with_policy (
struct inode * inode , const struct f2fs_encryption_policy * policy )
{
struct f2fs_encryption_context ctx ;
int res = f2fs_getxattr ( inode , F2FS_XATTR_INDEX_ENCRYPTION ,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT , & ctx ,
sizeof ( ctx ) , NULL ) ;
if ( res ! = sizeof ( ctx ) )
return 0 ;
return ( memcmp ( ctx . master_key_descriptor , policy - > master_key_descriptor ,
F2FS_KEY_DESCRIPTOR_SIZE ) = = 0 & &
( ctx . flags = = policy - > flags ) & &
( ctx . contents_encryption_mode = =
policy - > contents_encryption_mode ) & &
( ctx . filenames_encryption_mode = =
policy - > filenames_encryption_mode ) ) ;
}
static int f2fs_create_encryption_context_from_policy (
struct inode * inode , const struct f2fs_encryption_policy * policy )
{
struct f2fs_encryption_context ctx ;
ctx . format = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1 ;
memcpy ( ctx . master_key_descriptor , policy - > master_key_descriptor ,
F2FS_KEY_DESCRIPTOR_SIZE ) ;
if ( ! f2fs_valid_contents_enc_mode ( policy - > contents_encryption_mode ) ) {
printk ( KERN_WARNING
" %s: Invalid contents encryption mode %d \n " , __func__ ,
policy - > contents_encryption_mode ) ;
return - EINVAL ;
}
if ( ! f2fs_valid_filenames_enc_mode ( policy - > filenames_encryption_mode ) ) {
printk ( KERN_WARNING
" %s: Invalid filenames encryption mode %d \n " , __func__ ,
policy - > filenames_encryption_mode ) ;
return - EINVAL ;
}
if ( policy - > flags & ~ F2FS_POLICY_FLAGS_VALID )
return - EINVAL ;
ctx . contents_encryption_mode = policy - > contents_encryption_mode ;
ctx . filenames_encryption_mode = policy - > filenames_encryption_mode ;
ctx . flags = policy - > flags ;
BUILD_BUG_ON ( sizeof ( ctx . nonce ) ! = F2FS_KEY_DERIVATION_NONCE_SIZE ) ;
get_random_bytes ( ctx . nonce , F2FS_KEY_DERIVATION_NONCE_SIZE ) ;
return f2fs_setxattr ( inode , F2FS_XATTR_INDEX_ENCRYPTION ,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT , & ctx ,
2015-05-25 18:09:03 +08:00
sizeof ( ctx ) , NULL , XATTR_CREATE ) ;
2015-04-20 15:19:06 -07:00
}
int f2fs_process_policy ( const struct f2fs_encryption_policy * policy ,
struct inode * inode )
{
if ( policy - > version ! = 0 )
return - EINVAL ;
2015-05-27 15:27:49 +08:00
if ( ! S_ISDIR ( inode - > i_mode ) )
return - EINVAL ;
2015-04-20 15:19:06 -07:00
if ( ! f2fs_inode_has_encryption_context ( inode ) ) {
if ( ! f2fs_empty_dir ( inode ) )
return - ENOTEMPTY ;
return f2fs_create_encryption_context_from_policy ( inode ,
policy ) ;
}
if ( f2fs_is_encryption_context_consistent_with_policy ( inode , policy ) )
return 0 ;
printk ( KERN_WARNING " %s: Policy inconsistent with encryption context \n " ,
__func__ ) ;
return - EINVAL ;
}
int f2fs_get_policy ( struct inode * inode , struct f2fs_encryption_policy * policy )
{
struct f2fs_encryption_context ctx ;
int res ;
if ( ! f2fs_encrypted_inode ( inode ) )
return - ENODATA ;
res = f2fs_getxattr ( inode , F2FS_XATTR_INDEX_ENCRYPTION ,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT ,
& ctx , sizeof ( ctx ) , NULL ) ;
if ( res ! = sizeof ( ctx ) )
return - ENODATA ;
if ( ctx . format ! = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1 )
return - EINVAL ;
policy - > version = 0 ;
policy - > contents_encryption_mode = ctx . contents_encryption_mode ;
policy - > filenames_encryption_mode = ctx . filenames_encryption_mode ;
policy - > flags = ctx . flags ;
memcpy ( & policy - > master_key_descriptor , ctx . master_key_descriptor ,
F2FS_KEY_DESCRIPTOR_SIZE ) ;
return 0 ;
}
int f2fs_is_child_context_consistent_with_parent ( struct inode * parent ,
struct inode * child )
{
struct f2fs_crypt_info * parent_ci , * child_ci ;
int res ;
if ( ( parent = = NULL ) | | ( child = = NULL ) ) {
pr_err ( " parent %p child %p \n " , parent , child ) ;
BUG_ON ( 1 ) ;
}
/* no restrictions if the parent directory is not encrypted */
if ( ! f2fs_encrypted_inode ( parent ) )
return 1 ;
/* if the child directory is not encrypted, this is always a problem */
if ( ! f2fs_encrypted_inode ( child ) )
return 0 ;
res = f2fs_get_encryption_info ( parent ) ;
if ( res )
return 0 ;
res = f2fs_get_encryption_info ( child ) ;
if ( res )
return 0 ;
parent_ci = F2FS_I ( parent ) - > i_crypt_info ;
child_ci = F2FS_I ( child ) - > i_crypt_info ;
if ( ! parent_ci & & ! child_ci )
return 1 ;
if ( ! parent_ci | | ! child_ci )
return 0 ;
return ( memcmp ( parent_ci - > ci_master_key ,
child_ci - > ci_master_key ,
F2FS_KEY_DESCRIPTOR_SIZE ) = = 0 & &
( parent_ci - > ci_data_mode = = child_ci - > ci_data_mode ) & &
( parent_ci - > ci_filename_mode = = child_ci - > ci_filename_mode ) & &
( parent_ci - > ci_flags = = child_ci - > ci_flags ) ) ;
}
/**
* f2fs_inherit_context ( ) - Sets a child context from its parent
* @ parent : Parent inode from which the context is inherited .
* @ child : Child inode that inherits the context from @ parent .
*
* Return : Zero on success , non - zero otherwise
*/
int f2fs_inherit_context ( struct inode * parent , struct inode * child ,
struct page * ipage )
{
struct f2fs_encryption_context ctx ;
struct f2fs_crypt_info * ci ;
int res ;
res = f2fs_get_encryption_info ( parent ) ;
if ( res < 0 )
return res ;
ci = F2FS_I ( parent ) - > i_crypt_info ;
BUG_ON ( ci = = NULL ) ;
ctx . format = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1 ;
ctx . contents_encryption_mode = ci - > ci_data_mode ;
ctx . filenames_encryption_mode = ci - > ci_filename_mode ;
ctx . flags = ci - > ci_flags ;
memcpy ( ctx . master_key_descriptor , ci - > ci_master_key ,
F2FS_KEY_DESCRIPTOR_SIZE ) ;
get_random_bytes ( ctx . nonce , F2FS_KEY_DERIVATION_NONCE_SIZE ) ;
return f2fs_setxattr ( child , F2FS_XATTR_INDEX_ENCRYPTION ,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT , & ctx ,
2015-05-25 18:09:03 +08:00
sizeof ( ctx ) , ipage , XATTR_CREATE ) ;
2015-04-20 15:19:06 -07:00
}