1164 lines · 32.9 KB · C
RawDownload
/** * eCryptfs: Linux filesystem encryption layer * * Copyright (C) 1997-2004 Erez Zadok * Copyright (C) 2001-2004 Stony Brook University * Copyright (C) 2004-2007 International Business Machines Corp. *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> *              Michael C. Thompsion <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/vmalloc.h>#include <linux/pagemap.h>#include <linux/dcache.h>#include <linux/namei.h>#include <linux/mount.h>#include <linux/crypto.h>#include <linux/fs_stack.h>#include <linux/slab.h>#include <linux/xattr.h>#include <asm/unaligned.h>#include "ecryptfs_kernel.h" static struct dentry *lock_parent(struct dentry *dentry){	struct dentry *dir; 	dir = dget_parent(dentry);	mutex_lock_nested(&(dir->d_inode->i_mutex), I_MUTEX_PARENT);	return dir;} static void unlock_dir(struct dentry *dir){	mutex_unlock(&dir->d_inode->i_mutex);	dput(dir);} static int ecryptfs_inode_test(struct inode *inode, void *lower_inode){	if (ecryptfs_inode_to_lower(inode) == (struct inode *)lower_inode)		return 1;	return 0;} static int ecryptfs_inode_set(struct inode *inode, void *opaque){	struct inode *lower_inode = opaque; 	ecryptfs_set_inode_lower(inode, lower_inode);	fsstack_copy_attr_all(inode, lower_inode);	/* i_size will be overwritten for encrypted regular files */	fsstack_copy_inode_size(inode, lower_inode);	inode->i_ino = lower_inode->i_ino;	inode->i_version++;	inode->i_mapping->a_ops = &ecryptfs_aops;	inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi; 	if (S_ISLNK(inode->i_mode))		inode->i_op = &ecryptfs_symlink_iops;	else if (S_ISDIR(inode->i_mode))		inode->i_op = &ecryptfs_dir_iops;	else		inode->i_op = &ecryptfs_main_iops; 	if (S_ISDIR(inode->i_mode))		inode->i_fop = &ecryptfs_dir_fops;	else if (special_file(inode->i_mode))		init_special_inode(inode, inode->i_mode, inode->i_rdev);	else		inode->i_fop = &ecryptfs_main_fops; 	return 0;} static struct inode *__ecryptfs_get_inode(struct inode *lower_inode,					  struct super_block *sb){	struct inode *inode; 	if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb))		return ERR_PTR(-EXDEV);	if (!igrab(lower_inode))		return ERR_PTR(-ESTALE);	inode = iget5_locked(sb, (unsigned long)lower_inode,			     ecryptfs_inode_test, ecryptfs_inode_set,			     lower_inode);	if (!inode) {		iput(lower_inode);		return ERR_PTR(-EACCES);	}	if (!(inode->i_state & I_NEW))		iput(lower_inode); 	return inode;} struct inode *ecryptfs_get_inode(struct inode *lower_inode,				 struct super_block *sb){	struct inode *inode = __ecryptfs_get_inode(lower_inode, sb); 	if (!IS_ERR(inode) && (inode->i_state & I_NEW))		unlock_new_inode(inode); 	return inode;} /** * ecryptfs_interpose * @lower_dentry: Existing dentry in the lower filesystem * @dentry: ecryptfs' dentry * @sb: ecryptfs's super_block * * Interposes upper and lower dentries. * * Returns zero on success; non-zero otherwise */static int ecryptfs_interpose(struct dentry *lower_dentry,			      struct dentry *dentry, struct super_block *sb){	struct inode *inode = ecryptfs_get_inode(lower_dentry->d_inode, sb); 	if (IS_ERR(inode))		return PTR_ERR(inode);	d_instantiate(dentry, inode); 	return 0;} /** * ecryptfs_do_create * @directory_inode: inode of the new file's dentry's parent in ecryptfs * @ecryptfs_dentry: New file's dentry in ecryptfs * @mode: The mode of the new file * @nd: nameidata of ecryptfs' parent's dentry & vfsmount * * Creates the underlying file and the eCryptfs inode which will link to * it. It will also update the eCryptfs directory inode to mimic the * stat of the lower directory inode. * * Returns the new eCryptfs inode on success; an ERR_PTR on error condition */static struct inode *ecryptfs_do_create(struct inode *directory_inode,		   struct dentry *ecryptfs_dentry, umode_t mode){	int rc;	struct dentry *lower_dentry;	struct dentry *lower_dir_dentry;	struct inode *inode; 	lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);	lower_dir_dentry = lock_parent(lower_dentry);	if (IS_ERR(lower_dir_dentry)) {		ecryptfs_printk(KERN_ERR, "Error locking directory of "				"dentry\n");		inode = ERR_CAST(lower_dir_dentry);		goto out;	}	rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, NULL);	if (rc) {		printk(KERN_ERR "%s: Failure to create dentry in lower fs; "		       "rc = [%d]\n", __func__, rc);		inode = ERR_PTR(rc);		goto out_lock;	}	inode = __ecryptfs_get_inode(lower_dentry->d_inode,				     directory_inode->i_sb);	if (IS_ERR(inode))		goto out_lock;	fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode);	fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode);out_lock:	unlock_dir(lower_dir_dentry);out:	return inode;} /** * ecryptfs_initialize_file * * Cause the file to be changed from a basic empty file to an ecryptfs * file with a header and first data page. * * Returns zero on success */static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,				    struct inode *ecryptfs_inode){	struct ecryptfs_crypt_stat *crypt_stat =		&ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;	int rc = 0; 	if (S_ISDIR(ecryptfs_inode->i_mode)) {		ecryptfs_printk(KERN_DEBUG, "This is a directory\n");		crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);		goto out;	}	ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n");	rc = ecryptfs_new_file_context(ecryptfs_inode);	if (rc) {		ecryptfs_printk(KERN_ERR, "Error creating new file "				"context; rc = [%d]\n", rc);		goto out;	}	rc = ecryptfs_get_lower_file(ecryptfs_dentry, ecryptfs_inode);	if (rc) {		printk(KERN_ERR "%s: Error attempting to initialize "			"the lower file for the dentry with name "			"[%s]; rc = [%d]\n", __func__,			ecryptfs_dentry->d_name.name, rc);		goto out;	}	rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode);	if (rc)		printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc);	ecryptfs_put_lower_file(ecryptfs_inode);out:	return rc;} /** * ecryptfs_create * @dir: The inode of the directory in which to create the file. * @dentry: The eCryptfs dentry * @mode: The mode of the new file. * @nd: nameidata * * Creates a new file. * * Returns zero on success; non-zero on error condition */static intecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,		umode_t mode, struct nameidata *nd){	struct inode *ecryptfs_inode;	int rc; 	ecryptfs_inode = ecryptfs_do_create(directory_inode, ecryptfs_dentry,					    mode);	if (unlikely(IS_ERR(ecryptfs_inode))) {		ecryptfs_printk(KERN_WARNING, "Failed to create file in"				"lower filesystem\n");		rc = PTR_ERR(ecryptfs_inode);		goto out;	}	/* At this point, a file exists on "disk"; we need to make sure	 * that this on disk file is prepared to be an ecryptfs file */	rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode);	if (rc) {		drop_nlink(ecryptfs_inode);		unlock_new_inode(ecryptfs_inode);		iput(ecryptfs_inode);		goto out;	}	d_instantiate(ecryptfs_dentry, ecryptfs_inode);	unlock_new_inode(ecryptfs_inode);out:	return rc;} static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode){	struct ecryptfs_crypt_stat *crypt_stat;	int rc; 	rc = ecryptfs_get_lower_file(dentry, inode);	if (rc) {		printk(KERN_ERR "%s: Error attempting to initialize "			"the lower file for the dentry with name "			"[%s]; rc = [%d]\n", __func__,			dentry->d_name.name, rc);		return rc;	} 	crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;	/* TODO: lock for crypt_stat comparison */	if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED))		ecryptfs_set_default_sizes(crypt_stat); 	rc = ecryptfs_read_and_validate_header_region(inode);	ecryptfs_put_lower_file(inode);	if (rc) {		rc = ecryptfs_read_and_validate_xattr_region(dentry, inode);		if (!rc)			crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;	} 	/* Must return 0 to allow non-eCryptfs files to be looked up, too */	return 0;} /** * ecryptfs_lookup_interpose - Dentry interposition for a lookup */static int ecryptfs_lookup_interpose(struct dentry *dentry,				     struct dentry *lower_dentry,				     struct inode *dir_inode){	struct inode *inode, *lower_inode = lower_dentry->d_inode;	struct ecryptfs_dentry_info *dentry_info;	struct vfsmount *lower_mnt;	int rc = 0; 	lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));	fsstack_copy_attr_atime(dir_inode, lower_dentry->d_parent->d_inode);	BUG_ON(!lower_dentry->d_count); 	dentry_info = kmem_cache_alloc(ecryptfs_dentry_info_cache, GFP_KERNEL);	ecryptfs_set_dentry_private(dentry, dentry_info);	if (!dentry_info) {		printk(KERN_ERR "%s: Out of memory whilst attempting "		       "to allocate ecryptfs_dentry_info struct\n",			__func__);		dput(lower_dentry);		mntput(lower_mnt);		d_drop(dentry);		return -ENOMEM;	}	ecryptfs_set_dentry_lower(dentry, lower_dentry);	ecryptfs_set_dentry_lower_mnt(dentry, lower_mnt); 	if (!lower_dentry->d_inode) {		/* We want to add because we couldn't find in lower */		d_add(dentry, NULL);		return 0;	}	inode = __ecryptfs_get_inode(lower_inode, dir_inode->i_sb);	if (IS_ERR(inode)) {		printk(KERN_ERR "%s: Error interposing; rc = [%ld]\n",		       __func__, PTR_ERR(inode));		return PTR_ERR(inode);	}	if (S_ISREG(inode->i_mode)) {		rc = ecryptfs_i_size_read(dentry, inode);		if (rc) {			make_bad_inode(inode);			return rc;		}	} 	if (inode->i_state & I_NEW)		unlock_new_inode(inode);	d_add(dentry, inode); 	return rc;} /** * ecryptfs_lookup * @ecryptfs_dir_inode: The eCryptfs directory inode * @ecryptfs_dentry: The eCryptfs dentry that we are looking up * @ecryptfs_nd: nameidata; may be NULL * * Find a file on disk. If the file does not exist, then we'll add it to the * dentry cache and continue on to read it from the disk. */static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,				      struct dentry *ecryptfs_dentry,				      struct nameidata *ecryptfs_nd){	char *encrypted_and_encoded_name = NULL;	size_t encrypted_and_encoded_name_size;	struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL;	struct dentry *lower_dir_dentry, *lower_dentry;	int rc = 0; 	if ((ecryptfs_dentry->d_name.len == 1	     && !strcmp(ecryptfs_dentry->d_name.name, "."))	    || (ecryptfs_dentry->d_name.len == 2		&& !strcmp(ecryptfs_dentry->d_name.name, ".."))) {		goto out_d_drop;	}	lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent);	mutex_lock(&lower_dir_dentry->d_inode->i_mutex);	lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name,				      lower_dir_dentry,				      ecryptfs_dentry->d_name.len);	mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);	if (IS_ERR(lower_dentry)) {		rc = PTR_ERR(lower_dentry);		ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "				"[%d] on lower_dentry = [%s]\n", __func__, rc,				encrypted_and_encoded_name);		goto out_d_drop;	}	if (lower_dentry->d_inode)		goto interpose;	mount_crypt_stat = &ecryptfs_superblock_to_private(				ecryptfs_dentry->d_sb)->mount_crypt_stat;	if (!(mount_crypt_stat	    && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)))		goto interpose;	dput(lower_dentry);	rc = ecryptfs_encrypt_and_encode_filename(		&encrypted_and_encoded_name, &encrypted_and_encoded_name_size,		NULL, mount_crypt_stat, ecryptfs_dentry->d_name.name,		ecryptfs_dentry->d_name.len);	if (rc) {		printk(KERN_ERR "%s: Error attempting to encrypt and encode "		       "filename; rc = [%d]\n", __func__, rc);		goto out_d_drop;	}	mutex_lock(&lower_dir_dentry->d_inode->i_mutex);	lower_dentry = lookup_one_len(encrypted_and_encoded_name,				      lower_dir_dentry,				      encrypted_and_encoded_name_size);	mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);	if (IS_ERR(lower_dentry)) {		rc = PTR_ERR(lower_dentry);		ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "				"[%d] on lower_dentry = [%s]\n", __func__, rc,				encrypted_and_encoded_name);		goto out_d_drop;	}interpose:	rc = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry,				       ecryptfs_dir_inode);	goto out;out_d_drop:	d_drop(ecryptfs_dentry);out:	kfree(encrypted_and_encoded_name);	return ERR_PTR(rc);} static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,			 struct dentry *new_dentry){	struct dentry *lower_old_dentry;	struct dentry *lower_new_dentry;	struct dentry *lower_dir_dentry;	u64 file_size_save;	int rc; 	file_size_save = i_size_read(old_dentry->d_inode);	lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);	lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);	dget(lower_old_dentry);	dget(lower_new_dentry);	lower_dir_dentry = lock_parent(lower_new_dentry);	rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,		      lower_new_dentry);	if (rc || !lower_new_dentry->d_inode)		goto out_lock;	rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb);	if (rc)		goto out_lock;	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);	fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);	set_nlink(old_dentry->d_inode,		  ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink);	i_size_write(new_dentry->d_inode, file_size_save);out_lock:	unlock_dir(lower_dir_dentry);	dput(lower_new_dentry);	dput(lower_old_dentry);	return rc;} static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry){	int rc = 0;	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);	struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);	struct dentry *lower_dir_dentry; 	dget(lower_dentry);	lower_dir_dentry = lock_parent(lower_dentry);	rc = vfs_unlink(lower_dir_inode, lower_dentry);	if (rc) {		printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);		goto out_unlock;	}	fsstack_copy_attr_times(dir, lower_dir_inode);	set_nlink(dentry->d_inode,		  ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink);	dentry->d_inode->i_ctime = dir->i_ctime;	d_drop(dentry);out_unlock:	unlock_dir(lower_dir_dentry);	dput(lower_dentry);	return rc;

Lines 1–500 of 1164.