diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-05-04 14:04:13 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-05-04 14:04:13 -0400 |
commit | 6a480a7842545ec520a91730209ec0bae41694c1 (patch) | |
tree | ba40d93639c0cce7e461880199023d371f1b2535 /fs/ecryptfs | |
parent | 10c64cea04d3c75c306b3f990586ffb343b63287 (diff) |
ecryptfs: fix handling of directory opening
First of all, trying to open them r/w is idiocy; it's guaranteed to fail.
Moreover, assigning ->f_pos and assuming that everything will work is
blatantly broken - try that with e.g. tmpfs as underlying layer and watch
the fireworks. There may be a non-trivial amount of state associated with
current IO position, well beyond the numeric offset. Using the single
struct file associated with underlying inode is really not a good idea;
we ought to open one for each ecryptfs directory struct file.
Additionally, file_operations both for directories and non-directories are
full of pointless methods; non-directories should *not* have ->iterate(),
directories should not have ->flush(), ->fasync() and ->splice_read().
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/ecryptfs')
-rw-r--r-- | fs/ecryptfs/file.c | 71 |
1 files changed, 55 insertions, 16 deletions
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index feef8a9c4de7..f02404052b7b 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c | |||
@@ -112,7 +112,6 @@ static int ecryptfs_readdir(struct file *file, struct dir_context *ctx) | |||
112 | .sb = inode->i_sb, | 112 | .sb = inode->i_sb, |
113 | }; | 113 | }; |
114 | lower_file = ecryptfs_file_to_lower(file); | 114 | lower_file = ecryptfs_file_to_lower(file); |
115 | lower_file->f_pos = ctx->pos; | ||
116 | rc = iterate_dir(lower_file, &buf.ctx); | 115 | rc = iterate_dir(lower_file, &buf.ctx); |
117 | ctx->pos = buf.ctx.pos; | 116 | ctx->pos = buf.ctx.pos; |
118 | if (rc < 0) | 117 | if (rc < 0) |
@@ -223,14 +222,6 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
223 | } | 222 | } |
224 | ecryptfs_set_file_lower( | 223 | ecryptfs_set_file_lower( |
225 | file, ecryptfs_inode_to_private(inode)->lower_file); | 224 | file, ecryptfs_inode_to_private(inode)->lower_file); |
226 | if (d_is_dir(ecryptfs_dentry)) { | ||
227 | ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); | ||
228 | mutex_lock(&crypt_stat->cs_mutex); | ||
229 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); | ||
230 | mutex_unlock(&crypt_stat->cs_mutex); | ||
231 | rc = 0; | ||
232 | goto out; | ||
233 | } | ||
234 | rc = read_or_initialize_metadata(ecryptfs_dentry); | 225 | rc = read_or_initialize_metadata(ecryptfs_dentry); |
235 | if (rc) | 226 | if (rc) |
236 | goto out_put; | 227 | goto out_put; |
@@ -247,6 +238,45 @@ out: | |||
247 | return rc; | 238 | return rc; |
248 | } | 239 | } |
249 | 240 | ||
241 | /** | ||
242 | * ecryptfs_dir_open | ||
243 | * @inode: inode speciying file to open | ||
244 | * @file: Structure to return filled in | ||
245 | * | ||
246 | * Opens the file specified by inode. | ||
247 | * | ||
248 | * Returns zero on success; non-zero otherwise | ||
249 | */ | ||
250 | static int ecryptfs_dir_open(struct inode *inode, struct file *file) | ||
251 | { | ||
252 | struct dentry *ecryptfs_dentry = file->f_path.dentry; | ||
253 | /* Private value of ecryptfs_dentry allocated in | ||
254 | * ecryptfs_lookup() */ | ||
255 | struct ecryptfs_file_info *file_info; | ||
256 | struct file *lower_file; | ||
257 | |||
258 | /* Released in ecryptfs_release or end of function if failure */ | ||
259 | file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); | ||
260 | ecryptfs_set_file_private(file, file_info); | ||
261 | if (unlikely(!file_info)) { | ||
262 | ecryptfs_printk(KERN_ERR, | ||
263 | "Error attempting to allocate memory\n"); | ||
264 | return -ENOMEM; | ||
265 | } | ||
266 | lower_file = dentry_open(ecryptfs_dentry_to_lower_path(ecryptfs_dentry), | ||
267 | file->f_flags, current_cred()); | ||
268 | if (IS_ERR(lower_file)) { | ||
269 | printk(KERN_ERR "%s: Error attempting to initialize " | ||
270 | "the lower file for the dentry with name " | ||
271 | "[%pd]; rc = [%ld]\n", __func__, | ||
272 | ecryptfs_dentry, PTR_ERR(lower_file)); | ||
273 | kmem_cache_free(ecryptfs_file_info_cache, file_info); | ||
274 | return PTR_ERR(lower_file); | ||
275 | } | ||
276 | ecryptfs_set_file_lower(file, lower_file); | ||
277 | return 0; | ||
278 | } | ||
279 | |||
250 | static int ecryptfs_flush(struct file *file, fl_owner_t td) | 280 | static int ecryptfs_flush(struct file *file, fl_owner_t td) |
251 | { | 281 | { |
252 | struct file *lower_file = ecryptfs_file_to_lower(file); | 282 | struct file *lower_file = ecryptfs_file_to_lower(file); |
@@ -267,6 +297,19 @@ static int ecryptfs_release(struct inode *inode, struct file *file) | |||
267 | return 0; | 297 | return 0; |
268 | } | 298 | } |
269 | 299 | ||
300 | static int ecryptfs_dir_release(struct inode *inode, struct file *file) | ||
301 | { | ||
302 | fput(ecryptfs_file_to_lower(file)); | ||
303 | kmem_cache_free(ecryptfs_file_info_cache, | ||
304 | ecryptfs_file_to_private(file)); | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static loff_t ecryptfs_dir_llseek(struct file *file, loff_t offset, int whence) | ||
309 | { | ||
310 | return vfs_llseek(ecryptfs_file_to_lower(file), offset, whence); | ||
311 | } | ||
312 | |||
270 | static int | 313 | static int |
271 | ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) | 314 | ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
272 | { | 315 | { |
@@ -346,20 +389,16 @@ const struct file_operations ecryptfs_dir_fops = { | |||
346 | #ifdef CONFIG_COMPAT | 389 | #ifdef CONFIG_COMPAT |
347 | .compat_ioctl = ecryptfs_compat_ioctl, | 390 | .compat_ioctl = ecryptfs_compat_ioctl, |
348 | #endif | 391 | #endif |
349 | .open = ecryptfs_open, | 392 | .open = ecryptfs_dir_open, |
350 | .flush = ecryptfs_flush, | 393 | .release = ecryptfs_dir_release, |
351 | .release = ecryptfs_release, | ||
352 | .fsync = ecryptfs_fsync, | 394 | .fsync = ecryptfs_fsync, |
353 | .fasync = ecryptfs_fasync, | 395 | .llseek = ecryptfs_dir_llseek, |
354 | .splice_read = generic_file_splice_read, | ||
355 | .llseek = default_llseek, | ||
356 | }; | 396 | }; |
357 | 397 | ||
358 | const struct file_operations ecryptfs_main_fops = { | 398 | const struct file_operations ecryptfs_main_fops = { |
359 | .llseek = generic_file_llseek, | 399 | .llseek = generic_file_llseek, |
360 | .read_iter = ecryptfs_read_update_atime, | 400 | .read_iter = ecryptfs_read_update_atime, |
361 | .write_iter = generic_file_write_iter, | 401 | .write_iter = generic_file_write_iter, |
362 | .iterate = ecryptfs_readdir, | ||
363 | .unlocked_ioctl = ecryptfs_unlocked_ioctl, | 402 | .unlocked_ioctl = ecryptfs_unlocked_ioctl, |
364 | #ifdef CONFIG_COMPAT | 403 | #ifdef CONFIG_COMPAT |
365 | .compat_ioctl = ecryptfs_compat_ioctl, | 404 | .compat_ioctl = ecryptfs_compat_ioctl, |