866 lines · 24.4 KB · C
RawDownload
/** * eCryptfs: Linux filesystem encryption layer * * Copyright (C) 1997-2003 Erez Zadok * Copyright (C) 2001-2003 Stony Brook University * Copyright (C) 2004-2007 International Business Machines Corp. *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> *              Michael C. Thompson <mcthomps@us.ibm.com> *              Tyler Hicks <tyhicks@ou.edu> * * 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/dcache.h>#include <linux/file.h>#include <linux/module.h>#include <linux/namei.h>#include <linux/skbuff.h>#include <linux/crypto.h>#include <linux/mount.h>#include <linux/pagemap.h>#include <linux/key.h>#include <linux/parser.h>#include <linux/fs_stack.h>#include <linux/slab.h>#include <linux/magic.h>#include "ecryptfs_kernel.h" /** * Module parameter that defines the ecryptfs_verbosity level. */int ecryptfs_verbosity = 0; module_param(ecryptfs_verbosity, int, 0);MODULE_PARM_DESC(ecryptfs_verbosity,		 "Initial verbosity level (0 or 1; defaults to "		 "0, which is Quiet)"); /** * Module parameter that defines the number of message buffer elements */unsigned int ecryptfs_message_buf_len = ECRYPTFS_DEFAULT_MSG_CTX_ELEMS; module_param(ecryptfs_message_buf_len, uint, 0);MODULE_PARM_DESC(ecryptfs_message_buf_len,		 "Number of message buffer elements"); /** * Module parameter that defines the maximum guaranteed amount of time to wait * for a response from ecryptfsd.  The actual sleep time will be, more than * likely, a small amount greater than this specified value, but only less if * the message successfully arrives. */signed long ecryptfs_message_wait_timeout = ECRYPTFS_MAX_MSG_CTX_TTL / HZ; module_param(ecryptfs_message_wait_timeout, long, 0);MODULE_PARM_DESC(ecryptfs_message_wait_timeout,		 "Maximum number of seconds that an operation will "		 "sleep while waiting for a message response from "		 "userspace"); /** * Module parameter that is an estimate of the maximum number of users * that will be concurrently using eCryptfs. Set this to the right * value to balance performance and memory use. */unsigned int ecryptfs_number_of_users = ECRYPTFS_DEFAULT_NUM_USERS; module_param(ecryptfs_number_of_users, uint, 0);MODULE_PARM_DESC(ecryptfs_number_of_users, "An estimate of the number of "		 "concurrent users of eCryptfs"); void __ecryptfs_printk(const char *fmt, ...){	va_list args;	va_start(args, fmt);	if (fmt[1] == '7') { /* KERN_DEBUG */		if (ecryptfs_verbosity >= 1)			vprintk(fmt, args);	} else		vprintk(fmt, args);	va_end(args);} /** * ecryptfs_init_lower_file * @ecryptfs_dentry: Fully initialized eCryptfs dentry object, with *                   the lower dentry and the lower mount set * * eCryptfs only ever keeps a single open file for every lower * 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 * 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 lower file will be opened with read/write permissions, if * possible. Otherwise, it is opened read-only. * * This function does nothing if a lower file is already * associated with the eCryptfs inode. * * Returns zero on success; non-zero otherwise */static int ecryptfs_init_lower_file(struct dentry *dentry,				    struct file **lower_file){	const struct cred *cred = current_cred();	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);	struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);	int rc; 	rc = ecryptfs_privileged_open(lower_file, lower_dentry, lower_mnt,				      cred);	if (rc) {		printk(KERN_ERR "Error opening lower file "		       "for lower_dentry [0x%p] and lower_mnt [0x%p]; "		       "rc = [%d]\n", lower_dentry, lower_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);	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;} void ecryptfs_put_lower_file(struct inode *inode){	struct ecryptfs_inode_info *inode_info; 	inode_info = ecryptfs_inode_to_private(inode);	if (atomic_dec_and_mutex_lock(&inode_info->lower_file_count,				      &inode_info->lower_file_mutex)) {		fput(inode_info->lower_file);		inode_info->lower_file = NULL;		mutex_unlock(&inode_info->lower_file_mutex);	}} enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,       ecryptfs_opt_cipher, ecryptfs_opt_ecryptfs_cipher,       ecryptfs_opt_ecryptfs_key_bytes,       ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata,       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 = {	{ecryptfs_opt_sig, "sig=%s"},	{ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},	{ecryptfs_opt_cipher, "cipher=%s"},	{ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"},	{ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"},	{ecryptfs_opt_passthrough, "ecryptfs_passthrough"},	{ecryptfs_opt_xattr_metadata, "ecryptfs_xattr_metadata"},	{ecryptfs_opt_encrypted_view, "ecryptfs_encrypted_view"},	{ecryptfs_opt_fnek_sig, "ecryptfs_fnek_sig=%s"},	{ecryptfs_opt_fn_cipher, "ecryptfs_fn_cipher=%s"},	{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}}; 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, &auth_tok,			global_auth_tok->sig);		if (rc) {			printk(KERN_ERR "Could not find valid key in user "			       "session keyring for sig specified in mount "			       "option: [%s]\n", global_auth_tok->sig);			global_auth_tok->flags |= ECRYPTFS_AUTH_TOK_INVALID;			goto out;		} else {			global_auth_tok->flags &= ~ECRYPTFS_AUTH_TOK_INVALID;			up_write(&(global_auth_tok->global_auth_tok_key)->sem);		}	}out:	return rc;} static void ecryptfs_init_mount_crypt_stat(	struct ecryptfs_mount_crypt_stat *mount_crypt_stat){	memset((void *)mount_crypt_stat, 0,	       sizeof(struct ecryptfs_mount_crypt_stat));	INIT_LIST_HEAD(&mount_crypt_stat->global_auth_tok_list);	mutex_init(&mount_crypt_stat->global_auth_tok_list_mutex);	mount_crypt_stat->flags |= ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED;} /** * ecryptfs_parse_options * @sb: The ecryptfs super block * @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 * sig=XXX	   - description(signature) of the key to use * * Returns the dentry object of the lower-level (lower/interposed) * directory; We want to mount our stackable file system on top of * that lower directory. * * The signature of the key to use must be the description of a key * already in the keyring. Mounting will fail if the key can not be * found. * * Returns zero on success; non-zero on error */static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,				  uid_t *check_ruid){	char *p;	int rc = 0;	int sig_set = 0;	int cipher_name_set = 0;	int fn_cipher_name_set = 0;	int cipher_key_bytes;	int cipher_key_bytes_set = 0;	int fn_cipher_key_bytes;	int fn_cipher_key_bytes_set = 0;	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =		&sbi->mount_crypt_stat;	substring_t args[MAX_OPT_ARGS];	int token;	char *sig_src;	char *cipher_name_dst;	char *cipher_name_src;	char *fn_cipher_name_dst;	char *fn_cipher_name_src;	char *fnek_dst;	char *fnek_src;	char *cipher_key_bytes_src;	char *fn_cipher_key_bytes_src; 	*check_ruid = 0; 	if (!options) {		rc = -EINVAL;		goto out;	}	ecryptfs_init_mount_crypt_stat(mount_crypt_stat);	while ((p = strsep(&options, ",")) != NULL) {		if (!*p)			continue;		token = match_token(p, tokens, args);		switch (token) {		case ecryptfs_opt_sig:		case ecryptfs_opt_ecryptfs_sig:			sig_src = args[0].from;			rc = ecryptfs_add_global_auth_tok(mount_crypt_stat,							  sig_src, 0);			if (rc) {				printk(KERN_ERR "Error attempting to register "				       "global sig; rc = [%d]\n", rc);				goto out;			}			sig_set = 1;			break;		case ecryptfs_opt_cipher:		case ecryptfs_opt_ecryptfs_cipher:			cipher_name_src = args[0].from;			cipher_name_dst =				mount_crypt_stat->				global_default_cipher_name;			strncpy(cipher_name_dst, cipher_name_src,				ECRYPTFS_MAX_CIPHER_NAME_SIZE);			cipher_name_dst[ECRYPTFS_MAX_CIPHER_NAME_SIZE] = '\0';			cipher_name_set = 1;			break;		case ecryptfs_opt_ecryptfs_key_bytes:			cipher_key_bytes_src = args[0].from;			cipher_key_bytes =				(int)simple_strtol(cipher_key_bytes_src,						   &cipher_key_bytes_src, 0);			mount_crypt_stat->global_default_cipher_key_size =				cipher_key_bytes;			cipher_key_bytes_set = 1;			break;		case ecryptfs_opt_passthrough:			mount_crypt_stat->flags |=				ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED;			break;		case ecryptfs_opt_xattr_metadata:			mount_crypt_stat->flags |=				ECRYPTFS_XATTR_METADATA_ENABLED;			break;		case ecryptfs_opt_encrypted_view:			mount_crypt_stat->flags |=				ECRYPTFS_XATTR_METADATA_ENABLED;			mount_crypt_stat->flags |=				ECRYPTFS_ENCRYPTED_VIEW_ENABLED;			break;		case ecryptfs_opt_fnek_sig:			fnek_src = args[0].from;			fnek_dst =				mount_crypt_stat->global_default_fnek_sig;			strncpy(fnek_dst, fnek_src, ECRYPTFS_SIG_SIZE_HEX);			mount_crypt_stat->global_default_fnek_sig[				ECRYPTFS_SIG_SIZE_HEX] = '\0';			rc = ecryptfs_add_global_auth_tok(				mount_crypt_stat,				mount_crypt_stat->global_default_fnek_sig,				ECRYPTFS_AUTH_TOK_FNEK);			if (rc) {				printk(KERN_ERR "Error attempting to register "				       "global fnek sig [%s]; rc = [%d]\n",				       mount_crypt_stat->global_default_fnek_sig,				       rc);				goto out;			}			mount_crypt_stat->flags |=				(ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES				 | ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK);			break;		case ecryptfs_opt_fn_cipher:			fn_cipher_name_src = args[0].from;			fn_cipher_name_dst =				mount_crypt_stat->global_default_fn_cipher_name;			strncpy(fn_cipher_name_dst, fn_cipher_name_src,				ECRYPTFS_MAX_CIPHER_NAME_SIZE);			mount_crypt_stat->global_default_fn_cipher_name[				ECRYPTFS_MAX_CIPHER_NAME_SIZE] = '\0';			fn_cipher_name_set = 1;			break;		case ecryptfs_opt_fn_cipher_key_bytes:			fn_cipher_key_bytes_src = args[0].from;			fn_cipher_key_bytes =				(int)simple_strtol(fn_cipher_key_bytes_src,						   &fn_cipher_key_bytes_src, 0);			mount_crypt_stat->global_default_fn_cipher_key_bytes =				fn_cipher_key_bytes;			fn_cipher_key_bytes_set = 1;			break;		case ecryptfs_opt_unlink_sigs:			mount_crypt_stat->flags |= ECRYPTFS_UNLINK_SIGS;			break;		case ecryptfs_opt_mount_auth_tok_only:			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			       "%s: eCryptfs: unrecognized option [%s]\n",			       __func__, p);		}	}	if (!sig_set) {		rc = -EINVAL;		ecryptfs_printk(KERN_ERR, "You must supply at least one valid "				"auth tok signature as a mount "				"parameter; see the eCryptfs README\n");		goto out;	}	if (!cipher_name_set) {		int cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER); 		BUG_ON(cipher_name_len >= ECRYPTFS_MAX_CIPHER_NAME_SIZE);		strcpy(mount_crypt_stat->global_default_cipher_name,		       ECRYPTFS_DEFAULT_CIPHER);	}	if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)	    && !fn_cipher_name_set)		strcpy(mount_crypt_stat->global_default_fn_cipher_name,		       mount_crypt_stat->global_default_cipher_name);	if (!cipher_key_bytes_set)		mount_crypt_stat->global_default_cipher_key_size = 0;	if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)	    && !fn_cipher_key_bytes_set)		mount_crypt_stat->global_default_fn_cipher_key_bytes =			mount_crypt_stat->global_default_cipher_key_size;	mutex_lock(&key_tfm_list_mutex);	if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name,				 NULL)) {		rc = ecryptfs_add_new_key_tfm(			NULL, mount_crypt_stat->global_default_cipher_name,			mount_crypt_stat->global_default_cipher_key_size);		if (rc) {			printk(KERN_ERR "Error attempting to initialize "			       "cipher with name = [%s] and key size = [%td]; "			       "rc = [%d]\n",			       mount_crypt_stat->global_default_cipher_name,			       mount_crypt_stat->global_default_cipher_key_size,			       rc);			rc = -EINVAL;			mutex_unlock(&key_tfm_list_mutex);			goto out;		}	}	if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)	    && !ecryptfs_tfm_exists(		    mount_crypt_stat->global_default_fn_cipher_name, NULL)) {		rc = ecryptfs_add_new_key_tfm(			NULL, mount_crypt_stat->global_default_fn_cipher_name,			mount_crypt_stat->global_default_fn_cipher_key_bytes);		if (rc) {			printk(KERN_ERR "Error attempting to initialize "			       "cipher with name = [%s] and key size = [%td]; "			       "rc = [%d]\n",			       mount_crypt_stat->global_default_fn_cipher_name,			       mount_crypt_stat->global_default_fn_cipher_key_bytes,			       rc);			rc = -EINVAL;			mutex_unlock(&key_tfm_list_mutex);			goto out;		}	}	mutex_unlock(&key_tfm_list_mutex);	rc = ecryptfs_init_global_auth_toks(mount_crypt_stat);	if (rc)		printk(KERN_WARNING "One or more global auth toks could not "		       "properly register; rc = [%d]\n", rc);out:	return rc;} struct kmem_cache *ecryptfs_sb_info_cache;static struct file_system_type ecryptfs_fs_type; /** * ecryptfs_get_sb * @fs_type * @flags * @dev_name: The path to mount over * @raw_data: The options passed into the kernel */static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags,			const char *dev_name, void *raw_data){	struct super_block *s;	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);	if (!sbi) {		rc = -ENOMEM;		goto out;	} 	rc = ecryptfs_parse_options(sbi, raw_data, &check_ruid);	if (rc) {		err = "Error parsing options";		goto out;	}

Lines 1–500 of 866.