diff options
Diffstat (limited to 'fs/ecryptfs/main.c')
| -rw-r--r-- | fs/ecryptfs/main.c | 340 | 
1 files changed, 159 insertions, 181 deletions
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index a9dbd62518e..1b119d3bf92 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -36,6 +36,7 @@  #include <linux/parser.h>  #include <linux/fs_stack.h>  #include <linux/slab.h> +#include <linux/magic.h>  #include "ecryptfs_kernel.h"  /** @@ -95,7 +96,7 @@ void __ecryptfs_printk(const char *fmt, ...)  }  /** - * ecryptfs_init_persistent_file + * ecryptfs_init_lower_file   * @ecryptfs_dentry: Fully initialized eCryptfs dentry object, with   *                   the lower dentry and the lower mount set   * @@ -103,103 +104,68 @@ void __ecryptfs_printk(const char *fmt, ...)   * inode. All I/O operations to the lower inode occur through that   * file. When the first eCryptfs dentry that interposes with the first   * lower dentry for that inode is created, this function creates the - * persistent file struct and associates it with the eCryptfs - * inode. When the eCryptfs inode is destroyed, the file is closed. + * lower file struct and associates it with the eCryptfs + * inode. When all eCryptfs files associated with the inode are released, the + * file is closed.   * - * The persistent file will be opened with read/write permissions, if + * The lower file will be opened with read/write permissions, if   * possible. Otherwise, it is opened read-only.   * - * This function does nothing if a lower persistent file is already + * This function does nothing if a lower file is already   * associated with the eCryptfs inode.   *   * Returns zero on success; non-zero otherwise   */ -int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) +static int ecryptfs_init_lower_file(struct dentry *dentry, +				    struct file **lower_file)  {  	const struct cred *cred = current_cred(); -	struct ecryptfs_inode_info *inode_info = -		ecryptfs_inode_to_private(ecryptfs_dentry->d_inode); -	int rc = 0; +	struct path *path = ecryptfs_dentry_to_lower_path(dentry); +	int rc; + +	rc = ecryptfs_privileged_open(lower_file, path->dentry, path->mnt, +				      cred); +	if (rc) { +		printk(KERN_ERR "Error opening lower file " +		       "for lower_dentry [0x%p] and lower_mnt [0x%p]; " +		       "rc = [%d]\n", path->dentry, path->mnt, rc); +		(*lower_file) = NULL; +	} +	return rc; +} + +int ecryptfs_get_lower_file(struct dentry *dentry, struct inode *inode) +{ +	struct ecryptfs_inode_info *inode_info; +	int count, rc = 0; +	inode_info = ecryptfs_inode_to_private(inode);  	mutex_lock(&inode_info->lower_file_mutex); -	if (!inode_info->lower_file) { -		struct dentry *lower_dentry; -		struct vfsmount *lower_mnt = -			ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); - -		lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); -		rc = ecryptfs_privileged_open(&inode_info->lower_file, -					      lower_dentry, lower_mnt, cred); -		if (rc) { -			printk(KERN_ERR "Error opening lower persistent file " -			       "for lower_dentry [0x%p] and lower_mnt [0x%p]; " -			       "rc = [%d]\n", lower_dentry, lower_mnt, rc); -			inode_info->lower_file = NULL; -		} +	count = atomic_inc_return(&inode_info->lower_file_count); +	if (WARN_ON_ONCE(count < 1)) +		rc = -EINVAL; +	else if (count == 1) { +		rc = ecryptfs_init_lower_file(dentry, +					      &inode_info->lower_file); +		if (rc) +			atomic_set(&inode_info->lower_file_count, 0);  	}  	mutex_unlock(&inode_info->lower_file_mutex);  	return rc;  } -/** - * ecryptfs_interpose - * @lower_dentry: Existing dentry in the lower filesystem - * @dentry: ecryptfs' dentry - * @sb: ecryptfs's super_block - * @flags: flags to govern behavior of interpose procedure - * - * Interposes upper and lower dentries. - * - * Returns zero on success; non-zero otherwise - */ -int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, -		       struct super_block *sb, u32 flags) +void ecryptfs_put_lower_file(struct inode *inode)  { -	struct inode *lower_inode; -	struct inode *inode; -	int rc = 0; +	struct ecryptfs_inode_info *inode_info; -	lower_inode = lower_dentry->d_inode; -	if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) { -		rc = -EXDEV; -		goto out; -	} -	if (!igrab(lower_inode)) { -		rc = -ESTALE; -		goto out; -	} -	inode = iget5_locked(sb, (unsigned long)lower_inode, -			     ecryptfs_inode_test, ecryptfs_inode_set, -			     lower_inode); -	if (!inode) { -		rc = -EACCES; -		iput(lower_inode); -		goto out; +	inode_info = ecryptfs_inode_to_private(inode); +	if (atomic_dec_and_mutex_lock(&inode_info->lower_file_count, +				      &inode_info->lower_file_mutex)) { +		filemap_write_and_wait(inode->i_mapping); +		fput(inode_info->lower_file); +		inode_info->lower_file = NULL; +		mutex_unlock(&inode_info->lower_file_mutex);  	} -	if (inode->i_state & I_NEW) -		unlock_new_inode(inode); -	else -		iput(lower_inode); -	if (S_ISLNK(lower_inode->i_mode)) -		inode->i_op = &ecryptfs_symlink_iops; -	else if (S_ISDIR(lower_inode->i_mode)) -		inode->i_op = &ecryptfs_dir_iops; -	if (S_ISDIR(lower_inode->i_mode)) -		inode->i_fop = &ecryptfs_dir_fops; -	if (special_file(lower_inode->i_mode)) -		init_special_inode(inode, lower_inode->i_mode, -				   lower_inode->i_rdev); -	dentry->d_op = &ecryptfs_dops; -	fsstack_copy_attr_all(inode, lower_inode); -	/* This size will be overwritten for real files w/ headers and -	 * other metadata */ -	fsstack_copy_inode_size(inode, lower_inode); -	if (flags & ECRYPTFS_INTERPOSE_FLAG_D_ADD) -		d_add(dentry, inode); -	else -		d_instantiate(dentry, inode); -out: -	return rc;  }  enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, @@ -209,6 +175,7 @@ enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,         ecryptfs_opt_encrypted_view, ecryptfs_opt_fnek_sig,         ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes,         ecryptfs_opt_unlink_sigs, ecryptfs_opt_mount_auth_tok_only, +       ecryptfs_opt_check_dev_ruid,         ecryptfs_opt_err };  static const match_table_t tokens = { @@ -225,6 +192,7 @@ static const match_table_t tokens = {  	{ecryptfs_opt_fn_cipher_key_bytes, "ecryptfs_fn_key_bytes=%u"},  	{ecryptfs_opt_unlink_sigs, "ecryptfs_unlink_sigs"},  	{ecryptfs_opt_mount_auth_tok_only, "ecryptfs_mount_auth_tok_only"}, +	{ecryptfs_opt_check_dev_ruid, "ecryptfs_check_dev_ruid"},  	{ecryptfs_opt_err, NULL}  }; @@ -232,14 +200,14 @@ static int ecryptfs_init_global_auth_toks(  	struct ecryptfs_mount_crypt_stat *mount_crypt_stat)  {  	struct ecryptfs_global_auth_tok *global_auth_tok; +	struct ecryptfs_auth_tok *auth_tok;  	int rc = 0;  	list_for_each_entry(global_auth_tok,  			    &mount_crypt_stat->global_auth_tok_list,  			    mount_crypt_stat_list) {  		rc = ecryptfs_keyring_auth_tok_for_sig( -			&global_auth_tok->global_auth_tok_key, -			&global_auth_tok->global_auth_tok, +			&global_auth_tok->global_auth_tok_key, &auth_tok,  			global_auth_tok->sig);  		if (rc) {  			printk(KERN_ERR "Could not find valid key in user " @@ -247,8 +215,10 @@ static int ecryptfs_init_global_auth_toks(  			       "option: [%s]\n", global_auth_tok->sig);  			global_auth_tok->flags |= ECRYPTFS_AUTH_TOK_INVALID;  			goto out; -		} else +		} else {  			global_auth_tok->flags &= ~ECRYPTFS_AUTH_TOK_INVALID; +			up_write(&(global_auth_tok->global_auth_tok_key)->sem); +		}  	}  out:  	return rc; @@ -267,7 +237,8 @@ static void ecryptfs_init_mount_crypt_stat(  /**   * ecryptfs_parse_options   * @sb: The ecryptfs super block - * @options: The options pased to the kernel + * @options: The options passed to the kernel + * @check_ruid: set to 1 if device uid should be checked against the ruid   *   * Parse mount options:   * debug=N 	   - ecryptfs_verbosity level for debug output @@ -283,7 +254,8 @@ static void ecryptfs_init_mount_crypt_stat(   *   * Returns zero on success; non-zero on error   */ -static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options) +static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, +				  uid_t *check_ruid)  {  	char *p;  	int rc = 0; @@ -307,6 +279,9 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)  	char *fnek_src;  	char *cipher_key_bytes_src;  	char *fn_cipher_key_bytes_src; +	u8 cipher_code; + +	*check_ruid = 0;  	if (!options) {  		rc = -EINVAL; @@ -412,6 +387,9 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)  			mount_crypt_stat->flags |=  				ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY;  			break; +		case ecryptfs_opt_check_dev_ruid: +			*check_ruid = 1; +			break;  		case ecryptfs_opt_err:  		default:  			printk(KERN_WARNING @@ -443,6 +421,18 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)  	    && !fn_cipher_key_bytes_set)  		mount_crypt_stat->global_default_fn_cipher_key_bytes =  			mount_crypt_stat->global_default_cipher_key_size; + +	cipher_code = ecryptfs_code_for_cipher_string( +		mount_crypt_stat->global_default_cipher_name, +		mount_crypt_stat->global_default_cipher_key_size); +	if (!cipher_code) { +		ecryptfs_printk(KERN_ERR, +				"eCryptfs doesn't support cipher: %s", +				mount_crypt_stat->global_default_cipher_name); +		rc = -EINVAL; +		goto out; +	} +  	mutex_lock(&key_tfm_list_mutex);  	if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name,  				 NULL)) { @@ -492,59 +482,11 @@ struct kmem_cache *ecryptfs_sb_info_cache;  static struct file_system_type ecryptfs_fs_type;  /** - * ecryptfs_read_super - * @sb: The ecryptfs super block - * @dev_name: The path to mount over - * - * Read the super block of the lower filesystem, and use - * ecryptfs_interpose to create our initial inode and super block - * struct. - */ -static int ecryptfs_read_super(struct super_block *sb, const char *dev_name) -{ -	struct path path; -	int rc; - -	rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); -	if (rc) { -		ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n"); -		goto out; -	} -	if (path.dentry->d_sb->s_type == &ecryptfs_fs_type) { -		rc = -EINVAL; -		printk(KERN_ERR "Mount on filesystem of type " -			"eCryptfs explicitly disallowed due to " -			"known incompatibilities\n"); -		goto out_free; -	} -	ecryptfs_set_superblock_lower(sb, path.dentry->d_sb); -	sb->s_maxbytes = path.dentry->d_sb->s_maxbytes; -	sb->s_blocksize = path.dentry->d_sb->s_blocksize; -	ecryptfs_set_dentry_lower(sb->s_root, path.dentry); -	ecryptfs_set_dentry_lower_mnt(sb->s_root, path.mnt); -	rc = ecryptfs_interpose(path.dentry, sb->s_root, sb, 0); -	if (rc) -		goto out_free; -	rc = 0; -	goto out; -out_free: -	path_put(&path); -out: -	return rc; -} - -/**   * ecryptfs_get_sb   * @fs_type   * @flags   * @dev_name: The path to mount over   * @raw_data: The options passed into the kernel - * - * The whole ecryptfs_get_sb process is broken into 3 functions: - * ecryptfs_parse_options(): handle options passed to ecryptfs, if any - * ecryptfs_read_super(): this accesses the lower filesystem and uses - *                        ecryptfs_interpose to perform most of the linking - * ecryptfs_interpose(): links the lower filesystem into ecryptfs (inode.c)   */  static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags,  			const char *dev_name, void *raw_data) @@ -553,6 +495,9 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags  	struct ecryptfs_sb_info *sbi;  	struct ecryptfs_dentry_info *root_info;  	const char *err = "Getting sb failed"; +	struct inode *inode; +	struct path path; +	uid_t check_ruid;  	int rc;  	sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL); @@ -561,24 +506,21 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags  		goto out;  	} -	rc = ecryptfs_parse_options(sbi, raw_data); +	rc = ecryptfs_parse_options(sbi, raw_data, &check_ruid);  	if (rc) {  		err = "Error parsing options";  		goto out;  	} -	s = sget(fs_type, NULL, set_anon_super, NULL); +	s = sget(fs_type, NULL, set_anon_super, flags, NULL);  	if (IS_ERR(s)) {  		rc = PTR_ERR(s);  		goto out;  	} -	s->s_flags = flags;  	rc = bdi_setup_and_register(&sbi->bdi, "ecryptfs", BDI_CAP_MAP_COPY); -	if (rc) { -		deactivate_locked_super(s); -		goto out; -	} +	if (rc) +		goto out1;  	ecryptfs_set_superblock_private(s, sbi);  	s->s_bdi = &sbi->bdi; @@ -586,34 +528,72 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags  	/* ->kill_sb() will take care of sbi after that point */  	sbi = NULL;  	s->s_op = &ecryptfs_sops; +	s->s_d_op = &ecryptfs_dops; -	rc = -ENOMEM; -	s->s_root = d_alloc(NULL, &(const struct qstr) { -			     .hash = 0,.name = "/",.len = 1}); +	err = "Reading sb failed"; +	rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); +	if (rc) { +		ecryptfs_printk(KERN_WARNING, "kern_path() failed\n"); +		goto out1; +	} +	if (path.dentry->d_sb->s_type == &ecryptfs_fs_type) { +		rc = -EINVAL; +		printk(KERN_ERR "Mount on filesystem of type " +			"eCryptfs explicitly disallowed due to " +			"known incompatibilities\n"); +		goto out_free; +	} + +	if (check_ruid && !uid_eq(path.dentry->d_inode->i_uid, current_uid())) { +		rc = -EPERM; +		printk(KERN_ERR "Mount of device (uid: %d) not owned by " +		       "requested user (uid: %d)\n", +			i_uid_read(path.dentry->d_inode), +			from_kuid(&init_user_ns, current_uid())); +		goto out_free; +	} + +	ecryptfs_set_superblock_lower(s, path.dentry->d_sb); + +	/** +	 * Set the POSIX ACL flag based on whether they're enabled in the lower +	 * mount. Force a read-only eCryptfs mount if the lower mount is ro. +	 * Allow a ro eCryptfs mount even when the lower mount is rw. +	 */ +	s->s_flags = flags & ~MS_POSIXACL; +	s->s_flags |= path.dentry->d_sb->s_flags & (MS_RDONLY | MS_POSIXACL); + +	s->s_maxbytes = path.dentry->d_sb->s_maxbytes; +	s->s_blocksize = path.dentry->d_sb->s_blocksize; +	s->s_magic = ECRYPTFS_SUPER_MAGIC; + +	inode = ecryptfs_get_inode(path.dentry->d_inode, s); +	rc = PTR_ERR(inode); +	if (IS_ERR(inode)) +		goto out_free; + +	s->s_root = d_make_root(inode);  	if (!s->s_root) { -		deactivate_locked_super(s); -		goto out; +		rc = -ENOMEM; +		goto out_free;  	} -	s->s_root->d_op = &ecryptfs_dops; -	s->s_root->d_sb = s; -	s->s_root->d_parent = s->s_root; +	rc = -ENOMEM;  	root_info = kmem_cache_zalloc(ecryptfs_dentry_info_cache, GFP_KERNEL); -	if (!root_info) { -		deactivate_locked_super(s); -		goto out; -	} +	if (!root_info) +		goto out_free; +  	/* ->kill_sb() will take care of root_info */  	ecryptfs_set_dentry_private(s->s_root, root_info); +	root_info->lower_path = path; +  	s->s_flags |= MS_ACTIVE; -	rc = ecryptfs_read_super(s, dev_name); -	if (rc) { -		deactivate_locked_super(s); -		err = "Reading sb failed"; -		goto out; -	}  	return dget(s->s_root); +out_free: +	path_put(&path); +out1: +	deactivate_locked_super(s);  out:  	if (sbi) {  		ecryptfs_destroy_mount_crypt_stat(&sbi->mount_crypt_stat); @@ -647,6 +627,7 @@ static struct file_system_type ecryptfs_fs_type = {  	.kill_sb = ecryptfs_kill_block_super,  	.fs_flags = 0  }; +MODULE_ALIAS_FS("ecryptfs");  /**   * inode_info_init_once @@ -694,13 +675,8 @@ static struct ecryptfs_cache_info {  		.size = sizeof(struct ecryptfs_sb_info),  	},  	{ -		.cache = &ecryptfs_header_cache_1, -		.name = "ecryptfs_headers_1", -		.size = PAGE_CACHE_SIZE, -	}, -	{ -		.cache = &ecryptfs_header_cache_2, -		.name = "ecryptfs_headers_2", +		.cache = &ecryptfs_header_cache, +		.name = "ecryptfs_headers",  		.size = PAGE_CACHE_SIZE,  	},  	{ @@ -728,17 +704,18 @@ static struct ecryptfs_cache_info {  		.name = "ecryptfs_key_tfm_cache",  		.size = sizeof(struct ecryptfs_key_tfm),  	}, -	{ -		.cache = &ecryptfs_open_req_cache, -		.name = "ecryptfs_open_req_cache", -		.size = sizeof(struct ecryptfs_open_req), -	},  };  static void ecryptfs_free_kmem_caches(void)  {  	int i; +	/* +	 * Make sure all delayed rcu free inodes are flushed before we +	 * destroy cache. +	 */ +	rcu_barrier(); +  	for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {  		struct ecryptfs_cache_info *info; @@ -828,9 +805,10 @@ static int __init ecryptfs_init(void)  		ecryptfs_printk(KERN_ERR, "The eCryptfs extent size is "  				"larger than the host's page size, and so "  				"eCryptfs cannot run on this system. The " -				"default eCryptfs extent size is [%d] bytes; " -				"the page size is [%d] bytes.\n", -				ECRYPTFS_DEFAULT_EXTENT_SIZE, PAGE_CACHE_SIZE); +				"default eCryptfs extent size is [%u] bytes; " +				"the page size is [%lu] bytes.\n", +				ECRYPTFS_DEFAULT_EXTENT_SIZE, +				(unsigned long)PAGE_CACHE_SIZE);  		goto out;  	}  	rc = ecryptfs_init_kmem_caches(); @@ -839,15 +817,10 @@ static int __init ecryptfs_init(void)  		       "Failed to allocate one or more kmem_cache objects\n");  		goto out;  	} -	rc = register_filesystem(&ecryptfs_fs_type); -	if (rc) { -		printk(KERN_ERR "Failed to register filesystem\n"); -		goto out_free_kmem_caches; -	}  	rc = do_sysfs_registration();  	if (rc) {  		printk(KERN_ERR "sysfs registration failed\n"); -		goto out_unregister_filesystem; +		goto out_free_kmem_caches;  	}  	rc = ecryptfs_init_kthread();  	if (rc) { @@ -857,7 +830,7 @@ static int __init ecryptfs_init(void)  	}  	rc = ecryptfs_init_messaging();  	if (rc) { -		printk(KERN_ERR "Failure occured while attempting to " +		printk(KERN_ERR "Failure occurred while attempting to "  				"initialize the communications channel to "  				"ecryptfsd\n");  		goto out_destroy_kthread; @@ -868,19 +841,24 @@ static int __init ecryptfs_init(void)  		       "rc = [%d]\n", rc);  		goto out_release_messaging;  	} +	rc = register_filesystem(&ecryptfs_fs_type); +	if (rc) { +		printk(KERN_ERR "Failed to register filesystem\n"); +		goto out_destroy_crypto; +	}  	if (ecryptfs_verbosity > 0)  		printk(KERN_CRIT "eCryptfs verbosity set to %d. Secret values "  			"will be written to the syslog!\n", ecryptfs_verbosity);  	goto out; +out_destroy_crypto: +	ecryptfs_destroy_crypto();  out_release_messaging:  	ecryptfs_release_messaging();  out_destroy_kthread:  	ecryptfs_destroy_kthread();  out_do_sysfs_unregistration:  	do_sysfs_unregistration(); -out_unregister_filesystem: -	unregister_filesystem(&ecryptfs_fs_type);  out_free_kmem_caches:  	ecryptfs_free_kmem_caches();  out:  | 
