Blame view

fs/ecryptfs/miscdev.c 14 KB
450515395   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
2
3
4
5
6
  /**
   * eCryptfs: Linux filesystem encryption layer
   *
   * Copyright (C) 2008 International Business Machines Corp.
   *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
7
8
9
10
11
12
13
   */
  
  #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: ...
14
  #include <linux/slab.h>
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
15
16
17
18
19
20
21
22
  #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...
23
   * @file: dev file
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
24
25
26
27
   * @pt: dev poll table (ignored)
   *
   * Returns the poll mask
   */
076ccb76e   Al Viro   fs: annotate ->po...
28
  static __poll_t
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
29
30
  ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
  {
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
31
  	struct ecryptfs_daemon *daemon = file->private_data;
076ccb76e   Al Viro   fs: annotate ->po...
32
  	__poll_t mask = 0;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
33

8bf2debd5   Michael Halcrow   eCryptfs: introdu...
34
  	mutex_lock(&daemon->mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  	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))
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
50
  		mask |= EPOLLIN | EPOLLRDNORM;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
51
52
53
54
55
56
57
58
59
  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...
60
   * @file: file for miscdev handle
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
61
62
63
64
65
66
67
68
69
70
   *
   * 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...
71
72
  	rc = ecryptfs_find_daemon_by_euid(&daemon);
  	if (!rc) {
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
73
  		rc = -EINVAL;
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
74
75
76
77
78
79
80
  		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...
81
  		goto out_unlock_daemon_list;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
82
  	}
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
83
  	mutex_lock(&daemon->mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
84
85
  	if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
  		rc = -EBUSY;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
86
87
88
  		goto out_unlock_daemon;
  	}
  	daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
8dc678058   Tyler Hicks   eCryptfs: Gracefu...
89
  	file->private_data = daemon;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
