diff options
Diffstat (limited to 'fs/ecryptfs/file.c')
-rw-r--r-- | fs/ecryptfs/file.c | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c new file mode 100644 index 000000000000..c8550c9f9cd2 --- /dev/null +++ b/fs/ecryptfs/file.c | |||
@@ -0,0 +1,440 @@ | |||
1 | /** | ||
2 | * eCryptfs: Linux filesystem encryption layer | ||
3 | * | ||
4 | * Copyright (C) 1997-2004 Erez Zadok | ||
5 | * Copyright (C) 2001-2004 Stony Brook University | ||
6 | * Copyright (C) 2004-2006 International Business Machines Corp. | ||
7 | * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com> | ||
8 | * Michael C. Thompson <mcthomps@us.ibm.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation; either version 2 of the | ||
13 | * License, or (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||
23 | * 02111-1307, USA. | ||
24 | */ | ||
25 | |||
26 | #include <linux/file.h> | ||
27 | #include <linux/poll.h> | ||
28 | #include <linux/mount.h> | ||
29 | #include <linux/pagemap.h> | ||
30 | #include <linux/security.h> | ||
31 | #include <linux/smp_lock.h> | ||
32 | #include <linux/compat.h> | ||
33 | #include "ecryptfs_kernel.h" | ||
34 | |||
35 | /** | ||
36 | * ecryptfs_llseek | ||
37 | * @file: File we are seeking in | ||
38 | * @offset: The offset to seek to | ||
39 | * @origin: 2 - offset from i_size; 1 - offset from f_pos | ||
40 | * | ||
41 | * Returns the position we have seeked to, or negative on error | ||
42 | */ | ||
43 | static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin) | ||
44 | { | ||
45 | loff_t rv; | ||
46 | loff_t new_end_pos; | ||
47 | int rc; | ||
48 | int expanding_file = 0; | ||
49 | struct inode *inode = file->f_mapping->host; | ||
50 | |||
51 | /* If our offset is past the end of our file, we're going to | ||
52 | * need to grow it so we have a valid length of 0's */ | ||
53 | new_end_pos = offset; | ||
54 | switch (origin) { | ||
55 | case 2: | ||
56 | new_end_pos += i_size_read(inode); | ||
57 | expanding_file = 1; | ||
58 | break; | ||
59 | case 1: | ||
60 | new_end_pos += file->f_pos; | ||
61 | if (new_end_pos > i_size_read(inode)) { | ||
62 | ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) " | ||
63 | "> i_size_read(inode)(=[0x%.16x])\n", | ||
64 | new_end_pos, i_size_read(inode)); | ||
65 | expanding_file = 1; | ||
66 | } | ||
67 | break; | ||
68 | default: | ||
69 | if (new_end_pos > i_size_read(inode)) { | ||
70 | ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) " | ||
71 | "> i_size_read(inode)(=[0x%.16x])\n", | ||
72 | new_end_pos, i_size_read(inode)); | ||
73 | expanding_file = 1; | ||
74 | } | ||
75 | } | ||
76 | ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos); | ||
77 | if (expanding_file) { | ||
78 | rc = ecryptfs_truncate(file->f_dentry, new_end_pos); | ||
79 | if (rc) { | ||
80 | rv = rc; | ||
81 | ecryptfs_printk(KERN_ERR, "Error on attempt to " | ||
82 | "truncate to (higher) offset [0x%.16x];" | ||
83 | " rc = [%d]\n", new_end_pos, rc); | ||
84 | goto out; | ||
85 | } | ||
86 | } | ||
87 | rv = generic_file_llseek(file, offset, origin); | ||
88 | out: | ||
89 | return rv; | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * ecryptfs_read_update_atime | ||
94 | * | ||
95 | * generic_file_read updates the atime of upper layer inode. But, it | ||
96 | * doesn't give us a chance to update the atime of the lower layer | ||
97 | * inode. This function is a wrapper to generic_file_read. It | ||
98 | * updates the atime of the lower level inode if generic_file_read | ||
99 | * returns without any errors. This is to be used only for file reads. | ||
100 | * The function to be used for directory reads is ecryptfs_read. | ||
101 | */ | ||
102 | static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb, | ||
103 | const struct iovec *iov, | ||
104 | unsigned long nr_segs, loff_t pos) | ||
105 | { | ||
106 | int rc; | ||
107 | struct dentry *lower_dentry; | ||
108 | struct vfsmount *lower_vfsmount; | ||
109 | struct file *file = iocb->ki_filp; | ||
110 | |||
111 | rc = generic_file_aio_read(iocb, iov, nr_segs, pos); | ||
112 | /* | ||
113 | * Even though this is a async interface, we need to wait | ||
114 | * for IO to finish to update atime | ||
115 | */ | ||
116 | if (-EIOCBQUEUED == rc) | ||
117 | rc = wait_on_sync_kiocb(iocb); | ||
118 | if (rc >= 0) { | ||
119 | lower_dentry = ecryptfs_dentry_to_lower(file->f_dentry); | ||
120 | lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_dentry); | ||
121 | touch_atime(lower_vfsmount, lower_dentry); | ||
122 | } | ||
123 | return rc; | ||
124 | } | ||
125 | |||
126 | struct ecryptfs_getdents_callback { | ||
127 | void *dirent; | ||
128 | struct dentry *dentry; | ||
129 | filldir_t filldir; | ||
130 | int err; | ||
131 | int filldir_called; | ||
132 | int entries_written; | ||
133 | }; | ||
134 | |||
135 | /* Inspired by generic filldir in fs/readir.c */ | ||
136 | static int | ||
137 | ecryptfs_filldir(void *dirent, const char *name, int namelen, loff_t offset, | ||
138 | u64 ino, unsigned int d_type) | ||
139 | { | ||
140 | struct ecryptfs_crypt_stat *crypt_stat; | ||
141 | struct ecryptfs_getdents_callback *buf = | ||
142 | (struct ecryptfs_getdents_callback *)dirent; | ||
143 | int rc; | ||
144 | int decoded_length; | ||
145 | char *decoded_name; | ||
146 | |||
147 | crypt_stat = ecryptfs_dentry_to_private(buf->dentry)->crypt_stat; | ||
148 | buf->filldir_called++; | ||
149 | decoded_length = ecryptfs_decode_filename(crypt_stat, name, namelen, | ||
150 | &decoded_name); | ||
151 | if (decoded_length < 0) { | ||
152 | rc = decoded_length; | ||
153 | goto out; | ||
154 | } | ||
155 | rc = buf->filldir(buf->dirent, decoded_name, decoded_length, offset, | ||
156 | ino, d_type); | ||
157 | kfree(decoded_name); | ||
158 | if (rc >= 0) | ||
159 | buf->entries_written++; | ||
160 | out: | ||
161 | return rc; | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * ecryptfs_readdir | ||
166 | * @file: The ecryptfs file struct | ||
167 | * @dirent: Directory entry | ||
168 | * @filldir: The filldir callback function | ||
169 | */ | ||
170 | static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir) | ||
171 | { | ||
172 | int rc; | ||
173 | struct file *lower_file; | ||
174 | struct inode *inode; | ||
175 | struct ecryptfs_getdents_callback buf; | ||
176 | |||
177 | lower_file = ecryptfs_file_to_lower(file); | ||
178 | lower_file->f_pos = file->f_pos; | ||
179 | inode = file->f_dentry->d_inode; | ||
180 | memset(&buf, 0, sizeof(buf)); | ||
181 | buf.dirent = dirent; | ||
182 | buf.dentry = file->f_dentry; | ||
183 | buf.filldir = filldir; | ||
184 | retry: | ||
185 | buf.filldir_called = 0; | ||
186 | buf.entries_written = 0; | ||
187 | buf.err = 0; | ||
188 | rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf); | ||
189 | if (buf.err) | ||
190 | rc = buf.err; | ||
191 | if (buf.filldir_called && !buf.entries_written) | ||
192 | goto retry; | ||
193 | file->f_pos = lower_file->f_pos; | ||
194 | if (rc >= 0) | ||
195 | ecryptfs_copy_attr_atime(inode, lower_file->f_dentry->d_inode); | ||
196 | return rc; | ||
197 | } | ||
198 | |||
199 | struct kmem_cache *ecryptfs_file_info_cache; | ||
200 | |||
201 | /** | ||
202 | * ecryptfs_open | ||
203 | * @inode: inode speciying file to open | ||
204 | * @file: Structure to return filled in | ||
205 | * | ||
206 | * Opens the file specified by inode. | ||
207 | * | ||
208 | * Returns zero on success; non-zero otherwise | ||
209 | */ | ||
210 | static int ecryptfs_open(struct inode *inode, struct file *file) | ||
211 | { | ||
212 | int rc = 0; | ||
213 | struct ecryptfs_crypt_stat *crypt_stat = NULL; | ||
214 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat; | ||
215 | struct dentry *ecryptfs_dentry = file->f_dentry; | ||
216 | /* Private value of ecryptfs_dentry allocated in | ||
217 | * ecryptfs_lookup() */ | ||
218 | struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); | ||
219 | struct inode *lower_inode = NULL; | ||
220 | struct file *lower_file = NULL; | ||
221 | struct vfsmount *lower_mnt; | ||
222 | struct ecryptfs_file_info *file_info; | ||
223 | int lower_flags; | ||
224 | |||
225 | /* Released in ecryptfs_release or end of function if failure */ | ||
226 | file_info = kmem_cache_alloc(ecryptfs_file_info_cache, SLAB_KERNEL); | ||
227 | ecryptfs_set_file_private(file, file_info); | ||
228 | if (!file_info) { | ||
229 | ecryptfs_printk(KERN_ERR, | ||
230 | "Error attempting to allocate memory\n"); | ||
231 | rc = -ENOMEM; | ||
232 | goto out; | ||
233 | } | ||
234 | memset(file_info, 0, sizeof(*file_info)); | ||
235 | lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); | ||
236 | crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; | ||
237 | mount_crypt_stat = &ecryptfs_superblock_to_private( | ||
238 | ecryptfs_dentry->d_sb)->mount_crypt_stat; | ||
239 | mutex_lock(&crypt_stat->cs_mutex); | ||
240 | if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) { | ||
241 | ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); | ||
242 | /* Policy code enabled in future release */ | ||
243 | ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED); | ||
244 | ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); | ||
245 | } | ||
246 | mutex_unlock(&crypt_stat->cs_mutex); | ||
247 | /* This mntget & dget is undone via fput when the file is released */ | ||
248 | dget(lower_dentry); | ||
249 | lower_flags = file->f_flags; | ||
250 | if ((lower_flags & O_ACCMODE) == O_WRONLY) | ||
251 | lower_flags = (lower_flags & O_ACCMODE) | O_RDWR; | ||
252 | if (file->f_flags & O_APPEND) | ||
253 | lower_flags &= ~O_APPEND; | ||
254 | lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); | ||
255 | mntget(lower_mnt); | ||
256 | /* Corresponding fput() in ecryptfs_release() */ | ||
257 | lower_file = dentry_open(lower_dentry, lower_mnt, lower_flags); | ||
258 | if (IS_ERR(lower_file)) { | ||
259 | rc = PTR_ERR(lower_file); | ||
260 | ecryptfs_printk(KERN_ERR, "Error opening lower file\n"); | ||
261 | goto out_puts; | ||
262 | } | ||
263 | ecryptfs_set_file_lower(file, lower_file); | ||
264 | /* Isn't this check the same as the one in lookup? */ | ||
265 | lower_inode = lower_dentry->d_inode; | ||
266 | if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { | ||
267 | ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); | ||
268 | ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); | ||
269 | rc = 0; | ||
270 | goto out; | ||
271 | } | ||
272 | mutex_lock(&crypt_stat->cs_mutex); | ||
273 | if (i_size_read(lower_inode) < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) { | ||
274 | if (!(mount_crypt_stat->flags | ||
275 | & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { | ||
276 | rc = -EIO; | ||
277 | printk(KERN_WARNING "Attempt to read file that is " | ||
278 | "not in a valid eCryptfs format, and plaintext " | ||
279 | "passthrough mode is not enabled; returning " | ||
280 | "-EIO\n"); | ||
281 | mutex_unlock(&crypt_stat->cs_mutex); | ||
282 | goto out_puts; | ||
283 | } | ||
284 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); | ||
285 | rc = 0; | ||
286 | mutex_unlock(&crypt_stat->cs_mutex); | ||
287 | goto out; | ||
288 | } else if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, | ||
289 | ECRYPTFS_POLICY_APPLIED) | ||
290 | || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, | ||
291 | ECRYPTFS_KEY_VALID)) { | ||
292 | rc = ecryptfs_read_headers(ecryptfs_dentry, lower_file); | ||
293 | if (rc) { | ||
294 | ecryptfs_printk(KERN_DEBUG, | ||
295 | "Valid headers not found\n"); | ||
296 | if (!(mount_crypt_stat->flags | ||
297 | & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { | ||
298 | rc = -EIO; | ||
299 | printk(KERN_WARNING "Attempt to read file that " | ||
300 | "is not in a valid eCryptfs format, " | ||
301 | "and plaintext passthrough mode is not " | ||
302 | "enabled; returning -EIO\n"); | ||
303 | mutex_unlock(&crypt_stat->cs_mutex); | ||
304 | goto out_puts; | ||
305 | } | ||
306 | ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, | ||
307 | ECRYPTFS_ENCRYPTED); | ||
308 | rc = 0; | ||
309 | mutex_unlock(&crypt_stat->cs_mutex); | ||
310 | goto out; | ||
311 | } | ||
312 | } | ||
313 | mutex_unlock(&crypt_stat->cs_mutex); | ||
314 | ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] " | ||
315 | "size: [0x%.16x]\n", inode, inode->i_ino, | ||
316 | i_size_read(inode)); | ||
317 | ecryptfs_set_file_lower(file, lower_file); | ||
318 | goto out; | ||
319 | out_puts: | ||
320 | mntput(lower_mnt); | ||
321 | dput(lower_dentry); | ||
322 | kmem_cache_free(ecryptfs_file_info_cache, | ||
323 | ecryptfs_file_to_private(file)); | ||
324 | out: | ||
325 | return rc; | ||
326 | } | ||
327 | |||
328 | static int ecryptfs_flush(struct file *file, fl_owner_t td) | ||
329 | { | ||
330 | int rc = 0; | ||
331 | struct file *lower_file = NULL; | ||
332 | |||
333 | lower_file = ecryptfs_file_to_lower(file); | ||
334 | if (lower_file->f_op && lower_file->f_op->flush) | ||
335 | rc = lower_file->f_op->flush(lower_file, td); | ||
336 | return rc; | ||
337 | } | ||
338 | |||
339 | static int ecryptfs_release(struct inode *inode, struct file *file) | ||
340 | { | ||
341 | struct file *lower_file = ecryptfs_file_to_lower(file); | ||
342 | struct ecryptfs_file_info *file_info = ecryptfs_file_to_private(file); | ||
343 | struct inode *lower_inode = ecryptfs_inode_to_lower(inode); | ||
344 | |||
345 | fput(lower_file); | ||
346 | inode->i_blocks = lower_inode->i_blocks; | ||
347 | kmem_cache_free(ecryptfs_file_info_cache, file_info); | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int | ||
352 | ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync) | ||
353 | { | ||
354 | struct file *lower_file = ecryptfs_file_to_lower(file); | ||
355 | struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); | ||
356 | struct inode *lower_inode = lower_dentry->d_inode; | ||
357 | int rc = -EINVAL; | ||
358 | |||
359 | if (lower_inode->i_fop->fsync) { | ||
360 | mutex_lock(&lower_inode->i_mutex); | ||
361 | rc = lower_inode->i_fop->fsync(lower_file, lower_dentry, | ||
362 | datasync); | ||
363 | mutex_unlock(&lower_inode->i_mutex); | ||
364 | } | ||
365 | return rc; | ||
366 | } | ||
367 | |||
368 | static int ecryptfs_fasync(int fd, struct file *file, int flag) | ||
369 | { | ||
370 | int rc = 0; | ||
371 | struct file *lower_file = NULL; | ||
372 | |||
373 | lower_file = ecryptfs_file_to_lower(file); | ||
374 | if (lower_file->f_op && lower_file->f_op->fasync) | ||
375 | rc = lower_file->f_op->fasync(fd, lower_file, flag); | ||
376 | return rc; | ||
377 | } | ||
378 | |||
379 | static ssize_t ecryptfs_sendfile(struct file *file, loff_t * ppos, | ||
380 | size_t count, read_actor_t actor, void *target) | ||
381 | { | ||
382 | struct file *lower_file = NULL; | ||
383 | int rc = -EINVAL; | ||
384 | |||
385 | lower_file = ecryptfs_file_to_lower(file); | ||
386 | if (lower_file->f_op && lower_file->f_op->sendfile) | ||
387 | rc = lower_file->f_op->sendfile(lower_file, ppos, count, | ||
388 | actor, target); | ||
389 | |||
390 | return rc; | ||
391 | } | ||
392 | |||
393 | static int ecryptfs_ioctl(struct inode *inode, struct file *file, | ||
394 | unsigned int cmd, unsigned long arg); | ||
395 | |||
396 | const struct file_operations ecryptfs_dir_fops = { | ||
397 | .readdir = ecryptfs_readdir, | ||
398 | .ioctl = ecryptfs_ioctl, | ||
399 | .mmap = generic_file_mmap, | ||
400 | .open = ecryptfs_open, | ||
401 | .flush = ecryptfs_flush, | ||
402 | .release = ecryptfs_release, | ||
403 | .fsync = ecryptfs_fsync, | ||
404 | .fasync = ecryptfs_fasync, | ||
405 | .sendfile = ecryptfs_sendfile, | ||
406 | }; | ||
407 | |||
408 | const struct file_operations ecryptfs_main_fops = { | ||
409 | .llseek = ecryptfs_llseek, | ||
410 | .read = do_sync_read, | ||
411 | .aio_read = ecryptfs_read_update_atime, | ||
412 | .write = do_sync_write, | ||
413 | .aio_write = generic_file_aio_write, | ||
414 | .readdir = ecryptfs_readdir, | ||
415 | .ioctl = ecryptfs_ioctl, | ||
416 | .mmap = generic_file_mmap, | ||
417 | .open = ecryptfs_open, | ||
418 | .flush = ecryptfs_flush, | ||
419 | .release = ecryptfs_release, | ||
420 | .fsync = ecryptfs_fsync, | ||
421 | .fasync = ecryptfs_fasync, | ||
422 | .sendfile = ecryptfs_sendfile, | ||
423 | }; | ||
424 | |||
425 | static int | ||
426 | ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
427 | unsigned long arg) | ||
428 | { | ||
429 | int rc = 0; | ||
430 | struct file *lower_file = NULL; | ||
431 | |||
432 | if (ecryptfs_file_to_private(file)) | ||
433 | lower_file = ecryptfs_file_to_lower(file); | ||
434 | if (lower_file && lower_file->f_op && lower_file->f_op->ioctl) | ||
435 | rc = lower_file->f_op->ioctl(ecryptfs_inode_to_lower(inode), | ||
436 | lower_file, cmd, arg); | ||
437 | else | ||
438 | rc = -ENOTTY; | ||
439 | return rc; | ||
440 | } | ||