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