162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * eCryptfs: Linux filesystem encryption layer
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2004-2008 International Business Machines Corp.
662306a36Sopenharmony_ci *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
762306a36Sopenharmony_ci *		Tyler Hicks <code@tyhicks.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/sched.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include <linux/user_namespace.h>
1262306a36Sopenharmony_ci#include <linux/nsproxy.h>
1362306a36Sopenharmony_ci#include "ecryptfs_kernel.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic LIST_HEAD(ecryptfs_msg_ctx_free_list);
1662306a36Sopenharmony_cistatic LIST_HEAD(ecryptfs_msg_ctx_alloc_list);
1762306a36Sopenharmony_cistatic DEFINE_MUTEX(ecryptfs_msg_ctx_lists_mux);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic struct hlist_head *ecryptfs_daemon_hash;
2062306a36Sopenharmony_ciDEFINE_MUTEX(ecryptfs_daemon_hash_mux);
2162306a36Sopenharmony_cistatic int ecryptfs_hash_bits;
2262306a36Sopenharmony_ci#define ecryptfs_current_euid_hash(uid) \
2362306a36Sopenharmony_ci	hash_long((unsigned long)from_kuid(&init_user_ns, current_euid()), ecryptfs_hash_bits)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic u32 ecryptfs_msg_counter;
2662306a36Sopenharmony_cistatic struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/**
2962306a36Sopenharmony_ci * ecryptfs_acquire_free_msg_ctx
3062306a36Sopenharmony_ci * @msg_ctx: The context that was acquired from the free list
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * Acquires a context element from the free list and locks the mutex
3362306a36Sopenharmony_ci * on the context.  Sets the msg_ctx task to current.  Returns zero on
3462306a36Sopenharmony_ci * success; non-zero on error or upon failure to acquire a free
3562306a36Sopenharmony_ci * context element.  Must be called with ecryptfs_msg_ctx_lists_mux
3662306a36Sopenharmony_ci * held.
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_cistatic int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct list_head *p;
4162306a36Sopenharmony_ci	int rc;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (list_empty(&ecryptfs_msg_ctx_free_list)) {
4462306a36Sopenharmony_ci		printk(KERN_WARNING "%s: The eCryptfs free "
4562306a36Sopenharmony_ci		       "context list is empty.  It may be helpful to "
4662306a36Sopenharmony_ci		       "specify the ecryptfs_message_buf_len "
4762306a36Sopenharmony_ci		       "parameter to be greater than the current "
4862306a36Sopenharmony_ci		       "value of [%d]\n", __func__, ecryptfs_message_buf_len);
4962306a36Sopenharmony_ci		rc = -ENOMEM;
5062306a36Sopenharmony_ci		goto out;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci	list_for_each(p, &ecryptfs_msg_ctx_free_list) {
5362306a36Sopenharmony_ci		*msg_ctx = list_entry(p, struct ecryptfs_msg_ctx, node);
5462306a36Sopenharmony_ci		if (mutex_trylock(&(*msg_ctx)->mux)) {
5562306a36Sopenharmony_ci			(*msg_ctx)->task = current;
5662306a36Sopenharmony_ci			rc = 0;
5762306a36Sopenharmony_ci			goto out;
5862306a36Sopenharmony_ci		}
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci	rc = -ENOMEM;
6162306a36Sopenharmony_ciout:
6262306a36Sopenharmony_ci	return rc;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/**
6662306a36Sopenharmony_ci * ecryptfs_msg_ctx_free_to_alloc
6762306a36Sopenharmony_ci * @msg_ctx: The context to move from the free list to the alloc list
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * Must be called with ecryptfs_msg_ctx_lists_mux held.
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_cistatic void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	list_move(&msg_ctx->node, &ecryptfs_msg_ctx_alloc_list);
7462306a36Sopenharmony_ci	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_PENDING;
7562306a36Sopenharmony_ci	msg_ctx->counter = ++ecryptfs_msg_counter;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/**
7962306a36Sopenharmony_ci * ecryptfs_msg_ctx_alloc_to_free
8062306a36Sopenharmony_ci * @msg_ctx: The context to move from the alloc list to the free list
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * Must be called with ecryptfs_msg_ctx_lists_mux held.
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_civoid ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	list_move(&(msg_ctx->node), &ecryptfs_msg_ctx_free_list);
8762306a36Sopenharmony_ci	kfree(msg_ctx->msg);
8862306a36Sopenharmony_ci	msg_ctx->msg = NULL;
8962306a36Sopenharmony_ci	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_FREE;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/**
9362306a36Sopenharmony_ci * ecryptfs_find_daemon_by_euid
9462306a36Sopenharmony_ci * @daemon: If return value is zero, points to the desired daemon pointer
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * Must be called with ecryptfs_daemon_hash_mux held.
9762306a36Sopenharmony_ci *
9862306a36Sopenharmony_ci * Search the hash list for the current effective user id.
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * Returns zero if the user id exists in the list; non-zero otherwise.
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_ciint ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	int rc;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	hlist_for_each_entry(*daemon,
10762306a36Sopenharmony_ci			    &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()],
10862306a36Sopenharmony_ci			    euid_chain) {
10962306a36Sopenharmony_ci		if (uid_eq((*daemon)->file->f_cred->euid, current_euid())) {
11062306a36Sopenharmony_ci			rc = 0;
11162306a36Sopenharmony_ci			goto out;
11262306a36Sopenharmony_ci		}
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci	rc = -EINVAL;
11562306a36Sopenharmony_ciout:
11662306a36Sopenharmony_ci	return rc;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/**
12062306a36Sopenharmony_ci * ecryptfs_spawn_daemon - Create and initialize a new daemon struct
12162306a36Sopenharmony_ci * @daemon: Pointer to set to newly allocated daemon struct
12262306a36Sopenharmony_ci * @file: File used when opening /dev/ecryptfs
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci * Must be called ceremoniously while in possession of
12562306a36Sopenharmony_ci * ecryptfs_sacred_daemon_hash_mux
12662306a36Sopenharmony_ci *
12762306a36Sopenharmony_ci * Returns zero on success; non-zero otherwise
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_ciint
13062306a36Sopenharmony_ciecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, struct file *file)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	int rc = 0;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	(*daemon) = kzalloc(sizeof(**daemon), GFP_KERNEL);
13562306a36Sopenharmony_ci	if (!(*daemon)) {
13662306a36Sopenharmony_ci		rc = -ENOMEM;
13762306a36Sopenharmony_ci		goto out;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci	(*daemon)->file = file;
14062306a36Sopenharmony_ci	mutex_init(&(*daemon)->mux);
14162306a36Sopenharmony_ci	INIT_LIST_HEAD(&(*daemon)->msg_ctx_out_queue);
14262306a36Sopenharmony_ci	init_waitqueue_head(&(*daemon)->wait);
14362306a36Sopenharmony_ci	(*daemon)->num_queued_msg_ctx = 0;
14462306a36Sopenharmony_ci	hlist_add_head(&(*daemon)->euid_chain,
14562306a36Sopenharmony_ci		       &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()]);
14662306a36Sopenharmony_ciout:
14762306a36Sopenharmony_ci	return rc;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/*
15162306a36Sopenharmony_ci * ecryptfs_exorcise_daemon - Destroy the daemon struct
15262306a36Sopenharmony_ci *
15362306a36Sopenharmony_ci * Must be called ceremoniously while in possession of
15462306a36Sopenharmony_ci * ecryptfs_daemon_hash_mux and the daemon's own mux.
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_ciint ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct ecryptfs_msg_ctx *msg_ctx, *msg_ctx_tmp;
15962306a36Sopenharmony_ci	int rc = 0;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	mutex_lock(&daemon->mux);
16262306a36Sopenharmony_ci	if ((daemon->flags & ECRYPTFS_DAEMON_IN_READ)
16362306a36Sopenharmony_ci	    || (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)) {
16462306a36Sopenharmony_ci		rc = -EBUSY;
16562306a36Sopenharmony_ci		mutex_unlock(&daemon->mux);
16662306a36Sopenharmony_ci		goto out;
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci	list_for_each_entry_safe(msg_ctx, msg_ctx_tmp,
16962306a36Sopenharmony_ci				 &daemon->msg_ctx_out_queue, daemon_out_list) {
17062306a36Sopenharmony_ci		list_del(&msg_ctx->daemon_out_list);
17162306a36Sopenharmony_ci		daemon->num_queued_msg_ctx--;
17262306a36Sopenharmony_ci		printk(KERN_WARNING "%s: Warning: dropping message that is in "
17362306a36Sopenharmony_ci		       "the out queue of a dying daemon\n", __func__);
17462306a36Sopenharmony_ci		ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci	hlist_del(&daemon->euid_chain);
17762306a36Sopenharmony_ci	mutex_unlock(&daemon->mux);
17862306a36Sopenharmony_ci	kfree_sensitive(daemon);
17962306a36Sopenharmony_ciout:
18062306a36Sopenharmony_ci	return rc;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/**
18462306a36Sopenharmony_ci * ecryptfs_process_response
18562306a36Sopenharmony_ci * @daemon: eCryptfs daemon object
18662306a36Sopenharmony_ci * @msg: The ecryptfs message received; the caller should sanity check
18762306a36Sopenharmony_ci *       msg->data_len and free the memory
18862306a36Sopenharmony_ci * @seq: The sequence number of the message; must match the sequence
18962306a36Sopenharmony_ci *       number for the existing message context waiting for this
19062306a36Sopenharmony_ci *       response
19162306a36Sopenharmony_ci *
19262306a36Sopenharmony_ci * Processes a response message after sending an operation request to
19362306a36Sopenharmony_ci * userspace. Some other process is awaiting this response. Before
19462306a36Sopenharmony_ci * sending out its first communications, the other process allocated a
19562306a36Sopenharmony_ci * msg_ctx from the ecryptfs_msg_ctx_arr at a particular index. The
19662306a36Sopenharmony_ci * response message contains this index so that we can copy over the
19762306a36Sopenharmony_ci * response message into the msg_ctx that the process holds a
19862306a36Sopenharmony_ci * reference to. The other process is going to wake up, check to see
19962306a36Sopenharmony_ci * that msg_ctx->state == ECRYPTFS_MSG_CTX_STATE_DONE, and then
20062306a36Sopenharmony_ci * proceed to read off and process the response message. Returns zero
20162306a36Sopenharmony_ci * upon delivery to desired context element; non-zero upon delivery
20262306a36Sopenharmony_ci * failure or error.
20362306a36Sopenharmony_ci *
20462306a36Sopenharmony_ci * Returns zero on success; non-zero otherwise
20562306a36Sopenharmony_ci */
20662306a36Sopenharmony_ciint ecryptfs_process_response(struct ecryptfs_daemon *daemon,
20762306a36Sopenharmony_ci			      struct ecryptfs_message *msg, u32 seq)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	struct ecryptfs_msg_ctx *msg_ctx;
21062306a36Sopenharmony_ci	size_t msg_size;
21162306a36Sopenharmony_ci	int rc;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (msg->index >= ecryptfs_message_buf_len) {
21462306a36Sopenharmony_ci		rc = -EINVAL;
21562306a36Sopenharmony_ci		printk(KERN_ERR "%s: Attempt to reference "
21662306a36Sopenharmony_ci		       "context buffer at index [%d]; maximum "
21762306a36Sopenharmony_ci		       "allowable is [%d]\n", __func__, msg->index,
21862306a36Sopenharmony_ci		       (ecryptfs_message_buf_len - 1));
21962306a36Sopenharmony_ci		goto out;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci	msg_ctx = &ecryptfs_msg_ctx_arr[msg->index];
22262306a36Sopenharmony_ci	mutex_lock(&msg_ctx->mux);
22362306a36Sopenharmony_ci	if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
22462306a36Sopenharmony_ci		rc = -EINVAL;
22562306a36Sopenharmony_ci		printk(KERN_WARNING "%s: Desired context element is not "
22662306a36Sopenharmony_ci		       "pending a response\n", __func__);
22762306a36Sopenharmony_ci		goto unlock;
22862306a36Sopenharmony_ci	} else if (msg_ctx->counter != seq) {
22962306a36Sopenharmony_ci		rc = -EINVAL;
23062306a36Sopenharmony_ci		printk(KERN_WARNING "%s: Invalid message sequence; "
23162306a36Sopenharmony_ci		       "expected [%d]; received [%d]\n", __func__,
23262306a36Sopenharmony_ci		       msg_ctx->counter, seq);
23362306a36Sopenharmony_ci		goto unlock;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci	msg_size = (sizeof(*msg) + msg->data_len);
23662306a36Sopenharmony_ci	msg_ctx->msg = kmemdup(msg, msg_size, GFP_KERNEL);
23762306a36Sopenharmony_ci	if (!msg_ctx->msg) {
23862306a36Sopenharmony_ci		rc = -ENOMEM;
23962306a36Sopenharmony_ci		goto unlock;
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE;
24262306a36Sopenharmony_ci	wake_up_process(msg_ctx->task);
24362306a36Sopenharmony_ci	rc = 0;
24462306a36Sopenharmony_ciunlock:
24562306a36Sopenharmony_ci	mutex_unlock(&msg_ctx->mux);
24662306a36Sopenharmony_ciout:
24762306a36Sopenharmony_ci	return rc;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/**
25162306a36Sopenharmony_ci * ecryptfs_send_message_locked
25262306a36Sopenharmony_ci * @data: The data to send
25362306a36Sopenharmony_ci * @data_len: The length of data
25462306a36Sopenharmony_ci * @msg_type: Type of message
25562306a36Sopenharmony_ci * @msg_ctx: The message context allocated for the send
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci * Must be called with ecryptfs_daemon_hash_mux held.
25862306a36Sopenharmony_ci *
25962306a36Sopenharmony_ci * Returns zero on success; non-zero otherwise
26062306a36Sopenharmony_ci */
26162306a36Sopenharmony_cistatic int
26262306a36Sopenharmony_ciecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,
26362306a36Sopenharmony_ci			     struct ecryptfs_msg_ctx **msg_ctx)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct ecryptfs_daemon *daemon;
26662306a36Sopenharmony_ci	int rc;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	rc = ecryptfs_find_daemon_by_euid(&daemon);
26962306a36Sopenharmony_ci	if (rc) {
27062306a36Sopenharmony_ci		rc = -ENOTCONN;
27162306a36Sopenharmony_ci		goto out;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci	mutex_lock(&ecryptfs_msg_ctx_lists_mux);
27462306a36Sopenharmony_ci	rc = ecryptfs_acquire_free_msg_ctx(msg_ctx);
27562306a36Sopenharmony_ci	if (rc) {
27662306a36Sopenharmony_ci		mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
27762306a36Sopenharmony_ci		printk(KERN_WARNING "%s: Could not claim a free "
27862306a36Sopenharmony_ci		       "context element\n", __func__);
27962306a36Sopenharmony_ci		goto out;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci	ecryptfs_msg_ctx_free_to_alloc(*msg_ctx);
28262306a36Sopenharmony_ci	mutex_unlock(&(*msg_ctx)->mux);
28362306a36Sopenharmony_ci	mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
28462306a36Sopenharmony_ci	rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type, 0,
28562306a36Sopenharmony_ci				   daemon);
28662306a36Sopenharmony_ci	if (rc)
28762306a36Sopenharmony_ci		printk(KERN_ERR "%s: Error attempting to send message to "
28862306a36Sopenharmony_ci		       "userspace daemon; rc = [%d]\n", __func__, rc);
28962306a36Sopenharmony_ciout:
29062306a36Sopenharmony_ci	return rc;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci/**
29462306a36Sopenharmony_ci * ecryptfs_send_message
29562306a36Sopenharmony_ci * @data: The data to send
29662306a36Sopenharmony_ci * @data_len: The length of data
29762306a36Sopenharmony_ci * @msg_ctx: The message context allocated for the send
29862306a36Sopenharmony_ci *
29962306a36Sopenharmony_ci * Grabs ecryptfs_daemon_hash_mux.
30062306a36Sopenharmony_ci *
30162306a36Sopenharmony_ci * Returns zero on success; non-zero otherwise
30262306a36Sopenharmony_ci */
30362306a36Sopenharmony_ciint ecryptfs_send_message(char *data, int data_len,
30462306a36Sopenharmony_ci			  struct ecryptfs_msg_ctx **msg_ctx)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	int rc;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	mutex_lock(&ecryptfs_daemon_hash_mux);
30962306a36Sopenharmony_ci	rc = ecryptfs_send_message_locked(data, data_len, ECRYPTFS_MSG_REQUEST,
31062306a36Sopenharmony_ci					  msg_ctx);
31162306a36Sopenharmony_ci	mutex_unlock(&ecryptfs_daemon_hash_mux);
31262306a36Sopenharmony_ci	return rc;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/**
31662306a36Sopenharmony_ci * ecryptfs_wait_for_response
31762306a36Sopenharmony_ci * @msg_ctx: The context that was assigned when sending a message
31862306a36Sopenharmony_ci * @msg: The incoming message from userspace; not set if rc != 0
31962306a36Sopenharmony_ci *
32062306a36Sopenharmony_ci * Sleeps until awaken by ecryptfs_receive_message or until the amount
32162306a36Sopenharmony_ci * of time exceeds ecryptfs_message_wait_timeout.  If zero is
32262306a36Sopenharmony_ci * returned, msg will point to a valid message from userspace; a
32362306a36Sopenharmony_ci * non-zero value is returned upon failure to receive a message or an
32462306a36Sopenharmony_ci * error occurs. Callee must free @msg on success.
32562306a36Sopenharmony_ci */
32662306a36Sopenharmony_ciint ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
32762306a36Sopenharmony_ci			       struct ecryptfs_message **msg)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	signed long timeout = ecryptfs_message_wait_timeout * HZ;
33062306a36Sopenharmony_ci	int rc = 0;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cisleep:
33362306a36Sopenharmony_ci	timeout = schedule_timeout_interruptible(timeout);
33462306a36Sopenharmony_ci	mutex_lock(&ecryptfs_msg_ctx_lists_mux);
33562306a36Sopenharmony_ci	mutex_lock(&msg_ctx->mux);
33662306a36Sopenharmony_ci	if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_DONE) {
33762306a36Sopenharmony_ci		if (timeout) {
33862306a36Sopenharmony_ci			mutex_unlock(&msg_ctx->mux);
33962306a36Sopenharmony_ci			mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
34062306a36Sopenharmony_ci			goto sleep;
34162306a36Sopenharmony_ci		}
34262306a36Sopenharmony_ci		rc = -ENOMSG;
34362306a36Sopenharmony_ci	} else {
34462306a36Sopenharmony_ci		*msg = msg_ctx->msg;
34562306a36Sopenharmony_ci		msg_ctx->msg = NULL;
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci	ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
34862306a36Sopenharmony_ci	mutex_unlock(&msg_ctx->mux);
34962306a36Sopenharmony_ci	mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
35062306a36Sopenharmony_ci	return rc;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ciint __init ecryptfs_init_messaging(void)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	int i;
35662306a36Sopenharmony_ci	int rc = 0;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (ecryptfs_number_of_users > ECRYPTFS_MAX_NUM_USERS) {
35962306a36Sopenharmony_ci		ecryptfs_number_of_users = ECRYPTFS_MAX_NUM_USERS;
36062306a36Sopenharmony_ci		printk(KERN_WARNING "%s: Specified number of users is "
36162306a36Sopenharmony_ci		       "too large, defaulting to [%d] users\n", __func__,
36262306a36Sopenharmony_ci		       ecryptfs_number_of_users);
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci	mutex_lock(&ecryptfs_daemon_hash_mux);
36562306a36Sopenharmony_ci	ecryptfs_hash_bits = 1;
36662306a36Sopenharmony_ci	while (ecryptfs_number_of_users >> ecryptfs_hash_bits)
36762306a36Sopenharmony_ci		ecryptfs_hash_bits++;
36862306a36Sopenharmony_ci	ecryptfs_daemon_hash = kmalloc((sizeof(struct hlist_head)
36962306a36Sopenharmony_ci					* (1 << ecryptfs_hash_bits)),
37062306a36Sopenharmony_ci				       GFP_KERNEL);
37162306a36Sopenharmony_ci	if (!ecryptfs_daemon_hash) {
37262306a36Sopenharmony_ci		rc = -ENOMEM;
37362306a36Sopenharmony_ci		mutex_unlock(&ecryptfs_daemon_hash_mux);
37462306a36Sopenharmony_ci		goto out;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci	for (i = 0; i < (1 << ecryptfs_hash_bits); i++)
37762306a36Sopenharmony_ci		INIT_HLIST_HEAD(&ecryptfs_daemon_hash[i]);
37862306a36Sopenharmony_ci	mutex_unlock(&ecryptfs_daemon_hash_mux);
37962306a36Sopenharmony_ci	ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx)
38062306a36Sopenharmony_ci					* ecryptfs_message_buf_len),
38162306a36Sopenharmony_ci				       GFP_KERNEL);
38262306a36Sopenharmony_ci	if (!ecryptfs_msg_ctx_arr) {
38362306a36Sopenharmony_ci		kfree(ecryptfs_daemon_hash);
38462306a36Sopenharmony_ci		rc = -ENOMEM;
38562306a36Sopenharmony_ci		goto out;
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci	mutex_lock(&ecryptfs_msg_ctx_lists_mux);
38862306a36Sopenharmony_ci	ecryptfs_msg_counter = 0;
38962306a36Sopenharmony_ci	for (i = 0; i < ecryptfs_message_buf_len; i++) {
39062306a36Sopenharmony_ci		INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].node);
39162306a36Sopenharmony_ci		INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].daemon_out_list);
39262306a36Sopenharmony_ci		mutex_init(&ecryptfs_msg_ctx_arr[i].mux);
39362306a36Sopenharmony_ci		mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);
39462306a36Sopenharmony_ci		ecryptfs_msg_ctx_arr[i].index = i;
39562306a36Sopenharmony_ci		ecryptfs_msg_ctx_arr[i].state = ECRYPTFS_MSG_CTX_STATE_FREE;
39662306a36Sopenharmony_ci		ecryptfs_msg_ctx_arr[i].counter = 0;
39762306a36Sopenharmony_ci		ecryptfs_msg_ctx_arr[i].task = NULL;
39862306a36Sopenharmony_ci		ecryptfs_msg_ctx_arr[i].msg = NULL;
39962306a36Sopenharmony_ci		list_add_tail(&ecryptfs_msg_ctx_arr[i].node,
40062306a36Sopenharmony_ci			      &ecryptfs_msg_ctx_free_list);
40162306a36Sopenharmony_ci		mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux);
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci	mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
40462306a36Sopenharmony_ci	rc = ecryptfs_init_ecryptfs_miscdev();
40562306a36Sopenharmony_ci	if (rc)
40662306a36Sopenharmony_ci		ecryptfs_release_messaging();
40762306a36Sopenharmony_ciout:
40862306a36Sopenharmony_ci	return rc;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_civoid ecryptfs_release_messaging(void)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	if (ecryptfs_msg_ctx_arr) {
41462306a36Sopenharmony_ci		int i;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci		mutex_lock(&ecryptfs_msg_ctx_lists_mux);
41762306a36Sopenharmony_ci		for (i = 0; i < ecryptfs_message_buf_len; i++) {
41862306a36Sopenharmony_ci			mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);
41962306a36Sopenharmony_ci			kfree(ecryptfs_msg_ctx_arr[i].msg);
42062306a36Sopenharmony_ci			mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux);
42162306a36Sopenharmony_ci		}
42262306a36Sopenharmony_ci		kfree(ecryptfs_msg_ctx_arr);
42362306a36Sopenharmony_ci		mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci	if (ecryptfs_daemon_hash) {
42662306a36Sopenharmony_ci		struct ecryptfs_daemon *daemon;
42762306a36Sopenharmony_ci		struct hlist_node *n;
42862306a36Sopenharmony_ci		int i;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci		mutex_lock(&ecryptfs_daemon_hash_mux);
43162306a36Sopenharmony_ci		for (i = 0; i < (1 << ecryptfs_hash_bits); i++) {
43262306a36Sopenharmony_ci			int rc;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci			hlist_for_each_entry_safe(daemon, n,
43562306a36Sopenharmony_ci						  &ecryptfs_daemon_hash[i],
43662306a36Sopenharmony_ci						  euid_chain) {
43762306a36Sopenharmony_ci				rc = ecryptfs_exorcise_daemon(daemon);
43862306a36Sopenharmony_ci				if (rc)
43962306a36Sopenharmony_ci					printk(KERN_ERR "%s: Error whilst "
44062306a36Sopenharmony_ci					       "attempting to destroy daemon; "
44162306a36Sopenharmony_ci					       "rc = [%d]. Dazed and confused, "
44262306a36Sopenharmony_ci					       "but trying to continue.\n",
44362306a36Sopenharmony_ci					       __func__, rc);
44462306a36Sopenharmony_ci			}
44562306a36Sopenharmony_ci		}
44662306a36Sopenharmony_ci		kfree(ecryptfs_daemon_hash);
44762306a36Sopenharmony_ci		mutex_unlock(&ecryptfs_daemon_hash_mux);
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci	ecryptfs_destroy_ecryptfs_miscdev();
45062306a36Sopenharmony_ci	return;
45162306a36Sopenharmony_ci}
452