Bug 1269169 - Unable to remount nfs 4.0 partition when using kerberos
Unable to remount nfs 4.0 partition when using kerberos
Status: CLOSED NEXTRELEASE
Product: nfs-ganesha
Classification: Community
Component: NFS (Show other bugs)
unspecified
x86_64 Linux
unspecified Severity unspecified
: ---
: ---
Assigned To: Frank Filz
:
Depends On:
Blocks: 1329950
  Show dependency treegraph
 
Reported: 2015-10-06 09:50 EDT by Alexander Bersenev
Modified: 2016-05-23 11:43 EDT (History)
2 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2016-05-23 11:43:31 EDT
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Alexander Bersenev 2015-10-06 09:50:46 EDT
(originally reported at https://github.com/nfs-ganesha/nfs-ganesha/issues/59)

When nfs 4.0 is used and partition is unmounted an then mounted on the same client the error occurs:

$ mount.nfs4 -o sec=krb5i,minorversion=0 example.com:/dir1/ /mnt/nfs
mount.nfs4: Operation not permitted
This error stops to occur after 60 seconds, or after Lease_Lifetime, if set.

The "operation not permitted" is reported because SETCLIENTID nfs call returns NFS4ERR_CLID_INUSE.

From src/Protocols/NFS/nfs4_op_setclientid.c, nfs4_op_setclientid function:

if (!nfs_compare_clientcred(&conf->cid_credential,
                    &data->credential)  ...)  { 
... return NFS4ERR_CLID_INUSE ... 
}
The nfs_compare_clientcred function(src/support/nfs_creds.c) compares old credential for this client with new credential:

bool nfs_compare_clientcred(nfs_client_cred_t *cred1,
            nfs_client_cred_t *cred2)
{
     // ..
 switch (cred1->flavor) {
 case AUTH_UNIX:
          // ... handling AUTH UNIX ...
 default:
    if (memcmp
        (&cred1->auth_union, &cred2->auth_union, cred1->length))
        return false;
    break;
 }
}
In the case of RPCSEC_GSS the memcmp is used which compares two structs of:
auth_gss = {svc, qop, gss_context_id}

The result of comparison of two structs is always false, because gss_context_id is a handle.

Because of this, if the same client unmounts and mounts the nfs partition in a lease time, the access is denied. Also, this will occur in case of connection problems.

From RFC 3530, page 67:

As a security measure, the server MUST NOT cancel a client's leased
   state if the principal established the state for a given id string is
   not the same as the principal issuing the SETCLIENTID.
(so it is possible to check a principals, not handles)

...

Note that if the id string in a SETCLIENTID request is properly
constructed, and if the client takes care to use the same principal
for each successive use of SETCLIENTID, then, barring an active
denial of service attack, NFS4ERR_CLID_INUSE should never be
returned.

However, client bugs, server bugs, or perhaps a deliberate change of
the principal owner of the id string (such as the case of a client
that changes security flavors, and under the new flavor, there is no
mapping to the previous owner) will in rare cases result in
NFS4ERR_CLID_INUSE.




Best,
Alexander Bersenev
Comment 1 Alexander Bersenev 2015-10-06 09:51:30 EDT
Here is an example of a patch:

diff --git a/src/support/nfs_creds.c b/src/support/nfs_creds.c
index 15c6623..e2b2701 100644
--- a/src/support/nfs_creds.c
+++ b/src/support/nfs_creds.c
@@ -114,6 +114,13 @@ void squash_setattr(struct attrlist *attr)
 bool nfs_compare_clientcred(nfs_client_cred_t *cred1,
                nfs_client_cred_t *cred2)
 {
+#ifdef _HAVE_GSSAPI
+   gss_name_t cred1_cred_name;
+   gss_name_t cred2_cred_name;
+   OM_uint32 maj_stat, min_stat;
+   int status;
+#endif
+
    if (cred1 == NULL)
        return false;
    if (cred2 == NULL)
@@ -132,6 +139,38 @@ bool nfs_compare_clientcred(nfs_client_cred_t *cred1,
            return false;
        break;

+#ifdef _HAVE_GSSAPI
+   case RPCSEC_GSS:
+       maj_stat =
+           gss_inquire_context(&min_stat,
+               cred1->auth_union.auth_gss.gss_context_id,
+               &cred1_cred_name, NULL, NULL, NULL, NULL, NULL, NULL);
+
+       if(maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTEXT_EXPIRED) {
+           return false;
+       }
+
+       maj_stat =
+           gss_inquire_context(&min_stat,
+               cred2->auth_union.auth_gss.gss_context_id,
+               &cred2_cred_name, NULL, NULL, NULL, NULL, NULL, NULL);
+
+       if(maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTEXT_EXPIRED) {
+           return false;
+       }
+
+       maj_stat = gss_compare_name(&min_stat, cred1_cred_name, cred2_cred_name, &status);
+       if(maj_stat != GSS_S_COMPLETE) {
+           return false;
+       }
+
+       if(status == 0) {
+           return false;
+       }
+
+       break;
+#endif
+
    default:
        if (memcmp
            (&cred1->auth_union, &cred2->auth_union, cred1->length))
I am not sure about it, so it's need to be checked.

About expired credentials(RFC 3530):

In that event, when the server gets a SETCLIENTID for a client id
that currently has no state, or it has state, but the lease has
expired, rather than returning NFS4ERR_CLID_INUSE, the server MUST
allow the SETCLIENTID, and confirm the new clientid if followed by
the appropriate SETCLIENTID_CONFIRM.
Comment 2 Soumya Koduri 2016-04-22 03:36:41 EDT
Hi Alexander,

We are hitting similar issue and would appreciate  if you could submit the fix for review using "https://review.gerrithub.io/#/q/project:ffilz/nfs-ganesha" and get it merged. Thanks!
Comment 3 Alexander Bersenev 2016-05-23 08:41:22 EDT
Hello,

It was submitted by Frank Filz on https://review.gerrithub.io/#/c/274710/. The page shows it merged.

Best,
Alexander Bersenev
Comment 4 Soumya Koduri 2016-05-23 11:43:31 EDT
yes. Thanks for the fix!

Note You need to log in before you can comment on or make changes to this bug.