Blame view

fs/ecryptfs/miscdev.c 14.7 KB
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /**
   * eCryptfs: Linux filesystem encryption layer
   *
   * Copyright (C) 2008 International Business Machines Corp.
   *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
   *
   * 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/fs.h>
  #include <linux/hash.h>
  #include <linux/random.h>
  #include <linux/miscdevice.h>
  #include <linux/poll.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
27
  #include <linux/slab.h>
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
28
29
30
31
32
33
34
35
  #include <linux/wait.h>
  #include <linux/module.h>
  #include "ecryptfs_kernel.h"
  
  static atomic_t ecryptfs_num_miscdev_opens;
  
  /**
   * ecryptfs_miscdev_poll
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
36
   * @file: dev file
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
37
38
39
40
41
42
43
   * @pt: dev poll table (ignored)
   *
   * Returns the poll mask
   */
  static unsigned int
  ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
  {
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
44
  	struct ecryptfs_daemon *daemon = file->private_data;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
45
  	unsigned int mask = 0;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
46

8bf2debd5   Michael Halcrow   eCryptfs: introdu...
47
  	mutex_lock(&daemon->mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
  		printk(KERN_WARNING "%s: Attempt to poll on zombified "
  		       "daemon
  ", __func__);
  		goto out_unlock_daemon;
  	}
  	if (daemon->flags & ECRYPTFS_DAEMON_IN_READ)
  		goto out_unlock_daemon;
  	if (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)
  		goto out_unlock_daemon;
  	daemon->flags |= ECRYPTFS_DAEMON_IN_POLL;
  	mutex_unlock(&daemon->mux);
  	poll_wait(file, &daemon->wait, pt);
  	mutex_lock(&daemon->mux);
  	if (!list_empty(&daemon->msg_ctx_out_queue))
  		mask |= POLLIN | POLLRDNORM;
  out_unlock_daemon:
  	daemon->flags &= ~ECRYPTFS_DAEMON_IN_POLL;
  	mutex_unlock(&daemon->mux);
  	return mask;
  }
  
  /**
   * ecryptfs_miscdev_open
   * @inode: inode of miscdev handle (ignored)
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
73
   * @file: file for miscdev handle
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
74
75
76
77
78
79
80
81
82
83
   *
   * Returns zero on success; non-zero otherwise
   */
  static int
  ecryptfs_miscdev_open(struct inode *inode, struct file *file)
  {
  	struct ecryptfs_daemon *daemon = NULL;
  	int rc;
  
  	mutex_lock(&ecryptfs_daemon_hash_mux);
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
84
85
  	rc = ecryptfs_find_daemon_by_euid(&daemon);
  	if (!rc) {
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
86
  		rc = -EINVAL;
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
87
88
89
90
91
92
93
  		goto out_unlock_daemon_list;
  	}
  	rc = ecryptfs_spawn_daemon(&daemon, file);
  	if (rc) {
  		printk(KERN_ERR "%s: Error attempting to spawn daemon; "
  		       "rc = [%d]
  ", __func__, rc);
52f21999c   Al Viro   ecryptfs: close r...
94
  		goto out_unlock_daemon_list;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
95
  	}
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
96
  	mutex_lock(&daemon->mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
97
98
  	if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
  		rc = -EBUSY;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
99
100
101
  		goto out_unlock_daemon;
  	}
  	daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
8dc678058   Tyler Hicks   eCryptfs: Gracefu...
102
  	file->private_data = daemon;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
103
104
105
  	atomic_inc(&ecryptfs_num_miscdev_opens);
  out_unlock_daemon:
  	mutex_unlock(&daemon->mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
106
107
108
109
110
111
112
113
  out_unlock_daemon_list:
  	mutex_unlock(&ecryptfs_daemon_hash_mux);
  	return rc;
  }
  
  /**
   * ecryptfs_miscdev_release
   * @inode: inode of fs/ecryptfs/euid handle (ignored)
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
114
   * @file: file for fs/ecryptfs/euid handle
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
115
116
117
118
119
120
121
122
123
   *
   * This keeps the daemon registered until the daemon sends another
   * ioctl to fs/ecryptfs/ctl or until the kernel module unregisters.
   *
   * Returns zero on success; non-zero otherwise
   */
  static int
  ecryptfs_miscdev_release(struct inode *inode, struct file *file)
  {
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
124
  	struct ecryptfs_daemon *daemon = file->private_data;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
125
  	int rc;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
126
  	mutex_lock(&daemon->mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
127
128
129
130
  	BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
  	daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
  	atomic_dec(&ecryptfs_num_miscdev_opens);
  	mutex_unlock(&daemon->mux);
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
131
132
  
  	mutex_lock(&ecryptfs_daemon_hash_mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
133
  	rc = ecryptfs_exorcise_daemon(daemon);
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
134
  	mutex_unlock(&ecryptfs_daemon_hash_mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
135
136
137
138
139
140
141
  	if (rc) {
  		printk(KERN_CRIT "%s: Fatal error whilst attempting to "
  		       "shut down daemon; rc = [%d]. Please report this "
  		       "bug.
  ", __func__, rc);
  		BUG();
  	}
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  	return rc;
  }
  
  /**
   * ecryptfs_send_miscdev
   * @data: Data to send to daemon; may be NULL
   * @data_size: Amount of data to send to daemon
   * @msg_ctx: Message context, which is used to handle the reply. If
   *           this is NULL, then we do not expect a reply.
   * @msg_type: Type of message
   * @msg_flags: Flags for message
   * @daemon: eCryptfs daemon object
   *
   * Add msg_ctx to queue and then, if it exists, notify the blocked
   * miscdevess about the data being available. Must be called with
   * ecryptfs_daemon_hash_mux held.
   *
   * Returns zero on success; non-zero otherwise
   */
  int 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)
  {
60d65f1f0   Tyler Hicks   eCryptfs: Fix loc...
165
  	struct ecryptfs_message *msg;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
166

60d65f1f0   Tyler Hicks   eCryptfs: Fix loc...
167
168
  	msg = kmalloc((sizeof(*msg) + data_size), GFP_KERNEL);
  	if (!msg) {
57ea34d19   Tyler Hicks   eCryptfs: NULL po...
169
170
171
  		printk(KERN_ERR "%s: Out of memory whilst attempting "
  		       "to kmalloc(%zd, GFP_KERNEL)
  ", __func__,
60d65f1f0   Tyler Hicks   eCryptfs: Fix loc...
172
173
  		       (sizeof(*msg) + data_size));
  		return -ENOMEM;
57ea34d19   Tyler Hicks   eCryptfs: NULL po...
174
  	}
60d65f1f0   Tyler Hicks   eCryptfs: Fix loc...
175
176
177
  
  	mutex_lock(&msg_ctx->mux);
  	msg_ctx->msg = msg;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
178
179
180
  	msg_ctx->msg->index = msg_ctx->index;
  	msg_ctx->msg->data_len = data_size;
  	msg_ctx->type = msg_type;
57ea34d19   Tyler Hicks   eCryptfs: NULL po...
181
182
  	memcpy(msg_ctx->msg->data, data, data_size);
  	msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
183
  	list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue);
60d65f1f0   Tyler Hicks   eCryptfs: Fix loc...
184
185
186
  	mutex_unlock(&msg_ctx->mux);
  
  	mutex_lock(&daemon->mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
187
188
189
  	daemon->num_queued_msg_ctx++;
  	wake_up_interruptible(&daemon->wait);
  	mutex_unlock(&daemon->mux);
60d65f1f0   Tyler Hicks   eCryptfs: Fix loc...
190
191
  
  	return 0;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
192
  }
48399c0b0   Tyler Hicks   eCryptfs: Replace...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  /*
   * miscdevfs packet format:
   *  Octet 0: Type
   *  Octets 1-4: network byte order msg_ctx->counter
   *  Octets 5-N0: Size of struct ecryptfs_message to follow
   *  Octets N0-N1: struct ecryptfs_message (including data)
   *
   *  Octets 5-N1 not written if the packet type does not include a message
   */
  #define PKT_TYPE_SIZE		1
  #define PKT_CTR_SIZE		4
  #define MIN_NON_MSG_PKT_SIZE	(PKT_TYPE_SIZE + PKT_CTR_SIZE)
  #define MIN_MSG_PKT_SIZE	(PKT_TYPE_SIZE + PKT_CTR_SIZE \
  				 + ECRYPTFS_MIN_PKT_LEN_SIZE)
  /* 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES comes from tag 65 packet format */
  #define MAX_MSG_PKT_SIZE	(PKT_TYPE_SIZE + PKT_CTR_SIZE \
  				 + ECRYPTFS_MAX_PKT_LEN_SIZE \
  				 + sizeof(struct ecryptfs_message) \
  				 + 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES)
  #define PKT_TYPE_OFFSET		0
  #define PKT_CTR_OFFSET		PKT_TYPE_SIZE
  #define PKT_LEN_OFFSET		(PKT_TYPE_SIZE + PKT_CTR_SIZE)
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
215
216
  /**
   * ecryptfs_miscdev_read - format and send message from queue
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
217
   * @file: miscdevfs handle
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
218
219
220
221
222
223
224
225
226
   * @buf: User buffer into which to copy the next message on the daemon queue
   * @count: Amount of space available in @buf
   * @ppos: Offset in file (ignored)
   *
   * Pulls the most recent message from the daemon queue, formats it for
   * being sent via a miscdevfs handle, and copies it into @buf
   *
   * Returns the number of bytes copied into the user buffer
   */
f66e883eb   Michael Halcrow   eCryptfs: integra...
227
  static ssize_t
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
228
229
230
  ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
  		      loff_t *ppos)
  {
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
231
  	struct ecryptfs_daemon *daemon = file->private_data;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
232
233
  	struct ecryptfs_msg_ctx *msg_ctx;
  	size_t packet_length_size;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
234
  	char packet_length[ECRYPTFS_MAX_PKT_LEN_SIZE];
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
235
236
237
  	size_t i;
  	size_t total_length;
  	int rc;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  	mutex_lock(&daemon->mux);
  	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
  		rc = 0;
  		printk(KERN_WARNING "%s: Attempt to read from zombified "
  		       "daemon
  ", __func__);
  		goto out_unlock_daemon;
  	}
  	if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) {
  		rc = 0;
  		goto out_unlock_daemon;
  	}
  	/* This daemon will not go away so long as this flag is set */
  	daemon->flags |= ECRYPTFS_DAEMON_IN_READ;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  check_list:
  	if (list_empty(&daemon->msg_ctx_out_queue)) {
  		mutex_unlock(&daemon->mux);
  		rc = wait_event_interruptible(
  			daemon->wait, !list_empty(&daemon->msg_ctx_out_queue));
  		mutex_lock(&daemon->mux);
  		if (rc < 0) {
  			rc = 0;
  			goto out_unlock_daemon;
  		}
  	}
  	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
  		rc = 0;
  		goto out_unlock_daemon;
  	}
  	if (list_empty(&daemon->msg_ctx_out_queue)) {
  		/* Something else jumped in since the
  		 * wait_event_interruptable() and removed the
  		 * message from the queue; try again */
  		goto check_list;
  	}
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  	msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
  				   struct ecryptfs_msg_ctx, daemon_out_list);
  	BUG_ON(!msg_ctx);
  	mutex_lock(&msg_ctx->mux);
  	if (msg_ctx->msg) {
  		rc = ecryptfs_write_packet_length(packet_length,
  						  msg_ctx->msg_size,
  						  &packet_length_size);
  		if (rc) {
  			rc = 0;
  			printk(KERN_WARNING "%s: Error writing packet length; "
  			       "rc = [%d]
  ", __func__, rc);
  			goto out_unlock_msg_ctx;
  		}
  	} else {
  		packet_length_size = 0;
  		msg_ctx->msg_size = 0;
  	}
48399c0b0   Tyler Hicks   eCryptfs: Replace...
292
293
  	total_length = (PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_length_size
  			+ msg_ctx->msg_size);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
294
295
296
  	if (count < total_length) {
  		rc = 0;
  		printk(KERN_WARNING "%s: Only given user buffer of "
df261c52a   Michael Halcrow   eCryptfs: Replace...
297
  		       "size [%zd], but we need [%zd] to read the "
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
298
299
300
301
  		       "pending message
  ", __func__, count, total_length);
  		goto out_unlock_msg_ctx;
  	}
79bc12a0a   Al Viro   ecryptfs fixes
302
303
304
  	rc = -EFAULT;
  	if (put_user(msg_ctx->type, buf))
  		goto out_unlock_msg_ctx;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
305
306
  	if (put_user(cpu_to_be32(msg_ctx->counter),
  		     (__be32 __user *)(&buf[PKT_CTR_OFFSET])))
79bc12a0a   Al Viro   ecryptfs fixes
307
  		goto out_unlock_msg_ctx;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
308
  	i = PKT_TYPE_SIZE + PKT_CTR_SIZE;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
309
  	if (msg_ctx->msg) {
79bc12a0a   Al Viro   ecryptfs fixes
310
311
  		if (copy_to_user(&buf[i], packet_length, packet_length_size))
  			goto out_unlock_msg_ctx;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
312
  		i += packet_length_size;
79bc12a0a   Al Viro   ecryptfs fixes
313
  		if (copy_to_user(&buf[i], msg_ctx->msg, msg_ctx->msg_size))
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
314
  			goto out_unlock_msg_ctx;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
  		i += msg_ctx->msg_size;
  	}
  	rc = i;
  	list_del(&msg_ctx->daemon_out_list);
  	kfree(msg_ctx->msg);
  	msg_ctx->msg = NULL;
  	/* We do not expect a reply from the userspace daemon for any
  	 * message type other than ECRYPTFS_MSG_REQUEST */
  	if (msg_ctx->type != ECRYPTFS_MSG_REQUEST)
  		ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
  out_unlock_msg_ctx:
  	mutex_unlock(&msg_ctx->mux);
  out_unlock_daemon:
  	daemon->flags &= ~ECRYPTFS_DAEMON_IN_READ;
  	mutex_unlock(&daemon->mux);
  	return rc;
  }
  
  /**
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
334
335
336
   * ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon
   * @data: Bytes comprising struct ecryptfs_message
   * @data_size: sizeof(struct ecryptfs_message) + data len
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
337
338
339
340
   * @seq: Sequence number for miscdev response packet
   *
   * Returns zero on success; non-zero otherwise
   */
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
341
342
  static int ecryptfs_miscdev_response(struct ecryptfs_daemon *daemon, char *data,
  				     size_t data_size, u32 seq)
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
343
344
345
346
347
348
  {
  	struct ecryptfs_message *msg = (struct ecryptfs_message *)data;
  	int rc;
  
  	if ((sizeof(*msg) + msg->data_len) != data_size) {
  		printk(KERN_WARNING "%s: (sizeof(*msg) + msg->data_len) = "
df261c52a   Michael Halcrow   eCryptfs: Replace...
349
350
  		       "[%zd]; data_size = [%zd]. Invalid packet.
  ", __func__,
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
351
352
353
354
  		       (sizeof(*msg) + msg->data_len), data_size);
  		rc = -EINVAL;
  		goto out;
  	}
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
355
  	rc = ecryptfs_process_response(daemon, msg, seq);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
356
357
358
359
360
361
362
363
364
365
  	if (rc)
  		printk(KERN_ERR
  		       "Error processing response message; rc = [%d]
  ", rc);
  out:
  	return rc;
  }
  
  /**
   * ecryptfs_miscdev_write - handle write to daemon miscdev handle
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
366
   * @file: File for misc dev handle
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
367
368
369
370
   * @buf: Buffer containing user data
   * @count: Amount of data in @buf
   * @ppos: Pointer to offset in file (ignored)
   *
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
371
372
373
374
375
376
   * Returns the number of bytes read from @buf
   */
  static ssize_t
  ecryptfs_miscdev_write(struct file *file, const char __user *buf,
  		       size_t count, loff_t *ppos)
  {
79bc12a0a   Al Viro   ecryptfs fixes
377
378
  	__be32 counter_nbo;
  	u32 seq;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
379
  	size_t packet_size, packet_size_length;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
380
  	char *data;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
381
  	unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE];
7f1335042   Tyler Hicks   eCryptfs: Report ...
382
  	ssize_t rc;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
383

db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
384
  	if (count == 0) {
7f1335042   Tyler Hicks   eCryptfs: Report ...
385
  		return 0;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
386
  	} else if (count == MIN_NON_MSG_PKT_SIZE) {
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
387
388
  		/* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */
  		goto memdup;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
389
  	} else if (count < MIN_MSG_PKT_SIZE || count > MAX_MSG_PKT_SIZE) {
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
390
  		printk(KERN_WARNING "%s: Acceptable packet size range is "
164974a8f   Randy Dunlap   ecryptfs: fix pri...
391
  		       "[%d-%zu], but amount of data written is [%zu].",
48399c0b0   Tyler Hicks   eCryptfs: Replace...
392
  		       __func__, MIN_MSG_PKT_SIZE, MAX_MSG_PKT_SIZE, count);
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
393
394
  		return -EINVAL;
  	}
48399c0b0   Tyler Hicks   eCryptfs: Replace...
395
  	if (copy_from_user(packet_size_peek, &buf[PKT_LEN_OFFSET],
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
396
397
398
399
400
401
402
403
404
405
406
  			   sizeof(packet_size_peek))) {
  		printk(KERN_WARNING "%s: Error while inspecting packet size
  ",
  		       __func__);
  		return -EFAULT;
  	}
  
  	rc = ecryptfs_parse_packet_length(packet_size_peek, &packet_size,
  					  &packet_size_length);
  	if (rc) {
  		printk(KERN_WARNING "%s: Error parsing packet length; "
7f1335042   Tyler Hicks   eCryptfs: Report ...
407
408
  		       "rc = [%zd]
  ", __func__, rc);
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
409
410
  		return rc;
  	}
48399c0b0   Tyler Hicks   eCryptfs: Replace...
411
412
  	if ((PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_size_length + packet_size)
  	    != count) {
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
413
414
415
416
417
  		printk(KERN_WARNING "%s: Invalid packet size [%zu]
  ", __func__,
  		       packet_size);
  		return -EINVAL;
  	}
fd56d242b   Li Zefan   ecryptfs: use mem...
418

db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
419
  memdup:
fd56d242b   Li Zefan   ecryptfs: use mem...
420
421
422
423
424
  	data = memdup_user(buf, count);
  	if (IS_ERR(data)) {
  		printk(KERN_ERR "%s: memdup_user returned error [%ld]
  ",
  		       __func__, PTR_ERR(data));
7f1335042   Tyler Hicks   eCryptfs: Report ...
425
  		return PTR_ERR(data);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
426
  	}
48399c0b0   Tyler Hicks   eCryptfs: Replace...
427
  	switch (data[PKT_TYPE_OFFSET]) {
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
428
  	case ECRYPTFS_MSG_RESPONSE:
48399c0b0   Tyler Hicks   eCryptfs: Replace...
429
430
  		if (count < (MIN_MSG_PKT_SIZE
  			     + sizeof(struct ecryptfs_message))) {
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
431
  			printk(KERN_WARNING "%s: Minimum acceptable packet "
df261c52a   Michael Halcrow   eCryptfs: Replace...
432
433
434
  			       "size is [%zd], but amount of data written is "
  			       "only [%zd]. Discarding response packet.
  ",
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
435
  			       __func__,
48399c0b0   Tyler Hicks   eCryptfs: Replace...
436
437
  			       (MIN_MSG_PKT_SIZE
  				+ sizeof(struct ecryptfs_message)), count);
7f1335042   Tyler Hicks   eCryptfs: Report ...
438
  			rc = -EINVAL;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
439
440
  			goto out_free;
  		}
48399c0b0   Tyler Hicks   eCryptfs: Replace...
441
  		memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
442
  		seq = be32_to_cpu(counter_nbo);
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
443
  		rc = ecryptfs_miscdev_response(file->private_data,
48399c0b0   Tyler Hicks   eCryptfs: Replace...
444
  				&data[PKT_LEN_OFFSET + packet_size_length],
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
445
  				packet_size, seq);
7f1335042   Tyler Hicks   eCryptfs: Report ...
446
  		if (rc) {
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
447
  			printk(KERN_WARNING "%s: Failed to deliver miscdev "
7f1335042   Tyler Hicks   eCryptfs: Report ...
448
449
  			       "response to requesting operation; rc = [%zd]
  ",
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
450
  			       __func__, rc);
7f1335042   Tyler Hicks   eCryptfs: Report ...
451
452
  			goto out_free;
  		}
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
453
454
  		break;
  	case ECRYPTFS_MSG_HELO:
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
455
  	case ECRYPTFS_MSG_QUIT:
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
456
457
458
459
460
461
  		break;
  	default:
  		ecryptfs_printk(KERN_WARNING, "Dropping miscdev "
  				"message of unrecognized type [%d]
  ",
  				data[0]);
7f1335042   Tyler Hicks   eCryptfs: Report ...
462
463
  		rc = -EINVAL;
  		goto out_free;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
464
  	}
7f1335042   Tyler Hicks   eCryptfs: Report ...
465
  	rc = count;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
466
467
  out_free:
  	kfree(data);
7f1335042   Tyler Hicks   eCryptfs: Report ...
468
  	return rc;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
469
470
471
472
  }
  
  
  static const struct file_operations ecryptfs_miscdev_fops = {
52f21999c   Al Viro   ecryptfs: close r...
473
  	.owner   = THIS_MODULE,
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
474
475
476
477
478
  	.open    = ecryptfs_miscdev_open,
  	.poll    = ecryptfs_miscdev_poll,
  	.read    = ecryptfs_miscdev_read,
  	.write   = ecryptfs_miscdev_write,
  	.release = ecryptfs_miscdev_release,
6038f373a   Arnd Bergmann   llseek: automatic...
479
  	.llseek  = noop_llseek,
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  };
  
  static struct miscdevice ecryptfs_miscdev = {
  	.minor = MISC_DYNAMIC_MINOR,
  	.name  = "ecryptfs",
  	.fops  = &ecryptfs_miscdev_fops
  };
  
  /**
   * ecryptfs_init_ecryptfs_miscdev
   *
   * Messages sent to the userspace daemon from the kernel are placed on
   * a queue associated with the daemon. The next read against the
   * miscdev handle by that daemon will return the oldest message placed
   * on the message queue for the daemon.
   *
   * Returns zero on success; non-zero otherwise
   */
7371a3820   Jerome Marchand   ecryptfs: properl...
498
  int __init ecryptfs_init_ecryptfs_miscdev(void)
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
499
500
501
502
  {
  	int rc;
  
  	atomic_set(&ecryptfs_num_miscdev_opens, 0);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
503
504
505
506
507
508
  	rc = misc_register(&ecryptfs_miscdev);
  	if (rc)
  		printk(KERN_ERR "%s: Failed to register miscellaneous device "
  		       "for communications with userspace daemons; rc = [%d]
  ",
  		       __func__, rc);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
  	return rc;
  }
  
  /**
   * ecryptfs_destroy_ecryptfs_miscdev
   *
   * All of the daemons must be exorcised prior to calling this
   * function.
   */
  void ecryptfs_destroy_ecryptfs_miscdev(void)
  {
  	BUG_ON(atomic_read(&ecryptfs_num_miscdev_opens) != 0);
  	misc_deregister(&ecryptfs_miscdev);
  }