xref: /OK3568_Linux_fs/kernel/fs/ecryptfs/miscdev.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /**
3*4882a593Smuzhiyun  * eCryptfs: Linux filesystem encryption layer
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2008 International Business Machines Corp.
6*4882a593Smuzhiyun  *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/fs.h>
10*4882a593Smuzhiyun #include <linux/hash.h>
11*4882a593Smuzhiyun #include <linux/random.h>
12*4882a593Smuzhiyun #include <linux/miscdevice.h>
13*4882a593Smuzhiyun #include <linux/poll.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun #include <linux/wait.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include "ecryptfs_kernel.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun static atomic_t ecryptfs_num_miscdev_opens;
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /**
22*4882a593Smuzhiyun  * ecryptfs_miscdev_poll
23*4882a593Smuzhiyun  * @file: dev file
24*4882a593Smuzhiyun  * @pt: dev poll table (ignored)
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  * Returns the poll mask
27*4882a593Smuzhiyun  */
28*4882a593Smuzhiyun static __poll_t
ecryptfs_miscdev_poll(struct file * file,poll_table * pt)29*4882a593Smuzhiyun ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	struct ecryptfs_daemon *daemon = file->private_data;
32*4882a593Smuzhiyun 	__poll_t mask = 0;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	mutex_lock(&daemon->mux);
35*4882a593Smuzhiyun 	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
36*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: Attempt to poll on zombified "
37*4882a593Smuzhiyun 		       "daemon\n", __func__);
38*4882a593Smuzhiyun 		goto out_unlock_daemon;
39*4882a593Smuzhiyun 	}
40*4882a593Smuzhiyun 	if (daemon->flags & ECRYPTFS_DAEMON_IN_READ)
41*4882a593Smuzhiyun 		goto out_unlock_daemon;
42*4882a593Smuzhiyun 	if (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)
43*4882a593Smuzhiyun 		goto out_unlock_daemon;
44*4882a593Smuzhiyun 	daemon->flags |= ECRYPTFS_DAEMON_IN_POLL;
45*4882a593Smuzhiyun 	mutex_unlock(&daemon->mux);
46*4882a593Smuzhiyun 	poll_wait(file, &daemon->wait, pt);
47*4882a593Smuzhiyun 	mutex_lock(&daemon->mux);
48*4882a593Smuzhiyun 	if (!list_empty(&daemon->msg_ctx_out_queue))
49*4882a593Smuzhiyun 		mask |= EPOLLIN | EPOLLRDNORM;
50*4882a593Smuzhiyun out_unlock_daemon:
51*4882a593Smuzhiyun 	daemon->flags &= ~ECRYPTFS_DAEMON_IN_POLL;
52*4882a593Smuzhiyun 	mutex_unlock(&daemon->mux);
53*4882a593Smuzhiyun 	return mask;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun /**
57*4882a593Smuzhiyun  * ecryptfs_miscdev_open
58*4882a593Smuzhiyun  * @inode: inode of miscdev handle (ignored)
59*4882a593Smuzhiyun  * @file: file for miscdev handle
60*4882a593Smuzhiyun  *
61*4882a593Smuzhiyun  * Returns zero on success; non-zero otherwise
62*4882a593Smuzhiyun  */
63*4882a593Smuzhiyun static int
ecryptfs_miscdev_open(struct inode * inode,struct file * file)64*4882a593Smuzhiyun ecryptfs_miscdev_open(struct inode *inode, struct file *file)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	struct ecryptfs_daemon *daemon = NULL;
67*4882a593Smuzhiyun 	int rc;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	mutex_lock(&ecryptfs_daemon_hash_mux);
70*4882a593Smuzhiyun 	rc = ecryptfs_find_daemon_by_euid(&daemon);
71*4882a593Smuzhiyun 	if (!rc) {
72*4882a593Smuzhiyun 		rc = -EINVAL;
73*4882a593Smuzhiyun 		goto out_unlock_daemon_list;
74*4882a593Smuzhiyun 	}
75*4882a593Smuzhiyun 	rc = ecryptfs_spawn_daemon(&daemon, file);
76*4882a593Smuzhiyun 	if (rc) {
77*4882a593Smuzhiyun 		printk(KERN_ERR "%s: Error attempting to spawn daemon; "
78*4882a593Smuzhiyun 		       "rc = [%d]\n", __func__, rc);
79*4882a593Smuzhiyun 		goto out_unlock_daemon_list;
80*4882a593Smuzhiyun 	}
81*4882a593Smuzhiyun 	mutex_lock(&daemon->mux);
82*4882a593Smuzhiyun 	if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
83*4882a593Smuzhiyun 		rc = -EBUSY;
84*4882a593Smuzhiyun 		goto out_unlock_daemon;
85*4882a593Smuzhiyun 	}
86*4882a593Smuzhiyun 	daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
87*4882a593Smuzhiyun 	file->private_data = daemon;
88*4882a593Smuzhiyun 	atomic_inc(&ecryptfs_num_miscdev_opens);
89*4882a593Smuzhiyun out_unlock_daemon:
90*4882a593Smuzhiyun 	mutex_unlock(&daemon->mux);
91*4882a593Smuzhiyun out_unlock_daemon_list:
92*4882a593Smuzhiyun 	mutex_unlock(&ecryptfs_daemon_hash_mux);
93*4882a593Smuzhiyun 	return rc;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun /**
97*4882a593Smuzhiyun  * ecryptfs_miscdev_release
98*4882a593Smuzhiyun  * @inode: inode of fs/ecryptfs/euid handle (ignored)
99*4882a593Smuzhiyun  * @file: file for fs/ecryptfs/euid handle
100*4882a593Smuzhiyun  *
101*4882a593Smuzhiyun  * This keeps the daemon registered until the daemon sends another
102*4882a593Smuzhiyun  * ioctl to fs/ecryptfs/ctl or until the kernel module unregisters.
103*4882a593Smuzhiyun  *
104*4882a593Smuzhiyun  * Returns zero on success; non-zero otherwise
105*4882a593Smuzhiyun  */
106*4882a593Smuzhiyun static int
ecryptfs_miscdev_release(struct inode * inode,struct file * file)107*4882a593Smuzhiyun ecryptfs_miscdev_release(struct inode *inode, struct file *file)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	struct ecryptfs_daemon *daemon = file->private_data;
110*4882a593Smuzhiyun 	int rc;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	mutex_lock(&daemon->mux);
113*4882a593Smuzhiyun 	BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
114*4882a593Smuzhiyun 	daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
115*4882a593Smuzhiyun 	atomic_dec(&ecryptfs_num_miscdev_opens);
116*4882a593Smuzhiyun 	mutex_unlock(&daemon->mux);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	mutex_lock(&ecryptfs_daemon_hash_mux);
119*4882a593Smuzhiyun 	rc = ecryptfs_exorcise_daemon(daemon);
120*4882a593Smuzhiyun 	mutex_unlock(&ecryptfs_daemon_hash_mux);
121*4882a593Smuzhiyun 	if (rc) {
122*4882a593Smuzhiyun 		printk(KERN_CRIT "%s: Fatal error whilst attempting to "
123*4882a593Smuzhiyun 		       "shut down daemon; rc = [%d]. Please report this "
124*4882a593Smuzhiyun 		       "bug.\n", __func__, rc);
125*4882a593Smuzhiyun 		BUG();
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun 	return rc;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun /**
131*4882a593Smuzhiyun  * ecryptfs_send_miscdev
132*4882a593Smuzhiyun  * @data: Data to send to daemon; may be NULL
133*4882a593Smuzhiyun  * @data_size: Amount of data to send to daemon
134*4882a593Smuzhiyun  * @msg_ctx: Message context, which is used to handle the reply. If
135*4882a593Smuzhiyun  *           this is NULL, then we do not expect a reply.
136*4882a593Smuzhiyun  * @msg_type: Type of message
137*4882a593Smuzhiyun  * @msg_flags: Flags for message
138*4882a593Smuzhiyun  * @daemon: eCryptfs daemon object
139*4882a593Smuzhiyun  *
140*4882a593Smuzhiyun  * Add msg_ctx to queue and then, if it exists, notify the blocked
141*4882a593Smuzhiyun  * miscdevess about the data being available. Must be called with
142*4882a593Smuzhiyun  * ecryptfs_daemon_hash_mux held.
143*4882a593Smuzhiyun  *
144*4882a593Smuzhiyun  * Returns zero on success; non-zero otherwise
145*4882a593Smuzhiyun  */
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)146*4882a593Smuzhiyun int ecryptfs_send_miscdev(char *data, size_t data_size,
147*4882a593Smuzhiyun 			  struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
148*4882a593Smuzhiyun 			  u16 msg_flags, struct ecryptfs_daemon *daemon)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun 	struct ecryptfs_message *msg;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	msg = kmalloc((sizeof(*msg) + data_size), GFP_KERNEL);
153*4882a593Smuzhiyun 	if (!msg)
154*4882a593Smuzhiyun 		return -ENOMEM;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	mutex_lock(&msg_ctx->mux);
157*4882a593Smuzhiyun 	msg_ctx->msg = msg;
158*4882a593Smuzhiyun 	msg_ctx->msg->index = msg_ctx->index;
159*4882a593Smuzhiyun 	msg_ctx->msg->data_len = data_size;
160*4882a593Smuzhiyun 	msg_ctx->type = msg_type;
161*4882a593Smuzhiyun 	memcpy(msg_ctx->msg->data, data, data_size);
162*4882a593Smuzhiyun 	msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);
163*4882a593Smuzhiyun 	list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue);
164*4882a593Smuzhiyun 	mutex_unlock(&msg_ctx->mux);
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	mutex_lock(&daemon->mux);
167*4882a593Smuzhiyun 	daemon->num_queued_msg_ctx++;
168*4882a593Smuzhiyun 	wake_up_interruptible(&daemon->wait);
169*4882a593Smuzhiyun 	mutex_unlock(&daemon->mux);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	return 0;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun /*
175*4882a593Smuzhiyun  * miscdevfs packet format:
176*4882a593Smuzhiyun  *  Octet 0: Type
177*4882a593Smuzhiyun  *  Octets 1-4: network byte order msg_ctx->counter
178*4882a593Smuzhiyun  *  Octets 5-N0: Size of struct ecryptfs_message to follow
179*4882a593Smuzhiyun  *  Octets N0-N1: struct ecryptfs_message (including data)
180*4882a593Smuzhiyun  *
181*4882a593Smuzhiyun  *  Octets 5-N1 not written if the packet type does not include a message
182*4882a593Smuzhiyun  */
183*4882a593Smuzhiyun #define PKT_TYPE_SIZE		1
184*4882a593Smuzhiyun #define PKT_CTR_SIZE		4
185*4882a593Smuzhiyun #define MIN_NON_MSG_PKT_SIZE	(PKT_TYPE_SIZE + PKT_CTR_SIZE)
186*4882a593Smuzhiyun #define MIN_MSG_PKT_SIZE	(PKT_TYPE_SIZE + PKT_CTR_SIZE \
187*4882a593Smuzhiyun 				 + ECRYPTFS_MIN_PKT_LEN_SIZE)
188*4882a593Smuzhiyun /* 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES comes from tag 65 packet format */
189*4882a593Smuzhiyun #define MAX_MSG_PKT_SIZE	(PKT_TYPE_SIZE + PKT_CTR_SIZE \
190*4882a593Smuzhiyun 				 + ECRYPTFS_MAX_PKT_LEN_SIZE \
191*4882a593Smuzhiyun 				 + sizeof(struct ecryptfs_message) \
192*4882a593Smuzhiyun 				 + 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES)
193*4882a593Smuzhiyun #define PKT_TYPE_OFFSET		0
194*4882a593Smuzhiyun #define PKT_CTR_OFFSET		PKT_TYPE_SIZE
195*4882a593Smuzhiyun #define PKT_LEN_OFFSET		(PKT_TYPE_SIZE + PKT_CTR_SIZE)
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun /**
198*4882a593Smuzhiyun  * ecryptfs_miscdev_read - format and send message from queue
199*4882a593Smuzhiyun  * @file: miscdevfs handle
200*4882a593Smuzhiyun  * @buf: User buffer into which to copy the next message on the daemon queue
201*4882a593Smuzhiyun  * @count: Amount of space available in @buf
202*4882a593Smuzhiyun  * @ppos: Offset in file (ignored)
203*4882a593Smuzhiyun  *
204*4882a593Smuzhiyun  * Pulls the most recent message from the daemon queue, formats it for
205*4882a593Smuzhiyun  * being sent via a miscdevfs handle, and copies it into @buf
206*4882a593Smuzhiyun  *
207*4882a593Smuzhiyun  * Returns the number of bytes copied into the user buffer
208*4882a593Smuzhiyun  */
209*4882a593Smuzhiyun static ssize_t
ecryptfs_miscdev_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)210*4882a593Smuzhiyun ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
211*4882a593Smuzhiyun 		      loff_t *ppos)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	struct ecryptfs_daemon *daemon = file->private_data;
214*4882a593Smuzhiyun 	struct ecryptfs_msg_ctx *msg_ctx;
215*4882a593Smuzhiyun 	size_t packet_length_size;
216*4882a593Smuzhiyun 	char packet_length[ECRYPTFS_MAX_PKT_LEN_SIZE];
217*4882a593Smuzhiyun 	size_t i;
218*4882a593Smuzhiyun 	size_t total_length;
219*4882a593Smuzhiyun 	int rc;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	mutex_lock(&daemon->mux);
222*4882a593Smuzhiyun 	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
223*4882a593Smuzhiyun 		rc = 0;
224*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: Attempt to read from zombified "
225*4882a593Smuzhiyun 		       "daemon\n", __func__);
226*4882a593Smuzhiyun 		goto out_unlock_daemon;
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 	if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) {
229*4882a593Smuzhiyun 		rc = 0;
230*4882a593Smuzhiyun 		goto out_unlock_daemon;
231*4882a593Smuzhiyun 	}
232*4882a593Smuzhiyun 	/* This daemon will not go away so long as this flag is set */
233*4882a593Smuzhiyun 	daemon->flags |= ECRYPTFS_DAEMON_IN_READ;
234*4882a593Smuzhiyun check_list:
235*4882a593Smuzhiyun 	if (list_empty(&daemon->msg_ctx_out_queue)) {
236*4882a593Smuzhiyun 		mutex_unlock(&daemon->mux);
237*4882a593Smuzhiyun 		rc = wait_event_interruptible(
238*4882a593Smuzhiyun 			daemon->wait, !list_empty(&daemon->msg_ctx_out_queue));
239*4882a593Smuzhiyun 		mutex_lock(&daemon->mux);
240*4882a593Smuzhiyun 		if (rc < 0) {
241*4882a593Smuzhiyun 			rc = 0;
242*4882a593Smuzhiyun 			goto out_unlock_daemon;
243*4882a593Smuzhiyun 		}
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
246*4882a593Smuzhiyun 		rc = 0;
247*4882a593Smuzhiyun 		goto out_unlock_daemon;
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 	if (list_empty(&daemon->msg_ctx_out_queue)) {
250*4882a593Smuzhiyun 		/* Something else jumped in since the
251*4882a593Smuzhiyun 		 * wait_event_interruptable() and removed the
252*4882a593Smuzhiyun 		 * message from the queue; try again */
253*4882a593Smuzhiyun 		goto check_list;
254*4882a593Smuzhiyun 	}
255*4882a593Smuzhiyun 	msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
256*4882a593Smuzhiyun 				   struct ecryptfs_msg_ctx, daemon_out_list);
257*4882a593Smuzhiyun 	BUG_ON(!msg_ctx);
258*4882a593Smuzhiyun 	mutex_lock(&msg_ctx->mux);
259*4882a593Smuzhiyun 	if (msg_ctx->msg) {
260*4882a593Smuzhiyun 		rc = ecryptfs_write_packet_length(packet_length,
261*4882a593Smuzhiyun 						  msg_ctx->msg_size,
262*4882a593Smuzhiyun 						  &packet_length_size);
263*4882a593Smuzhiyun 		if (rc) {
264*4882a593Smuzhiyun 			rc = 0;
265*4882a593Smuzhiyun 			printk(KERN_WARNING "%s: Error writing packet length; "
266*4882a593Smuzhiyun 			       "rc = [%d]\n", __func__, rc);
267*4882a593Smuzhiyun 			goto out_unlock_msg_ctx;
268*4882a593Smuzhiyun 		}
269*4882a593Smuzhiyun 	} else {
270*4882a593Smuzhiyun 		packet_length_size = 0;
271*4882a593Smuzhiyun 		msg_ctx->msg_size = 0;
272*4882a593Smuzhiyun 	}
273*4882a593Smuzhiyun 	total_length = (PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_length_size
274*4882a593Smuzhiyun 			+ msg_ctx->msg_size);
275*4882a593Smuzhiyun 	if (count < total_length) {
276*4882a593Smuzhiyun 		rc = 0;
277*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: Only given user buffer of "
278*4882a593Smuzhiyun 		       "size [%zd], but we need [%zd] to read the "
279*4882a593Smuzhiyun 		       "pending message\n", __func__, count, total_length);
280*4882a593Smuzhiyun 		goto out_unlock_msg_ctx;
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 	rc = -EFAULT;
283*4882a593Smuzhiyun 	if (put_user(msg_ctx->type, buf))
284*4882a593Smuzhiyun 		goto out_unlock_msg_ctx;
285*4882a593Smuzhiyun 	if (put_user(cpu_to_be32(msg_ctx->counter),
286*4882a593Smuzhiyun 		     (__be32 __user *)(&buf[PKT_CTR_OFFSET])))
287*4882a593Smuzhiyun 		goto out_unlock_msg_ctx;
288*4882a593Smuzhiyun 	i = PKT_TYPE_SIZE + PKT_CTR_SIZE;
289*4882a593Smuzhiyun 	if (msg_ctx->msg) {
290*4882a593Smuzhiyun 		if (copy_to_user(&buf[i], packet_length, packet_length_size))
291*4882a593Smuzhiyun 			goto out_unlock_msg_ctx;
292*4882a593Smuzhiyun 		i += packet_length_size;
293*4882a593Smuzhiyun 		if (copy_to_user(&buf[i], msg_ctx->msg, msg_ctx->msg_size))
294*4882a593Smuzhiyun 			goto out_unlock_msg_ctx;
295*4882a593Smuzhiyun 		i += msg_ctx->msg_size;
296*4882a593Smuzhiyun 	}
297*4882a593Smuzhiyun 	rc = i;
298*4882a593Smuzhiyun 	list_del(&msg_ctx->daemon_out_list);
299*4882a593Smuzhiyun 	kfree(msg_ctx->msg);
300*4882a593Smuzhiyun 	msg_ctx->msg = NULL;
301*4882a593Smuzhiyun 	/* We do not expect a reply from the userspace daemon for any
302*4882a593Smuzhiyun 	 * message type other than ECRYPTFS_MSG_REQUEST */
303*4882a593Smuzhiyun 	if (msg_ctx->type != ECRYPTFS_MSG_REQUEST)
304*4882a593Smuzhiyun 		ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
305*4882a593Smuzhiyun out_unlock_msg_ctx:
306*4882a593Smuzhiyun 	mutex_unlock(&msg_ctx->mux);
307*4882a593Smuzhiyun out_unlock_daemon:
308*4882a593Smuzhiyun 	daemon->flags &= ~ECRYPTFS_DAEMON_IN_READ;
309*4882a593Smuzhiyun 	mutex_unlock(&daemon->mux);
310*4882a593Smuzhiyun 	return rc;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun /**
314*4882a593Smuzhiyun  * ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon
315*4882a593Smuzhiyun  * @data: Bytes comprising struct ecryptfs_message
316*4882a593Smuzhiyun  * @data_size: sizeof(struct ecryptfs_message) + data len
317*4882a593Smuzhiyun  * @seq: Sequence number for miscdev response packet
318*4882a593Smuzhiyun  *
319*4882a593Smuzhiyun  * Returns zero on success; non-zero otherwise
320*4882a593Smuzhiyun  */
ecryptfs_miscdev_response(struct ecryptfs_daemon * daemon,char * data,size_t data_size,u32 seq)321*4882a593Smuzhiyun static int ecryptfs_miscdev_response(struct ecryptfs_daemon *daemon, char *data,
322*4882a593Smuzhiyun 				     size_t data_size, u32 seq)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	struct ecryptfs_message *msg = (struct ecryptfs_message *)data;
325*4882a593Smuzhiyun 	int rc;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	if ((sizeof(*msg) + msg->data_len) != data_size) {
328*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: (sizeof(*msg) + msg->data_len) = "
329*4882a593Smuzhiyun 		       "[%zd]; data_size = [%zd]. Invalid packet.\n", __func__,
330*4882a593Smuzhiyun 		       (sizeof(*msg) + msg->data_len), data_size);
331*4882a593Smuzhiyun 		rc = -EINVAL;
332*4882a593Smuzhiyun 		goto out;
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 	rc = ecryptfs_process_response(daemon, msg, seq);
335*4882a593Smuzhiyun 	if (rc)
336*4882a593Smuzhiyun 		printk(KERN_ERR
337*4882a593Smuzhiyun 		       "Error processing response message; rc = [%d]\n", rc);
338*4882a593Smuzhiyun out:
339*4882a593Smuzhiyun 	return rc;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun /**
343*4882a593Smuzhiyun  * ecryptfs_miscdev_write - handle write to daemon miscdev handle
344*4882a593Smuzhiyun  * @file: File for misc dev handle
345*4882a593Smuzhiyun  * @buf: Buffer containing user data
346*4882a593Smuzhiyun  * @count: Amount of data in @buf
347*4882a593Smuzhiyun  * @ppos: Pointer to offset in file (ignored)
348*4882a593Smuzhiyun  *
349*4882a593Smuzhiyun  * Returns the number of bytes read from @buf
350*4882a593Smuzhiyun  */
351*4882a593Smuzhiyun static ssize_t
ecryptfs_miscdev_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)352*4882a593Smuzhiyun ecryptfs_miscdev_write(struct file *file, const char __user *buf,
353*4882a593Smuzhiyun 		       size_t count, loff_t *ppos)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun 	__be32 counter_nbo;
356*4882a593Smuzhiyun 	u32 seq;
357*4882a593Smuzhiyun 	size_t packet_size, packet_size_length;
358*4882a593Smuzhiyun 	char *data;
359*4882a593Smuzhiyun 	unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE];
360*4882a593Smuzhiyun 	ssize_t rc;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	if (count == 0) {
363*4882a593Smuzhiyun 		return 0;
364*4882a593Smuzhiyun 	} else if (count == MIN_NON_MSG_PKT_SIZE) {
365*4882a593Smuzhiyun 		/* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */
366*4882a593Smuzhiyun 		goto memdup;
367*4882a593Smuzhiyun 	} else if (count < MIN_MSG_PKT_SIZE || count > MAX_MSG_PKT_SIZE) {
368*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: Acceptable packet size range is "
369*4882a593Smuzhiyun 		       "[%d-%zu], but amount of data written is [%zu].\n",
370*4882a593Smuzhiyun 		       __func__, MIN_MSG_PKT_SIZE, MAX_MSG_PKT_SIZE, count);
371*4882a593Smuzhiyun 		return -EINVAL;
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	if (copy_from_user(packet_size_peek, &buf[PKT_LEN_OFFSET],
375*4882a593Smuzhiyun 			   sizeof(packet_size_peek))) {
376*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: Error while inspecting packet size\n",
377*4882a593Smuzhiyun 		       __func__);
378*4882a593Smuzhiyun 		return -EFAULT;
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	rc = ecryptfs_parse_packet_length(packet_size_peek, &packet_size,
382*4882a593Smuzhiyun 					  &packet_size_length);
383*4882a593Smuzhiyun 	if (rc) {
384*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: Error parsing packet length; "
385*4882a593Smuzhiyun 		       "rc = [%zd]\n", __func__, rc);
386*4882a593Smuzhiyun 		return rc;
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	if ((PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_size_length + packet_size)
390*4882a593Smuzhiyun 	    != count) {
391*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: Invalid packet size [%zu]\n", __func__,
392*4882a593Smuzhiyun 		       packet_size);
393*4882a593Smuzhiyun 		return -EINVAL;
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun memdup:
397*4882a593Smuzhiyun 	data = memdup_user(buf, count);
398*4882a593Smuzhiyun 	if (IS_ERR(data)) {
399*4882a593Smuzhiyun 		printk(KERN_ERR "%s: memdup_user returned error [%ld]\n",
400*4882a593Smuzhiyun 		       __func__, PTR_ERR(data));
401*4882a593Smuzhiyun 		return PTR_ERR(data);
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun 	switch (data[PKT_TYPE_OFFSET]) {
404*4882a593Smuzhiyun 	case ECRYPTFS_MSG_RESPONSE:
405*4882a593Smuzhiyun 		if (count < (MIN_MSG_PKT_SIZE
406*4882a593Smuzhiyun 			     + sizeof(struct ecryptfs_message))) {
407*4882a593Smuzhiyun 			printk(KERN_WARNING "%s: Minimum acceptable packet "
408*4882a593Smuzhiyun 			       "size is [%zd], but amount of data written is "
409*4882a593Smuzhiyun 			       "only [%zd]. Discarding response packet.\n",
410*4882a593Smuzhiyun 			       __func__,
411*4882a593Smuzhiyun 			       (MIN_MSG_PKT_SIZE
412*4882a593Smuzhiyun 				+ sizeof(struct ecryptfs_message)), count);
413*4882a593Smuzhiyun 			rc = -EINVAL;
414*4882a593Smuzhiyun 			goto out_free;
415*4882a593Smuzhiyun 		}
416*4882a593Smuzhiyun 		memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE);
417*4882a593Smuzhiyun 		seq = be32_to_cpu(counter_nbo);
418*4882a593Smuzhiyun 		rc = ecryptfs_miscdev_response(file->private_data,
419*4882a593Smuzhiyun 				&data[PKT_LEN_OFFSET + packet_size_length],
420*4882a593Smuzhiyun 				packet_size, seq);
421*4882a593Smuzhiyun 		if (rc) {
422*4882a593Smuzhiyun 			printk(KERN_WARNING "%s: Failed to deliver miscdev "
423*4882a593Smuzhiyun 			       "response to requesting operation; rc = [%zd]\n",
424*4882a593Smuzhiyun 			       __func__, rc);
425*4882a593Smuzhiyun 			goto out_free;
426*4882a593Smuzhiyun 		}
427*4882a593Smuzhiyun 		break;
428*4882a593Smuzhiyun 	case ECRYPTFS_MSG_HELO:
429*4882a593Smuzhiyun 	case ECRYPTFS_MSG_QUIT:
430*4882a593Smuzhiyun 		break;
431*4882a593Smuzhiyun 	default:
432*4882a593Smuzhiyun 		ecryptfs_printk(KERN_WARNING, "Dropping miscdev "
433*4882a593Smuzhiyun 				"message of unrecognized type [%d]\n",
434*4882a593Smuzhiyun 				data[0]);
435*4882a593Smuzhiyun 		rc = -EINVAL;
436*4882a593Smuzhiyun 		goto out_free;
437*4882a593Smuzhiyun 	}
438*4882a593Smuzhiyun 	rc = count;
439*4882a593Smuzhiyun out_free:
440*4882a593Smuzhiyun 	kfree(data);
441*4882a593Smuzhiyun 	return rc;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun static const struct file_operations ecryptfs_miscdev_fops = {
446*4882a593Smuzhiyun 	.owner   = THIS_MODULE,
447*4882a593Smuzhiyun 	.open    = ecryptfs_miscdev_open,
448*4882a593Smuzhiyun 	.poll    = ecryptfs_miscdev_poll,
449*4882a593Smuzhiyun 	.read    = ecryptfs_miscdev_read,
450*4882a593Smuzhiyun 	.write   = ecryptfs_miscdev_write,
451*4882a593Smuzhiyun 	.release = ecryptfs_miscdev_release,
452*4882a593Smuzhiyun 	.llseek  = noop_llseek,
453*4882a593Smuzhiyun };
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun static struct miscdevice ecryptfs_miscdev = {
456*4882a593Smuzhiyun 	.minor = MISC_DYNAMIC_MINOR,
457*4882a593Smuzhiyun 	.name  = "ecryptfs",
458*4882a593Smuzhiyun 	.fops  = &ecryptfs_miscdev_fops
459*4882a593Smuzhiyun };
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun /**
462*4882a593Smuzhiyun  * ecryptfs_init_ecryptfs_miscdev
463*4882a593Smuzhiyun  *
464*4882a593Smuzhiyun  * Messages sent to the userspace daemon from the kernel are placed on
465*4882a593Smuzhiyun  * a queue associated with the daemon. The next read against the
466*4882a593Smuzhiyun  * miscdev handle by that daemon will return the oldest message placed
467*4882a593Smuzhiyun  * on the message queue for the daemon.
468*4882a593Smuzhiyun  *
469*4882a593Smuzhiyun  * Returns zero on success; non-zero otherwise
470*4882a593Smuzhiyun  */
ecryptfs_init_ecryptfs_miscdev(void)471*4882a593Smuzhiyun int __init ecryptfs_init_ecryptfs_miscdev(void)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun 	int rc;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	atomic_set(&ecryptfs_num_miscdev_opens, 0);
476*4882a593Smuzhiyun 	rc = misc_register(&ecryptfs_miscdev);
477*4882a593Smuzhiyun 	if (rc)
478*4882a593Smuzhiyun 		printk(KERN_ERR "%s: Failed to register miscellaneous device "
479*4882a593Smuzhiyun 		       "for communications with userspace daemons; rc = [%d]\n",
480*4882a593Smuzhiyun 		       __func__, rc);
481*4882a593Smuzhiyun 	return rc;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun /**
485*4882a593Smuzhiyun  * ecryptfs_destroy_ecryptfs_miscdev
486*4882a593Smuzhiyun  *
487*4882a593Smuzhiyun  * All of the daemons must be exorcised prior to calling this
488*4882a593Smuzhiyun  * function.
489*4882a593Smuzhiyun  */
ecryptfs_destroy_ecryptfs_miscdev(void)490*4882a593Smuzhiyun void ecryptfs_destroy_ecryptfs_miscdev(void)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun 	BUG_ON(atomic_read(&ecryptfs_num_miscdev_opens) != 0);
493*4882a593Smuzhiyun 	misc_deregister(&ecryptfs_miscdev);
494*4882a593Smuzhiyun }
495