ovl: do operations on underlying file system in mounter's context 68/307868/1
authorVivek Goyal <vgoyal@redhat.com>
Fri, 1 Jul 2016 20:34:28 +0000 (16:34 -0400)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Wed, 13 Mar 2024 10:30:39 +0000 (19:30 +0900)
Given we are now doing checks both on overlay inode as well underlying
inode, we should be able to do checks and operations on underlying file
system using mounter's context.

So modify all operations to do checks/operations on underlying dentry/inode
in the context of mounter.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
[sw0312.kim: backport upstream commit 1175b6b8d96331676f1d436b089b965807f23b4a to resolve overlayfs smack deny issue]
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Change-Id: I550e2ed212f8a3a578cc48430556fa2c7e1eb3a2

fs/overlayfs/dir.c
fs/overlayfs/inode.c
fs/overlayfs/super.c

index eedacae889b95475a863d4691eded586702c7a43..19f984cccac1120f57a096f04a2503bb3daafae4 100644 (file)
@@ -141,9 +141,12 @@ static int ovl_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
        int err;
        enum ovl_path_type type;
        struct path realpath;
+       const struct cred *old_cred;
 
        type = ovl_path_real(dentry, &realpath);
+       old_cred = ovl_override_creds(dentry->d_sb);
        err = vfs_getattr(&realpath, stat);
+       revert_creds(old_cred);
        if (err)
                return err;
 
