diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-14 12:02:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-14 12:02:14 -0400 |
commit | 7e9890a3500d95c01511a4c45b7e7192dfa47ae2 (patch) | |
tree | 277a857b30cbffd9ef000a23f1342ad71e3c2746 | |
parent | 4856118f4953627e9a087253766b9e7361f5f4a0 (diff) | |
parent | acf3062a7e1ccf67c6f7e7c28671a6708fde63b0 (diff) |
Merge tag 'ovl-update-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs update from Miklos Szeredi:
"Just bug fixes in this small update"
* tag 'ovl-update-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
ovl: relax WARN_ON() for overlapping layers use case
ovl: check the capability before cred overridden
ovl: do not generate duplicate fsnotify events for "fake" path
ovl: support stacked SEEK_HOLE/SEEK_DATA
ovl: fix missing upper fs freeze protection on copy up for ioctl
-rw-r--r-- | fs/overlayfs/copy_up.c | 6 | ||||
-rw-r--r-- | fs/overlayfs/dir.c | 2 | ||||
-rw-r--r-- | fs/overlayfs/file.c | 133 | ||||
-rw-r--r-- | fs/overlayfs/inode.c | 3 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 2 |
5 files changed, 113 insertions, 33 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 68b3303e4b46..56feaa739979 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c | |||
@@ -909,14 +909,14 @@ static bool ovl_open_need_copy_up(struct dentry *dentry, int flags) | |||
909 | return true; | 909 | return true; |
910 | } | 910 | } |
911 | 911 | ||
912 | int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags) | 912 | int ovl_maybe_copy_up(struct dentry *dentry, int flags) |
913 | { | 913 | { |
914 | int err = 0; | 914 | int err = 0; |
915 | 915 | ||
916 | if (ovl_open_need_copy_up(dentry, file_flags)) { | 916 | if (ovl_open_need_copy_up(dentry, flags)) { |
917 | err = ovl_want_write(dentry); | 917 | err = ovl_want_write(dentry); |
918 | if (!err) { | 918 | if (!err) { |
919 | err = ovl_copy_up_flags(dentry, file_flags); | 919 | err = ovl_copy_up_flags(dentry, flags); |
920 | ovl_drop_write(dentry); | 920 | ovl_drop_write(dentry); |
921 | } | 921 | } |
922 | } | 922 | } |
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 82c129bfe58d..93872bb50230 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c | |||
@@ -260,7 +260,7 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode, | |||
260 | * hashed directory inode aliases. | 260 | * hashed directory inode aliases. |
261 | */ | 261 | */ |
262 | inode = ovl_get_inode(dentry->d_sb, &oip); | 262 | inode = ovl_get_inode(dentry->d_sb, &oip); |
263 | if (WARN_ON(IS_ERR(inode))) | 263 | if (IS_ERR(inode)) |
264 | return PTR_ERR(inode); | 264 | return PTR_ERR(inode); |
265 | } else { | 265 | } else { |
266 | WARN_ON(ovl_inode_real(inode) != d_inode(newdentry)); | 266 | WARN_ON(ovl_inode_real(inode) != d_inode(newdentry)); |
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 84dd957efa24..540a8b845145 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/mount.h> | 11 | #include <linux/mount.h> |
12 | #include <linux/xattr.h> | 12 | #include <linux/xattr.h> |
13 | #include <linux/uio.h> | 13 | #include <linux/uio.h> |
14 | #include <linux/uaccess.h> | ||
14 | #include "overlayfs.h" | 15 | #include "overlayfs.h" |
15 | 16 | ||
16 | static char ovl_whatisit(struct inode *inode, struct inode *realinode) | 17 | static char ovl_whatisit(struct inode *inode, struct inode *realinode) |
@@ -29,10 +30,11 @@ static struct file *ovl_open_realfile(const struct file *file, | |||
29 | struct inode *inode = file_inode(file); | 30 | struct inode *inode = file_inode(file); |
30 | struct file *realfile; | 31 | struct file *realfile; |
31 | const struct cred *old_cred; | 32 | const struct cred *old_cred; |
33 | int flags = file->f_flags | O_NOATIME | FMODE_NONOTIFY; | ||
32 | 34 | ||
33 | old_cred = ovl_override_creds(inode->i_sb); | 35 | old_cred = ovl_override_creds(inode->i_sb); |
34 | realfile = open_with_fake_path(&file->f_path, file->f_flags | O_NOATIME, | 36 | realfile = open_with_fake_path(&file->f_path, flags, realinode, |
35 | realinode, current_cred()); | 37 | current_cred()); |
36 | revert_creds(old_cred); | 38 | revert_creds(old_cred); |
37 | 39 | ||
38 | pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n", | 40 | pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n", |
@@ -50,7 +52,7 @@ static int ovl_change_flags(struct file *file, unsigned int flags) | |||
50 | int err; | 52 | int err; |
51 | 53 | ||
52 | /* No atime modificaton on underlying */ | 54 | /* No atime modificaton on underlying */ |
53 | flags |= O_NOATIME; | 55 | flags |= O_NOATIME | FMODE_NONOTIFY; |
54 | 56 | ||
55 | /* If some flag changed that cannot be changed then something's amiss */ | 57 | /* If some flag changed that cannot be changed then something's amiss */ |
56 | if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK)) | 58 | if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK)) |
@@ -116,11 +118,10 @@ static int ovl_real_fdget(const struct file *file, struct fd *real) | |||
116 | 118 | ||
117 | static int ovl_open(struct inode *inode, struct file *file) | 119 | static int ovl_open(struct inode *inode, struct file *file) |
118 | { | 120 | { |
119 | struct dentry *dentry = file_dentry(file); | ||
120 | struct file *realfile; | 121 | struct file *realfile; |
121 | int err; | 122 | int err; |
122 | 123 | ||
123 | err = ovl_open_maybe_copy_up(dentry, file->f_flags); | 124 | err = ovl_maybe_copy_up(file_dentry(file), file->f_flags); |
124 | if (err) | 125 | if (err) |
125 | return err; | 126 | return err; |
126 | 127 | ||
@@ -145,11 +146,47 @@ static int ovl_release(struct inode *inode, struct file *file) | |||
145 | 146 | ||
146 | static loff_t ovl_llseek(struct file *file, loff_t offset, int whence) | 147 | static loff_t ovl_llseek(struct file *file, loff_t offset, int whence) |
147 | { | 148 | { |
148 | struct inode *realinode = ovl_inode_real(file_inode(file)); | 149 | struct inode *inode = file_inode(file); |
150 | struct fd real; | ||
151 | const struct cred *old_cred; | ||
152 | ssize_t ret; | ||
153 | |||
154 | /* | ||
155 | * The two special cases below do not need to involve real fs, | ||
156 | * so we can optimizing concurrent callers. | ||
157 | */ | ||
158 | if (offset == 0) { | ||
159 | if (whence == SEEK_CUR) | ||
160 | return file->f_pos; | ||
161 | |||
162 | if (whence == SEEK_SET) | ||
163 | return vfs_setpos(file, 0, 0); | ||
164 | } | ||
165 | |||
166 | ret = ovl_real_fdget(file, &real); | ||
167 | if (ret) | ||
168 | return ret; | ||
169 | |||
170 | /* | ||
171 | * Overlay file f_pos is the master copy that is preserved | ||
172 | * through copy up and modified on read/write, but only real | ||
173 | * fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose | ||
174 | * limitations that are more strict than ->s_maxbytes for specific | ||
175 | * files, so we use the real file to perform seeks. | ||
176 | */ | ||
177 | inode_lock(inode); | ||
178 | real.file->f_pos = file->f_pos; | ||
179 | |||
180 | old_cred = ovl_override_creds(inode->i_sb); | ||
181 | ret = vfs_llseek(real.file, offset, whence); | ||
182 | revert_creds(old_cred); | ||
183 | |||
184 | file->f_pos = real.file->f_pos; | ||
185 | inode_unlock(inode); | ||
186 | |||
187 | fdput(real); | ||
149 | 188 | ||
150 | return generic_file_llseek_size(file, offset, whence, | 189 | return ret; |
151 | realinode->i_sb->s_maxbytes, | ||
152 | i_size_read(realinode)); | ||
153 | } | 190 | } |
154 | 191 | ||
155 | static void ovl_file_accessed(struct file *file) | 192 | static void ovl_file_accessed(struct file *file) |
@@ -372,10 +409,68 @@ static long ovl_real_ioctl(struct file *file, unsigned int cmd, | |||
372 | return ret; | 409 | return ret; |
373 | } | 410 | } |
374 | 411 | ||
375 | static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 412 | static unsigned int ovl_get_inode_flags(struct inode *inode) |
413 | { | ||
414 | unsigned int flags = READ_ONCE(inode->i_flags); | ||
415 | unsigned int ovl_iflags = 0; | ||
416 | |||
417 | if (flags & S_SYNC) | ||
418 | ovl_iflags |= FS_SYNC_FL; | ||
419 | if (flags & S_APPEND) | ||
420 | ovl_iflags |= FS_APPEND_FL; | ||
421 | if (flags & S_IMMUTABLE) | ||
422 | ovl_iflags |= FS_IMMUTABLE_FL; | ||
423 | if (flags & S_NOATIME) | ||
424 | ovl_iflags |= FS_NOATIME_FL; | ||
425 | |||
426 | return ovl_iflags; | ||
427 | } | ||
428 | |||
429 | static long ovl_ioctl_set_flags(struct file *file, unsigned long arg) | ||
376 | { | 430 | { |
377 | long ret; | 431 | long ret; |
378 | struct inode *inode = file_inode(file); | 432 | struct inode *inode = file_inode(file); |
433 | unsigned int flags; | ||
434 | unsigned int old_flags; | ||
435 | |||
436 | if (!inode_owner_or_capable(inode)) | ||
437 | return -EACCES; | ||
438 | |||
439 | if (get_user(flags, (int __user *) arg)) | ||
440 | return -EFAULT; | ||
441 | |||
442 | ret = mnt_want_write_file(file); | ||
443 | if (ret) | ||
444 | return ret; | ||
445 | |||
446 | inode_lock(inode); | ||
447 | |||
448 | /* Check the capability before cred override */ | ||
449 | ret = -EPERM; | ||
450 | old_flags = ovl_get_inode_flags(inode); | ||
451 | if (((flags ^ old_flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) && | ||
452 | !capable(CAP_LINUX_IMMUTABLE)) | ||
453 | goto unlock; | ||
454 | |||
455 | ret = ovl_maybe_copy_up(file_dentry(file), O_WRONLY); | ||
456 | if (ret) | ||
457 | goto unlock; | ||
458 | |||
459 | ret = ovl_real_ioctl(file, FS_IOC_SETFLAGS, arg); | ||
460 | |||
461 | ovl_copyflags(ovl_inode_real(inode), inode); | ||
462 | unlock: | ||
463 | inode_unlock(inode); | ||
464 | |||
465 | mnt_drop_write_file(file); | ||
466 | |||
467 | return ret; | ||
468 | |||
469 | } | ||
470 | |||
471 | static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
472 | { | ||
473 | long ret; | ||
379 | 474 | ||
380 | switch (cmd) { | 475 | switch (cmd) { |
381 | case FS_IOC_GETFLAGS: | 476 | case FS_IOC_GETFLAGS: |
@@ -383,23 +478,7 @@ static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
383 | break; | 478 | break; |
384 | 479 | ||
385 | case FS_IOC_SETFLAGS: | 480 | case FS_IOC_SETFLAGS: |
386 | if (!inode_owner_or_capable(inode)) | 481 | ret = ovl_ioctl_set_flags(file, arg); |
387 | return -EACCES; | ||
388 | |||
389 | ret = mnt_want_write_file(file); | ||
390 | if (ret) | ||
391 | return ret; | ||
392 | |||
393 | ret = ovl_copy_up_with_data(file_dentry(file)); | ||
394 | if (!ret) { | ||
395 | ret = ovl_real_ioctl(file, cmd, arg); | ||
396 | |||
397 | inode_lock(inode); | ||
398 | ovl_copyflags(ovl_inode_real(inode), inode); | ||
399 | inode_unlock(inode); | ||
400 | } | ||
401 | |||
402 | mnt_drop_write_file(file); | ||
403 | break; | 482 | break; |
404 | 483 | ||
405 | default: | 484 | default: |
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 3b7ed5d2279c..b48273e846ad 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c | |||
@@ -832,7 +832,7 @@ struct inode *ovl_get_inode(struct super_block *sb, | |||
832 | int fsid = bylower ? oip->lowerpath->layer->fsid : 0; | 832 | int fsid = bylower ? oip->lowerpath->layer->fsid : 0; |
833 | bool is_dir, metacopy = false; | 833 | bool is_dir, metacopy = false; |
834 | unsigned long ino = 0; | 834 | unsigned long ino = 0; |
835 | int err = -ENOMEM; | 835 | int err = oip->newinode ? -EEXIST : -ENOMEM; |
836 | 836 | ||
837 | if (!realinode) | 837 | if (!realinode) |
838 | realinode = d_inode(lowerdentry); | 838 | realinode = d_inode(lowerdentry); |
@@ -917,6 +917,7 @@ out: | |||
917 | return inode; | 917 | return inode; |
918 | 918 | ||
919 | out_err: | 919 | out_err: |
920 | pr_warn_ratelimited("overlayfs: failed to get inode (%i)\n", err); | ||
920 | inode = ERR_PTR(err); | 921 | inode = ERR_PTR(err); |
921 | goto out; | 922 | goto out; |
922 | } | 923 | } |
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 9c6018287d57..d26efed9f80a 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h | |||
@@ -421,7 +421,7 @@ extern const struct file_operations ovl_file_operations; | |||
421 | int ovl_copy_up(struct dentry *dentry); | 421 | int ovl_copy_up(struct dentry *dentry); |
422 | int ovl_copy_up_with_data(struct dentry *dentry); | 422 | int ovl_copy_up_with_data(struct dentry *dentry); |
423 | int ovl_copy_up_flags(struct dentry *dentry, int flags); | 423 | int ovl_copy_up_flags(struct dentry *dentry, int flags); |
424 | int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags); | 424 | int ovl_maybe_copy_up(struct dentry *dentry, int flags); |
425 | int ovl_copy_xattr(struct dentry *old, struct dentry *new); | 425 | int ovl_copy_xattr(struct dentry *old, struct dentry *new); |
426 | int ovl_set_attr(struct dentry *upper, struct kstat *stat); | 426 | int ovl_set_attr(struct dentry *upper, struct kstat *stat); |
427 | struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper); | 427 | struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper); |