162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * eCryptfs: Linux filesystem encryption layer 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1997-2003 Erez Zadok 662306a36Sopenharmony_ci * Copyright (C) 2001-2003 Stony Brook University 762306a36Sopenharmony_ci * Copyright (C) 2004-2007 International Business Machines Corp. 862306a36Sopenharmony_ci * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> 962306a36Sopenharmony_ci * Michael C. Thompson <mcthomps@us.ibm.com> 1062306a36Sopenharmony_ci * Tyler Hicks <code@tyhicks.com> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/dcache.h> 1462306a36Sopenharmony_ci#include <linux/file.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/namei.h> 1762306a36Sopenharmony_ci#include <linux/skbuff.h> 1862306a36Sopenharmony_ci#include <linux/mount.h> 1962306a36Sopenharmony_ci#include <linux/pagemap.h> 2062306a36Sopenharmony_ci#include <linux/key.h> 2162306a36Sopenharmony_ci#include <linux/parser.h> 2262306a36Sopenharmony_ci#include <linux/fs_stack.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <linux/magic.h> 2562306a36Sopenharmony_ci#include "ecryptfs_kernel.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * Module parameter that defines the ecryptfs_verbosity level. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ciint ecryptfs_verbosity = 0; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cimodule_param(ecryptfs_verbosity, int, 0); 3362306a36Sopenharmony_ciMODULE_PARM_DESC(ecryptfs_verbosity, 3462306a36Sopenharmony_ci "Initial verbosity level (0 or 1; defaults to " 3562306a36Sopenharmony_ci "0, which is Quiet)"); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * Module parameter that defines the number of message buffer elements 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ciunsigned int ecryptfs_message_buf_len = ECRYPTFS_DEFAULT_MSG_CTX_ELEMS; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cimodule_param(ecryptfs_message_buf_len, uint, 0); 4362306a36Sopenharmony_ciMODULE_PARM_DESC(ecryptfs_message_buf_len, 4462306a36Sopenharmony_ci "Number of message buffer elements"); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * Module parameter that defines the maximum guaranteed amount of time to wait 4862306a36Sopenharmony_ci * for a response from ecryptfsd. The actual sleep time will be, more than 4962306a36Sopenharmony_ci * likely, a small amount greater than this specified value, but only less if 5062306a36Sopenharmony_ci * the message successfully arrives. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_cisigned long ecryptfs_message_wait_timeout = ECRYPTFS_MAX_MSG_CTX_TTL / HZ; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cimodule_param(ecryptfs_message_wait_timeout, long, 0); 5562306a36Sopenharmony_ciMODULE_PARM_DESC(ecryptfs_message_wait_timeout, 5662306a36Sopenharmony_ci "Maximum number of seconds that an operation will " 5762306a36Sopenharmony_ci "sleep while waiting for a message response from " 5862306a36Sopenharmony_ci "userspace"); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * Module parameter that is an estimate of the maximum number of users 6262306a36Sopenharmony_ci * that will be concurrently using eCryptfs. Set this to the right 6362306a36Sopenharmony_ci * value to balance performance and memory use. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ciunsigned int ecryptfs_number_of_users = ECRYPTFS_DEFAULT_NUM_USERS; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cimodule_param(ecryptfs_number_of_users, uint, 0); 6862306a36Sopenharmony_ciMODULE_PARM_DESC(ecryptfs_number_of_users, "An estimate of the number of " 6962306a36Sopenharmony_ci "concurrent users of eCryptfs"); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_civoid __ecryptfs_printk(const char *fmt, ...) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci va_list args; 7462306a36Sopenharmony_ci va_start(args, fmt); 7562306a36Sopenharmony_ci if (fmt[1] == '7') { /* KERN_DEBUG */ 7662306a36Sopenharmony_ci if (ecryptfs_verbosity >= 1) 7762306a36Sopenharmony_ci vprintk(fmt, args); 7862306a36Sopenharmony_ci } else 7962306a36Sopenharmony_ci vprintk(fmt, args); 8062306a36Sopenharmony_ci va_end(args); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* 8462306a36Sopenharmony_ci * ecryptfs_init_lower_file 8562306a36Sopenharmony_ci * @ecryptfs_dentry: Fully initialized eCryptfs dentry object, with 8662306a36Sopenharmony_ci * the lower dentry and the lower mount set 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * eCryptfs only ever keeps a single open file for every lower 8962306a36Sopenharmony_ci * inode. All I/O operations to the lower inode occur through that 9062306a36Sopenharmony_ci * file. When the first eCryptfs dentry that interposes with the first 9162306a36Sopenharmony_ci * lower dentry for that inode is created, this function creates the 9262306a36Sopenharmony_ci * lower file struct and associates it with the eCryptfs 9362306a36Sopenharmony_ci * inode. When all eCryptfs files associated with the inode are released, the 9462306a36Sopenharmony_ci * file is closed. 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * The lower file will be opened with read/write permissions, if 9762306a36Sopenharmony_ci * possible. Otherwise, it is opened read-only. 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * This function does nothing if a lower file is already 10062306a36Sopenharmony_ci * associated with the eCryptfs inode. 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci * Returns zero on success; non-zero otherwise 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistatic int ecryptfs_init_lower_file(struct dentry *dentry, 10562306a36Sopenharmony_ci struct file **lower_file) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci const struct cred *cred = current_cred(); 10862306a36Sopenharmony_ci const struct path *path = ecryptfs_dentry_to_lower_path(dentry); 10962306a36Sopenharmony_ci int rc; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci rc = ecryptfs_privileged_open(lower_file, path->dentry, path->mnt, 11262306a36Sopenharmony_ci cred); 11362306a36Sopenharmony_ci if (rc) { 11462306a36Sopenharmony_ci printk(KERN_ERR "Error opening lower file " 11562306a36Sopenharmony_ci "for lower_dentry [0x%p] and lower_mnt [0x%p]; " 11662306a36Sopenharmony_ci "rc = [%d]\n", path->dentry, path->mnt, rc); 11762306a36Sopenharmony_ci (*lower_file) = NULL; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci return rc; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciint ecryptfs_get_lower_file(struct dentry *dentry, struct inode *inode) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct ecryptfs_inode_info *inode_info; 12562306a36Sopenharmony_ci int count, rc = 0; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci inode_info = ecryptfs_inode_to_private(inode); 12862306a36Sopenharmony_ci mutex_lock(&inode_info->lower_file_mutex); 12962306a36Sopenharmony_ci count = atomic_inc_return(&inode_info->lower_file_count); 13062306a36Sopenharmony_ci if (WARN_ON_ONCE(count < 1)) 13162306a36Sopenharmony_ci rc = -EINVAL; 13262306a36Sopenharmony_ci else if (count == 1) { 13362306a36Sopenharmony_ci rc = ecryptfs_init_lower_file(dentry, 13462306a36Sopenharmony_ci &inode_info->lower_file); 13562306a36Sopenharmony_ci if (rc) 13662306a36Sopenharmony_ci atomic_set(&inode_info->lower_file_count, 0); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci mutex_unlock(&inode_info->lower_file_mutex); 13962306a36Sopenharmony_ci return rc; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_civoid ecryptfs_put_lower_file(struct inode *inode) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct ecryptfs_inode_info *inode_info; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci inode_info = ecryptfs_inode_to_private(inode); 14762306a36Sopenharmony_ci if (atomic_dec_and_mutex_lock(&inode_info->lower_file_count, 14862306a36Sopenharmony_ci &inode_info->lower_file_mutex)) { 14962306a36Sopenharmony_ci filemap_write_and_wait(inode->i_mapping); 15062306a36Sopenharmony_ci fput(inode_info->lower_file); 15162306a36Sopenharmony_ci inode_info->lower_file = NULL; 15262306a36Sopenharmony_ci mutex_unlock(&inode_info->lower_file_mutex); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cienum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, 15762306a36Sopenharmony_ci ecryptfs_opt_cipher, ecryptfs_opt_ecryptfs_cipher, 15862306a36Sopenharmony_ci ecryptfs_opt_ecryptfs_key_bytes, 15962306a36Sopenharmony_ci ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata, 16062306a36Sopenharmony_ci ecryptfs_opt_encrypted_view, ecryptfs_opt_fnek_sig, 16162306a36Sopenharmony_ci ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes, 16262306a36Sopenharmony_ci ecryptfs_opt_unlink_sigs, ecryptfs_opt_mount_auth_tok_only, 16362306a36Sopenharmony_ci ecryptfs_opt_check_dev_ruid, 16462306a36Sopenharmony_ci ecryptfs_opt_err }; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic const match_table_t tokens = { 16762306a36Sopenharmony_ci {ecryptfs_opt_sig, "sig=%s"}, 16862306a36Sopenharmony_ci {ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"}, 16962306a36Sopenharmony_ci {ecryptfs_opt_cipher, "cipher=%s"}, 17062306a36Sopenharmony_ci {ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"}, 17162306a36Sopenharmony_ci {ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"}, 17262306a36Sopenharmony_ci {ecryptfs_opt_passthrough, "ecryptfs_passthrough"}, 17362306a36Sopenharmony_ci {ecryptfs_opt_xattr_metadata, "ecryptfs_xattr_metadata"}, 17462306a36Sopenharmony_ci {ecryptfs_opt_encrypted_view, "ecryptfs_encrypted_view"}, 17562306a36Sopenharmony_ci {ecryptfs_opt_fnek_sig, "ecryptfs_fnek_sig=%s"}, 17662306a36Sopenharmony_ci {ecryptfs_opt_fn_cipher, "ecryptfs_fn_cipher=%s"}, 17762306a36Sopenharmony_ci {ecryptfs_opt_fn_cipher_key_bytes, "ecryptfs_fn_key_bytes=%u"}, 17862306a36Sopenharmony_ci {ecryptfs_opt_unlink_sigs, "ecryptfs_unlink_sigs"}, 17962306a36Sopenharmony_ci {ecryptfs_opt_mount_auth_tok_only, "ecryptfs_mount_auth_tok_only"}, 18062306a36Sopenharmony_ci {ecryptfs_opt_check_dev_ruid, "ecryptfs_check_dev_ruid"}, 18162306a36Sopenharmony_ci {ecryptfs_opt_err, NULL} 18262306a36Sopenharmony_ci}; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic int ecryptfs_init_global_auth_toks( 18562306a36Sopenharmony_ci struct ecryptfs_mount_crypt_stat *mount_crypt_stat) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct ecryptfs_global_auth_tok *global_auth_tok; 18862306a36Sopenharmony_ci struct ecryptfs_auth_tok *auth_tok; 18962306a36Sopenharmony_ci int rc = 0; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci list_for_each_entry(global_auth_tok, 19262306a36Sopenharmony_ci &mount_crypt_stat->global_auth_tok_list, 19362306a36Sopenharmony_ci mount_crypt_stat_list) { 19462306a36Sopenharmony_ci rc = ecryptfs_keyring_auth_tok_for_sig( 19562306a36Sopenharmony_ci &global_auth_tok->global_auth_tok_key, &auth_tok, 19662306a36Sopenharmony_ci global_auth_tok->sig); 19762306a36Sopenharmony_ci if (rc) { 19862306a36Sopenharmony_ci printk(KERN_ERR "Could not find valid key in user " 19962306a36Sopenharmony_ci "session keyring for sig specified in mount " 20062306a36Sopenharmony_ci "option: [%s]\n", global_auth_tok->sig); 20162306a36Sopenharmony_ci global_auth_tok->flags |= ECRYPTFS_AUTH_TOK_INVALID; 20262306a36Sopenharmony_ci goto out; 20362306a36Sopenharmony_ci } else { 20462306a36Sopenharmony_ci global_auth_tok->flags &= ~ECRYPTFS_AUTH_TOK_INVALID; 20562306a36Sopenharmony_ci up_write(&(global_auth_tok->global_auth_tok_key)->sem); 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ciout: 20962306a36Sopenharmony_ci return rc; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void ecryptfs_init_mount_crypt_stat( 21362306a36Sopenharmony_ci struct ecryptfs_mount_crypt_stat *mount_crypt_stat) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci memset((void *)mount_crypt_stat, 0, 21662306a36Sopenharmony_ci sizeof(struct ecryptfs_mount_crypt_stat)); 21762306a36Sopenharmony_ci INIT_LIST_HEAD(&mount_crypt_stat->global_auth_tok_list); 21862306a36Sopenharmony_ci mutex_init(&mount_crypt_stat->global_auth_tok_list_mutex); 21962306a36Sopenharmony_ci mount_crypt_stat->flags |= ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/** 22362306a36Sopenharmony_ci * ecryptfs_parse_options 22462306a36Sopenharmony_ci * @sbi: The ecryptfs super block 22562306a36Sopenharmony_ci * @options: The options passed to the kernel 22662306a36Sopenharmony_ci * @check_ruid: set to 1 if device uid should be checked against the ruid 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * Parse mount options: 22962306a36Sopenharmony_ci * debug=N - ecryptfs_verbosity level for debug output 23062306a36Sopenharmony_ci * sig=XXX - description(signature) of the key to use 23162306a36Sopenharmony_ci * 23262306a36Sopenharmony_ci * Returns the dentry object of the lower-level (lower/interposed) 23362306a36Sopenharmony_ci * directory; We want to mount our stackable file system on top of 23462306a36Sopenharmony_ci * that lower directory. 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci * The signature of the key to use must be the description of a key 23762306a36Sopenharmony_ci * already in the keyring. Mounting will fail if the key can not be 23862306a36Sopenharmony_ci * found. 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * Returns zero on success; non-zero on error 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_cistatic int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options, 24362306a36Sopenharmony_ci uid_t *check_ruid) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci char *p; 24662306a36Sopenharmony_ci int rc = 0; 24762306a36Sopenharmony_ci int sig_set = 0; 24862306a36Sopenharmony_ci int cipher_name_set = 0; 24962306a36Sopenharmony_ci int fn_cipher_name_set = 0; 25062306a36Sopenharmony_ci int cipher_key_bytes; 25162306a36Sopenharmony_ci int cipher_key_bytes_set = 0; 25262306a36Sopenharmony_ci int fn_cipher_key_bytes; 25362306a36Sopenharmony_ci int fn_cipher_key_bytes_set = 0; 25462306a36Sopenharmony_ci struct ecryptfs_mount_crypt_stat *mount_crypt_stat = 25562306a36Sopenharmony_ci &sbi->mount_crypt_stat; 25662306a36Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 25762306a36Sopenharmony_ci int token; 25862306a36Sopenharmony_ci char *sig_src; 25962306a36Sopenharmony_ci char *cipher_name_dst; 26062306a36Sopenharmony_ci char *cipher_name_src; 26162306a36Sopenharmony_ci char *fn_cipher_name_dst; 26262306a36Sopenharmony_ci char *fn_cipher_name_src; 26362306a36Sopenharmony_ci char *fnek_dst; 26462306a36Sopenharmony_ci char *fnek_src; 26562306a36Sopenharmony_ci char *cipher_key_bytes_src; 26662306a36Sopenharmony_ci char *fn_cipher_key_bytes_src; 26762306a36Sopenharmony_ci u8 cipher_code; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci *check_ruid = 0; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (!options) { 27262306a36Sopenharmony_ci rc = -EINVAL; 27362306a36Sopenharmony_ci goto out; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci ecryptfs_init_mount_crypt_stat(mount_crypt_stat); 27662306a36Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 27762306a36Sopenharmony_ci if (!*p) 27862306a36Sopenharmony_ci continue; 27962306a36Sopenharmony_ci token = match_token(p, tokens, args); 28062306a36Sopenharmony_ci switch (token) { 28162306a36Sopenharmony_ci case ecryptfs_opt_sig: 28262306a36Sopenharmony_ci case ecryptfs_opt_ecryptfs_sig: 28362306a36Sopenharmony_ci sig_src = args[0].from; 28462306a36Sopenharmony_ci rc = ecryptfs_add_global_auth_tok(mount_crypt_stat, 28562306a36Sopenharmony_ci sig_src, 0); 28662306a36Sopenharmony_ci if (rc) { 28762306a36Sopenharmony_ci printk(KERN_ERR "Error attempting to register " 28862306a36Sopenharmony_ci "global sig; rc = [%d]\n", rc); 28962306a36Sopenharmony_ci goto out; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci sig_set = 1; 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci case ecryptfs_opt_cipher: 29462306a36Sopenharmony_ci case ecryptfs_opt_ecryptfs_cipher: 29562306a36Sopenharmony_ci cipher_name_src = args[0].from; 29662306a36Sopenharmony_ci cipher_name_dst = 29762306a36Sopenharmony_ci mount_crypt_stat-> 29862306a36Sopenharmony_ci global_default_cipher_name; 29962306a36Sopenharmony_ci strncpy(cipher_name_dst, cipher_name_src, 30062306a36Sopenharmony_ci ECRYPTFS_MAX_CIPHER_NAME_SIZE); 30162306a36Sopenharmony_ci cipher_name_dst[ECRYPTFS_MAX_CIPHER_NAME_SIZE] = '\0'; 30262306a36Sopenharmony_ci cipher_name_set = 1; 30362306a36Sopenharmony_ci break; 30462306a36Sopenharmony_ci case ecryptfs_opt_ecryptfs_key_bytes: 30562306a36Sopenharmony_ci cipher_key_bytes_src = args[0].from; 30662306a36Sopenharmony_ci cipher_key_bytes = 30762306a36Sopenharmony_ci (int)simple_strtol(cipher_key_bytes_src, 30862306a36Sopenharmony_ci &cipher_key_bytes_src, 0); 30962306a36Sopenharmony_ci mount_crypt_stat->global_default_cipher_key_size = 31062306a36Sopenharmony_ci cipher_key_bytes; 31162306a36Sopenharmony_ci cipher_key_bytes_set = 1; 31262306a36Sopenharmony_ci break; 31362306a36Sopenharmony_ci case ecryptfs_opt_passthrough: 31462306a36Sopenharmony_ci mount_crypt_stat->flags |= 31562306a36Sopenharmony_ci ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED; 31662306a36Sopenharmony_ci break; 31762306a36Sopenharmony_ci case ecryptfs_opt_xattr_metadata: 31862306a36Sopenharmony_ci mount_crypt_stat->flags |= 31962306a36Sopenharmony_ci ECRYPTFS_XATTR_METADATA_ENABLED; 32062306a36Sopenharmony_ci break; 32162306a36Sopenharmony_ci case ecryptfs_opt_encrypted_view: 32262306a36Sopenharmony_ci mount_crypt_stat->flags |= 32362306a36Sopenharmony_ci ECRYPTFS_XATTR_METADATA_ENABLED; 32462306a36Sopenharmony_ci mount_crypt_stat->flags |= 32562306a36Sopenharmony_ci ECRYPTFS_ENCRYPTED_VIEW_ENABLED; 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci case ecryptfs_opt_fnek_sig: 32862306a36Sopenharmony_ci fnek_src = args[0].from; 32962306a36Sopenharmony_ci fnek_dst = 33062306a36Sopenharmony_ci mount_crypt_stat->global_default_fnek_sig; 33162306a36Sopenharmony_ci strncpy(fnek_dst, fnek_src, ECRYPTFS_SIG_SIZE_HEX); 33262306a36Sopenharmony_ci mount_crypt_stat->global_default_fnek_sig[ 33362306a36Sopenharmony_ci ECRYPTFS_SIG_SIZE_HEX] = '\0'; 33462306a36Sopenharmony_ci rc = ecryptfs_add_global_auth_tok( 33562306a36Sopenharmony_ci mount_crypt_stat, 33662306a36Sopenharmony_ci mount_crypt_stat->global_default_fnek_sig, 33762306a36Sopenharmony_ci ECRYPTFS_AUTH_TOK_FNEK); 33862306a36Sopenharmony_ci if (rc) { 33962306a36Sopenharmony_ci printk(KERN_ERR "Error attempting to register " 34062306a36Sopenharmony_ci "global fnek sig [%s]; rc = [%d]\n", 34162306a36Sopenharmony_ci mount_crypt_stat->global_default_fnek_sig, 34262306a36Sopenharmony_ci rc); 34362306a36Sopenharmony_ci goto out; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci mount_crypt_stat->flags |= 34662306a36Sopenharmony_ci (ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES 34762306a36Sopenharmony_ci | ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK); 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci case ecryptfs_opt_fn_cipher: 35062306a36Sopenharmony_ci fn_cipher_name_src = args[0].from; 35162306a36Sopenharmony_ci fn_cipher_name_dst = 35262306a36Sopenharmony_ci mount_crypt_stat->global_default_fn_cipher_name; 35362306a36Sopenharmony_ci strncpy(fn_cipher_name_dst, fn_cipher_name_src, 35462306a36Sopenharmony_ci ECRYPTFS_MAX_CIPHER_NAME_SIZE); 35562306a36Sopenharmony_ci mount_crypt_stat->global_default_fn_cipher_name[ 35662306a36Sopenharmony_ci ECRYPTFS_MAX_CIPHER_NAME_SIZE] = '\0'; 35762306a36Sopenharmony_ci fn_cipher_name_set = 1; 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci case ecryptfs_opt_fn_cipher_key_bytes: 36062306a36Sopenharmony_ci fn_cipher_key_bytes_src = args[0].from; 36162306a36Sopenharmony_ci fn_cipher_key_bytes = 36262306a36Sopenharmony_ci (int)simple_strtol(fn_cipher_key_bytes_src, 36362306a36Sopenharmony_ci &fn_cipher_key_bytes_src, 0); 36462306a36Sopenharmony_ci mount_crypt_stat->global_default_fn_cipher_key_bytes = 36562306a36Sopenharmony_ci fn_cipher_key_bytes; 36662306a36Sopenharmony_ci fn_cipher_key_bytes_set = 1; 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci case ecryptfs_opt_unlink_sigs: 36962306a36Sopenharmony_ci mount_crypt_stat->flags |= ECRYPTFS_UNLINK_SIGS; 37062306a36Sopenharmony_ci break; 37162306a36Sopenharmony_ci case ecryptfs_opt_mount_auth_tok_only: 37262306a36Sopenharmony_ci mount_crypt_stat->flags |= 37362306a36Sopenharmony_ci ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY; 37462306a36Sopenharmony_ci break; 37562306a36Sopenharmony_ci case ecryptfs_opt_check_dev_ruid: 37662306a36Sopenharmony_ci *check_ruid = 1; 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci case ecryptfs_opt_err: 37962306a36Sopenharmony_ci default: 38062306a36Sopenharmony_ci printk(KERN_WARNING 38162306a36Sopenharmony_ci "%s: eCryptfs: unrecognized option [%s]\n", 38262306a36Sopenharmony_ci __func__, p); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci if (!sig_set) { 38662306a36Sopenharmony_ci rc = -EINVAL; 38762306a36Sopenharmony_ci ecryptfs_printk(KERN_ERR, "You must supply at least one valid " 38862306a36Sopenharmony_ci "auth tok signature as a mount " 38962306a36Sopenharmony_ci "parameter; see the eCryptfs README\n"); 39062306a36Sopenharmony_ci goto out; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci if (!cipher_name_set) { 39362306a36Sopenharmony_ci int cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci BUG_ON(cipher_name_len > ECRYPTFS_MAX_CIPHER_NAME_SIZE); 39662306a36Sopenharmony_ci strcpy(mount_crypt_stat->global_default_cipher_name, 39762306a36Sopenharmony_ci ECRYPTFS_DEFAULT_CIPHER); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) 40062306a36Sopenharmony_ci && !fn_cipher_name_set) 40162306a36Sopenharmony_ci strcpy(mount_crypt_stat->global_default_fn_cipher_name, 40262306a36Sopenharmony_ci mount_crypt_stat->global_default_cipher_name); 40362306a36Sopenharmony_ci if (!cipher_key_bytes_set) 40462306a36Sopenharmony_ci mount_crypt_stat->global_default_cipher_key_size = 0; 40562306a36Sopenharmony_ci if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) 40662306a36Sopenharmony_ci && !fn_cipher_key_bytes_set) 40762306a36Sopenharmony_ci mount_crypt_stat->global_default_fn_cipher_key_bytes = 40862306a36Sopenharmony_ci mount_crypt_stat->global_default_cipher_key_size; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci cipher_code = ecryptfs_code_for_cipher_string( 41162306a36Sopenharmony_ci mount_crypt_stat->global_default_cipher_name, 41262306a36Sopenharmony_ci mount_crypt_stat->global_default_cipher_key_size); 41362306a36Sopenharmony_ci if (!cipher_code) { 41462306a36Sopenharmony_ci ecryptfs_printk(KERN_ERR, 41562306a36Sopenharmony_ci "eCryptfs doesn't support cipher: %s\n", 41662306a36Sopenharmony_ci mount_crypt_stat->global_default_cipher_name); 41762306a36Sopenharmony_ci rc = -EINVAL; 41862306a36Sopenharmony_ci goto out; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci mutex_lock(&key_tfm_list_mutex); 42262306a36Sopenharmony_ci if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name, 42362306a36Sopenharmony_ci NULL)) { 42462306a36Sopenharmony_ci rc = ecryptfs_add_new_key_tfm( 42562306a36Sopenharmony_ci NULL, mount_crypt_stat->global_default_cipher_name, 42662306a36Sopenharmony_ci mount_crypt_stat->global_default_cipher_key_size); 42762306a36Sopenharmony_ci if (rc) { 42862306a36Sopenharmony_ci printk(KERN_ERR "Error attempting to initialize " 42962306a36Sopenharmony_ci "cipher with name = [%s] and key size = [%td]; " 43062306a36Sopenharmony_ci "rc = [%d]\n", 43162306a36Sopenharmony_ci mount_crypt_stat->global_default_cipher_name, 43262306a36Sopenharmony_ci mount_crypt_stat->global_default_cipher_key_size, 43362306a36Sopenharmony_ci rc); 43462306a36Sopenharmony_ci rc = -EINVAL; 43562306a36Sopenharmony_ci mutex_unlock(&key_tfm_list_mutex); 43662306a36Sopenharmony_ci goto out; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) 44062306a36Sopenharmony_ci && !ecryptfs_tfm_exists( 44162306a36Sopenharmony_ci mount_crypt_stat->global_default_fn_cipher_name, NULL)) { 44262306a36Sopenharmony_ci rc = ecryptfs_add_new_key_tfm( 44362306a36Sopenharmony_ci NULL, mount_crypt_stat->global_default_fn_cipher_name, 44462306a36Sopenharmony_ci mount_crypt_stat->global_default_fn_cipher_key_bytes); 44562306a36Sopenharmony_ci if (rc) { 44662306a36Sopenharmony_ci printk(KERN_ERR "Error attempting to initialize " 44762306a36Sopenharmony_ci "cipher with name = [%s] and key size = [%td]; " 44862306a36Sopenharmony_ci "rc = [%d]\n", 44962306a36Sopenharmony_ci mount_crypt_stat->global_default_fn_cipher_name, 45062306a36Sopenharmony_ci mount_crypt_stat->global_default_fn_cipher_key_bytes, 45162306a36Sopenharmony_ci rc); 45262306a36Sopenharmony_ci rc = -EINVAL; 45362306a36Sopenharmony_ci mutex_unlock(&key_tfm_list_mutex); 45462306a36Sopenharmony_ci goto out; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci mutex_unlock(&key_tfm_list_mutex); 45862306a36Sopenharmony_ci rc = ecryptfs_init_global_auth_toks(mount_crypt_stat); 45962306a36Sopenharmony_ci if (rc) 46062306a36Sopenharmony_ci printk(KERN_WARNING "One or more global auth toks could not " 46162306a36Sopenharmony_ci "properly register; rc = [%d]\n", rc); 46262306a36Sopenharmony_ciout: 46362306a36Sopenharmony_ci return rc; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistruct kmem_cache *ecryptfs_sb_info_cache; 46762306a36Sopenharmony_cistatic struct file_system_type ecryptfs_fs_type; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/* 47062306a36Sopenharmony_ci * ecryptfs_mount 47162306a36Sopenharmony_ci * @fs_type: The filesystem type that the superblock should belong to 47262306a36Sopenharmony_ci * @flags: The flags associated with the mount 47362306a36Sopenharmony_ci * @dev_name: The path to mount over 47462306a36Sopenharmony_ci * @raw_data: The options passed into the kernel 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_cistatic struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags, 47762306a36Sopenharmony_ci const char *dev_name, void *raw_data) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct super_block *s; 48062306a36Sopenharmony_ci struct ecryptfs_sb_info *sbi; 48162306a36Sopenharmony_ci struct ecryptfs_mount_crypt_stat *mount_crypt_stat; 48262306a36Sopenharmony_ci struct ecryptfs_dentry_info *root_info; 48362306a36Sopenharmony_ci const char *err = "Getting sb failed"; 48462306a36Sopenharmony_ci struct inode *inode; 48562306a36Sopenharmony_ci struct path path; 48662306a36Sopenharmony_ci uid_t check_ruid; 48762306a36Sopenharmony_ci int rc; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL); 49062306a36Sopenharmony_ci if (!sbi) { 49162306a36Sopenharmony_ci rc = -ENOMEM; 49262306a36Sopenharmony_ci goto out; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (!dev_name) { 49662306a36Sopenharmony_ci rc = -EINVAL; 49762306a36Sopenharmony_ci err = "Device name cannot be null"; 49862306a36Sopenharmony_ci goto out; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci rc = ecryptfs_parse_options(sbi, raw_data, &check_ruid); 50262306a36Sopenharmony_ci if (rc) { 50362306a36Sopenharmony_ci err = "Error parsing options"; 50462306a36Sopenharmony_ci goto out; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci mount_crypt_stat = &sbi->mount_crypt_stat; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci s = sget(fs_type, NULL, set_anon_super, flags, NULL); 50962306a36Sopenharmony_ci if (IS_ERR(s)) { 51062306a36Sopenharmony_ci rc = PTR_ERR(s); 51162306a36Sopenharmony_ci goto out; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci rc = super_setup_bdi(s); 51562306a36Sopenharmony_ci if (rc) 51662306a36Sopenharmony_ci goto out1; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci ecryptfs_set_superblock_private(s, sbi); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* ->kill_sb() will take care of sbi after that point */ 52162306a36Sopenharmony_ci sbi = NULL; 52262306a36Sopenharmony_ci s->s_op = &ecryptfs_sops; 52362306a36Sopenharmony_ci s->s_xattr = ecryptfs_xattr_handlers; 52462306a36Sopenharmony_ci s->s_d_op = &ecryptfs_dops; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci err = "Reading sb failed"; 52762306a36Sopenharmony_ci rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); 52862306a36Sopenharmony_ci if (rc) { 52962306a36Sopenharmony_ci ecryptfs_printk(KERN_WARNING, "kern_path() failed\n"); 53062306a36Sopenharmony_ci goto out1; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci if (path.dentry->d_sb->s_type == &ecryptfs_fs_type) { 53362306a36Sopenharmony_ci rc = -EINVAL; 53462306a36Sopenharmony_ci printk(KERN_ERR "Mount on filesystem of type " 53562306a36Sopenharmony_ci "eCryptfs explicitly disallowed due to " 53662306a36Sopenharmony_ci "known incompatibilities\n"); 53762306a36Sopenharmony_ci goto out_free; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (is_idmapped_mnt(path.mnt)) { 54162306a36Sopenharmony_ci rc = -EINVAL; 54262306a36Sopenharmony_ci printk(KERN_ERR "Mounting on idmapped mounts currently disallowed\n"); 54362306a36Sopenharmony_ci goto out_free; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (check_ruid && !uid_eq(d_inode(path.dentry)->i_uid, current_uid())) { 54762306a36Sopenharmony_ci rc = -EPERM; 54862306a36Sopenharmony_ci printk(KERN_ERR "Mount of device (uid: %d) not owned by " 54962306a36Sopenharmony_ci "requested user (uid: %d)\n", 55062306a36Sopenharmony_ci i_uid_read(d_inode(path.dentry)), 55162306a36Sopenharmony_ci from_kuid(&init_user_ns, current_uid())); 55262306a36Sopenharmony_ci goto out_free; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci ecryptfs_set_superblock_lower(s, path.dentry->d_sb); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /** 55862306a36Sopenharmony_ci * Set the POSIX ACL flag based on whether they're enabled in the lower 55962306a36Sopenharmony_ci * mount. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ci s->s_flags = flags & ~SB_POSIXACL; 56262306a36Sopenharmony_ci s->s_flags |= path.dentry->d_sb->s_flags & SB_POSIXACL; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /** 56562306a36Sopenharmony_ci * Force a read-only eCryptfs mount when: 56662306a36Sopenharmony_ci * 1) The lower mount is ro 56762306a36Sopenharmony_ci * 2) The ecryptfs_encrypted_view mount option is specified 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_ci if (sb_rdonly(path.dentry->d_sb) || mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) 57062306a36Sopenharmony_ci s->s_flags |= SB_RDONLY; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci s->s_maxbytes = path.dentry->d_sb->s_maxbytes; 57362306a36Sopenharmony_ci s->s_blocksize = path.dentry->d_sb->s_blocksize; 57462306a36Sopenharmony_ci s->s_magic = ECRYPTFS_SUPER_MAGIC; 57562306a36Sopenharmony_ci s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci rc = -EINVAL; 57862306a36Sopenharmony_ci if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { 57962306a36Sopenharmony_ci pr_err("eCryptfs: maximum fs stacking depth exceeded\n"); 58062306a36Sopenharmony_ci goto out_free; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci inode = ecryptfs_get_inode(d_inode(path.dentry), s); 58462306a36Sopenharmony_ci rc = PTR_ERR(inode); 58562306a36Sopenharmony_ci if (IS_ERR(inode)) 58662306a36Sopenharmony_ci goto out_free; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci s->s_root = d_make_root(inode); 58962306a36Sopenharmony_ci if (!s->s_root) { 59062306a36Sopenharmony_ci rc = -ENOMEM; 59162306a36Sopenharmony_ci goto out_free; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci rc = -ENOMEM; 59562306a36Sopenharmony_ci root_info = kmem_cache_zalloc(ecryptfs_dentry_info_cache, GFP_KERNEL); 59662306a36Sopenharmony_ci if (!root_info) 59762306a36Sopenharmony_ci goto out_free; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci /* ->kill_sb() will take care of root_info */ 60062306a36Sopenharmony_ci ecryptfs_set_dentry_private(s->s_root, root_info); 60162306a36Sopenharmony_ci root_info->lower_path = path; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci s->s_flags |= SB_ACTIVE; 60462306a36Sopenharmony_ci return dget(s->s_root); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ciout_free: 60762306a36Sopenharmony_ci path_put(&path); 60862306a36Sopenharmony_ciout1: 60962306a36Sopenharmony_ci deactivate_locked_super(s); 61062306a36Sopenharmony_ciout: 61162306a36Sopenharmony_ci if (sbi) { 61262306a36Sopenharmony_ci ecryptfs_destroy_mount_crypt_stat(&sbi->mount_crypt_stat); 61362306a36Sopenharmony_ci kmem_cache_free(ecryptfs_sb_info_cache, sbi); 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci printk(KERN_ERR "%s; rc = [%d]\n", err, rc); 61662306a36Sopenharmony_ci return ERR_PTR(rc); 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci/** 62062306a36Sopenharmony_ci * ecryptfs_kill_block_super 62162306a36Sopenharmony_ci * @sb: The ecryptfs super block 62262306a36Sopenharmony_ci * 62362306a36Sopenharmony_ci * Used to bring the superblock down and free the private data. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_cistatic void ecryptfs_kill_block_super(struct super_block *sb) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb); 62862306a36Sopenharmony_ci kill_anon_super(sb); 62962306a36Sopenharmony_ci if (!sb_info) 63062306a36Sopenharmony_ci return; 63162306a36Sopenharmony_ci ecryptfs_destroy_mount_crypt_stat(&sb_info->mount_crypt_stat); 63262306a36Sopenharmony_ci kmem_cache_free(ecryptfs_sb_info_cache, sb_info); 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic struct file_system_type ecryptfs_fs_type = { 63662306a36Sopenharmony_ci .owner = THIS_MODULE, 63762306a36Sopenharmony_ci .name = "ecryptfs", 63862306a36Sopenharmony_ci .mount = ecryptfs_mount, 63962306a36Sopenharmony_ci .kill_sb = ecryptfs_kill_block_super, 64062306a36Sopenharmony_ci .fs_flags = 0 64162306a36Sopenharmony_ci}; 64262306a36Sopenharmony_ciMODULE_ALIAS_FS("ecryptfs"); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci/* 64562306a36Sopenharmony_ci * inode_info_init_once 64662306a36Sopenharmony_ci * 64762306a36Sopenharmony_ci * Initializes the ecryptfs_inode_info_cache when it is created 64862306a36Sopenharmony_ci */ 64962306a36Sopenharmony_cistatic void 65062306a36Sopenharmony_ciinode_info_init_once(void *vptr) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci inode_init_once(&ei->vfs_inode); 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic struct ecryptfs_cache_info { 65862306a36Sopenharmony_ci struct kmem_cache **cache; 65962306a36Sopenharmony_ci const char *name; 66062306a36Sopenharmony_ci size_t size; 66162306a36Sopenharmony_ci slab_flags_t flags; 66262306a36Sopenharmony_ci void (*ctor)(void *obj); 66362306a36Sopenharmony_ci} ecryptfs_cache_infos[] = { 66462306a36Sopenharmony_ci { 66562306a36Sopenharmony_ci .cache = &ecryptfs_auth_tok_list_item_cache, 66662306a36Sopenharmony_ci .name = "ecryptfs_auth_tok_list_item", 66762306a36Sopenharmony_ci .size = sizeof(struct ecryptfs_auth_tok_list_item), 66862306a36Sopenharmony_ci }, 66962306a36Sopenharmony_ci { 67062306a36Sopenharmony_ci .cache = &ecryptfs_file_info_cache, 67162306a36Sopenharmony_ci .name = "ecryptfs_file_cache", 67262306a36Sopenharmony_ci .size = sizeof(struct ecryptfs_file_info), 67362306a36Sopenharmony_ci }, 67462306a36Sopenharmony_ci { 67562306a36Sopenharmony_ci .cache = &ecryptfs_dentry_info_cache, 67662306a36Sopenharmony_ci .name = "ecryptfs_dentry_info_cache", 67762306a36Sopenharmony_ci .size = sizeof(struct ecryptfs_dentry_info), 67862306a36Sopenharmony_ci }, 67962306a36Sopenharmony_ci { 68062306a36Sopenharmony_ci .cache = &ecryptfs_inode_info_cache, 68162306a36Sopenharmony_ci .name = "ecryptfs_inode_cache", 68262306a36Sopenharmony_ci .size = sizeof(struct ecryptfs_inode_info), 68362306a36Sopenharmony_ci .flags = SLAB_ACCOUNT, 68462306a36Sopenharmony_ci .ctor = inode_info_init_once, 68562306a36Sopenharmony_ci }, 68662306a36Sopenharmony_ci { 68762306a36Sopenharmony_ci .cache = &ecryptfs_sb_info_cache, 68862306a36Sopenharmony_ci .name = "ecryptfs_sb_cache", 68962306a36Sopenharmony_ci .size = sizeof(struct ecryptfs_sb_info), 69062306a36Sopenharmony_ci }, 69162306a36Sopenharmony_ci { 69262306a36Sopenharmony_ci .cache = &ecryptfs_header_cache, 69362306a36Sopenharmony_ci .name = "ecryptfs_headers", 69462306a36Sopenharmony_ci .size = PAGE_SIZE, 69562306a36Sopenharmony_ci }, 69662306a36Sopenharmony_ci { 69762306a36Sopenharmony_ci .cache = &ecryptfs_xattr_cache, 69862306a36Sopenharmony_ci .name = "ecryptfs_xattr_cache", 69962306a36Sopenharmony_ci .size = PAGE_SIZE, 70062306a36Sopenharmony_ci }, 70162306a36Sopenharmony_ci { 70262306a36Sopenharmony_ci .cache = &ecryptfs_key_record_cache, 70362306a36Sopenharmony_ci .name = "ecryptfs_key_record_cache", 70462306a36Sopenharmony_ci .size = sizeof(struct ecryptfs_key_record), 70562306a36Sopenharmony_ci }, 70662306a36Sopenharmony_ci { 70762306a36Sopenharmony_ci .cache = &ecryptfs_key_sig_cache, 70862306a36Sopenharmony_ci .name = "ecryptfs_key_sig_cache", 70962306a36Sopenharmony_ci .size = sizeof(struct ecryptfs_key_sig), 71062306a36Sopenharmony_ci }, 71162306a36Sopenharmony_ci { 71262306a36Sopenharmony_ci .cache = &ecryptfs_global_auth_tok_cache, 71362306a36Sopenharmony_ci .name = "ecryptfs_global_auth_tok_cache", 71462306a36Sopenharmony_ci .size = sizeof(struct ecryptfs_global_auth_tok), 71562306a36Sopenharmony_ci }, 71662306a36Sopenharmony_ci { 71762306a36Sopenharmony_ci .cache = &ecryptfs_key_tfm_cache, 71862306a36Sopenharmony_ci .name = "ecryptfs_key_tfm_cache", 71962306a36Sopenharmony_ci .size = sizeof(struct ecryptfs_key_tfm), 72062306a36Sopenharmony_ci }, 72162306a36Sopenharmony_ci}; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic void ecryptfs_free_kmem_caches(void) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci int i; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* 72862306a36Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 72962306a36Sopenharmony_ci * destroy cache. 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_ci rcu_barrier(); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) { 73462306a36Sopenharmony_ci struct ecryptfs_cache_info *info; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci info = &ecryptfs_cache_infos[i]; 73762306a36Sopenharmony_ci kmem_cache_destroy(*(info->cache)); 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci/** 74262306a36Sopenharmony_ci * ecryptfs_init_kmem_caches 74362306a36Sopenharmony_ci * 74462306a36Sopenharmony_ci * Returns zero on success; non-zero otherwise 74562306a36Sopenharmony_ci */ 74662306a36Sopenharmony_cistatic int ecryptfs_init_kmem_caches(void) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci int i; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) { 75162306a36Sopenharmony_ci struct ecryptfs_cache_info *info; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci info = &ecryptfs_cache_infos[i]; 75462306a36Sopenharmony_ci *(info->cache) = kmem_cache_create(info->name, info->size, 0, 75562306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN | info->flags, info->ctor); 75662306a36Sopenharmony_ci if (!*(info->cache)) { 75762306a36Sopenharmony_ci ecryptfs_free_kmem_caches(); 75862306a36Sopenharmony_ci ecryptfs_printk(KERN_WARNING, "%s: " 75962306a36Sopenharmony_ci "kmem_cache_create failed\n", 76062306a36Sopenharmony_ci info->name); 76162306a36Sopenharmony_ci return -ENOMEM; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci return 0; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic struct kobject *ecryptfs_kobj; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic ssize_t version_show(struct kobject *kobj, 77062306a36Sopenharmony_ci struct kobj_attribute *attr, char *buff) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK); 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cistatic struct kobj_attribute version_attr = __ATTR_RO(version); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic struct attribute *attributes[] = { 77862306a36Sopenharmony_ci &version_attr.attr, 77962306a36Sopenharmony_ci NULL, 78062306a36Sopenharmony_ci}; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic const struct attribute_group attr_group = { 78362306a36Sopenharmony_ci .attrs = attributes, 78462306a36Sopenharmony_ci}; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic int do_sysfs_registration(void) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci int rc; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci ecryptfs_kobj = kobject_create_and_add("ecryptfs", fs_kobj); 79162306a36Sopenharmony_ci if (!ecryptfs_kobj) { 79262306a36Sopenharmony_ci printk(KERN_ERR "Unable to create ecryptfs kset\n"); 79362306a36Sopenharmony_ci rc = -ENOMEM; 79462306a36Sopenharmony_ci goto out; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci rc = sysfs_create_group(ecryptfs_kobj, &attr_group); 79762306a36Sopenharmony_ci if (rc) { 79862306a36Sopenharmony_ci printk(KERN_ERR 79962306a36Sopenharmony_ci "Unable to create ecryptfs version attributes\n"); 80062306a36Sopenharmony_ci kobject_put(ecryptfs_kobj); 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ciout: 80362306a36Sopenharmony_ci return rc; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic void do_sysfs_unregistration(void) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci sysfs_remove_group(ecryptfs_kobj, &attr_group); 80962306a36Sopenharmony_ci kobject_put(ecryptfs_kobj); 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic int __init ecryptfs_init(void) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci int rc; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (ECRYPTFS_DEFAULT_EXTENT_SIZE > PAGE_SIZE) { 81762306a36Sopenharmony_ci rc = -EINVAL; 81862306a36Sopenharmony_ci ecryptfs_printk(KERN_ERR, "The eCryptfs extent size is " 81962306a36Sopenharmony_ci "larger than the host's page size, and so " 82062306a36Sopenharmony_ci "eCryptfs cannot run on this system. The " 82162306a36Sopenharmony_ci "default eCryptfs extent size is [%u] bytes; " 82262306a36Sopenharmony_ci "the page size is [%lu] bytes.\n", 82362306a36Sopenharmony_ci ECRYPTFS_DEFAULT_EXTENT_SIZE, 82462306a36Sopenharmony_ci (unsigned long)PAGE_SIZE); 82562306a36Sopenharmony_ci goto out; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci rc = ecryptfs_init_kmem_caches(); 82862306a36Sopenharmony_ci if (rc) { 82962306a36Sopenharmony_ci printk(KERN_ERR 83062306a36Sopenharmony_ci "Failed to allocate one or more kmem_cache objects\n"); 83162306a36Sopenharmony_ci goto out; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci rc = do_sysfs_registration(); 83462306a36Sopenharmony_ci if (rc) { 83562306a36Sopenharmony_ci printk(KERN_ERR "sysfs registration failed\n"); 83662306a36Sopenharmony_ci goto out_free_kmem_caches; 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci rc = ecryptfs_init_kthread(); 83962306a36Sopenharmony_ci if (rc) { 84062306a36Sopenharmony_ci printk(KERN_ERR "%s: kthread initialization failed; " 84162306a36Sopenharmony_ci "rc = [%d]\n", __func__, rc); 84262306a36Sopenharmony_ci goto out_do_sysfs_unregistration; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci rc = ecryptfs_init_messaging(); 84562306a36Sopenharmony_ci if (rc) { 84662306a36Sopenharmony_ci printk(KERN_ERR "Failure occurred while attempting to " 84762306a36Sopenharmony_ci "initialize the communications channel to " 84862306a36Sopenharmony_ci "ecryptfsd\n"); 84962306a36Sopenharmony_ci goto out_destroy_kthread; 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci rc = ecryptfs_init_crypto(); 85262306a36Sopenharmony_ci if (rc) { 85362306a36Sopenharmony_ci printk(KERN_ERR "Failure whilst attempting to init crypto; " 85462306a36Sopenharmony_ci "rc = [%d]\n", rc); 85562306a36Sopenharmony_ci goto out_release_messaging; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci rc = register_filesystem(&ecryptfs_fs_type); 85862306a36Sopenharmony_ci if (rc) { 85962306a36Sopenharmony_ci printk(KERN_ERR "Failed to register filesystem\n"); 86062306a36Sopenharmony_ci goto out_destroy_crypto; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci if (ecryptfs_verbosity > 0) 86362306a36Sopenharmony_ci printk(KERN_CRIT "eCryptfs verbosity set to %d. Secret values " 86462306a36Sopenharmony_ci "will be written to the syslog!\n", ecryptfs_verbosity); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci goto out; 86762306a36Sopenharmony_ciout_destroy_crypto: 86862306a36Sopenharmony_ci ecryptfs_destroy_crypto(); 86962306a36Sopenharmony_ciout_release_messaging: 87062306a36Sopenharmony_ci ecryptfs_release_messaging(); 87162306a36Sopenharmony_ciout_destroy_kthread: 87262306a36Sopenharmony_ci ecryptfs_destroy_kthread(); 87362306a36Sopenharmony_ciout_do_sysfs_unregistration: 87462306a36Sopenharmony_ci do_sysfs_unregistration(); 87562306a36Sopenharmony_ciout_free_kmem_caches: 87662306a36Sopenharmony_ci ecryptfs_free_kmem_caches(); 87762306a36Sopenharmony_ciout: 87862306a36Sopenharmony_ci return rc; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic void __exit ecryptfs_exit(void) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci int rc; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci rc = ecryptfs_destroy_crypto(); 88662306a36Sopenharmony_ci if (rc) 88762306a36Sopenharmony_ci printk(KERN_ERR "Failure whilst attempting to destroy crypto; " 88862306a36Sopenharmony_ci "rc = [%d]\n", rc); 88962306a36Sopenharmony_ci ecryptfs_release_messaging(); 89062306a36Sopenharmony_ci ecryptfs_destroy_kthread(); 89162306a36Sopenharmony_ci do_sysfs_unregistration(); 89262306a36Sopenharmony_ci unregister_filesystem(&ecryptfs_fs_type); 89362306a36Sopenharmony_ci ecryptfs_free_kmem_caches(); 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ciMODULE_AUTHOR("Michael A. Halcrow <mhalcrow@us.ibm.com>"); 89762306a36Sopenharmony_ciMODULE_DESCRIPTION("eCryptfs"); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cimodule_init(ecryptfs_init) 90262306a36Sopenharmony_cimodule_exit(ecryptfs_exit) 903