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