⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 messaging.c

📁 linux 内核源代码
💻 C
字号:
/** * eCryptfs: Linux filesystem encryption layer * * Copyright (C) 2004-2006 International Business Machines Corp. *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com> *		Tyler Hicks <tyhicks@ou.edu> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */#include <linux/sched.h>#include "ecryptfs_kernel.h"static LIST_HEAD(ecryptfs_msg_ctx_free_list);static LIST_HEAD(ecryptfs_msg_ctx_alloc_list);static struct mutex ecryptfs_msg_ctx_lists_mux;static struct hlist_head *ecryptfs_daemon_id_hash;static struct mutex ecryptfs_daemon_id_hash_mux;static int ecryptfs_hash_buckets;#define ecryptfs_uid_hash(uid) \        hash_long((unsigned long)uid, ecryptfs_hash_buckets)static unsigned int ecryptfs_msg_counter;static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;/** * ecryptfs_acquire_free_msg_ctx * @msg_ctx: The context that was acquired from the free list * * Acquires a context element from the free list and locks the mutex * on the context.  Returns zero on success; non-zero on error or upon * failure to acquire a free context element.  Be sure to lock the * list mutex before calling. */static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx){	struct list_head *p;	int rc;	if (list_empty(&ecryptfs_msg_ctx_free_list)) {		ecryptfs_printk(KERN_WARNING, "The eCryptfs free "				"context list is empty.  It may be helpful to "				"specify the ecryptfs_message_buf_len "				"parameter to be greater than the current "				"value of [%d]\n", ecryptfs_message_buf_len);		rc = -ENOMEM;		goto out;	}	list_for_each(p, &ecryptfs_msg_ctx_free_list) {		*msg_ctx = list_entry(p, struct ecryptfs_msg_ctx, node);		if (mutex_trylock(&(*msg_ctx)->mux)) {			(*msg_ctx)->task = current;			rc = 0;			goto out;		}	}	rc = -ENOMEM;out:	return rc;}/** * ecryptfs_msg_ctx_free_to_alloc * @msg_ctx: The context to move from the free list to the alloc list * * Be sure to lock the list mutex and the context mutex before * calling. */static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx){	list_move(&msg_ctx->node, &ecryptfs_msg_ctx_alloc_list);	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_PENDING;	msg_ctx->counter = ++ecryptfs_msg_counter;}/** * ecryptfs_msg_ctx_alloc_to_free * @msg_ctx: The context to move from the alloc list to the free list * * Be sure to lock the list mutex and the context mutex before * calling. */static void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx){	list_move(&(msg_ctx->node), &ecryptfs_msg_ctx_free_list);	if (msg_ctx->msg)		kfree(msg_ctx->msg);	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_FREE;}/** * ecryptfs_find_daemon_id * @uid: The user id which maps to the desired daemon id * @id: If return value is zero, points to the desired daemon id *      pointer * * Search the hash list for the given user id.  Returns zero if the * user id exists in the list; non-zero otherwise.  The daemon id hash * mutex should be held before calling this function. */static int ecryptfs_find_daemon_id(uid_t uid, struct ecryptfs_daemon_id **id){	struct hlist_node *elem;	int rc;	hlist_for_each_entry(*id, elem,			     &ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)],			     id_chain) {		if ((*id)->uid == uid) {			rc = 0;			goto out;		}	}	rc = -EINVAL;out:	return rc;}static int ecryptfs_send_raw_message(unsigned int transport, u16 msg_type,				     pid_t pid){	int rc;	switch(transport) {	case ECRYPTFS_TRANSPORT_NETLINK:		rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0, pid);		break;	case ECRYPTFS_TRANSPORT_CONNECTOR:	case ECRYPTFS_TRANSPORT_RELAYFS:	default:		rc = -ENOSYS;	}	return rc;}/** * ecryptfs_process_helo * @transport: The underlying transport (netlink, etc.) * @uid: The user ID owner of the message * @pid: The process ID for the userspace program that sent the *       message * * Adds the uid and pid values to the daemon id hash.  If a uid * already has a daemon pid registered, the daemon will be * unregistered before the new daemon id is put into the hash list. * Returns zero after adding a new daemon id to the hash list; * non-zero otherwise. */int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid){	struct ecryptfs_daemon_id *new_id;	struct ecryptfs_daemon_id *old_id;	int rc;	mutex_lock(&ecryptfs_daemon_id_hash_mux);	new_id = kmalloc(sizeof(*new_id), GFP_KERNEL);	if (!new_id) {		rc = -ENOMEM;		ecryptfs_printk(KERN_ERR, "Failed to allocate memory; unable "				"to register daemon [%d] for user [%d]\n",				pid, uid);		goto unlock;	}	if (!ecryptfs_find_daemon_id(uid, &old_id)) {		printk(KERN_WARNING "Received request from user [%d] "		       "to register daemon [%d]; unregistering daemon "		       "[%d]\n", uid, pid, old_id->pid);		hlist_del(&old_id->id_chain);		rc = ecryptfs_send_raw_message(transport, ECRYPTFS_NLMSG_QUIT,					       old_id->pid);		if (rc)			printk(KERN_WARNING "Failed to send QUIT "			       "message to daemon [%d]; rc = [%d]\n",			       old_id->pid, rc);		kfree(old_id);	}	new_id->uid = uid;	new_id->pid = pid;	hlist_add_head(&new_id->id_chain,		       &ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)]);	rc = 0;unlock:	mutex_unlock(&ecryptfs_daemon_id_hash_mux);	return rc;}/** * ecryptfs_process_quit * @uid: The user ID owner of the message * @pid: The process ID for the userspace program that sent the *       message * * Deletes the corresponding daemon id for the given uid and pid, if * it is the registered that is requesting the deletion. Returns zero * after deleting the desired daemon id; non-zero otherwise. */int ecryptfs_process_quit(uid_t uid, pid_t pid){	struct ecryptfs_daemon_id *id;	int rc;	mutex_lock(&ecryptfs_daemon_id_hash_mux);	if (ecryptfs_find_daemon_id(uid, &id)) {		rc = -EINVAL;		ecryptfs_printk(KERN_ERR, "Received request from user [%d] to "				"unregister unrecognized daemon [%d]\n", uid,				pid);		goto unlock;	}	if (id->pid != pid) {		rc = -EINVAL;		ecryptfs_printk(KERN_WARNING, "Received request from user [%d] "				"with pid [%d] to unregister daemon [%d]\n",				uid, pid, id->pid);		goto unlock;	}	hlist_del(&id->id_chain);	kfree(id);	rc = 0;unlock:	mutex_unlock(&ecryptfs_daemon_id_hash_mux);	return rc;}/** * ecryptfs_process_reponse * @msg: The ecryptfs message received; the caller should sanity check *       msg->data_len * @pid: The process ID of the userspace application that sent the *       message * @seq: The sequence number of the message * * Processes a response message after sending a operation request to * userspace. Returns zero upon delivery to desired context element; * non-zero upon delivery failure or error. */int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid,			      pid_t pid, u32 seq){	struct ecryptfs_daemon_id *id;	struct ecryptfs_msg_ctx *msg_ctx;	int msg_size;	int rc;	if (msg->index >= ecryptfs_message_buf_len) {		rc = -EINVAL;		ecryptfs_printk(KERN_ERR, "Attempt to reference "				"context buffer at index [%d]; maximum "				"allowable is [%d]\n", msg->index,				(ecryptfs_message_buf_len - 1));		goto out;	}	msg_ctx = &ecryptfs_msg_ctx_arr[msg->index];	mutex_lock(&msg_ctx->mux);	if (ecryptfs_find_daemon_id(msg_ctx->task->euid, &id)) {		rc = -EBADMSG;		ecryptfs_printk(KERN_WARNING, "User [%d] received a "				"message response from process [%d] but does "				"not have a registered daemon\n",				msg_ctx->task->euid, pid);		goto wake_up;	}	if (msg_ctx->task->euid != uid) {		rc = -EBADMSG;		ecryptfs_printk(KERN_WARNING, "Received message from user "				"[%d]; expected message from user [%d]\n",				uid, msg_ctx->task->euid);		goto unlock;	}	if (id->pid != pid) {		rc = -EBADMSG;		ecryptfs_printk(KERN_ERR, "User [%d] received a "				"message response from an unrecognized "				"process [%d]\n", msg_ctx->task->euid, pid);		goto unlock;	}	if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {		rc = -EINVAL;		ecryptfs_printk(KERN_WARNING, "Desired context element is not "				"pending a response\n");		goto unlock;	} else if (msg_ctx->counter != seq) {		rc = -EINVAL;		ecryptfs_printk(KERN_WARNING, "Invalid message sequence; "				"expected [%d]; received [%d]\n",				msg_ctx->counter, seq);		goto unlock;	}	msg_size = sizeof(*msg) + msg->data_len;	msg_ctx->msg = kmalloc(msg_size, GFP_KERNEL);	if (!msg_ctx->msg) {		rc = -ENOMEM;		ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");		goto unlock;	}	memcpy(msg_ctx->msg, msg, msg_size);	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE;	rc = 0;wake_up:	wake_up_process(msg_ctx->task);unlock:	mutex_unlock(&msg_ctx->mux);out:	return rc;}/** * ecryptfs_send_message * @transport: The transport over which to send the message (i.e., *             netlink) * @data: The data to send * @data_len: The length of data * @msg_ctx: The message context allocated for the send */int ecryptfs_send_message(unsigned int transport, char *data, int data_len,			  struct ecryptfs_msg_ctx **msg_ctx){	struct ecryptfs_daemon_id *id;	int rc;	mutex_lock(&ecryptfs_daemon_id_hash_mux);	if (ecryptfs_find_daemon_id(current->euid, &id)) {		mutex_unlock(&ecryptfs_daemon_id_hash_mux);		rc = -ENOTCONN;		ecryptfs_printk(KERN_ERR, "User [%d] does not have a daemon "				"registered\n", current->euid);		goto out;	}	mutex_unlock(&ecryptfs_daemon_id_hash_mux);	mutex_lock(&ecryptfs_msg_ctx_lists_mux);	rc = ecryptfs_acquire_free_msg_ctx(msg_ctx);	if (rc) {		mutex_unlock(&ecryptfs_msg_ctx_lists_mux);		ecryptfs_printk(KERN_WARNING, "Could not claim a free "				"context element\n");		goto out;	}	ecryptfs_msg_ctx_free_to_alloc(*msg_ctx);	mutex_unlock(&(*msg_ctx)->mux);	mutex_unlock(&ecryptfs_msg_ctx_lists_mux);	switch (transport) {	case ECRYPTFS_TRANSPORT_NETLINK:		rc = ecryptfs_send_netlink(data, data_len, *msg_ctx,					   ECRYPTFS_NLMSG_REQUEST, 0, id->pid);		break;	case ECRYPTFS_TRANSPORT_CONNECTOR:	case ECRYPTFS_TRANSPORT_RELAYFS:	default:		rc = -ENOSYS;	}	if (rc) {		printk(KERN_ERR "Error attempting to send message to userspace "		       "daemon; rc = [%d]\n", rc);	}out:	return rc;}/** * ecryptfs_wait_for_response * @msg_ctx: The context that was assigned when sending a message * @msg: The incoming message from userspace; not set if rc != 0 * * Sleeps until awaken by ecryptfs_receive_message or until the amount * of time exceeds ecryptfs_message_wait_timeout.  If zero is * returned, msg will point to a valid message from userspace; a * non-zero value is returned upon failure to receive a message or an * error occurs. */int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,			       struct ecryptfs_message **msg){	signed long timeout = ecryptfs_message_wait_timeout * HZ;	int rc = 0;sleep:	timeout = schedule_timeout_interruptible(timeout);	mutex_lock(&ecryptfs_msg_ctx_lists_mux);	mutex_lock(&msg_ctx->mux);	if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_DONE) {		if (timeout) {			mutex_unlock(&msg_ctx->mux);			mutex_unlock(&ecryptfs_msg_ctx_lists_mux);			goto sleep;		}		rc = -ENOMSG;	} else {		*msg = msg_ctx->msg;		msg_ctx->msg = NULL;	}	ecryptfs_msg_ctx_alloc_to_free(msg_ctx);	mutex_unlock(&msg_ctx->mux);	mutex_unlock(&ecryptfs_msg_ctx_lists_mux);	return rc;}int ecryptfs_init_messaging(unsigned int transport){	int i;	int rc = 0;	if (ecryptfs_number_of_users > ECRYPTFS_MAX_NUM_USERS) {		ecryptfs_number_of_users = ECRYPTFS_MAX_NUM_USERS;		ecryptfs_printk(KERN_WARNING, "Specified number of users is "				"too large, defaulting to [%d] users\n",				ecryptfs_number_of_users);	}	mutex_init(&ecryptfs_daemon_id_hash_mux);	mutex_lock(&ecryptfs_daemon_id_hash_mux);	ecryptfs_hash_buckets = 1;	while (ecryptfs_number_of_users >> ecryptfs_hash_buckets)		ecryptfs_hash_buckets++;	ecryptfs_daemon_id_hash = kmalloc(sizeof(struct hlist_head)					  * ecryptfs_hash_buckets, GFP_KERNEL);	if (!ecryptfs_daemon_id_hash) {		rc = -ENOMEM;		ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");		mutex_unlock(&ecryptfs_daemon_id_hash_mux);		goto out;	}	for (i = 0; i < ecryptfs_hash_buckets; i++)		INIT_HLIST_HEAD(&ecryptfs_daemon_id_hash[i]);	mutex_unlock(&ecryptfs_daemon_id_hash_mux);	ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx)				      * ecryptfs_message_buf_len), GFP_KERNEL);	if (!ecryptfs_msg_ctx_arr) {		rc = -ENOMEM;		ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");		goto out;	}	mutex_init(&ecryptfs_msg_ctx_lists_mux);	mutex_lock(&ecryptfs_msg_ctx_lists_mux);	ecryptfs_msg_counter = 0;	for (i = 0; i < ecryptfs_message_buf_len; i++) {		INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].node);		mutex_init(&ecryptfs_msg_ctx_arr[i].mux);		mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);		ecryptfs_msg_ctx_arr[i].index = i;		ecryptfs_msg_ctx_arr[i].state = ECRYPTFS_MSG_CTX_STATE_FREE;		ecryptfs_msg_ctx_arr[i].counter = 0;		ecryptfs_msg_ctx_arr[i].task = NULL;		ecryptfs_msg_ctx_arr[i].msg = NULL;		list_add_tail(&ecryptfs_msg_ctx_arr[i].node,			      &ecryptfs_msg_ctx_free_list);		mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux);	}	mutex_unlock(&ecryptfs_msg_ctx_lists_mux);	switch(transport) {	case ECRYPTFS_TRANSPORT_NETLINK:		rc = ecryptfs_init_netlink();		if (rc)			ecryptfs_release_messaging(transport);		break;	case ECRYPTFS_TRANSPORT_CONNECTOR:	case ECRYPTFS_TRANSPORT_RELAYFS:	default:		rc = -ENOSYS;	}out:	return rc;}void ecryptfs_release_messaging(unsigned int transport){	if (ecryptfs_msg_ctx_arr) {		int i;		mutex_lock(&ecryptfs_msg_ctx_lists_mux);		for (i = 0; i < ecryptfs_message_buf_len; i++) {			mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);			if (ecryptfs_msg_ctx_arr[i].msg)				kfree(ecryptfs_msg_ctx_arr[i].msg);			mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux);		}		kfree(ecryptfs_msg_ctx_arr);		mutex_unlock(&ecryptfs_msg_ctx_lists_mux);	}	if (ecryptfs_daemon_id_hash) {		struct hlist_node *elem;		struct ecryptfs_daemon_id *id;		int i;		mutex_lock(&ecryptfs_daemon_id_hash_mux);		for (i = 0; i < ecryptfs_hash_buckets; i++) {			hlist_for_each_entry(id, elem,					     &ecryptfs_daemon_id_hash[i],					     id_chain) {				hlist_del(elem);				kfree(id);			}		}		kfree(ecryptfs_daemon_id_hash);		mutex_unlock(&ecryptfs_daemon_id_hash_mux);	}	switch(transport) {	case ECRYPTFS_TRANSPORT_NETLINK:		ecryptfs_release_netlink();		break;	case ECRYPTFS_TRANSPORT_CONNECTOR:	case ECRYPTFS_TRANSPORT_RELAYFS:	default:		break;	}	return;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -