All of lore.kernel.org
 help / color / mirror / Atom feed
From: 天赐张 <zhangtianci.1997@bytedance.com>
To: Christian Brauner <brauner@kernel.org>
Cc: Amir Goldstein <amir73il@gmail.com>,
	Miklos Szeredi <miklos@szeredi.hu>,
	overlayfs <linux-unionfs@vger.kernel.org>,
	linux-kernel <linux-kernel@vger.kernel.org>,
	Jiachen Zhang <zhangjiachen.jaycee@bytedance.com>
Subject: Re: [External] Re: [PATCH] ovl: Do not override fsuid and fsgid in ovl_link()
Date: Wed, 17 Aug 2022 19:36:44 +0800	[thread overview]
Message-ID: <CAP4dvscpm2FyuJ6gqZz=32ffrN9BORaa=Q0grPEgB+KUXbJniw@mail.gmail.com> (raw)
In-Reply-To: <20220817102951.xnvesg3a7rbv576x@wittgenstein>

On Wed, Aug 17, 2022 at 6:29 PM Christian Brauner <brauner@kernel.org> wrote:
>
> On Wed, Aug 17, 2022 at 12:27:27PM +0200, Christian Brauner wrote:
> > On Wed, Aug 17, 2022 at 12:55:22PM +0300, Amir Goldstein wrote:
> > > On Wed, Aug 17, 2022 at 12:53 PM Amir Goldstein <amir73il@gmail.com> wrote:
> > > >
> > > > On Wed, Aug 17, 2022 at 12:11 PM 天赐张 <zhangtianci.1997@bytedance.com> wrote:
> > > > >
> > > > > On Wed, Aug 17, 2022 at 3:36 PM Amir Goldstein <amir73il@gmail.com> wrote:
> > > > > >
> > > > > > On Wed, Aug 17, 2022 at 6:49 AM Zhang Tianci
> > > > > > <zhangtianci.1997@bytedance.com> wrote:
> > > > > > >
> > > > > > > ovl_link() did not create a new inode after commit
> > > > > > > 51f7e52dc943 ("ovl: share inode for hard link"), so
> > > > > > > in ovl_create_or_link() we should not override cred's
> > > > > > > fsuid and fsgid when called by ovl_link().
> > > > > > >
> > > > > > > Signed-off-by: Zhang Tianci <zhangtianci.1997@bytedance.com>
> > > > > > > Signed-off-by: Jiachen Zhang <zhangjiachen.jaycee@bytedance.com>
> > > > > > > ---
> > > > > > >  fs/overlayfs/dir.c | 4 ++--
> > > > > > >  1 file changed, 2 insertions(+), 2 deletions(-)
> > > > > > >
> > > > > > > diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> > > > > > > index 6b03457f72bb..568d338032db 100644
> > > > > > > --- a/fs/overlayfs/dir.c
> > > > > > > +++ b/fs/overlayfs/dir.c
> > > > > > > @@ -595,9 +595,9 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
> > > > > > >         err = -ENOMEM;
> > > > > > >         override_cred = prepare_creds();
> > > > > > >         if (override_cred) {
> > > > > > > -               override_cred->fsuid = inode->i_uid;
> > > > > > > -               override_cred->fsgid = inode->i_gid;
> > > > > > >                 if (!attr->hardlink) {
> > > > > > > +                       override_cred->fsuid = inode->i_uid;
> > > > > > > +                       override_cred->fsgid = inode->i_gid;
> > > > > > >                         err = security_dentry_create_files_as(dentry,
> > > > > > >                                         attr->mode, &dentry->d_name, old_cred,
> > > > > > >                                         override_cred);
> > > > > > > --
> > > > > >
> > > > > > This change looks incorrect.
> > > > > > Unless I am missing something, fsuid/fsgid still need to
> > > > > > be overridden for calling link() on underlying fs.
> > > > > > What made you do this change?
> > > > > >
> > > > > > Thanks,
> > > > > > Amir.
> > > > >
> > > > > Hi Amir,
> > > > >
> > > > > I ran into an error when I tested overlay on fuse:
> > > > >   $ 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 I got an error(EACCES) because fuse daemon checks the link()'s
> > > > > caller is "bin", it denied this request.
> > > > > I browsed 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. I think this is
> > > > > acceptable to use the caller's fsuid(But I still feel a little
> > > > > conflicted with the overlay's design).
> > > > > 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
> > > > > creator! So I think this is incorrect.
> > > > > I think the link() should be like unlink(), overlay fs should just use
> > > > > the creator cred to do underlying fs's operations.
> > > > >
> > > >
> > > > I see. The reproducer and explanation belong in the commit message.
> > > >
> > > > Your argument makes sense to me, but CC Christian to make
> > > > sure I am not missing anything related to ACLs and what not.
> > >
> > > Once again with correct email address...
> >
> > So we have:
> >
> > ovl_create_object()
> > -> ovl_override_creds(ovl_sb)
> > -> ovl_new_inode()
> >    -> inode_init_owner()
> >       {
> >               inode->i_uid = current_fsuid();
> >               inode->i_gid = current_fsgid();

In inode_init_owner(), the inode->i_gid may inherit from parent dir.
And this is the main purpose of the commit bb0d2b8ad296 ("ovl: fix
sgid on directory").

> >       }
> > -> ovl_create_or_link(inode, ...)
> > -> prepare_creds() // Copy of caller's creds
>
> s/caller's/creator's/
>
> > {
> >         override_creds->fsuid = inode->i_uid;
> >         override_creds->fsgid = inode->i_gid;
> > }
> > -> revert_creds()
> >
> > which afaict means that the mounter's credentials are used apart from
> > the fs{g,u}id which is taken from inode->i_{g,u}id which should
> > correspond to current_fs{g,u}id().
> >
> > The commit that is pointed out in the patch
> > 51f7e52dc943 ("ovl: share inode for hard link")
> > seems to have broken that assumption.
> >
> > Given that the intention was to use the creator's creds _with the
> > caller's fs{g,u}id_ wouldn't it make more sense to simply ensure that
> > the caller's fs{g,u}id are always used instead of using the full
> > creator's creds just for the link operation? So something like this
> > (untested):
> >
> > diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> > index 6b03457f72bb..4a3ee16a6d70 100644
> > --- a/fs/overlayfs/dir.c
> > +++ b/fs/overlayfs/dir.c
> > @@ -575,6 +575,9 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
> >         const struct cred *old_cred;
> >         struct cred *override_cred;
> >         struct dentry *parent = dentry->d_parent;
> > +       /* Retrieve caller's fs{g,u}id before we override creds below. */
> > +       kuid_t caller_fsuid = current_fsuid();
> > +       kgid_t caller_fsgid = current_fsgid();
> >
> >         err = ovl_copy_up(parent);
> >         if (err)
> > @@ -595,8 +598,8 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
> >         err = -ENOMEM;
> >         override_cred = prepare_creds();
> >         if (override_cred) {
> > -               override_cred->fsuid = inode->i_uid;
> > -               override_cred->fsgid = inode->i_gid;
> > +               override_cred->fsuid = caller_fsuid;
> > +               override_cred->fsgid = caller_fsgid;

So the override_cred->fsgid should be inode->i_gid if the inode is a new inode.

> >                 if (!attr->hardlink) {
> >                         err = security_dentry_create_files_as(dentry,
> >                                         attr->mode, &dentry->d_name, old_cred,

So your meaning should be like this:

diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 6b03457f72bb..9aead6ddc071 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -575,6 +575,8 @@ static int ovl_create_or_link(struct dentry
*dentry, struct inode *inode,
        const struct cred *old_cred;
        struct cred *override_cred;
        struct dentry *parent = dentry->d_parent;
+       kuid_t caller_fsuid = current_fsuid();
+       kgid_t caller_fsgid = current_fsgid();

        err = ovl_copy_up(parent);
        if (err)
@@ -595,9 +597,9 @@ static int ovl_create_or_link(struct dentry
*dentry, struct inode *inode,
        err = -ENOMEM;
        override_cred = prepare_creds();
        if (override_cred) {
-               override_cred->fsuid = inode->i_uid;
-               override_cred->fsgid = inode->i_gid;
                if (!attr->hardlink) {
+                       override_cred->fsuid = inode->i_uid;
+                       override_cred->fsgid = inode->i_gid;
                        err = security_dentry_create_files_as(dentry,
                                        attr->mode, &dentry->d_name, old_cred,
                                        override_cred);
@@ -605,6 +607,9 @@ static int ovl_create_or_link(struct dentry
*dentry, struct inode *inode,
                                put_cred(override_cred);
                                goto out_revert_creds;
                        }
+               } else {
+                       override_cred->fsuid = caller_fsuid;
+                       override_cred->fsgid = caller_fsgid;
                }
                put_cred(override_creds(override_cred));
                put_cred(override_cred);

As I said before, I think this is acceptable to use the caller's
fsuid. But I still feel a little conflicted with the overlay's design.
Because I am not sure if there should be some difference between
link() and unlink() after commit 51f7e52dc943 ("ovl: share inode for
hard link") remove the creation in ovl_link().

  reply	other threads:[~2022-08-17 11:37 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-17  3:45 [PATCH] ovl: Do not override fsuid and fsgid in ovl_link() Zhang Tianci
2022-08-17  7:36 ` Amir Goldstein
2022-08-17  9:11   ` [External] " 天赐张
2022-08-17  9:53     ` Amir Goldstein
2022-08-17  9:55       ` Amir Goldstein
2022-08-17 10:27         ` Christian Brauner
2022-08-17 10:29           ` Christian Brauner
2022-08-17 11:36             ` 天赐张 [this message]
2022-08-17 11:56               ` Christian Brauner
2022-08-17 12:29                 ` Christian Brauner
2022-08-17 12:37                   ` Christian Brauner
2022-08-25  8:46                     ` 天赐张

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAP4dvscpm2FyuJ6gqZz=32ffrN9BORaa=Q0grPEgB+KUXbJniw@mail.gmail.com' \
    --to=zhangtianci.1997@bytedance.com \
    --cc=amir73il@gmail.com \
    --cc=brauner@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-unionfs@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=zhangjiachen.jaycee@bytedance.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.