18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/**
38c2ecf20Sopenharmony_ci * eCryptfs: Linux filesystem encryption layer
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2004-2008 International Business Machines Corp.
68c2ecf20Sopenharmony_ci *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
78c2ecf20Sopenharmony_ci *		Tyler Hicks <code@tyhicks.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/sched.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/user_namespace.h>
128c2ecf20Sopenharmony_ci#include <linux/nsproxy.h>
138c2ecf20Sopenharmony_ci#include "ecryptfs_kernel.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic LIST_HEAD(ecryptfs_msg_ctx_free_list);
168c2ecf20Sopenharmony_cistatic LIST_HEAD(ecryptfs_msg_ctx_alloc_list);
178c2ecf20Sopenharmony_cistatic struct mutex ecryptfs_msg_ctx_lists_mux;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic struct hlist_head *ecryptfs_daemon_hash;
208c2ecf20Sopenharmony_cistruct mutex ecryptfs_daemon_hash_mux;
218c2ecf20Sopenharmony_cistatic int ecryptfs_hash_bits;
228c2ecf20Sopenharmony_ci#define ecryptfs_current_euid_hash(uid) \
238c2ecf20Sopenharmony_ci	hash_long((unsigned long)from_kuid(&init_user_ns, current_euid()), ecryptfs_hash_bits)
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic u32 ecryptfs_msg_counter;
268c2ecf20Sopenharmony_cistatic struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/**
298c2ecf20Sopenharmony_ci * ecryptfs_acquire_free_msg_ctx
308c2ecf20Sopenharmony_ci * @msg_ctx: The context that was acquired from the free list
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * Acquires a context element from the free list and locks the mutex
338c2ecf20Sopenharmony_ci * on the context.  Sets the msg_ctx task to current.  Returns zero on
348c2ecf20Sopenharmony_ci * success; non-zero on error or upon failure to acquire a free
358c2ecf20Sopenharmony_ci * context element.  Must be called with ecryptfs_msg_ctx_lists_mux
368c2ecf20Sopenharmony_ci * held.
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_cistatic int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	struct list_head *p;
418c2ecf20Sopenharmony_ci	int rc;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (list_empty(&ecryptfs_msg_ctx_free_list)) {
448c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: The eCryptfs free "
458c2ecf20Sopenharmony_ci		       "context list is empty.  It may be helpful to "
468c2ecf20Sopenharmony_ci		       "specify the ecryptfs_message_buf_len "
478c2ecf20Sopenharmony_ci		       "parameter to be greater than the current "
488c2ecf20Sopenharmony_ci		       "value of [%d]\n", __func__, ecryptfs_message_buf_len);
498c2ecf20Sopenharmony_ci		rc = -ENOMEM;
508c2ecf20Sopenharmony_ci		goto out;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci	list_for_each(p, &ecryptfs_msg_ctx_free_list) {
538c2ecf20Sopenharmony_ci		*msg_ctx = list_entry(p, struct ecryptfs_msg_ctx, node);
548c2ecf20Sopenharmony_ci		if (mutex_trylock(&(*msg_ctx)->mux)) {
558c2ecf20Sopenharmony_ci			(*msg_ctx)->task = current;
568c2ecf20Sopenharmony_ci			rc = 0;
578c2ecf20Sopenharmony_ci			goto out;
588c2ecf20Sopenharmony_ci		}
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci	rc = -ENOMEM;
618c2ecf20Sopenharmony_ciout:
628c2ecf20Sopenharmony_ci	return rc;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/**
668c2ecf20Sopenharmony_ci * ecryptfs_msg_ctx_free_to_alloc
678c2ecf20Sopenharmony_ci * @msg_ctx: The context to move from the free list to the alloc list
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci * Must be called with ecryptfs_msg_ctx_lists_mux held.
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_cistatic void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	list_move(&msg_ctx->node, &ecryptfs_msg_ctx_alloc_list);
748c2ecf20Sopenharmony_ci	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_PENDING;
758c2ecf20Sopenharmony_ci	msg_ctx->counter = ++ecryptfs_msg_counter;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/**
798c2ecf20Sopenharmony_ci * ecryptfs_msg_ctx_alloc_to_free
808c2ecf20Sopenharmony_ci * @msg_ctx: The context to move from the alloc list to the free list
818c2ecf20Sopenharmony_ci *
828c2ecf20Sopenharmony_ci * Must be called with ecryptfs_msg_ctx_lists_mux held.
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_civoid ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	list_move(&(msg_ctx->node), &ecryptfs_msg_ctx_free_list);
878c2ecf20Sopenharmony_ci	kfree(msg_ctx->msg);
888c2ecf20Sopenharmony_ci	msg_ctx->msg = NULL;
898c2ecf20Sopenharmony_ci	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_FREE;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/**
938c2ecf20Sopenharmony_ci * ecryptfs_find_daemon_by_euid
948c2ecf20Sopenharmony_ci * @daemon: If return value is zero, points to the desired daemon pointer
958c2ecf20Sopenharmony_ci *
968c2ecf20Sopenharmony_ci * Must be called with ecryptfs_daemon_hash_mux held.
978c2ecf20Sopenharmony_ci *
988c2ecf20Sopenharmony_ci * Search the hash list for the current effective user id.
998c2ecf20Sopenharmony_ci *
1008c2ecf20Sopenharmony_ci * Returns zero if the user id exists in the list; non-zero otherwise.
1018c2ecf20Sopenharmony_ci */
1028c2ecf20Sopenharmony_ciint ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	int rc;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	hlist_for_each_entry(*daemon,
1078c2ecf20Sopenharmony_ci			    &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()],
1088c2ecf20Sopenharmony_ci			    euid_chain) {
1098c2ecf20Sopenharmony_ci		if (uid_eq((*daemon)->file->f_cred->euid, current_euid())) {
1108c2ecf20Sopenharmony_ci			rc = 0;
1118c2ecf20Sopenharmony_ci			goto out;
1128c2ecf20Sopenharmony_ci		}
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci	rc = -EINVAL;
1158c2ecf20Sopenharmony_ciout:
1168c2ecf20Sopenharmony_ci	return rc;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/**
1208c2ecf20Sopenharmony_ci * ecryptfs_spawn_daemon - Create and initialize a new daemon struct
1218c2ecf20Sopenharmony_ci * @daemon: Pointer to set to newly allocated daemon struct
1228c2ecf20Sopenharmony_ci * @file: File used when opening /dev/ecryptfs
1238c2ecf20Sopenharmony_ci *
1248c2ecf20Sopenharmony_ci * Must be called ceremoniously while in possession of
1258c2ecf20Sopenharmony_ci * ecryptfs_sacred_daemon_hash_mux
1268c2ecf20Sopenharmony_ci *
1278c2ecf20Sopenharmony_ci * Returns zero on success; non-zero otherwise
1288c2ecf20Sopenharmony_ci */
1298c2ecf20Sopenharmony_ciint
1308c2ecf20Sopenharmony_ciecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, struct file *file)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	int rc = 0;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	(*daemon) = kzalloc(sizeof(**daemon), GFP_KERNEL);
1358c2ecf20Sopenharmony_ci	if (!(*daemon)) {
1368c2ecf20Sopenharmony_ci		rc = -ENOMEM;
1378c2ecf20Sopenharmony_ci		goto out;
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci	(*daemon)->file = file;
1408c2ecf20Sopenharmony_ci	mutex_init(&(*daemon)->mux);
1418c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&(*daemon)->msg_ctx_out_queue);
1428c2ecf20Sopenharmony_ci	init_waitqueue_head(&(*daemon)->wait);
1438c2ecf20Sopenharmony_ci	(*daemon)->num_queued_msg_ctx = 0;
1448c2ecf20Sopenharmony_ci	hlist_add_head(&(*daemon)->euid_chain,
1458c2ecf20Sopenharmony_ci		       &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()]);
1468c2ecf20Sopenharmony_ciout:
1478c2ecf20Sopenharmony_ci	return rc;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/**
1518c2ecf20Sopenharmony_ci * ecryptfs_exorcise_daemon - Destroy the daemon struct
1528c2ecf20Sopenharmony_ci *
1538c2ecf20Sopenharmony_ci * Must be called ceremoniously while in possession of
1548c2ecf20Sopenharmony_ci * ecryptfs_daemon_hash_mux and the daemon's own mux.
1558c2ecf20Sopenharmony_ci */
1568c2ecf20Sopenharmony_ciint ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct ecryptfs_msg_ctx *msg_ctx, *msg_ctx_tmp;
1598c2ecf20Sopenharmony_ci	int rc = 0;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	mutex_lock(&daemon->mux);
1628c2ecf20Sopenharmony_ci	if ((daemon->flags & ECRYPTFS_DAEMON_IN_READ)
1638c2ecf20Sopenharmony_ci	    || (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)) {
1648c2ecf20Sopenharmony_ci		rc = -EBUSY;
1658c2ecf20Sopenharmony_ci		mutex_unlock(&daemon->mux);
1668c2ecf20Sopenharmony_ci		goto out;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci	list_for_each_entry_safe(msg_ctx, msg_ctx_tmp,
1698c2ecf20Sopenharmony_ci				 &daemon->msg_ctx_out_queue, daemon_out_list) {
1708c2ecf20Sopenharmony_ci		list_del(&msg_ctx->daemon_out_list);
1718c2ecf20Sopenharmony_ci		daemon->num_queued_msg_ctx--;
1728c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Warning: dropping message that is in "
1738c2ecf20Sopenharmony_ci		       "the out queue of a dying daemon\n", __func__);
1748c2ecf20Sopenharmony_ci		ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci	hlist_del(&daemon->euid_chain);
1778c2ecf20Sopenharmony_ci	mutex_unlock(&daemon->mux);
1788c2ecf20Sopenharmony_ci	kfree_sensitive(daemon);
1798c2ecf20Sopenharmony_ciout:
1808c2ecf20Sopenharmony_ci	return rc;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci/**
1848c2ecf20Sopenharmony_ci * ecryptfs_process_reponse
1858c2ecf20Sopenharmony_ci * @msg: The ecryptfs message received; the caller should sanity check
1868c2ecf20Sopenharmony_ci *       msg->data_len and free the memory
1878c2ecf20Sopenharmony_ci * @seq: The sequence number of the message; must match the sequence
1888c2ecf20Sopenharmony_ci *       number for the existing message context waiting for this
1898c2ecf20Sopenharmony_ci *       response
1908c2ecf20Sopenharmony_ci *
1918c2ecf20Sopenharmony_ci * Processes a response message after sending an operation request to
1928c2ecf20Sopenharmony_ci * userspace. Some other process is awaiting this response. Before
1938c2ecf20Sopenharmony_ci * sending out its first communications, the other process allocated a
1948c2ecf20Sopenharmony_ci * msg_ctx from the ecryptfs_msg_ctx_arr at a particular index. The
1958c2ecf20Sopenharmony_ci * response message contains this index so that we can copy over the
1968c2ecf20Sopenharmony_ci * response message into the msg_ctx that the process holds a
1978c2ecf20Sopenharmony_ci * reference to. The other process is going to wake up, check to see
1988c2ecf20Sopenharmony_ci * that msg_ctx->state == ECRYPTFS_MSG_CTX_STATE_DONE, and then
1998c2ecf20Sopenharmony_ci * proceed to read off and process the response message. Returns zero
2008c2ecf20Sopenharmony_ci * upon delivery to desired context element; non-zero upon delivery
2018c2ecf20Sopenharmony_ci * failure or error.
2028c2ecf20Sopenharmony_ci *
2038c2ecf20Sopenharmony_ci * Returns zero on success; non-zero otherwise
2048c2ecf20Sopenharmony_ci */
2058c2ecf20Sopenharmony_ciint ecryptfs_process_response(struct ecryptfs_daemon *daemon,
2068c2ecf20Sopenharmony_ci			      struct ecryptfs_message *msg, u32 seq)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct ecryptfs_msg_ctx *msg_ctx;
2098c2ecf20Sopenharmony_ci	size_t msg_size;
2108c2ecf20Sopenharmony_ci	int rc;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (msg->index >= ecryptfs_message_buf_len) {
2138c2ecf20Sopenharmony_ci		rc = -EINVAL;
2148c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Attempt to reference "
2158c2ecf20Sopenharmony_ci		       "context buffer at index [%d]; maximum "
2168c2ecf20Sopenharmony_ci		       "allowable is [%d]\n", __func__, msg->index,
2178c2ecf20Sopenharmony_ci		       (ecryptfs_message_buf_len - 1));
2188c2ecf20Sopenharmony_ci		goto out;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci	msg_ctx = &ecryptfs_msg_ctx_arr[msg->index];
2218c2ecf20Sopenharmony_ci	mutex_lock(&msg_ctx->mux);
2228c2ecf20Sopenharmony_ci	if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
2238c2ecf20Sopenharmony_ci		rc = -EINVAL;
2248c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Desired context element is not "
2258c2ecf20Sopenharmony_ci		       "pending a response\n", __func__);
2268c2ecf20Sopenharmony_ci		goto unlock;
2278c2ecf20Sopenharmony_ci	} else if (msg_ctx->counter != seq) {
2288c2ecf20Sopenharmony_ci		rc = -EINVAL;
2298c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Invalid message sequence; "
2308c2ecf20Sopenharmony_ci		       "expected [%d]; received [%d]\n", __func__,
2318c2ecf20Sopenharmony_ci		       msg_ctx->counter, seq);
2328c2ecf20Sopenharmony_ci		goto unlock;
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci	msg_size = (sizeof(*msg) + msg->data_len);
2358c2ecf20Sopenharmony_ci	msg_ctx->msg = kmemdup(msg, msg_size, GFP_KERNEL);
2368c2ecf20Sopenharmony_ci	if (!msg_ctx->msg) {
2378c2ecf20Sopenharmony_ci		rc = -ENOMEM;
2388c2ecf20Sopenharmony_ci		goto unlock;
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE;
2418c2ecf20Sopenharmony_ci	wake_up_process(msg_ctx->task);
2428c2ecf20Sopenharmony_ci	rc = 0;
2438c2ecf20Sopenharmony_ciunlock:
2448c2ecf20Sopenharmony_ci	mutex_unlock(&msg_ctx->mux);
2458c2ecf20Sopenharmony_ciout:
2468c2ecf20Sopenharmony_ci	return rc;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci/**
2508c2ecf20Sopenharmony_ci * ecryptfs_send_message_locked
2518c2ecf20Sopenharmony_ci * @data: The data to send
2528c2ecf20Sopenharmony_ci * @data_len: The length of data
2538c2ecf20Sopenharmony_ci * @msg_ctx: The message context allocated for the send
2548c2ecf20Sopenharmony_ci *
2558c2ecf20Sopenharmony_ci * Must be called with ecryptfs_daemon_hash_mux held.
2568c2ecf20Sopenharmony_ci *
2578c2ecf20Sopenharmony_ci * Returns zero on success; non-zero otherwise
2588c2ecf20Sopenharmony_ci */
2598c2ecf20Sopenharmony_cistatic int
2608c2ecf20Sopenharmony_ciecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,
2618c2ecf20Sopenharmony_ci			     struct ecryptfs_msg_ctx **msg_ctx)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct ecryptfs_daemon *daemon;
2648c2ecf20Sopenharmony_ci	int rc;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	rc = ecryptfs_find_daemon_by_euid(&daemon);
2678c2ecf20Sopenharmony_ci	if (rc) {
2688c2ecf20Sopenharmony_ci		rc = -ENOTCONN;
2698c2ecf20Sopenharmony_ci		goto out;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci	mutex_lock(&ecryptfs_msg_ctx_lists_mux);
2728c2ecf20Sopenharmony_ci	rc = ecryptfs_acquire_free_msg_ctx(msg_ctx);
2738c2ecf20Sopenharmony_ci	if (rc) {
2748c2ecf20Sopenharmony_ci		mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
2758c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Could not claim a free "
2768c2ecf20Sopenharmony_ci		       "context element\n", __func__);
2778c2ecf20Sopenharmony_ci		goto out;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci	ecryptfs_msg_ctx_free_to_alloc(*msg_ctx);
2808c2ecf20Sopenharmony_ci	mutex_unlock(&(*msg_ctx)->mux);
2818c2ecf20Sopenharmony_ci	mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
2828c2ecf20Sopenharmony_ci	rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type, 0,
2838c2ecf20Sopenharmony_ci				   daemon);
2848c2ecf20Sopenharmony_ci	if (rc)
2858c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Error attempting to send message to "
2868c2ecf20Sopenharmony_ci		       "userspace daemon; rc = [%d]\n", __func__, rc);
2878c2ecf20Sopenharmony_ciout:
2888c2ecf20Sopenharmony_ci	return rc;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci/**
2928c2ecf20Sopenharmony_ci * ecryptfs_send_message
2938c2ecf20Sopenharmony_ci * @data: The data to send
2948c2ecf20Sopenharmony_ci * @data_len: The length of data
2958c2ecf20Sopenharmony_ci * @msg_ctx: The message context allocated for the send
2968c2ecf20Sopenharmony_ci *
2978c2ecf20Sopenharmony_ci * Grabs ecryptfs_daemon_hash_mux.
2988c2ecf20Sopenharmony_ci *
2998c2ecf20Sopenharmony_ci * Returns zero on success; non-zero otherwise
3008c2ecf20Sopenharmony_ci */
3018c2ecf20Sopenharmony_ciint ecryptfs_send_message(char *data, int data_len,
3028c2ecf20Sopenharmony_ci			  struct ecryptfs_msg_ctx **msg_ctx)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	int rc;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	mutex_lock(&ecryptfs_daemon_hash_mux);
3078c2ecf20Sopenharmony_ci	rc = ecryptfs_send_message_locked(data, data_len, ECRYPTFS_MSG_REQUEST,
3088c2ecf20Sopenharmony_ci					  msg_ctx);
3098c2ecf20Sopenharmony_ci	mutex_unlock(&ecryptfs_daemon_hash_mux);
3108c2ecf20Sopenharmony_ci	return rc;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci/**
3148c2ecf20Sopenharmony_ci * ecryptfs_wait_for_response
3158c2ecf20Sopenharmony_ci * @msg_ctx: The context that was assigned when sending a message
3168c2ecf20Sopenharmony_ci * @msg: The incoming message from userspace; not set if rc != 0
3178c2ecf20Sopenharmony_ci *
3188c2ecf20Sopenharmony_ci * Sleeps until awaken by ecryptfs_receive_message or until the amount
3198c2ecf20Sopenharmony_ci * of time exceeds ecryptfs_message_wait_timeout.  If zero is
3208c2ecf20Sopenharmony_ci * returned, msg will point to a valid message from userspace; a
3218c2ecf20Sopenharmony_ci * non-zero value is returned upon failure to receive a message or an
3228c2ecf20Sopenharmony_ci * error occurs. Callee must free @msg on success.
3238c2ecf20Sopenharmony_ci */
3248c2ecf20Sopenharmony_ciint ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
3258c2ecf20Sopenharmony_ci			       struct ecryptfs_message **msg)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	signed long timeout = ecryptfs_message_wait_timeout * HZ;
3288c2ecf20Sopenharmony_ci	int rc = 0;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cisleep:
3318c2ecf20Sopenharmony_ci	timeout = schedule_timeout_interruptible(timeout);
3328c2ecf20Sopenharmony_ci	mutex_lock(&ecryptfs_msg_ctx_lists_mux);
3338c2ecf20Sopenharmony_ci	mutex_lock(&msg_ctx->mux);
3348c2ecf20Sopenharmony_ci	if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_DONE) {
3358c2ecf20Sopenharmony_ci		if (timeout) {
3368c2ecf20Sopenharmony_ci			mutex_unlock(&msg_ctx->mux);
3378c2ecf20Sopenharmony_ci			mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
3388c2ecf20Sopenharmony_ci			goto sleep;
3398c2ecf20Sopenharmony_ci		}
3408c2ecf20Sopenharmony_ci		rc = -ENOMSG;
3418c2ecf20Sopenharmony_ci	} else {
3428c2ecf20Sopenharmony_ci		*msg = msg_ctx->msg;
3438c2ecf20Sopenharmony_ci		msg_ctx->msg = NULL;
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci	ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
3468c2ecf20Sopenharmony_ci	mutex_unlock(&msg_ctx->mux);
3478c2ecf20Sopenharmony_ci	mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
3488c2ecf20Sopenharmony_ci	return rc;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ciint __init ecryptfs_init_messaging(void)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	int i;
3548c2ecf20Sopenharmony_ci	int rc = 0;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (ecryptfs_number_of_users > ECRYPTFS_MAX_NUM_USERS) {
3578c2ecf20Sopenharmony_ci		ecryptfs_number_of_users = ECRYPTFS_MAX_NUM_USERS;
3588c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Specified number of users is "
3598c2ecf20Sopenharmony_ci		       "too large, defaulting to [%d] users\n", __func__,
3608c2ecf20Sopenharmony_ci		       ecryptfs_number_of_users);
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci	mutex_init(&ecryptfs_daemon_hash_mux);
3638c2ecf20Sopenharmony_ci	mutex_lock(&ecryptfs_daemon_hash_mux);
3648c2ecf20Sopenharmony_ci	ecryptfs_hash_bits = 1;
3658c2ecf20Sopenharmony_ci	while (ecryptfs_number_of_users >> ecryptfs_hash_bits)
3668c2ecf20Sopenharmony_ci		ecryptfs_hash_bits++;
3678c2ecf20Sopenharmony_ci	ecryptfs_daemon_hash = kmalloc((sizeof(struct hlist_head)
3688c2ecf20Sopenharmony_ci					* (1 << ecryptfs_hash_bits)),
3698c2ecf20Sopenharmony_ci				       GFP_KERNEL);
3708c2ecf20Sopenharmony_ci	if (!ecryptfs_daemon_hash) {
3718c2ecf20Sopenharmony_ci		rc = -ENOMEM;
3728c2ecf20Sopenharmony_ci		mutex_unlock(&ecryptfs_daemon_hash_mux);
3738c2ecf20Sopenharmony_ci		goto out;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci	for (i = 0; i < (1 << ecryptfs_hash_bits); i++)
3768c2ecf20Sopenharmony_ci		INIT_HLIST_HEAD(&ecryptfs_daemon_hash[i]);
3778c2ecf20Sopenharmony_ci	mutex_unlock(&ecryptfs_daemon_hash_mux);
3788c2ecf20Sopenharmony_ci	ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx)
3798c2ecf20Sopenharmony_ci					* ecryptfs_message_buf_len),
3808c2ecf20Sopenharmony_ci				       GFP_KERNEL);
3818c2ecf20Sopenharmony_ci	if (!ecryptfs_msg_ctx_arr) {
3828c2ecf20Sopenharmony_ci		kfree(ecryptfs_daemon_hash);
3838c2ecf20Sopenharmony_ci		rc = -ENOMEM;
3848c2ecf20Sopenharmony_ci		goto out;
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci	mutex_init(&ecryptfs_msg_ctx_lists_mux);
3878c2ecf20Sopenharmony_ci	mutex_lock(&ecryptfs_msg_ctx_lists_mux);
3888c2ecf20Sopenharmony_ci	ecryptfs_msg_counter = 0;
3898c2ecf20Sopenharmony_ci	for (i = 0; i < ecryptfs_message_buf_len; i++) {
3908c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].node);
3918c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].daemon_out_list);
3928c2ecf20Sopenharmony_ci		mutex_init(&ecryptfs_msg_ctx_arr[i].mux);
3938c2ecf20Sopenharmony_ci		mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);
3948c2ecf20Sopenharmony_ci		ecryptfs_msg_ctx_arr[i].index = i;
3958c2ecf20Sopenharmony_ci		ecryptfs_msg_ctx_arr[i].state = ECRYPTFS_MSG_CTX_STATE_FREE;
3968c2ecf20Sopenharmony_ci		ecryptfs_msg_ctx_arr[i].counter = 0;
3978c2ecf20Sopenharmony_ci		ecryptfs_msg_ctx_arr[i].task = NULL;
3988c2ecf20Sopenharmony_ci		ecryptfs_msg_ctx_arr[i].msg = NULL;
3998c2ecf20Sopenharmony_ci		list_add_tail(&ecryptfs_msg_ctx_arr[i].node,
4008c2ecf20Sopenharmony_ci			      &ecryptfs_msg_ctx_free_list);
4018c2ecf20Sopenharmony_ci		mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux);
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci	mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
4048c2ecf20Sopenharmony_ci	rc = ecryptfs_init_ecryptfs_miscdev();
4058c2ecf20Sopenharmony_ci	if (rc)
4068c2ecf20Sopenharmony_ci		ecryptfs_release_messaging();
4078c2ecf20Sopenharmony_ciout:
4088c2ecf20Sopenharmony_ci	return rc;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_civoid ecryptfs_release_messaging(void)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	if (ecryptfs_msg_ctx_arr) {
4148c2ecf20Sopenharmony_ci		int i;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci		mutex_lock(&ecryptfs_msg_ctx_lists_mux);
4178c2ecf20Sopenharmony_ci		for (i = 0; i < ecryptfs_message_buf_len; i++) {
4188c2ecf20Sopenharmony_ci			mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);
4198c2ecf20Sopenharmony_ci			kfree(ecryptfs_msg_ctx_arr[i].msg);
4208c2ecf20Sopenharmony_ci			mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux);
4218c2ecf20Sopenharmony_ci		}
4228c2ecf20Sopenharmony_ci		kfree(ecryptfs_msg_ctx_arr);
4238c2ecf20Sopenharmony_ci		mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
4248c2ecf20Sopenharmony_ci	}
4258c2ecf20Sopenharmony_ci	if (ecryptfs_daemon_hash) {
4268c2ecf20Sopenharmony_ci		struct ecryptfs_daemon *daemon;
4278c2ecf20Sopenharmony_ci		struct hlist_node *n;
4288c2ecf20Sopenharmony_ci		int i;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci		mutex_lock(&ecryptfs_daemon_hash_mux);
4318c2ecf20Sopenharmony_ci		for (i = 0; i < (1 << ecryptfs_hash_bits); i++) {
4328c2ecf20Sopenharmony_ci			int rc;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci			hlist_for_each_entry_safe(daemon, n,
4358c2ecf20Sopenharmony_ci						  &ecryptfs_daemon_hash[i],
4368c2ecf20Sopenharmony_ci						  euid_chain) {
4378c2ecf20Sopenharmony_ci				rc = ecryptfs_exorcise_daemon(daemon);
4388c2ecf20Sopenharmony_ci				if (rc)
4398c2ecf20Sopenharmony_ci					printk(KERN_ERR "%s: Error whilst "
4408c2ecf20Sopenharmony_ci					       "attempting to destroy daemon; "
4418c2ecf20Sopenharmony_ci					       "rc = [%d]. Dazed and confused, "
4428c2ecf20Sopenharmony_ci					       "but trying to continue.\n",
4438c2ecf20Sopenharmony_ci					       __func__, rc);
4448c2ecf20Sopenharmony_ci			}
4458c2ecf20Sopenharmony_ci		}
4468c2ecf20Sopenharmony_ci		kfree(ecryptfs_daemon_hash);
4478c2ecf20Sopenharmony_ci		mutex_unlock(&ecryptfs_daemon_hash_mux);
4488c2ecf20Sopenharmony_ci	}
4498c2ecf20Sopenharmony_ci	ecryptfs_destroy_ecryptfs_miscdev();
4508c2ecf20Sopenharmony_ci	return;
4518c2ecf20Sopenharmony_ci}
452