diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-21 23:20:46 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-21 23:20:46 +0300 |
commit | e9f57ebcba563e0cd532926cab83c92bb4d79360 (patch) | |
tree | 6cf11baa7851129145cc35f9218583287f41dd64 /fs/overlayfs/inode.c | |
parent | 5c89e9ea7ef1feaa147325b2ab47a89a147fb903 (diff) | |
parent | 84889d49335627bc770b32787c1ef9ebad1da232 (diff) | |
download | linux-e9f57ebcba563e0cd532926cab83c92bb4d79360.tar.xz |
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs updates from Miklos Szeredi:
"This contains several bug fixes and a new mount option
'default_permissions' that allows read-only exported NFS
filesystems to be used as lower layer"
* 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
ovl: check dentry positiveness in ovl_cleanup_whiteouts()
ovl: setattr: check permissions before copy-up
ovl: root: copy attr
ovl: move super block magic number to magic.h
ovl: use a minimal buffer in ovl_copy_xattr
ovl: allow zero size xattr
ovl: default permissions
Diffstat (limited to 'fs/overlayfs/inode.c')
-rw-r--r-- | fs/overlayfs/inode.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 964a60fa7afc..bf996e574f3d 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -42,6 +42,19 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr) int err; struct dentry *upperdentry; + /* + * Check for permissions before trying to copy-up. This is redundant + * since it will be rechecked later by ->setattr() on upper dentry. But + * without this, copy-up can be triggered by just about anybody. + * + * We don't initialize inode->size, which just means that + * inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not + * check for a swapfile (which this won't be anyway). + */ + err = inode_change_ok(dentry->d_inode, attr); + if (err) + return err; + err = ovl_want_write(dentry); if (err) goto out; @@ -95,6 +108,29 @@ int ovl_permission(struct inode *inode, int mask) realdentry = ovl_entry_real(oe, &is_upper); + if (ovl_is_default_permissions(inode)) { + struct kstat stat; + struct path realpath = { .dentry = realdentry }; + + if (mask & MAY_NOT_BLOCK) + return -ECHILD; + + realpath.mnt = ovl_entry_mnt_real(oe, inode, is_upper); + + err = vfs_getattr(&realpath, &stat); + if (err) + return err; + + if ((stat.mode ^ inode->i_mode) & S_IFMT) + return -ESTALE; + + inode->i_mode = stat.mode; + inode->i_uid = stat.uid; + inode->i_gid = stat.gid; + + return generic_permission(inode, mask); + } + /* Careful in RCU walk mode */ realinode = ACCESS_ONCE(realdentry->d_inode); if (!realinode) { |