Hello Miklos, Gentle ping... Thanks, Tianci On Thu, Sep 1, 2022 at 4:29 PM Zhang Tianci <zhangtianci.1997@xxxxxxxxxxxxx> wrote: > > There is a wrong case of link() on overlay: > $ mkdir /lower /fuse /merge > $ mount -t fuse /fuse > $ mkdir /fuse/upper /fuse/work > $ mount -t overlay /merge -o lowerdir=/lower,upperdir=/fuse/upper,\ > workdir=work > $ touch /merge/file > $ chown bin.bin /merge/file // the file's caller becomes "bin" > $ ln /merge/file /merge/lnkfile > > Then we will get an error(EACCES) because fuse daemon checks the link()'s > caller is "bin", it denied this request. > > In the changing history of ovl_link(), there are two key commits: > > The first is commit bb0d2b8ad296 ("ovl: fix sgid on directory") which > overrides the cred's fsuid/fsgid using the new inode. The new inode's > owner is initialized by inode_init_owner(), and inode->fsuid is > assigned to the current user. So the override fsuid becomes the > current user. We know link() is actually modifying the directory, so > the caller must have the MAY_WRITE permission on the directory. The > current caller may should have this permission. This is acceptable > to use the caller's fsuid. > > The second is commit 51f7e52dc943 ("ovl: share inode for hard link") > which removed the inode creation in ovl_link(). This commit move > inode_init_owner() into ovl_create_object(), so the ovl_link() just > give the old inode to ovl_create_or_link(). Then the override fsuid > becomes the old inode's fsuid, neither the caller nor the overlay's > mounter! So this is incorrect. > > Fix this bug by using ovl mounter's fsuid/fsgid to do underlying > fs's link(). > > v1: https://lore.kernel.org/all/20220817102952.xnvesg3a7rbv576x@wittgenstein/T > v2: https://lore.kernel.org/lkml/20220825130552.29587-1-zhangtianci.1997@xxxxxxxxxxxxx/t > > Signed-off-by: Zhang Tianci <zhangtianci.1997@xxxxxxxxxxxxx> > Signed-off-by: Jiachen Zhang <zhangjiachen.jaycee@xxxxxxxxxxxxx> > --- > fs/overlayfs/dir.c | 46 ++++++++++++++++++++++++++++++---------------- > 1 file changed, 30 insertions(+), 16 deletions(-) > > diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c > index 6b03457f72bb..c3032cef391e 100644 > --- a/fs/overlayfs/dir.c > +++ b/fs/overlayfs/dir.c > @@ -592,28 +592,42 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, > goto out_revert_creds; > } > > - err = -ENOMEM; > - override_cred = prepare_creds(); > - if (override_cred) { > + if (!attr->hardlink) { > + err = -ENOMEM; > + override_cred = prepare_creds(); > + if (!override_cred) > + goto out_revert_creds; > + /* > + * In the creation cases(create, mkdir, mknod, symlink), > + * ovl should transfer current's fs{u,g}id to underlying > + * fs. Because underlying fs want to initialize its new > + * inode owner using current's fs{u,g}id. And in this > + * case, the @inode is a new inode that is initialized > + * in inode_init_owner() to current's fs{u,g}id. So use > + * the inode's i_{u,g}id to override the cred's fs{u,g}id. > + * > + * But in the other hardlink case, ovl_link() does not > + * create a new inode, so just use the ovl mounter's > + * fs{u,g}id. > + */ > override_cred->fsuid = inode->i_uid; > override_cred->fsgid = inode->i_gid; > - if (!attr->hardlink) { > - err = security_dentry_create_files_as(dentry, > - attr->mode, &dentry->d_name, old_cred, > - override_cred); > - if (err) { > - put_cred(override_cred); > - goto out_revert_creds; > - } > + err = security_dentry_create_files_as(dentry, > + attr->mode, &dentry->d_name, old_cred, > + override_cred); > + if (err) { > + put_cred(override_cred); > + goto out_revert_creds; > } > put_cred(override_creds(override_cred)); > put_cred(override_cred); > - > - if (!ovl_dentry_is_whiteout(dentry)) > - err = ovl_create_upper(dentry, inode, attr); > - else > - err = ovl_create_over_whiteout(dentry, inode, attr); > } > + > + if (!ovl_dentry_is_whiteout(dentry)) > + err = ovl_create_upper(dentry, inode, attr); > + else > + err = ovl_create_over_whiteout(dentry, inode, attr); > + > out_revert_creds: > revert_creds(old_cred); > return err; > -- > 2.32.1 (Apple Git-133) >