2006-10-04 13:16:22 +04:00
/**
* eCryptfs : Linux filesystem encryption layer
*
* Copyright ( C ) 1997 - 2004 Erez Zadok
* Copyright ( C ) 2001 - 2004 Stony Brook University
2007-02-12 11:53:46 +03:00
* Copyright ( C ) 2004 - 2007 International Business Machines Corp .
2006-10-04 13:16:22 +04:00
* Author ( s ) : Michael A . Halcrow < mhalcrow @ us . ibm . com >
* Michael C . Thompson < mcthomps @ us . ibm . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of the
* License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA
* 02111 - 1307 , USA .
*/
# include <linux/file.h>
# include <linux/poll.h>
# include <linux/mount.h>
# include <linux/pagemap.h>
# include <linux/security.h>
# include <linux/compat.h>
2006-12-08 13:36:31 +03:00
# include <linux/fs_stack.h>
2008-06-20 02:18:25 +04:00
# include <linux/smp_lock.h>
2006-10-04 13:16:22 +04:00
# include "ecryptfs_kernel.h"
/**
* ecryptfs_read_update_atime
*
* generic_file_read updates the atime of upper layer inode . But , it
* doesn ' t give us a chance to update the atime of the lower layer
* inode . This function is a wrapper to generic_file_read . It
* updates the atime of the lower level inode if generic_file_read
* returns without any errors . This is to be used only for file reads .
* The function to be used for directory reads is ecryptfs_read .
*/
static ssize_t ecryptfs_read_update_atime ( struct kiocb * iocb ,
const struct iovec * iov ,
unsigned long nr_segs , loff_t pos )
{
int rc ;
struct dentry * lower_dentry ;
struct vfsmount * lower_vfsmount ;
struct file * file = iocb - > ki_filp ;
rc = generic_file_aio_read ( iocb , iov , nr_segs , pos ) ;
/*
* Even though this is a async interface , we need to wait
* for IO to finish to update atime
*/
if ( - EIOCBQUEUED = = rc )
rc = wait_on_sync_kiocb ( iocb ) ;
if ( rc > = 0 ) {
2006-12-08 13:36:48 +03:00
lower_dentry = ecryptfs_dentry_to_lower ( file - > f_path . dentry ) ;
lower_vfsmount = ecryptfs_dentry_to_lower_mnt ( file - > f_path . dentry ) ;
2006-10-04 13:16:22 +04:00
touch_atime ( lower_vfsmount , lower_dentry ) ;
}
return rc ;
}
struct ecryptfs_getdents_callback {
void * dirent ;
struct dentry * dentry ;
filldir_t filldir ;
int filldir_called ;
int entries_written ;
} ;
2008-10-16 09:02:49 +04:00
/* Inspired by generic filldir in fs/readdir.c */
2006-10-04 13:16:22 +04:00
static int
ecryptfs_filldir ( void * dirent , const char * name , int namelen , loff_t offset ,
u64 ino , unsigned int d_type )
{
struct ecryptfs_crypt_stat * crypt_stat ;
struct ecryptfs_getdents_callback * buf =
( struct ecryptfs_getdents_callback * ) dirent ;
int rc ;
int decoded_length ;
char * decoded_name ;
crypt_stat = ecryptfs_dentry_to_private ( buf - > dentry ) - > crypt_stat ;
buf - > filldir_called + + ;
decoded_length = ecryptfs_decode_filename ( crypt_stat , name , namelen ,
& decoded_name ) ;
if ( decoded_length < 0 ) {
rc = decoded_length ;
goto out ;
}
rc = buf - > filldir ( buf - > dirent , decoded_name , decoded_length , offset ,
ino , d_type ) ;
kfree ( decoded_name ) ;
if ( rc > = 0 )
buf - > entries_written + + ;
out :
return rc ;
}
/**
* ecryptfs_readdir
* @ file : The ecryptfs file struct
* @ dirent : Directory entry
* @ filldir : The filldir callback function
*/
static int ecryptfs_readdir ( struct file * file , void * dirent , filldir_t filldir )
{
int rc ;
struct file * lower_file ;
struct inode * inode ;
struct ecryptfs_getdents_callback buf ;
lower_file = ecryptfs_file_to_lower ( file ) ;
lower_file - > f_pos = file - > f_pos ;
2006-12-08 13:36:48 +03:00
inode = file - > f_path . dentry - > d_inode ;
2006-10-04 13:16:22 +04:00
memset ( & buf , 0 , sizeof ( buf ) ) ;
buf . dirent = dirent ;
2006-12-08 13:36:48 +03:00
buf . dentry = file - > f_path . dentry ;
2006-10-04 13:16:22 +04:00
buf . filldir = filldir ;
buf . filldir_called = 0 ;
buf . entries_written = 0 ;
rc = vfs_readdir ( lower_file , ecryptfs_filldir , ( void * ) & buf ) ;
file - > f_pos = lower_file - > f_pos ;
2008-10-16 09:02:49 +04:00
if ( rc < 0 )
goto out ;
if ( buf . filldir_called & & ! buf . entries_written )
goto out ;
2006-10-04 13:16:22 +04:00
if ( rc > = 0 )
2008-10-16 09:02:49 +04:00
fsstack_copy_attr_atime ( inode ,
lower_file - > f_path . dentry - > d_inode ) ;
out :
2006-10-04 13:16:22 +04:00
return rc ;
}
struct kmem_cache * ecryptfs_file_info_cache ;
/**
* ecryptfs_open
* @ inode : inode speciying file to open
* @ file : Structure to return filled in
*
* Opens the file specified by inode .
*
* Returns zero on success ; non - zero otherwise
*/
static int ecryptfs_open ( struct inode * inode , struct file * file )
{
int rc = 0 ;
struct ecryptfs_crypt_stat * crypt_stat = NULL ;
struct ecryptfs_mount_crypt_stat * mount_crypt_stat ;
2006-12-08 13:36:48 +03:00
struct dentry * ecryptfs_dentry = file - > f_path . dentry ;
2006-10-04 13:16:22 +04:00
/* Private value of ecryptfs_dentry allocated in
* ecryptfs_lookup ( ) */
struct dentry * lower_dentry = ecryptfs_dentry_to_lower ( ecryptfs_dentry ) ;
struct ecryptfs_file_info * file_info ;
2007-02-12 11:53:47 +03:00
mount_crypt_stat = & ecryptfs_superblock_to_private (
ecryptfs_dentry - > d_sb ) - > mount_crypt_stat ;
if ( ( mount_crypt_stat - > flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED )
& & ( ( file - > f_flags & O_WRONLY ) | | ( file - > f_flags & O_RDWR )
| | ( file - > f_flags & O_CREAT ) | | ( file - > f_flags & O_TRUNC )
| | ( file - > f_flags & O_APPEND ) ) ) {
printk ( KERN_WARNING " Mount has encrypted view enabled; "
" files may only be read \n " ) ;
rc = - EPERM ;
goto out ;
}
2006-10-04 13:16:22 +04:00
/* Released in ecryptfs_release or end of function if failure */
2007-02-10 12:45:03 +03:00
file_info = kmem_cache_zalloc ( ecryptfs_file_info_cache , GFP_KERNEL ) ;
2006-10-04 13:16:22 +04:00
ecryptfs_set_file_private ( file , file_info ) ;
if ( ! file_info ) {
ecryptfs_printk ( KERN_ERR ,
" Error attempting to allocate memory \n " ) ;
rc = - ENOMEM ;
goto out ;
}
lower_dentry = ecryptfs_dentry_to_lower ( ecryptfs_dentry ) ;
crypt_stat = & ecryptfs_inode_to_private ( inode ) - > crypt_stat ;
mutex_lock ( & crypt_stat - > cs_mutex ) ;
2007-02-12 11:53:49 +03:00
if ( ! ( crypt_stat - > flags & ECRYPTFS_POLICY_APPLIED ) ) {
2006-10-04 13:16:22 +04:00
ecryptfs_printk ( KERN_DEBUG , " Setting flags for stat... \n " ) ;
/* Policy code enabled in future release */
2007-10-16 12:28:10 +04:00
crypt_stat - > flags | = ( ECRYPTFS_POLICY_APPLIED
| ECRYPTFS_ENCRYPTED ) ;
2006-10-04 13:16:22 +04:00
}
mutex_unlock ( & crypt_stat - > cs_mutex ) ;
2008-07-24 08:30:02 +04:00
if ( ( ecryptfs_inode_to_private ( inode ) - > lower_file - > f_flags & O_RDONLY )
& & ! ( file - > f_flags & O_RDONLY ) ) {
rc = - EPERM ;
printk ( KERN_WARNING " %s: Lower persistent file is RO; eCryptfs "
" file must hence be opened RO \n " , __func__ ) ;
goto out ;
}
2008-07-24 08:30:07 +04:00
if ( ! ecryptfs_inode_to_private ( inode ) - > lower_file ) {
rc = ecryptfs_init_persistent_file ( ecryptfs_dentry ) ;
if ( rc ) {
printk ( KERN_ERR " %s: Error attempting to initialize "
" the persistent file for the dentry with name "
" [%s]; rc = [%d] \n " , __func__ ,
ecryptfs_dentry - > d_name . name , rc ) ;
goto out ;
}
}
2007-10-16 12:28:10 +04:00
ecryptfs_set_file_lower (
file , ecryptfs_inode_to_private ( inode ) - > lower_file ) ;
2006-10-04 13:16:22 +04:00
if ( S_ISDIR ( ecryptfs_dentry - > d_inode - > i_mode ) ) {
ecryptfs_printk ( KERN_DEBUG , " This is a directory \n " ) ;
2008-04-29 11:59:52 +04:00
mutex_lock ( & crypt_stat - > cs_mutex ) ;
2007-02-12 11:53:49 +03:00
crypt_stat - > flags & = ~ ( ECRYPTFS_ENCRYPTED ) ;
2008-04-29 11:59:52 +04:00
mutex_unlock ( & crypt_stat - > cs_mutex ) ;
2006-10-04 13:16:22 +04:00
rc = 0 ;
goto out ;
}
mutex_lock ( & crypt_stat - > cs_mutex ) ;
2007-02-12 11:53:49 +03:00
if ( ! ( crypt_stat - > flags & ECRYPTFS_POLICY_APPLIED )
| | ! ( crypt_stat - > flags & ECRYPTFS_KEY_VALID ) ) {
2007-10-16 12:28:10 +04:00
rc = ecryptfs_read_metadata ( ecryptfs_dentry ) ;
2006-10-04 13:16:22 +04:00
if ( rc ) {
ecryptfs_printk ( KERN_DEBUG ,
" Valid headers not found \n " ) ;
if ( ! ( mount_crypt_stat - > flags
& ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED ) ) {
rc = - EIO ;
2008-02-06 12:38:35 +03:00
printk ( KERN_WARNING " Either the lower file "
2006-10-04 13:16:22 +04:00
" is not in a valid eCryptfs format, "
2008-02-06 12:38:35 +03:00
" or the key could not be retrieved. "
" Plaintext passthrough mode is not "
2006-10-04 13:16:22 +04:00
" enabled; returning -EIO \n " ) ;
mutex_unlock ( & crypt_stat - > cs_mutex ) ;
2007-10-16 12:28:10 +04:00
goto out_free ;
2006-10-04 13:16:22 +04:00
}
rc = 0 ;
2007-02-12 11:53:49 +03:00
crypt_stat - > flags & = ~ ( ECRYPTFS_ENCRYPTED ) ;
2006-10-04 13:16:22 +04:00
mutex_unlock ( & crypt_stat - > cs_mutex ) ;
goto out ;
}
}
mutex_unlock ( & crypt_stat - > cs_mutex ) ;
ecryptfs_printk ( KERN_DEBUG , " inode w/ addr = [0x%p], i_ino = [0x%.16x] "
" size: [0x%.16x] \n " , inode , inode - > i_ino ,
i_size_read ( inode ) ) ;
goto out ;
2007-10-16 12:28:10 +04:00
out_free :
2006-10-04 13:16:22 +04:00
kmem_cache_free ( ecryptfs_file_info_cache ,
ecryptfs_file_to_private ( file ) ) ;
out :
return rc ;
}
static int ecryptfs_flush ( struct file * file , fl_owner_t td )
{
int rc = 0 ;
struct file * lower_file = NULL ;
lower_file = ecryptfs_file_to_lower ( file ) ;
if ( lower_file - > f_op & & lower_file - > f_op - > flush )
rc = lower_file - > f_op - > flush ( lower_file , td ) ;
return rc ;
}
static int ecryptfs_release ( struct inode * inode , struct file * file )
{
2007-10-16 12:28:10 +04:00
kmem_cache_free ( ecryptfs_file_info_cache ,
ecryptfs_file_to_private ( file ) ) ;
return 0 ;
2006-10-04 13:16:22 +04:00
}
static int
ecryptfs_fsync ( struct file * file , struct dentry * dentry , int datasync )
{
struct file * lower_file = ecryptfs_file_to_lower ( file ) ;
struct dentry * lower_dentry = ecryptfs_dentry_to_lower ( dentry ) ;
struct inode * lower_inode = lower_dentry - > d_inode ;
int rc = - EINVAL ;
if ( lower_inode - > i_fop - > fsync ) {
mutex_lock ( & lower_inode - > i_mutex ) ;
rc = lower_inode - > i_fop - > fsync ( lower_file , lower_dentry ,
datasync ) ;
mutex_unlock ( & lower_inode - > i_mutex ) ;
}
return rc ;
}
static int ecryptfs_fasync ( int fd , struct file * file , int flag )
{
int rc = 0 ;
struct file * lower_file = NULL ;
2008-06-20 02:18:25 +04:00
lock_kernel ( ) ;
2006-10-04 13:16:22 +04:00
lower_file = ecryptfs_file_to_lower ( file ) ;
if ( lower_file - > f_op & & lower_file - > f_op - > fasync )
rc = lower_file - > f_op - > fasync ( fd , lower_file , flag ) ;
2008-06-20 02:18:25 +04:00
unlock_kernel ( ) ;
2006-10-04 13:16:22 +04:00
return rc ;
}
static int ecryptfs_ioctl ( struct inode * inode , struct file * file ,
unsigned int cmd , unsigned long arg ) ;
const struct file_operations ecryptfs_dir_fops = {
. readdir = ecryptfs_readdir ,
. ioctl = ecryptfs_ioctl ,
. mmap = generic_file_mmap ,
. open = ecryptfs_open ,
. flush = ecryptfs_flush ,
. release = ecryptfs_release ,
. fsync = ecryptfs_fsync ,
. fasync = ecryptfs_fasync ,
2007-10-16 12:28:04 +04:00
. splice_read = generic_file_splice_read ,
2006-10-04 13:16:22 +04:00
} ;
const struct file_operations ecryptfs_main_fops = {
2007-05-24 00:58:15 +04:00
. llseek = generic_file_llseek ,
2006-10-04 13:16:22 +04:00
. read = do_sync_read ,
. aio_read = ecryptfs_read_update_atime ,
. write = do_sync_write ,
. aio_write = generic_file_aio_write ,
. readdir = ecryptfs_readdir ,
. ioctl = ecryptfs_ioctl ,
. mmap = generic_file_mmap ,
. open = ecryptfs_open ,
. flush = ecryptfs_flush ,
. release = ecryptfs_release ,
. fsync = ecryptfs_fsync ,
. fasync = ecryptfs_fasync ,
2007-10-16 12:28:04 +04:00
. splice_read = generic_file_splice_read ,
2006-10-04 13:16:22 +04:00
} ;
static int
ecryptfs_ioctl ( struct inode * inode , struct file * file , unsigned int cmd ,
unsigned long arg )
{
int rc = 0 ;
struct file * lower_file = NULL ;
if ( ecryptfs_file_to_private ( file ) )
lower_file = ecryptfs_file_to_lower ( file ) ;
if ( lower_file & & lower_file - > f_op & & lower_file - > f_op - > ioctl )
rc = lower_file - > f_op - > ioctl ( ecryptfs_inode_to_lower ( inode ) ,
lower_file , cmd , arg ) ;
else
rc = - ENOTTY ;
return rc ;
}