90
91
92
  	atomic_inc(&ecryptfs_num_miscdev_opens);
  out_unlock_daemon:
  	mutex_unlock(&daemon->mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
93
94
95
96
97
98
99
100
  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...
101
   * @file: file for fs/ecryptfs/euid handle
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
102
103
104
105
106
107
108
109
110
   *
   * 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...
111
  	struct ecryptfs_daemon *daemon = file->private_data;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
112
  	int rc;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
113
  	mutex_lock(&daemon->mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
114
115
116
117
  	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...
118
119
  
  	mutex_lock(&ecryptfs_daemon_hash_mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
120
  	rc = ecryptfs_exorcise_daemon(daemon);
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
121
  	mutex_unlock(&ecryptfs_daemon_hash_mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
122
123
124
125
126
127
128
  	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...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  	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...
152
  	struct ecryptfs_message *msg;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
153

60d65f1f0   Tyler Hicks   eCryptfs: Fix loc...
154
  	msg = kmalloc((sizeof(*msg) + data_size), GFP_KERNEL);
1a0bba4ff   Markus Elfring   ecryptfs: Delete ...
155
  	if (!msg)
60d65f1f0   Tyler Hicks   eCryptfs: Fix loc...
156
  		return -ENOMEM;
60d65f1f0   Tyler Hicks   eCryptfs: Fix loc...
157
158
159
  
  	mutex_lock(&msg_ctx->mux);
  	msg_ctx->msg = msg;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
160
161
162
  	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...
163
164
  	memcpy(msg_ctx->msg->data, data, data_size);
  	msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
165
  	list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue);
60d65f1f0   Tyler Hicks   eCryptfs: Fix loc...
166
167
168
  	mutex_unlock(&msg_ctx->mux);
  
  	mutex_lock(&daemon->mux);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
169
170
171
  	daemon->num_queued_msg_ctx++;
  	wake_up_interruptible(&daemon->wait);
  	mutex_unlock(&daemon->mux);
60d65f1f0   Tyler Hicks   eCryptfs: Fix loc...
172
173
  
  	return 0;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
174
  }
48399c0b0   Tyler Hicks   eCryptfs: Replace...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  /*
   * 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...
197
198
  /**
   * ecryptfs_miscdev_read - format and send message from queue
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
199
   * @file: miscdevfs handle
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
200
201
202
203
204
205
206
207
208
   * @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...
209
  static ssize_t
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
210
211
212
  ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
  		      loff_t *ppos)
  {
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
213
  	struct ecryptfs_daemon *daemon = file->private_data;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
214
215
  	struct ecryptfs_msg_ctx *msg_ctx;
  	size_t packet_length_size;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
216
  	char packet_length[ECRYPTFS_MAX_PKT_LEN_SIZE];
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
217
218
219
  	size_t i;
  	size_t total_length;
  	int rc;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  	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...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  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...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  	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...
274
275
  	total_length = (PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_length_size
  			+ msg_ctx->msg_size);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
276
277
278
  	if (count < total_length) {
  		rc = 0;
  		printk(KERN_WARNING "%s: Only given user buffer of "
df261c52a   Michael Halcrow   eCryptfs: Replace...
279
  		       "size [%zd], but we need [%zd] to read the "
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
280
281
282
283
  		       "pending message
  ", __func__, count, total_length);
  		goto out_unlock_msg_ctx;
  	}
79bc12a0a   Al Viro   ecryptfs fixes
284
285
286
  	rc = -EFAULT;
  	if (put_user(msg_ctx->type, buf))
  		goto out_unlock_msg_ctx;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
287
288
  	if (put_user(cpu_to_be32(msg_ctx->counter),
  		     (__be32 __user *)(&buf[PKT_CTR_OFFSET])))
79bc12a0a   Al Viro   ecryptfs fixes
289
  		goto out_unlock_msg_ctx;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
290
  	i = PKT_TYPE_SIZE + PKT_CTR_SIZE;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
291
  	if (msg_ctx->msg) {
79bc12a0a   Al Viro   ecryptfs fixes
292
293
  		if (copy_to_user(&buf[i], packet_length, packet_length_size))
  			goto out_unlock_msg_ctx;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
294
  		i += packet_length_size;
79bc12a0a   Al Viro   ecryptfs fixes
295
  		if (copy_to_user(&buf[i], msg_ctx->msg, msg_ctx->msg_size))
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
296
  			goto out_unlock_msg_ctx;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
  		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...
316
317
318
   * 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...
319
320
321
322
   * @seq: Sequence number for miscdev response packet
   *
   * Returns zero on success; non-zero otherwise
   */
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
323
324
  static int ecryptfs_miscdev_response(struct ecryptfs_daemon *daemon, char *data,
  				     size_t data_size, u32 seq)
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
325
326
327
328
329
330
  {
  	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...
331
332
  		       "[%zd]; data_size = [%zd]. Invalid packet.
  ", __func__,
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
333
334
335
336
  		       (sizeof(*msg) + msg->data_len), data_size);
  		rc = -EINVAL;
  		goto out;
  	}
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
337
  	rc = ecryptfs_process_response(daemon, msg, seq);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
338
339
340
341
342
343
344
345
346
347
  	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...
348
   * @file: File for misc dev handle
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
349
350
351
352
   * @buf: Buffer containing user data
   * @count: Amount of data in @buf
   * @ppos: Pointer to offset in file (ignored)
   *
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
353
354
355
356
357
358
   * 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
359
360
  	__be32 counter_nbo;
  	u32 seq;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
361
  	size_t packet_size, packet_size_length;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
362
  	char *data;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
363
  	unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE];
7f1335042   Tyler Hicks   eCryptfs: Report ...
364
  	ssize_t rc;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
365

db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
366
  	if (count == 0) {
7f1335042   Tyler Hicks   eCryptfs: Report ...
367
  		return 0;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
368
  	} else if (count == MIN_NON_MSG_PKT_SIZE) {
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
369
370
  		/* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */
  		goto memdup;
48399c0b0   Tyler Hicks   eCryptfs: Replace...
371
  	} else if (count < MIN_MSG_PKT_SIZE || count > MAX_MSG_PKT_SIZE) {
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
372
  		printk(KERN_WARNING "%s: Acceptable packet size range is "
0996b67df   Colin Ian King   ecryptfs: add mis...
373
374
  		       "[%d-%zu], but amount of data written is [%zu].
  ",
48399c0b0   Tyler Hicks   eCryptfs: Replace...
375
  		       __func__, MIN_MSG_PKT_SIZE, MAX_MSG_PKT_SIZE, count);
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
376
377
  		return -EINVAL;
  	}
