aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-05-14 12:02:14 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-05-14 12:02:14 -0400
commit7e9890a3500d95c01511a4c45b7e7192dfa47ae2 (patch)
tree277a857b30cbffd9ef000a23f1342ad71e3c2746
parent4856118f4953627e9a087253766b9e7361f5f4a0 (diff)
parentacf3062a7e1ccf67c6f7e7c28671a6708fde63b0 (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.c6
-rw-r--r--fs/overlayfs/dir.c2
-rw-r--r--fs/overlayfs/file.c133
-rw-r--r--fs/overlayfs/inode.c3
-rw-r--r--fs/overlayfs/overlayfs.h2
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
912int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags) 912int 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
16static char ovl_whatisit(struct inode *inode, struct inode *realinode) 17static 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
117static int ovl_open(struct inode *inode, struct file *file) 119static 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
146static loff_t ovl_llseek(struct file *file, loff_t offset, int whence) 147static 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
155static void ovl_file_accessed(struct file *file) 192static 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
375static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 412static 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
429static 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);
462unlock:
463 inode_unlock(inode);
464
465 mnt_drop_write_file(file);
466
467 return ret;
468
469}
470
471static 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
919out_err: 919out_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;
421int ovl_copy_up(struct dentry *dentry); 421int ovl_copy_up(struct dentry *dentry);
422int ovl_copy_up_with_data(struct dentry *dentry); 422int ovl_copy_up_with_data(struct dentry *dentry);
423int ovl_copy_up_flags(struct dentry *dentry, int flags); 423int ovl_copy_up_flags(struct dentry *dentry, int flags);
424int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags); 424int ovl_maybe_copy_up(struct dentry *dentry, int flags);
425int ovl_copy_xattr(struct dentry *old, struct dentry *new); 425int ovl_copy_xattr(struct dentry *old, struct dentry *new);
426int ovl_set_attr(struct dentry *upper, struct kstat *stat); 426int ovl_set_attr(struct dentry *upper, struct kstat *stat);
427struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper); 427struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper);