diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2015-10-12 17:11:44 +0200 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2015-10-12 17:11:44 +0200 |
commit | 8d3095f4ad47ac409440a0ba1c80e13519ff867d (patch) | |
tree | dad58c7957fd832f1b7fbcbaa8a8fb0091177187 /fs/overlayfs/inode.c | |
parent | 5ffdbe8bf1e485026e1c7e4714d2841553cf0b40 (diff) |
ovl: default permissions
Add mount option "default_permissions" to alter the way permissions are
calculated.
Without this option and prior to this patch permissions were calculated by
underlying lower or upper filesystem.
With this option the permissions are calculated by overlayfs based on the
file owner, group and mode bits.
This has significance for example when a read-only exported NFS filesystem
is used as a lower layer. In this case the underlying NFS filesystem will
reply with EROFS, in which case all we know is that the filesystem is
read-only. But that's not what we are interested in, we are interested in
whether the access would be allowed if the filesystem wasn't read-only; the
server doesn't tell us that, and would need updating at various levels,
which doesn't seem practicable.
Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Diffstat (limited to 'fs/overlayfs/inode.c')
-rw-r--r-- | fs/overlayfs/inode.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index ec0c2a050043..76546314e35f 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -98,6 +98,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) { |