Re: [PATCH v2] nfsd: refine and rename NFSD_MAY_LOCK

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Mar 12, 2025 at 8:09 PM NeilBrown <neilb@xxxxxxx> wrote:
>
> On Thu, 13 Mar 2025, Olga Kornievskaia wrote:
> > On Wed, Mar 12, 2025 at 9:22 AM Olga Kornievskaia <aglo@xxxxxxxxx> wrote:
> > >
> > > On Tue, Mar 11, 2025 at 5:42 PM NeilBrown <neilb@xxxxxxx> wrote:
> > > >
> > > > On Wed, 12 Mar 2025, Olga Kornievskaia wrote:
> > > > > On Tue, Mar 11, 2025 at 11:28 AM Olga Kornievskaia <aglo@xxxxxxxxx> wrote:
> > > > > >
> > > > > > On Thu, Oct 17, 2024 at 5:42 PM NeilBrown <neilb@xxxxxxx> wrote:
> > > > > > >
> > > > > > >
> > > > > > > NFSD_MAY_LOCK means a few different things.
> > > > > > > - it means that GSS is not required.
> > > > > > > - it means that with NFSEXP_NOAUTHNLM, authentication is not required
> > > > > > > - it means that OWNER_OVERRIDE is allowed.
> > > > > > >
> > > > > > > None of these are specific to locking, they are specific to the NLM
> > > > > > > protocol.
> > > > > > > So:
> > > > > > >  - rename to NFSD_MAY_NLM
> > > > > > >  - set NFSD_MAY_OWNER_OVERRIDE and NFSD_MAY_BYPASS_GSS in nlm_fopen()
> > > > > > >    so that NFSD_MAY_NLM doesn't need to imply these.
> > > > > > >  - move the test on NFSEXP_NOAUTHNLM out of nfsd_permission() and
> > > > > > >    into fh_verify where other special-case tests on the MAY flags
> > > > > > >    happen.  nfsd_permission() can be called from other places than
> > > > > > >    fh_verify(), but none of these will have NFSD_MAY_NLM.
> > > > > >
> > > > > > This patch breaks NLM when used in combination with TLS.
> > > > >
> > > > > I was too quick to link this to TLS. It's presence of security policy
> > > > > so sec=krb* causes the same problems.
> > > > >
> > > > > >  If exports
> > > > > > have xprtsec=tls:mtls and mount is done with tls/mtls, the server
> > > > > > won't give any locks and client will get "no locks available" error.
> > > > > >
> > > > > > >
> > > > > > > Signed-off-by: NeilBrown <neilb@xxxxxxx>
> > > > > > > ---
> > > > > > >
> > > > > > > No change from previous patch - the corruption in the email has been
> > > > > > > avoided (I hope).
> > > > > > >
> > > > > > >
> > > > > > >  fs/nfsd/lockd.c | 13 +++++++++++--
> > > > > > >  fs/nfsd/nfsfh.c | 12 ++++--------
> > > > > > >  fs/nfsd/trace.h |  2 +-
> > > > > > >  fs/nfsd/vfs.c   | 12 +-----------
> > > > > > >  fs/nfsd/vfs.h   |  2 +-
> > > > > > >  5 files changed, 18 insertions(+), 23 deletions(-)
> > > > > > >
> > > > > > > diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
> > > > > > > index 46a7f9b813e5..edc9f75dc75c 100644
> > > > > > > --- a/fs/nfsd/lockd.c
> > > > > > > +++ b/fs/nfsd/lockd.c
> > > > > > > @@ -38,11 +38,20 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp,
> > > > > > >         memcpy(&fh.fh_handle.fh_raw, f->data, f->size);
> > > > > > >         fh.fh_export = NULL;
> > > > > > >
> > > > > > > +       /*
> > > > > > > +        * Allow BYPASS_GSS as some client implementations use AUTH_SYS
> > > > > > > +        * for NLM even when GSS is used for NFS.
> > > > > > > +        * Allow OWNER_OVERRIDE as permission might have been changed
> > > > > > > +        * after the file was opened.
> > > > > > > +        * Pass MAY_NLM so that authentication can be completely bypassed
> > > > > > > +        * if NFSEXP_NOAUTHNLM is set.  Some older clients use AUTH_NULL
> > > > > > > +        * for NLM requests.
> > > > > > > +        */
> > > > > > >         access = (mode == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ;
> > > > > > > -       access |= NFSD_MAY_LOCK;
> > > > > > > +       access |= NFSD_MAY_NLM | NFSD_MAY_OWNER_OVERRIDE | NFSD_MAY_BYPASS_GSS;
> > > > > > >         nfserr = nfsd_open(rqstp, &fh, S_IFREG, access, filp);
> > > > > > >         fh_put(&fh);
> > > > > > > -       /* We return nlm error codes as nlm doesn't know
> > > > > > > +       /* We return nlm error codes as nlm doesn't know
> > > > > > >          * about nfsd, but nfsd does know about nlm..
> > > > > > >          */
> > > > > > >         switch (nfserr) {
> > > > > > > diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
> > > > > > > index 40533f7c7297..6a831cb242df 100644
> > > > > > > --- a/fs/nfsd/nfsfh.c
> > > > > > > +++ b/fs/nfsd/nfsfh.c
> > > > > > > @@ -363,13 +363,10 @@ __fh_verify(struct svc_rqst *rqstp,
> > > > > > >         if (error)
> > > > > > >                 goto out;
> > > > > > >
> > > > > > > -       /*
> > > > > > > -        * pseudoflavor restrictions are not enforced on NLM,
> > > > > > > -        * which clients virtually always use auth_sys for,
> > > > > > > -        * even while using RPCSEC_GSS for NFS.
> > > > > > > -        */
> > > > > > > -       if (access & NFSD_MAY_LOCK)
> > > > > > > -               goto skip_pseudoflavor_check;
> > > > > > > +       if ((access & NFSD_MAY_NLM) && (exp->ex_flags & NFSEXP_NOAUTHNLM))
> > > > >
> > > > > I think this should either be an OR or the fact that "nlm but only
> > > > > with insecurelock export option and not other" is the only way to
> > > > > bypass checking is wrong. I think it's just a check for NLM that
> > > > > stays.
> > > >
> > > > I don't think that NLM gets a complete bypass unless no_auth_nlm is set.
> > > > For the case you are describing, I think NFSD_MAY_BYPASS_GSS is supposed
> > > > to make it work.
> > > >
> > > > I assume the NLM request is arriving with AUTH_SYS authentication?
> > >
> > > It does.
> > >
> > > Just to give you a practical example. exports have
> > > (rw,...,sec=krb5:krb5i:krb5p). Client does mount with sec=krb5. Then
> > > does an flock() on the file. What's more I have just now hit Kasan's
> > > out-of-bounds warning on that. I'll have to see if that exists on 6.14
> > > (as I'm debugging the matter on the commit of the patch itself and
> > > thus on 6.12-rc now).
> > >
> > > I will layout more reasoning but what allowed NLM to work was this
> > > -       /*
> > > -        * pseudoflavor restrictions are not enforced on NLM,
> > > -        * which clients virtually always use auth_sys for,
> > > -        * even while using RPCSEC_GSS for NFS.
> > > -        */
> > > -       if (access & NFSD_MAY_LOCK)
> > > -               goto skip_pseudoflavor_check;
> > >
> > > but I don't know why the replacement doesn't work.
> >
> > As I mentioned the patch removed the skip_pseudoflavor check (that for
> > NLM) would have bypassed calling check_nfsd_access(). Instead, the
> > problem is that even though may_bypass_gss is set to true it call into
> > nfsd4_spo_must_allow(rqstp) which now wrongly assumes there is
> > compound state (struct nfsd4_compound_state *cstate = &resp->cstate;)
> > ... (but this is NLM). So it proceed to deference it if
> > (!cstate->minorversion) causing the KASAN to do the out-of-bound error
> > that I mentioned. It most of the time now cause a crash. But on the
> > off non-deterministic times when it completes it fails.
> >
> > I really don't think calling into check_nfsd_access() is appropriate for NLM.
>
> Why not?  What is there is inherently inappropriate for NLM?

I spoke too soon. It's not about calling into check_nfsd_acces()
(though it's a problem for v3 because there isn't a compound state!).
The real problem is "access" content that's being passed into the
nfsd_permission() function.

I don't fully understand the logic. But before this patch, "access"
(acc) was (re)set to "NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE" before
calling into inode_permission():
@@ -2534,16 +2534,6 @@ nfsd_permission(struct svc_cred *cred, struct
svc_export *exp,
        if ((acc & NFSD_MAY_TRUNC) && IS_APPEND(inode))
                return nfserr_perm;

-       if (acc & NFSD_MAY_LOCK) {
-               /* If we cannot rely on authentication in NLM requests,
-                * just allow locks, otherwise require read permission, or
-                * ownership
-                */
-               if (exp->ex_flags & NFSEXP_NOAUTHNLM)
-                       return 0;
-               else
-                       acc = NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE;
-       }
        /*
         * The file owner always gets access permission for accesses that
         * would normally be checked at open time. This is to make

now it's doesn't get "reset" and passes all of what was set in nlm_fopen()

       access = (mode == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ;
-       access |= NFSD_MAY_LOCK;
+       access |= NFSD_MAY_NLM | NFSD_MAY_OWNER_OVERRIDE | NFSD_MAY_BYPASS_GSS;

which ends up being "write" instead of a read and inode_permission returned -13.

Here's my proposed fix for one the problems in the patch.

diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 4021b047eb18..eb139962ac4c 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -2600,6 +2600,9 @@ nfsd_permission(struct svc_cred *cred, struct
svc_export *exp,
            uid_eq(inode->i_uid, current_fsuid()))
                return 0;

+       if (acc & NFSD_MAY_NLM)
+               acc = NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE;
+
        /* This assumes  NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */
        err = inode_permission(&nop_mnt_idmap, inode,
                               acc & (MAY_READ | MAY_WRITE | MAY_EXEC));

Now the 2nd problem. You mentioned checking for version before calling
nfsd4_spo_must_allow for v3. So something like this perhaps but not
sure if that's right?

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 0363720280d4..0106da76da89 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1148,8 +1148,9 @@ __be32 check_nfsd_access(struct svc_export *exp,
struct svc_rqst *rqstp,
         * don't support it
         */

-       if (nfsd4_spo_must_allow(rqstp))
-               return nfs_ok;
+       if (rqstp->rq_prog == 100003)
+               if (nfsd4_spo_must_allow(rqstp))
+                       return nfs_ok;

        /* Some calls may be processed without authentication
         * on GSS exports. For example NFS2/3 calls on root


In the end, I question, why not revert the original patch instead?

> I agree that calling nfsd4_spo_must_allow(rqstp) isn't appropriate for
> NLM, but it isn't appropriate for v2 or v3 either.  We should add
> version checks either before it is called or before the minorversion
> check that it already has.
>
> NeilBrown
>
>
> >
> > >
> > > > So check_nfsd_access() is being called with may_bypass_gss and this:
> > > >
> > > >         if (may_bypass_gss && (
> > > >              rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
> > > >              rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)) {
> > > >                 for (f = exp->ex_flavors; f < end; f++) {
> > > >                         if (f->pseudoflavor >= RPC_AUTH_DES)
> > > >                                 return 0;
> > > >                 }
> > > >         }
> > > >
> > > > in check_nfsd_access() should succeed.
> > > > Can you add some tracing and see what is happening in here?
> > > > Maybe the "goto denied" earlier in the function is being reached.  I
> > > > don't fully understand the TLS code yet - maybe it needs some test on
> > > > may_bypass_gss.
> > > >
> > > > Thanks,
> > > > NeilBrown
> > > >
> > > >
> > > > >
> > > > > > > +               /* NLM is allowed to fully bypass authentication */
> > > > > > > +               goto out;
> > > > > > > +
> > > > > > >         if (access & NFSD_MAY_BYPASS_GSS)
> > > > > > >                 may_bypass_gss = true;
> > > > > > >         /*
> > > > > > > @@ -385,7 +382,6 @@ __fh_verify(struct svc_rqst *rqstp,
> > > > > > >         if (error)
> > > > > > >                 goto out;
> > > > > > >
> > > > > > > -skip_pseudoflavor_check:
> > > > > > >         /* Finally, check access permissions. */
> > > > > > >         error = nfsd_permission(cred, exp, dentry, access);
> > > > > > >  out:
> > > > > > > diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
> > > > > > > index b8470d4cbe99..3448e444d410 100644
> > > > > > > --- a/fs/nfsd/trace.h
> > > > > > > +++ b/fs/nfsd/trace.h
> > > > > > > @@ -79,7 +79,7 @@ DEFINE_NFSD_XDR_ERR_EVENT(cant_encode);
> > > > > > >                 { NFSD_MAY_READ,                "READ" },               \
> > > > > > >                 { NFSD_MAY_SATTR,               "SATTR" },              \
> > > > > > >                 { NFSD_MAY_TRUNC,               "TRUNC" },              \
> > > > > > > -               { NFSD_MAY_LOCK,                "LOCK" },               \
> > > > > > > +               { NFSD_MAY_NLM,                 "NLM" },                \
> > > > > > >                 { NFSD_MAY_OWNER_OVERRIDE,      "OWNER_OVERRIDE" },     \
> > > > > > >                 { NFSD_MAY_LOCAL_ACCESS,        "LOCAL_ACCESS" },       \
> > > > > > >                 { NFSD_MAY_BYPASS_GSS_ON_ROOT,  "BYPASS_GSS_ON_ROOT" }, \
> > > > > > > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> > > > > > > index 51f5a0b181f9..2610638f4301 100644
> > > > > > > --- a/fs/nfsd/vfs.c
> > > > > > > +++ b/fs/nfsd/vfs.c
> > > > > > > @@ -2509,7 +2509,7 @@ nfsd_permission(struct svc_cred *cred, struct svc_export *exp,
> > > > > > >                 (acc & NFSD_MAY_EXEC)?  " exec"  : "",
> > > > > > >                 (acc & NFSD_MAY_SATTR)? " sattr" : "",
> > > > > > >                 (acc & NFSD_MAY_TRUNC)? " trunc" : "",
> > > > > > > -               (acc & NFSD_MAY_LOCK)?  " lock"  : "",
> > > > > > > +               (acc & NFSD_MAY_NLM)?   " nlm"  : "",
> > > > > > >                 (acc & NFSD_MAY_OWNER_OVERRIDE)? " owneroverride" : "",
> > > > > > >                 inode->i_mode,
> > > > > > >                 IS_IMMUTABLE(inode)?    " immut" : "",
> > > > > > > @@ -2534,16 +2534,6 @@ nfsd_permission(struct svc_cred *cred, struct svc_export *exp,
> > > > > > >         if ((acc & NFSD_MAY_TRUNC) && IS_APPEND(inode))
> > > > > > >                 return nfserr_perm;
> > > > > > >
> > > > > > > -       if (acc & NFSD_MAY_LOCK) {
> > > > > > > -               /* If we cannot rely on authentication in NLM requests,
> > > > > > > -                * just allow locks, otherwise require read permission, or
> > > > > > > -                * ownership
> > > > > > > -                */
> > > > > > > -               if (exp->ex_flags & NFSEXP_NOAUTHNLM)
> > > > > > > -                       return 0;
> > > > > > > -               else
> > > > > > > -                       acc = NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE;
> > > > > > > -       }
> > > > > > >         /*
> > > > > > >          * The file owner always gets access permission for accesses that
> > > > > > >          * would normally be checked at open time. This is to make
> > > > > > > diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
> > > > > > > index 854fb95dfdca..f9b09b842856 100644
> > > > > > > --- a/fs/nfsd/vfs.h
> > > > > > > +++ b/fs/nfsd/vfs.h
> > > > > > > @@ -20,7 +20,7 @@
> > > > > > >  #define NFSD_MAY_READ                  0x004 /* == MAY_READ */
> > > > > > >  #define NFSD_MAY_SATTR                 0x008
> > > > > > >  #define NFSD_MAY_TRUNC                 0x010
> > > > > > > -#define NFSD_MAY_LOCK                  0x020
> > > > > > > +#define NFSD_MAY_NLM                   0x020 /* request is from lockd */
> > > > > > >  #define NFSD_MAY_MASK                  0x03f
> > > > > > >
> > > > > > >  /* extra hints to permission and open routines: */
> > > > > > >
> > > > > > > base-commit: c4e418a53fe30d8e1da68f5aabca352b682fd331
> > > > > > > --
> > > > > > > 2.46.0
> > > > > > >
> > > > > > >
> > > > >
> >
>





[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux