xref: /openbmc/linux/fs/ecryptfs/miscdev.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
145051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2*65bbb7b8SLee Jones /*
38bf2debdSMichael Halcrow  * eCryptfs: Linux filesystem encryption layer
48bf2debdSMichael Halcrow  *
58bf2debdSMichael Halcrow  * Copyright (C) 2008 International Business Machines Corp.
68bf2debdSMichael Halcrow  *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
78bf2debdSMichael Halcrow  */
88bf2debdSMichael Halcrow 
98bf2debdSMichael Halcrow #include <linux/fs.h>
108bf2debdSMichael Halcrow #include <linux/hash.h>
118bf2debdSMichael Halcrow #include <linux/random.h>
128bf2debdSMichael Halcrow #include <linux/miscdevice.h>
138bf2debdSMichael Halcrow #include <linux/poll.h>
145a0e3ad6STejun Heo #include <linux/slab.h>
158bf2debdSMichael Halcrow #include <linux/wait.h>
168bf2debdSMichael Halcrow #include <linux/module.h>
178bf2debdSMichael Halcrow #include "ecryptfs_kernel.h"
188bf2debdSMichael Halcrow 
198bf2debdSMichael Halcrow static atomic_t ecryptfs_num_miscdev_opens;
208bf2debdSMichael Halcrow 
218bf2debdSMichael Halcrow /**
228bf2debdSMichael Halcrow  * ecryptfs_miscdev_poll
232ecaf55dSTyler Hicks  * @file: dev file
248bf2debdSMichael Halcrow  * @pt: dev poll table (ignored)
258bf2debdSMichael Halcrow  *
268bf2debdSMichael Halcrow  * Returns the poll mask
278bf2debdSMichael Halcrow  */
28076ccb76SAl Viro static __poll_t
ecryptfs_miscdev_poll(struct file * file,poll_table * pt)298bf2debdSMichael Halcrow ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
308bf2debdSMichael Halcrow {
312ecaf55dSTyler Hicks 	struct ecryptfs_daemon *daemon = file->private_data;
32076ccb76SAl Viro 	__poll_t mask = 0;
338bf2debdSMichael Halcrow 
348bf2debdSMichael Halcrow 	mutex_lock(&daemon->mux);
358bf2debdSMichael Halcrow 	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
368bf2debdSMichael Halcrow 		printk(KERN_WARNING "%s: Attempt to poll on zombified "
378bf2debdSMichael Halcrow 		       "daemon\n", __func__);
388bf2debdSMichael Halcrow 		goto out_unlock_daemon;
398bf2debdSMichael Halcrow 	}
408bf2debdSMichael Halcrow 	if (daemon->flags & ECRYPTFS_DAEMON_IN_READ)
418bf2debdSMichael Halcrow 		goto out_unlock_daemon;
428bf2debdSMichael Halcrow 	if (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)
438bf2debdSMichael Halcrow 		goto out_unlock_daemon;
448bf2debdSMichael Halcrow 	daemon->flags |= ECRYPTFS_DAEMON_IN_POLL;
458bf2debdSMichael Halcrow 	mutex_unlock(&daemon->mux);
468bf2debdSMichael Halcrow 	poll_wait(file, &daemon->wait, pt);
478bf2debdSMichael Halcrow 	mutex_lock(&daemon->mux);
488bf2debdSMichael Halcrow 	if (!list_empty(&daemon->msg_ctx_out_queue))
49a9a08845SLinus Torvalds 		mask |= EPOLLIN | EPOLLRDNORM;
508bf2debdSMichael Halcrow out_unlock_daemon:
518bf2debdSMichael Halcrow 	daemon->flags &= ~ECRYPTFS_DAEMON_IN_POLL;
528bf2debdSMichael Halcrow 	mutex_unlock(&daemon->mux);
538bf2debdSMichael Halcrow 	return mask;
548bf2debdSMichael Halcrow }
558bf2debdSMichael Halcrow 
568bf2debdSMichael Halcrow /**
578bf2debdSMichael Halcrow  * ecryptfs_miscdev_open
588bf2debdSMichael Halcrow  * @inode: inode of miscdev handle (ignored)
592ecaf55dSTyler Hicks  * @file: file for miscdev handle
608bf2debdSMichael Halcrow  *
618bf2debdSMichael Halcrow  * Returns zero on success; non-zero otherwise
628bf2debdSMichael Halcrow  */
638bf2debdSMichael Halcrow static int
ecryptfs_miscdev_open(struct inode * inode,struct file * file)648bf2debdSMichael Halcrow ecryptfs_miscdev_open(struct inode *inode, struct file *file)
658bf2debdSMichael Halcrow {
668bf2debdSMichael Halcrow 	struct ecryptfs_daemon *daemon = NULL;
678bf2debdSMichael Halcrow 	int rc;
688bf2debdSMichael Halcrow 
698bf2debdSMichael Halcrow 	mutex_lock(&ecryptfs_daemon_hash_mux);
702ecaf55dSTyler Hicks 	rc = ecryptfs_find_daemon_by_euid(&daemon);
712ecaf55dSTyler Hicks 	if (!rc) {
722ecaf55dSTyler Hicks 		rc = -EINVAL;
732ecaf55dSTyler Hicks 		goto out_unlock_daemon_list;
742ecaf55dSTyler Hicks 	}
752ecaf55dSTyler Hicks 	rc = ecryptfs_spawn_daemon(&daemon, file);
768bf2debdSMichael Halcrow 	if (rc) {
778bf2debdSMichael Halcrow 		printk(KERN_ERR "%s: Error attempting to spawn daemon; "
788bf2debdSMichael Halcrow 		       "rc = [%d]\n", __func__, rc);
7952f21999SAl Viro 		goto out_unlock_daemon_list;
808bf2debdSMichael Halcrow 	}
818bf2debdSMichael Halcrow 	mutex_lock(&daemon->mux);
828bf2debdSMichael Halcrow 	if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
838bf2debdSMichael Halcrow 		rc = -EBUSY;
848bf2debdSMichael Halcrow 		goto out_unlock_daemon;
858bf2debdSMichael Halcrow 	}
868bf2debdSMichael Halcrow 	daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
878dc67805STyler Hicks 	file->private_data = daemon;
888bf2debdSMichael Halcrow 	atomic_inc(&ecryptfs_num_miscdev_opens);
898bf2debdSMichael Halcrow out_unlock_daemon:
908bf2debdSMichael Halcrow 	mutex_unlock(&daemon->mux);
918bf2debdSMichael Halcrow out_unlock_daemon_list:
928bf2debdSMichael Halcrow 	mutex_unlock(&ecryptfs_daemon_hash_mux);
938bf2debdSMichael Halcrow 	return rc;
948bf2debdSMichael Halcrow }
958bf2debdSMichael Halcrow 
968bf2debdSMichael Halcrow /**
978bf2debdSMichael Halcrow  * ecryptfs_miscdev_release
988bf2debdSMichael Halcrow  * @inode: inode of fs/ecryptfs/euid handle (ignored)
992ecaf55dSTyler Hicks  * @file: file for fs/ecryptfs/euid handle
1008bf2debdSMichael Halcrow  *
1018bf2debdSMichael Halcrow  * This keeps the daemon registered until the daemon sends another
1028bf2debdSMichael Halcrow  * ioctl to fs/ecryptfs/ctl or until the kernel module unregisters.
1038bf2debdSMichael Halcrow  *
1048bf2debdSMichael Halcrow  * Returns zero on success; non-zero otherwise
1058bf2debdSMichael Halcrow  */
1068bf2debdSMichael Halcrow static int
ecryptfs_miscdev_release(struct inode * inode,struct file * file)1078bf2debdSMichael Halcrow ecryptfs_miscdev_release(struct inode *inode, struct file *file)
1088bf2debdSMichael Halcrow {
1092ecaf55dSTyler Hicks 	struct ecryptfs_daemon *daemon = file->private_data;
1108bf2debdSMichael Halcrow 	int rc;
1118bf2debdSMichael Halcrow 
1128bf2debdSMichael Halcrow 	mutex_lock(&daemon->mux);
1138bf2debdSMichael Halcrow 	BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
1148bf2debdSMichael Halcrow 	daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
1158bf2debdSMichael Halcrow 	atomic_dec(&ecryptfs_num_miscdev_opens);
1168bf2debdSMichael Halcrow 	mutex_unlock(&daemon->mux);
1172ecaf55dSTyler Hicks 
1182ecaf55dSTyler Hicks 	mutex_lock(&ecryptfs_daemon_hash_mux);
1198bf2debdSMichael Halcrow 	rc = ecryptfs_exorcise_daemon(daemon);
1202ecaf55dSTyler Hicks 	mutex_unlock(&ecryptfs_daemon_hash_mux);
1218bf2debdSMichael Halcrow 	if (rc) {
1228bf2debdSMichael Halcrow 		printk(KERN_CRIT "%s: Fatal error whilst attempting to "
1238bf2debdSMichael Halcrow 		       "shut down daemon; rc = [%d]. Please report this "
1248bf2debdSMichael Halcrow 		       "bug.\n", __func__, rc);
1258bf2debdSMichael Halcrow 		BUG();
1268bf2debdSMichael Halcrow 	}
1278bf2debdSMichael Halcrow 	return rc;
1288bf2debdSMichael Halcrow }
1298bf2debdSMichael Halcrow 
1308bf2debdSMichael Halcrow /**
1318bf2debdSMichael Halcrow  * ecryptfs_send_miscdev
1328bf2debdSMichael Halcrow  * @data: Data to send to daemon; may be NULL
1338bf2debdSMichael Halcrow  * @data_size: Amount of data to send to daemon
1348bf2debdSMichael Halcrow  * @msg_ctx: Message context, which is used to handle the reply. If
1358bf2debdSMichael Halcrow  *           this is NULL, then we do not expect a reply.
1368bf2debdSMichael Halcrow  * @msg_type: Type of message
1378bf2debdSMichael Halcrow  * @msg_flags: Flags for message
1388bf2debdSMichael Halcrow  * @daemon: eCryptfs daemon object
1398bf2debdSMichael Halcrow  *
1408bf2debdSMichael Halcrow  * Add msg_ctx to queue and then, if it exists, notify the blocked
1418bf2debdSMichael Halcrow  * miscdevess about the data being available. Must be called with
1428bf2debdSMichael Halcrow  * ecryptfs_daemon_hash_mux held.
1438bf2debdSMichael Halcrow  *
1448bf2debdSMichael Halcrow  * Returns zero on success; non-zero otherwise
1458bf2debdSMichael Halcrow  */
ecryptfs_send_miscdev(char * data,size_t data_size,struct ecryptfs_msg_ctx * msg_ctx,u8 msg_type,u16 msg_flags,struct ecryptfs_daemon * daemon)1468bf2debdSMichael Halcrow int ecryptfs_send_miscdev(char *data, size_t data_size,
1478bf2debdSMichael Halcrow 			  struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
1488bf2debdSMichael Halcrow 			  u16 msg_flags, struct ecryptfs_daemon *daemon)
1498bf2debdSMichael Halcrow {
15060d65f1fSTyler Hicks 	struct ecryptfs_message *msg;
1518bf2debdSMichael Halcrow 
15260d65f1fSTyler Hicks 	msg = kmalloc((sizeof(*msg) + data_size), GFP_KERNEL);
1531a0bba4fSMarkus Elfring 	if (!msg)
15460d65f1fSTyler Hicks 		return -ENOMEM;
15560d65f1fSTyler Hicks 
15660d65f1fSTyler Hicks 	mutex_lock(&msg_ctx->mux);
15760d65f1fSTyler Hicks 	msg_ctx->msg = msg;
1588bf2debdSMichael Halcrow 	msg_ctx->msg->index = msg_ctx->index;
1598bf2debdSMichael Halcrow 	msg_ctx->msg->data_len = data_size;
1608bf2debdSMichael Halcrow 	msg_ctx->type = msg_type;
1618bf2debdSMichael Halcrow 	memcpy(msg_ctx->msg->data, data, data_size);
1628bf2debdSMichael Halcrow 	msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);
1638bf2debdSMichael Halcrow 	list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue);
16460d65f1fSTyler Hicks 	mutex_unlock(&msg_ctx->mux);
16560d65f1fSTyler Hicks 
16660d65f1fSTyler Hicks 	mutex_lock(&daemon->mux);
1678bf2debdSMichael Halcrow 	daemon->num_queued_msg_ctx++;
1688bf2debdSMichael Halcrow 	wake_up_interruptible(&daemon->wait);
1698bf2debdSMichael Halcrow 	mutex_unlock(&daemon->mux);
17060d65f1fSTyler Hicks 
17160d65f1fSTyler Hicks 	return 0;
1728bf2debdSMichael Halcrow }
1738bf2debdSMichael Halcrow 
17448399c0bSTyler Hicks /*
17548399c0bSTyler Hicks  * miscdevfs packet format:
17648399c0bSTyler Hicks  *  Octet 0: Type
17748399c0bSTyler Hicks  *  Octets 1-4: network byte order msg_ctx->counter
17848399c0bSTyler Hicks  *  Octets 5-N0: Size of struct ecryptfs_message to follow
17948399c0bSTyler Hicks  *  Octets N0-N1: struct ecryptfs_message (including data)
18048399c0bSTyler Hicks  *
18148399c0bSTyler Hicks  *  Octets 5-N1 not written if the packet type does not include a message
18248399c0bSTyler Hicks  */
18348399c0bSTyler Hicks #define PKT_TYPE_SIZE		1
18448399c0bSTyler Hicks #define PKT_CTR_SIZE		4
18548399c0bSTyler Hicks #define MIN_NON_MSG_PKT_SIZE	(PKT_TYPE_SIZE + PKT_CTR_SIZE)
18648399c0bSTyler Hicks #define MIN_MSG_PKT_SIZE	(PKT_TYPE_SIZE + PKT_CTR_SIZE \
18748399c0bSTyler Hicks 				 + ECRYPTFS_MIN_PKT_LEN_SIZE)
18848399c0bSTyler Hicks /* 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES comes from tag 65 packet format */
18948399c0bSTyler Hicks #define MAX_MSG_PKT_SIZE	(PKT_TYPE_SIZE + PKT_CTR_SIZE \
19048399c0bSTyler Hicks 				 + ECRYPTFS_MAX_PKT_LEN_SIZE \
19148399c0bSTyler Hicks 				 + sizeof(struct ecryptfs_message) \
19248399c0bSTyler Hicks 				 + 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES)
19348399c0bSTyler Hicks #define PKT_TYPE_OFFSET		0
19448399c0bSTyler Hicks #define PKT_CTR_OFFSET		PKT_TYPE_SIZE
19548399c0bSTyler Hicks #define PKT_LEN_OFFSET		(PKT_TYPE_SIZE + PKT_CTR_SIZE)
19648399c0bSTyler Hicks 
1978bf2debdSMichael Halcrow /**
1988bf2debdSMichael Halcrow  * ecryptfs_miscdev_read - format and send message from queue
1992ecaf55dSTyler Hicks  * @file: miscdevfs handle
2008bf2debdSMichael Halcrow  * @buf: User buffer into which to copy the next message on the daemon queue
2018bf2debdSMichael Halcrow  * @count: Amount of space available in @buf
2028bf2debdSMichael Halcrow  * @ppos: Offset in file (ignored)
2038bf2debdSMichael Halcrow  *
2048bf2debdSMichael Halcrow  * Pulls the most recent message from the daemon queue, formats it for
2058bf2debdSMichael Halcrow  * being sent via a miscdevfs handle, and copies it into @buf
2068bf2debdSMichael Halcrow  *
2078bf2debdSMichael Halcrow  * Returns the number of bytes copied into the user buffer
2088bf2debdSMichael Halcrow  */
209f66e883eSMichael Halcrow static ssize_t
ecryptfs_miscdev_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)2108bf2debdSMichael Halcrow ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
2118bf2debdSMichael Halcrow 		      loff_t *ppos)
2128bf2debdSMichael Halcrow {
2132ecaf55dSTyler Hicks 	struct ecryptfs_daemon *daemon = file->private_data;
2148bf2debdSMichael Halcrow 	struct ecryptfs_msg_ctx *msg_ctx;
2158bf2debdSMichael Halcrow 	size_t packet_length_size;
21648399c0bSTyler Hicks 	char packet_length[ECRYPTFS_MAX_PKT_LEN_SIZE];
2178bf2debdSMichael Halcrow 	size_t i;
2188bf2debdSMichael Halcrow 	size_t total_length;
2198bf2debdSMichael Halcrow 	int rc;
2208bf2debdSMichael Halcrow 
2218bf2debdSMichael Halcrow 	mutex_lock(&daemon->mux);
2228bf2debdSMichael Halcrow 	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
2238bf2debdSMichael Halcrow 		rc = 0;
2248bf2debdSMichael Halcrow 		printk(KERN_WARNING "%s: Attempt to read from zombified "
2258bf2debdSMichael Halcrow 		       "daemon\n", __func__);
2268bf2debdSMichael Halcrow 		goto out_unlock_daemon;
2278bf2debdSMichael Halcrow 	}
2288bf2debdSMichael Halcrow 	if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) {
2298bf2debdSMichael Halcrow 		rc = 0;
2308bf2debdSMichael Halcrow 		goto out_unlock_daemon;
2318bf2debdSMichael Halcrow 	}
2328bf2debdSMichael Halcrow 	/* This daemon will not go away so long as this flag is set */
2338bf2debdSMichael Halcrow 	daemon->flags |= ECRYPTFS_DAEMON_IN_READ;
2348bf2debdSMichael Halcrow check_list:
2358bf2debdSMichael Halcrow 	if (list_empty(&daemon->msg_ctx_out_queue)) {
2368bf2debdSMichael Halcrow 		mutex_unlock(&daemon->mux);
2378bf2debdSMichael Halcrow 		rc = wait_event_interruptible(
2388bf2debdSMichael Halcrow 			daemon->wait, !list_empty(&daemon->msg_ctx_out_queue));
2398bf2debdSMichael Halcrow 		mutex_lock(&daemon->mux);
2408bf2debdSMichael Halcrow 		if (rc < 0) {
2418bf2debdSMichael Halcrow 			rc = 0;
2428bf2debdSMichael Halcrow 			goto out_unlock_daemon;
2438bf2debdSMichael Halcrow 		}
2448bf2debdSMichael Halcrow 	}
2458bf2debdSMichael Halcrow 	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
2468bf2debdSMichael Halcrow 		rc = 0;
2478bf2debdSMichael Halcrow 		goto out_unlock_daemon;
2488bf2debdSMichael Halcrow 	}
2498bf2debdSMichael Halcrow 	if (list_empty(&daemon->msg_ctx_out_queue)) {
2508bf2debdSMichael Halcrow 		/* Something else jumped in since the
2518bf2debdSMichael Halcrow 		 * wait_event_interruptable() and removed the
2528bf2debdSMichael Halcrow 		 * message from the queue; try again */
2538bf2debdSMichael Halcrow 		goto check_list;
2548bf2debdSMichael Halcrow 	}
2558bf2debdSMichael Halcrow 	msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
2568bf2debdSMichael Halcrow 				   struct ecryptfs_msg_ctx, daemon_out_list);
2578bf2debdSMichael Halcrow 	BUG_ON(!msg_ctx);
2588bf2debdSMichael Halcrow 	mutex_lock(&msg_ctx->mux);
2598bf2debdSMichael Halcrow 	if (msg_ctx->msg) {
2608bf2debdSMichael Halcrow 		rc = ecryptfs_write_packet_length(packet_length,
2618bf2debdSMichael Halcrow 						  msg_ctx->msg_size,
2628bf2debdSMichael Halcrow 						  &packet_length_size);
2638bf2debdSMichael Halcrow 		if (rc) {
2648bf2debdSMichael Halcrow 			rc = 0;
2658bf2debdSMichael Halcrow 			printk(KERN_WARNING "%s: Error writing packet length; "
2668bf2debdSMichael Halcrow 			       "rc = [%d]\n", __func__, rc);
2678bf2debdSMichael Halcrow 			goto out_unlock_msg_ctx;
2688bf2debdSMichael Halcrow 		}
2698bf2debdSMichael Halcrow 	} else {
2708bf2debdSMichael Halcrow 		packet_length_size = 0;
2718bf2debdSMichael Halcrow 		msg_ctx->msg_size = 0;
2728bf2debdSMichael Halcrow 	}
27348399c0bSTyler Hicks 	total_length = (PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_length_size
27448399c0bSTyler Hicks 			+ msg_ctx->msg_size);
2758bf2debdSMichael Halcrow 	if (count < total_length) {
2768bf2debdSMichael Halcrow 		rc = 0;
2778bf2debdSMichael Halcrow 		printk(KERN_WARNING "%s: Only given user buffer of "
278df261c52SMichael Halcrow 		       "size [%zd], but we need [%zd] to read the "
2798bf2debdSMichael Halcrow 		       "pending message\n", __func__, count, total_length);
2808bf2debdSMichael Halcrow 		goto out_unlock_msg_ctx;
2818bf2debdSMichael Halcrow 	}
28279bc12a0SAl Viro 	rc = -EFAULT;
28379bc12a0SAl Viro 	if (put_user(msg_ctx->type, buf))
2848bf2debdSMichael Halcrow 		goto out_unlock_msg_ctx;
28548399c0bSTyler Hicks 	if (put_user(cpu_to_be32(msg_ctx->counter),
28648399c0bSTyler Hicks 		     (__be32 __user *)(&buf[PKT_CTR_OFFSET])))
28779bc12a0SAl Viro 		goto out_unlock_msg_ctx;
28848399c0bSTyler Hicks 	i = PKT_TYPE_SIZE + PKT_CTR_SIZE;
28979bc12a0SAl Viro 	if (msg_ctx->msg) {
29079bc12a0SAl Viro 		if (copy_to_user(&buf[i], packet_length, packet_length_size))
29179bc12a0SAl Viro 			goto out_unlock_msg_ctx;
29279bc12a0SAl Viro 		i += packet_length_size;
29379bc12a0SAl Viro 		if (copy_to_user(&buf[i], msg_ctx->msg, msg_ctx->msg_size))
29479bc12a0SAl Viro 			goto out_unlock_msg_ctx;
2958bf2debdSMichael Halcrow 		i += msg_ctx->msg_size;
2968bf2debdSMichael Halcrow 	}
2978bf2debdSMichael Halcrow 	rc = i;
2988bf2debdSMichael Halcrow 	list_del(&msg_ctx->daemon_out_list);
2998bf2debdSMichael Halcrow 	kfree(msg_ctx->msg);
3008bf2debdSMichael Halcrow 	msg_ctx->msg = NULL;
3018bf2debdSMichael Halcrow 	/* We do not expect a reply from the userspace daemon for any
3028bf2debdSMichael Halcrow 	 * message type other than ECRYPTFS_MSG_REQUEST */
3038bf2debdSMichael Halcrow 	if (msg_ctx->type != ECRYPTFS_MSG_REQUEST)
3048bf2debdSMichael Halcrow 		ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
3058bf2debdSMichael Halcrow out_unlock_msg_ctx:
3068bf2debdSMichael Halcrow 	mutex_unlock(&msg_ctx->mux);
3078bf2debdSMichael Halcrow out_unlock_daemon:
3088bf2debdSMichael Halcrow 	daemon->flags &= ~ECRYPTFS_DAEMON_IN_READ;
3098bf2debdSMichael Halcrow 	mutex_unlock(&daemon->mux);
3108bf2debdSMichael Halcrow 	return rc;
3118bf2debdSMichael Halcrow }
3128bf2debdSMichael Halcrow 
3138bf2debdSMichael Halcrow /**
3148bf2debdSMichael Halcrow  * ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon
315*65bbb7b8SLee Jones  * @daemon: eCryptfs daemon object
3168bf2debdSMichael Halcrow  * @data: Bytes comprising struct ecryptfs_message
3178bf2debdSMichael Halcrow  * @data_size: sizeof(struct ecryptfs_message) + data len
3188bf2debdSMichael Halcrow  * @seq: Sequence number for miscdev response packet
3198bf2debdSMichael Halcrow  *
3208bf2debdSMichael Halcrow  * Returns zero on success; non-zero otherwise
3218bf2debdSMichael Halcrow  */
ecryptfs_miscdev_response(struct ecryptfs_daemon * daemon,char * data,size_t data_size,u32 seq)3222ecaf55dSTyler Hicks static int ecryptfs_miscdev_response(struct ecryptfs_daemon *daemon, char *data,
3232ecaf55dSTyler Hicks 				     size_t data_size, u32 seq)
3248bf2debdSMichael Halcrow {
3258bf2debdSMichael Halcrow 	struct ecryptfs_message *msg = (struct ecryptfs_message *)data;
3268bf2debdSMichael Halcrow 	int rc;
3278bf2debdSMichael Halcrow 
3288bf2debdSMichael Halcrow 	if ((sizeof(*msg) + msg->data_len) != data_size) {
3298bf2debdSMichael Halcrow 		printk(KERN_WARNING "%s: (sizeof(*msg) + msg->data_len) = "
330df261c52SMichael Halcrow 		       "[%zd]; data_size = [%zd]. Invalid packet.\n", __func__,
3318bf2debdSMichael Halcrow 		       (sizeof(*msg) + msg->data_len), data_size);
3328bf2debdSMichael Halcrow 		rc = -EINVAL;
3338bf2debdSMichael Halcrow 		goto out;
3348bf2debdSMichael Halcrow 	}
3352ecaf55dSTyler Hicks 	rc = ecryptfs_process_response(daemon, msg, seq);
3368bf2debdSMichael Halcrow 	if (rc)
3378bf2debdSMichael Halcrow 		printk(KERN_ERR
3388bf2debdSMichael Halcrow 		       "Error processing response message; rc = [%d]\n", rc);
3398bf2debdSMichael Halcrow out:
3408bf2debdSMichael Halcrow 	return rc;
3418bf2debdSMichael Halcrow }
3428bf2debdSMichael Halcrow 
3438bf2debdSMichael Halcrow /**
3448bf2debdSMichael Halcrow  * ecryptfs_miscdev_write - handle write to daemon miscdev handle
3452ecaf55dSTyler Hicks  * @file: File for misc dev handle
3468bf2debdSMichael Halcrow  * @buf: Buffer containing user data
3478bf2debdSMichael Halcrow  * @count: Amount of data in @buf
3488bf2debdSMichael Halcrow  * @ppos: Pointer to offset in file (ignored)
3498bf2debdSMichael Halcrow  *
3508bf2debdSMichael Halcrow  * Returns the number of bytes read from @buf
3518bf2debdSMichael Halcrow  */
3528bf2debdSMichael Halcrow static ssize_t
ecryptfs_miscdev_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)3538bf2debdSMichael Halcrow ecryptfs_miscdev_write(struct file *file, const char __user *buf,
3548bf2debdSMichael Halcrow 		       size_t count, loff_t *ppos)
3558bf2debdSMichael Halcrow {
35679bc12a0SAl Viro 	__be32 counter_nbo;
35779bc12a0SAl Viro 	u32 seq;
35848399c0bSTyler Hicks 	size_t packet_size, packet_size_length;
3598bf2debdSMichael Halcrow 	char *data;
36048399c0bSTyler Hicks 	unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE];
3617f133504STyler Hicks 	ssize_t rc;
3628bf2debdSMichael Halcrow 
363db10e556STyler Hicks 	if (count == 0) {
3647f133504STyler Hicks 		return 0;
36548399c0bSTyler Hicks 	} else if (count == MIN_NON_MSG_PKT_SIZE) {
366db10e556STyler Hicks 		/* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */
367db10e556STyler Hicks 		goto memdup;
36848399c0bSTyler Hicks 	} else if (count < MIN_MSG_PKT_SIZE || count > MAX_MSG_PKT_SIZE) {
369db10e556STyler Hicks 		printk(KERN_WARNING "%s: Acceptable packet size range is "
3700996b67dSColin Ian King 		       "[%d-%zu], but amount of data written is [%zu].\n",
37148399c0bSTyler Hicks 		       __func__, MIN_MSG_PKT_SIZE, MAX_MSG_PKT_SIZE, count);
372db10e556STyler Hicks 		return -EINVAL;
373db10e556STyler Hicks 	}
374fd56d242SLi Zefan 
37548399c0bSTyler Hicks 	if (copy_from_user(packet_size_peek, &buf[PKT_LEN_OFFSET],
376db10e556STyler Hicks 			   sizeof(packet_size_peek))) {
377db10e556STyler Hicks 		printk(KERN_WARNING "%s: Error while inspecting packet size\n",
378db10e556STyler Hicks 		       __func__);
379db10e556STyler Hicks 		return -EFAULT;
380db10e556STyler Hicks 	}
381db10e556STyler Hicks 
382db10e556STyler Hicks 	rc = ecryptfs_parse_packet_length(packet_size_peek, &packet_size,
383db10e556STyler Hicks 					  &packet_size_length);
384db10e556STyler Hicks 	if (rc) {
385db10e556STyler Hicks 		printk(KERN_WARNING "%s: Error parsing packet length; "
3867f133504STyler Hicks 		       "rc = [%zd]\n", __func__, rc);
387db10e556STyler Hicks 		return rc;
388db10e556STyler Hicks 	}
389db10e556STyler Hicks 
39048399c0bSTyler Hicks 	if ((PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_size_length + packet_size)
39148399c0bSTyler Hicks 	    != count) {
392db10e556STyler Hicks 		printk(KERN_WARNING "%s: Invalid packet size [%zu]\n", __func__,
393db10e556STyler Hicks 		       packet_size);
394db10e556STyler Hicks 		return -EINVAL;
395db10e556STyler Hicks 	}
396db10e556STyler Hicks 
397db10e556STyler Hicks memdup:
398fd56d242SLi Zefan 	data = memdup_user(buf, count);
399fd56d242SLi Zefan 	if (IS_ERR(data)) {
400fd56d242SLi Zefan 		printk(KERN_ERR "%s: memdup_user returned error [%ld]\n",
401fd56d242SLi Zefan 		       __func__, PTR_ERR(data));
4027f133504STyler Hicks 		return PTR_ERR(data);
4038bf2debdSMichael Halcrow 	}
40448399c0bSTyler Hicks 	switch (data[PKT_TYPE_OFFSET]) {
4058bf2debdSMichael Halcrow 	case ECRYPTFS_MSG_RESPONSE:
40648399c0bSTyler Hicks 		if (count < (MIN_MSG_PKT_SIZE
40748399c0bSTyler Hicks 			     + sizeof(struct ecryptfs_message))) {
4088bf2debdSMichael Halcrow 			printk(KERN_WARNING "%s: Minimum acceptable packet "
409df261c52SMichael Halcrow 			       "size is [%zd], but amount of data written is "
410df261c52SMichael Halcrow 			       "only [%zd]. Discarding response packet.\n",
4118bf2debdSMichael Halcrow 			       __func__,
41248399c0bSTyler Hicks 			       (MIN_MSG_PKT_SIZE
41348399c0bSTyler Hicks 				+ sizeof(struct ecryptfs_message)), count);
4147f133504STyler Hicks 			rc = -EINVAL;
4158bf2debdSMichael Halcrow 			goto out_free;
4168bf2debdSMichael Halcrow 		}
41748399c0bSTyler Hicks 		memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE);
4188bf2debdSMichael Halcrow 		seq = be32_to_cpu(counter_nbo);
4192ecaf55dSTyler Hicks 		rc = ecryptfs_miscdev_response(file->private_data,
42048399c0bSTyler Hicks 				&data[PKT_LEN_OFFSET + packet_size_length],
4212ecaf55dSTyler Hicks 				packet_size, seq);
4227f133504STyler Hicks 		if (rc) {
4238bf2debdSMichael Halcrow 			printk(KERN_WARNING "%s: Failed to deliver miscdev "
4247f133504STyler Hicks 			       "response to requesting operation; rc = [%zd]\n",
4258bf2debdSMichael Halcrow 			       __func__, rc);
4267f133504STyler Hicks 			goto out_free;
4277f133504STyler Hicks 		}
4288bf2debdSMichael Halcrow 		break;
4298bf2debdSMichael Halcrow 	case ECRYPTFS_MSG_HELO:
4308bf2debdSMichael Halcrow 	case ECRYPTFS_MSG_QUIT:
4318bf2debdSMichael Halcrow 		break;
4328bf2debdSMichael Halcrow 	default:
4338bf2debdSMichael Halcrow 		ecryptfs_printk(KERN_WARNING, "Dropping miscdev "
4348bf2debdSMichael Halcrow 				"message of unrecognized type [%d]\n",
4358bf2debdSMichael Halcrow 				data[0]);
4367f133504STyler Hicks 		rc = -EINVAL;
4377f133504STyler Hicks 		goto out_free;
4388bf2debdSMichael Halcrow 	}
4397f133504STyler Hicks 	rc = count;
4408bf2debdSMichael Halcrow out_free:
4418bf2debdSMichael Halcrow 	kfree(data);
4427f133504STyler Hicks 	return rc;
4438bf2debdSMichael Halcrow }
4448bf2debdSMichael Halcrow 
4458bf2debdSMichael Halcrow 
4468bf2debdSMichael Halcrow static const struct file_operations ecryptfs_miscdev_fops = {
44752f21999SAl Viro 	.owner   = THIS_MODULE,
4488bf2debdSMichael Halcrow 	.open    = ecryptfs_miscdev_open,
4498bf2debdSMichael Halcrow 	.poll    = ecryptfs_miscdev_poll,
4508bf2debdSMichael Halcrow 	.read    = ecryptfs_miscdev_read,
4518bf2debdSMichael Halcrow 	.write   = ecryptfs_miscdev_write,
4528bf2debdSMichael Halcrow 	.release = ecryptfs_miscdev_release,
4536038f373SArnd Bergmann 	.llseek  = noop_llseek,
4548bf2debdSMichael Halcrow };
4558bf2debdSMichael Halcrow 
4568bf2debdSMichael Halcrow static struct miscdevice ecryptfs_miscdev = {
4578bf2debdSMichael Halcrow 	.minor = MISC_DYNAMIC_MINOR,
4588bf2debdSMichael Halcrow 	.name  = "ecryptfs",
4598bf2debdSMichael Halcrow 	.fops  = &ecryptfs_miscdev_fops
4608bf2debdSMichael Halcrow };
4618bf2debdSMichael Halcrow 
4628bf2debdSMichael Halcrow /**
4638bf2debdSMichael Halcrow  * ecryptfs_init_ecryptfs_miscdev
4648bf2debdSMichael Halcrow  *
4658bf2debdSMichael Halcrow  * Messages sent to the userspace daemon from the kernel are placed on
4668bf2debdSMichael Halcrow  * a queue associated with the daemon. The next read against the
4678bf2debdSMichael Halcrow  * miscdev handle by that daemon will return the oldest message placed
4688bf2debdSMichael Halcrow  * on the message queue for the daemon.
4698bf2debdSMichael Halcrow  *
4708bf2debdSMichael Halcrow  * Returns zero on success; non-zero otherwise
4718bf2debdSMichael Halcrow  */
ecryptfs_init_ecryptfs_miscdev(void)4727371a382SJerome Marchand int __init ecryptfs_init_ecryptfs_miscdev(void)
4738bf2debdSMichael Halcrow {
4748bf2debdSMichael Halcrow 	int rc;
4758bf2debdSMichael Halcrow 
4768bf2debdSMichael Halcrow 	atomic_set(&ecryptfs_num_miscdev_opens, 0);
4778bf2debdSMichael Halcrow 	rc = misc_register(&ecryptfs_miscdev);
4788bf2debdSMichael Halcrow 	if (rc)
4798bf2debdSMichael Halcrow 		printk(KERN_ERR "%s: Failed to register miscellaneous device "
4808bf2debdSMichael Halcrow 		       "for communications with userspace daemons; rc = [%d]\n",
4818bf2debdSMichael Halcrow 		       __func__, rc);
4828bf2debdSMichael Halcrow 	return rc;
4838bf2debdSMichael Halcrow }
4848bf2debdSMichael Halcrow 
4858bf2debdSMichael Halcrow /**
4868bf2debdSMichael Halcrow  * ecryptfs_destroy_ecryptfs_miscdev
4878bf2debdSMichael Halcrow  *
4888bf2debdSMichael Halcrow  * All of the daemons must be exorcised prior to calling this
4898bf2debdSMichael Halcrow  * function.
4908bf2debdSMichael Halcrow  */
ecryptfs_destroy_ecryptfs_miscdev(void)4918bf2debdSMichael Halcrow void ecryptfs_destroy_ecryptfs_miscdev(void)
4928bf2debdSMichael Halcrow {
4938bf2debdSMichael Halcrow 	BUG_ON(atomic_read(&ecryptfs_num_miscdev_opens) != 0);
4948bf2debdSMichael Halcrow 	misc_deregister(&ecryptfs_miscdev);
4958bf2debdSMichael Halcrow }
496