48399c0b0   Tyler Hicks   eCryptfs: Replace...
378
  	if (copy_from_user(packet_size_peek, &buf[PKT_LEN_OFFSET],
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
379
380
381
382
383
384
385
386
387
388
389
  			   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 ...
390
391
  		       "rc = [%zd]
  ", __func__, rc);
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
392
393
  		return rc;
  	}
48399c0b0   Tyler Hicks   eCryptfs: Replace...
394
395
  	if ((PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_size_length + packet_size)
  	    != count) {
db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
396
397
398
399
400
  		printk(KERN_WARNING "%s: Invalid packet size [%zu]
  ", __func__,
  		       packet_size);
  		return -EINVAL;
  	}
fd56d242b   Li Zefan   ecryptfs: use mem...
401

db10e5565   Tyler Hicks   eCryptfs: Sanitiz...
402
  memdup:
fd56d242b   Li Zefan   ecryptfs: use mem...
403
404
405
406
407
  	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 ...
408
  		return PTR_ERR(data);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
409
  	}
48399c0b0   Tyler Hicks   eCryptfs: Replace...
410
  	switch (data[PKT_TYPE_OFFSET]) {
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
411
  	case ECRYPTFS_MSG_RESPONSE:
48399c0b0   Tyler Hicks   eCryptfs: Replace...
412
413
  		if (count < (MIN_MSG_PKT_SIZE
  			     + sizeof(struct ecryptfs_message))) {
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
414
  			printk(KERN_WARNING "%s: Minimum acceptable packet "
df261c52a   Michael Halcrow   eCryptfs: Replace...
415
416
417
  			       "size is [%zd], but amount of data written is "
  			       "only [%zd]. Discarding response packet.
  ",
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
418
  			       __func__,
48399c0b0   Tyler Hicks   eCryptfs: Replace...
419
420
  			       (MIN_MSG_PKT_SIZE
  				+ sizeof(struct ecryptfs_message)), count);
7f1335042   Tyler Hicks   eCryptfs: Report ...
421
  			rc = -EINVAL;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
422
423
  			goto out_free;
  		}
48399c0b0   Tyler Hicks   eCryptfs: Replace...
424
  		memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
425
  		seq = be32_to_cpu(counter_nbo);
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
426
  		rc = ecryptfs_miscdev_response(file->private_data,
48399c0b0   Tyler Hicks   eCryptfs: Replace...
427
  				&data[PKT_LEN_OFFSET + packet_size_length],
2ecaf55db   Tyler Hicks   eCryptfs: Make al...
428
  				packet_size, seq);
7f1335042   Tyler Hicks   eCryptfs: Report ...
429
  		if (rc) {
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
430
  			printk(KERN_WARNING "%s: Failed to deliver miscdev "
7f1335042   Tyler Hicks   eCryptfs: Report ...
431
432
  			       "response to requesting operation; rc = [%zd]
  ",
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
433
  			       __func__, rc);
7f1335042   Tyler Hicks   eCryptfs: Report ...
434
435
  			goto out_free;
  		}
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
436
437
  		break;
  	case ECRYPTFS_MSG_HELO:
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
438
  	case ECRYPTFS_MSG_QUIT:
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
439
440
441
442
443
444
  		break;
  	default:
  		ecryptfs_printk(KERN_WARNING, "Dropping miscdev "
  				"message of unrecognized type [%d]
  ",
  				data[0]);
7f1335042   Tyler Hicks   eCryptfs: Report ...
445
446
  		rc = -EINVAL;
  		goto out_free;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
447
  	}
7f1335042   Tyler Hicks   eCryptfs: Report ...
448
  	rc = count;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
449
450
  out_free:
  	kfree(data);
7f1335042   Tyler Hicks   eCryptfs: Report ...
451
  	return rc;
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
452
453
454
455
  }
  
  
  static const struct file_operations ecryptfs_miscdev_fops = {
52f21999c   Al Viro   ecryptfs: close r...
456
  	.owner   = THIS_MODULE,
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
457
458
459
460
461
  	.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...
462
  	.llseek  = noop_llseek,
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  };
  
  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...
481
  int __init ecryptfs_init_ecryptfs_miscdev(void)
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
482
483
484
485
  {
  	int rc;
  
  	atomic_set(&ecryptfs_num_miscdev_opens, 0);
8bf2debd5   Michael Halcrow   eCryptfs: introdu...
486
487
488
489
490
491
  	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...
492
493
494
495
496
497
498
499
500
501
502
503
504
505
  	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);
  }