xref: /kernel/linux/linux-6.6/fs/ecryptfs/main.c (revision 62306a36)
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