@@ -390,6 +393,8 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
 {
        int err;
        struct inode *inode;
+       const struct cred *old_cred;
+       struct cred *override_cred;
        struct kstat stat = {
                .mode = mode,
                .rdev = rdev,
@@ -404,28 +409,23 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
        if (err)
                goto out_iput;
 
-       if (!ovl_dentry_is_opaque(dentry)) {
-               err = ovl_create_upper(dentry, inode, &stat, link, hardlink);
-       } else {
-               const struct cred *old_cred;
-               struct cred *override_cred;
-
-               old_cred = ovl_override_creds(dentry->d_sb);
-
-               err = -ENOMEM;
-               override_cred = prepare_creds();
-               if (override_cred) {
-                       override_cred->fsuid = old_cred->fsuid;
-                       override_cred->fsgid = old_cred->fsgid;
-                       put_cred(override_creds(override_cred));
-                       put_cred(override_cred);
-
+       old_cred = ovl_override_creds(dentry->d_sb);
+       err = -ENOMEM;
+       override_cred = prepare_creds();
+       if (override_cred) {
+               override_cred->fsuid = old_cred->fsuid;
+               override_cred->fsgid = old_cred->fsgid;
+               put_cred(override_creds(override_cred));
+               put_cred(override_cred);
+
+               if (!ovl_dentry_is_opaque(dentry))
+                       err = ovl_create_upper(dentry, inode, &stat, link,
+                                               hardlink);
+               else
                        err = ovl_create_over_whiteout(dentry, inode, &stat,
-                                                      link, hardlink);
-               }
-               revert_creds(old_cred);
+                                                       link, hardlink);
        }
-
+       revert_creds(old_cred);
        if (!err)
                inode = NULL;
 out_iput:
@@ -636,6 +636,8 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
 {
        enum ovl_path_type type;
        int err;
+       const struct cred *old_cred;
+
 
        err = ovl_check_sticky(dentry);
        if (err)
@@ -650,15 +652,13 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
                goto out_drop_write;
 
        type = ovl_path_type(dentry);
-       if (OVL_TYPE_PURE_UPPER(type)) {
-               err = ovl_remove_upper(dentry, is_dir);
-       } else {
-               const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
 
+       old_cred = ovl_override_creds(dentry->d_sb);
+       if (OVL_TYPE_PURE_UPPER(type))
+               err = ovl_remove_upper(dentry, is_dir);
+       else
                err = ovl_remove_and_whiteout(dentry, is_dir);
-
-               revert_creds(old_cred);
-       }
+       revert_creds(old_cred);
 out_drop_write:
        ovl_drop_write(dentry);
 out:
@@ -764,8 +764,7 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
        old_opaque = !OVL_TYPE_PURE_UPPER(old_type);
        new_opaque = !OVL_TYPE_PURE_UPPER(new_type);
 
-       if (old_opaque || new_opaque)
-               old_cred = ovl_override_creds(old->d_sb);
+       old_cred = ovl_override_creds(old->d_sb);
 
        if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) {
                opaquedir = ovl_check_empty_and_clear(new);
@@ -896,8 +895,7 @@ out_dput_old:
 out_unlock:
        unlock_rename(new_upperdir, old_upperdir);
 out_revert_creds:
-       if (old_opaque || new_opaque)
-               revert_creds(old_cred);
+       revert_creds(old_cred);
 out_drop_write:
        ovl_drop_write(old);
 out:
index 9aff8178aa8cd6ceac0febbe88e5f723fdc7def9..25205595f4f9e25c4b7545c3a76c77bb82955f8e 100644 (file)
@@ -42,6 +42,7 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
 {
        int err;
        struct dentry *upperdentry;
+       const struct cred *old_cred;
 
        /*
         * Check for permissions before trying to copy-up.  This is redundant
@@ -68,7 +69,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
                        attr->ia_valid &= ~ATTR_MODE;
 
                mutex_lock(&upperdentry->d_inode->i_mutex);
+               old_cred = ovl_override_creds(dentry->d_sb);
                err = notify_change(upperdentry, attr, NULL);
+               revert_creds(old_cred);
                if (!err)
                        ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
                mutex_unlock(&upperdentry->d_inode->i_mutex);
@@ -82,9 +85,14 @@ static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry,
                         struct kstat *stat)
 {
        struct path realpath;
+       const struct cred *old_cred;
+       int err;
 
        ovl_path_real(dentry, &realpath);
-       return vfs_getattr(&realpath, stat);
+       old_cred = ovl_override_creds(dentry->d_sb);
+       err = vfs_getattr(&realpath, stat);
+       revert_creds(old_cred);
+       return err;
 }
 
 int ovl_permission(struct inode *inode, int mask)
@@ -173,6 +181,7 @@ static const char *ovl_follow_link(struct dentry *dentry, void **cookie)
        struct dentry *realdentry;
        struct inode *realinode;
        struct ovl_link_data *data = NULL;
+       const struct cred *old_cred;
        const char *ret;
 
        realdentry = ovl_dentry_real(dentry);
@@ -188,7 +197,9 @@ static const char *ovl_follow_link(struct dentry *dentry, void **cookie)
                data->realdentry = realdentry;
        }
 
+       old_cred = ovl_override_creds(dentry->d_sb);
        ret = realinode->i_op->follow_link(realdentry, cookie);
+       revert_creds(old_cred);
        if (IS_ERR_OR_NULL(ret)) {
                kfree(data);
                return ret;
@@ -219,6 +230,8 @@ static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
 {
        struct path realpath;
        struct inode *realinode;
+       const struct cred *old_cred;
+       int err;
 
        ovl_path_real(dentry, &realpath);
        realinode = realpath.dentry->d_inode;
@@ -228,7 +241,10 @@ static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
 
        touch_atime(&realpath);
 
-       return realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
+       old_cred = ovl_override_creds(dentry->d_sb);
+       err = realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
+       revert_creds(old_cred);
+       return err;
 }
 
 
@@ -242,6 +258,7 @@ int ovl_setxattr(struct dentry *dentry, const char *name,
 {
        int err;
        struct dentry *upperdentry;
+       const struct cred *old_cred;
 
        err = ovl_want_write(dentry);
        if (err)
@@ -256,7 +273,9 @@ int ovl_setxattr(struct dentry *dentry, const char *name,
                goto out_drop_write;
 
        upperdentry = ovl_dentry_upper(dentry);
+       old_cred = ovl_override_creds(dentry->d_sb);
        err = vfs_setxattr(upperdentry, name, value, size, flags);
+       revert_creds(old_cred);
 
 out_drop_write:
        ovl_drop_write(dentry);
@@ -278,11 +297,16 @@ ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
 {
        struct path realpath;
        enum ovl_path_type type = ovl_path_real(dentry, &realpath);
+       ssize_t res;
+       const struct cred *old_cred;
 
        if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
                return -ENODATA;
 
-       return vfs_getxattr(realpath.dentry, name, value, size);
+       old_cred = ovl_override_creds(dentry->d_sb);
+       res = vfs_getxattr(realpath.dentry, name, value, size);
+       revert_creds(old_cred);
+       return res;
 }
 
 static bool ovl_can_list(const char *s)
@@ -302,8 +326,11 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
        ssize_t res;
        size_t len;
        char *s;
+       const struct cred *old_cred;
 
+       old_cred = ovl_override_creds(dentry->d_sb);
        res = vfs_listxattr(realpath.dentry, list, size);
+       revert_creds(old_cred);
        if (res <= 0 || size == 0)
                return res;
 
@@ -335,6 +362,7 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
        int err;
        struct path realpath;
        enum ovl_path_type type = ovl_path_real(dentry, &realpath);
+       const struct cred *old_cred;
 
        err = ovl_want_write(dentry);
        if (err)
@@ -356,7 +384,9 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
                ovl_path_upper(dentry, &realpath);
        }
 
+       old_cred = ovl_override_creds(dentry->d_sb);
        err = vfs_removexattr(realpath.dentry, name);
+       revert_creds(old_cred);
 out_drop_write:
        ovl_drop_write(dentry);
 out:
index fa20c95bd45695a2d16fa346a046d7548c4e20fd..974c28074a315d1f3e21b5bb181ab3db93f69192 100644 (file)
@@ -445,6 +445,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                          unsigned int flags)
 {
        struct ovl_entry *oe;
+       const struct cred *old_cred;
        struct ovl_entry *poe = dentry->d_parent->d_fsdata;
        struct path *stack = NULL;
        struct dentry *upperdir, *upperdentry = NULL;
@@ -455,6 +456,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
        unsigned int i;
        int err;
 
+       old_cred = ovl_override_creds(dentry->d_sb);
        upperdir = ovl_upperdentry_dereference(poe);
        if (upperdir) {
                this = ovl_lookup_real(upperdir, &dentry->d_name);
@@ -559,6 +561,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
        oe->opaque = upperopaque;
        oe->__upperdentry = upperdentry;
        memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
+       revert_creds(old_cred);
        kfree(stack);
        dentry->d_fsdata = oe;
        d_add(dentry, inode);
@@ -574,6 +577,7 @@ out_put:
 out_put_upper:
        dput(upperdentry);
 out:
+       revert_creds(old_cred);
        return ERR_PTR(err);
 }