All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/4] Improving WRONGSEC recovery during lookup_root
@ 2013-02-06 23:29 Chuck Lever
  2013-02-06 23:30 ` [PATCH v1 1/4] NFS: Handle missing rpc.gssd when looking up root FH Chuck Lever
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Chuck Lever @ 2013-02-06 23:29 UTC (permalink / raw)
  To: linux-nfs

I've been playing with some improvements to how the Linux NFS client
behaves when a server requires a stronger security flavor than
AUTH_UNIX to access its pseudo-fs.

AUTH_UNIX is the default flavor our client uses when no security
flavor preference was specified on the mount command.  The client
has to be smart enough to negotiate the security flavor when the
server may require something a little stronger.

Typically servers take a union of security flavors on all their
current real shares and use that set as the security flavors
required for the pseudo-fs.  If a server's real shares are exported
with only various flavors of Kerberos, for instance, then the
server's pseudo-fs will not allow AUTH_UNIX access, though the
server might still allow a SETCLIENTID operation with AUTH_UNIX in
this case.

This work is also relevant if we want to consider using an
integrity-protecting security flavor for lease management operations
(such as SETCLIENTID and RENEW) while allowing other flavors for
accessing data or the pseudo-fs.

Version 1 of this series is the result.  I've done some testing with
a Linux NFS server configured to require a flavor of Kerberos to
access its pseudo-fs.  I also tried some testing with a Solaris NFS
server.

Bryan, I copied you because you originally wrote the find_root_sec
code: any comments, review, or testing is appreciated.

---

Chuck Lever (4):
      NFS: Use static list of security flavors during root FH lookup recovery
      NFS: Avoid PUTROOTFH when managing leases
      NFS: Clean up nfs4_proc_get_rootfh
      NFS: Handle missing rpc.gssd when looking up root FH


 fs/nfs/nfs4proc.c |  134 ++++++++++++++++++++++++++++++++++++++++-------------
 fs/nfs/nfs4xdr.c  |   18 +------
 2 files changed, 104 insertions(+), 48 deletions(-)

-- 
Chuck Lever

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v1 1/4] NFS: Handle missing rpc.gssd when looking up root FH
  2013-02-06 23:29 [PATCH v1 0/4] Improving WRONGSEC recovery during lookup_root Chuck Lever
@ 2013-02-06 23:30 ` Chuck Lever
  2013-02-06 23:30 ` [PATCH v1 2/4] NFS: Clean up nfs4_proc_get_rootfh Chuck Lever
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Chuck Lever @ 2013-02-06 23:30 UTC (permalink / raw)
  To: linux-nfs; +Cc: Chuck Lever, Bryan Schumaker

When rpc.gssd is not running, any NFS operation that needs to use a
GSS security flavor of course does not work.

If looking up a server's root file handle results in an
NFS4ERR_WRONGSEC, nfs4_find_root_sec() is called to try a bunch of
security flavors until one works (or until all reasonable flavors
are tried).  But if rpc.gssd isn't running, it seems to fail
immediately after rpcauth_create() craps out on the first GSS
flavor.

When the rpcauth_create() call in nfs4_lookup_root_sec() fails
because rpc.gssd is not available, nfs4_lookup_root_sec()
unconditionally returns -EIO.  This prevents nfs4_find_root_sec()
from retrying any other flavors; it drops out of its loop and fails
immediately.

Having nfs4_lookup_root_sec() return -EACCES instead allows
nfs4_find_root_sec() to try all flavors in its list.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Cc: Bryan Schumaker <bjschuma@netapp.com>
---

 fs/nfs/nfs4proc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index cf747ef..debeb2d 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2408,7 +2408,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
 
 	auth = rpcauth_create(flavor, server->client);
 	if (IS_ERR(auth)) {
-		ret = -EIO;
+		ret = -EACCES;
 		goto out;
 	}
 	ret = nfs4_lookup_root(server, fhandle, info);


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v1 2/4] NFS: Clean up nfs4_proc_get_rootfh
  2013-02-06 23:29 [PATCH v1 0/4] Improving WRONGSEC recovery during lookup_root Chuck Lever
  2013-02-06 23:30 ` [PATCH v1 1/4] NFS: Handle missing rpc.gssd when looking up root FH Chuck Lever
@ 2013-02-06 23:30 ` Chuck Lever
  2013-02-06 23:30 ` [PATCH v1 3/4] NFS: Avoid PUTROOTFH when managing leases Chuck Lever
  2013-02-06 23:30 ` [PATCH v1 4/4] NFS: Use static list of security flavors during root FH lookup recovery Chuck Lever
  3 siblings, 0 replies; 5+ messages in thread
From: Chuck Lever @ 2013-02-06 23:30 UTC (permalink / raw)
  To: linux-nfs; +Cc: Chuck Lever, Bryan Schumaker

The long lines with no vertical white space make this function
difficult for humans to read.  Add a proper documenting comment
while we're here.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Cc: Bryan Schumaker <bjschuma@netapp.com>
---

 fs/nfs/nfs4proc.c |   32 ++++++++++++++++++++++----------
 1 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index debeb2d..ad86cfa 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2449,24 +2449,36 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
 	return status;
 }
 
-/*
- * get the file handle for the "/" directory on the server
+static int nfs4_do_find_root_sec(struct nfs_server *server,
+		struct nfs_fh *fhandle, struct nfs_fsinfo *info)
+{
+	int mv = server->nfs_client->cl_minorversion;
+	return nfs_v4_minor_ops[mv]->find_root_sec(server, fhandle, info);
+}
+
+/**
+ * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
+ * @server: initialized nfs_server handle 
+ * @fhandle: we fill in the pseudo-fs root file handle
+ * @info: we fill in an FSINFO struct
+ *
+ * Returns zero on success, or a negative errno.
  */
 int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
 			 struct nfs_fsinfo *info)
 {
-	int minor_version = server->nfs_client->cl_minorversion;
-	int status = nfs4_lookup_root(server, fhandle, info);
-	if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR))
-		/*
-		 * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM
-		 * by nfs4_map_errors() as this function exits.
-		 */
-		status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info);
+	int status;
+
+	status = nfs4_lookup_root(server, fhandle, info);
+	if ((status == -NFS4ERR_WRONGSEC) &&
+	    !(server->flags & NFS_MOUNT_SECFLAVOUR))
+		status = nfs4_do_find_root_sec(server, fhandle, info);
+
 	if (status == 0)
 		status = nfs4_server_capabilities(server, fhandle);
 	if (status == 0)
 		status = nfs4_do_fsinfo(server, fhandle, info);
+
 	return nfs4_map_errors(status);
 }
 


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v1 3/4] NFS: Avoid PUTROOTFH when managing leases
  2013-02-06 23:29 [PATCH v1 0/4] Improving WRONGSEC recovery during lookup_root Chuck Lever
  2013-02-06 23:30 ` [PATCH v1 1/4] NFS: Handle missing rpc.gssd when looking up root FH Chuck Lever
  2013-02-06 23:30 ` [PATCH v1 2/4] NFS: Clean up nfs4_proc_get_rootfh Chuck Lever
@ 2013-02-06 23:30 ` Chuck Lever
  2013-02-06 23:30 ` [PATCH v1 4/4] NFS: Use static list of security flavors during root FH lookup recovery Chuck Lever
  3 siblings, 0 replies; 5+ messages in thread
From: Chuck Lever @ 2013-02-06 23:30 UTC (permalink / raw)
  To: linux-nfs; +Cc: Chuck Lever, Bryan Schumaker

Currently, the compound operation the Linux NFS client sends to the
server to confirm a client ID looks like this:

	{ SETCLIENTID_CONFIRM; PUTROOTFH; GETATTR(lease_time) }

Performing these operations together saves a round trip.

Unfortunately, this arrangement assumes that the security flavor
used for establishing a client ID can also be used to access the
server's pseudo-fs.

If the server requires a different security flavor to access its
pseudo-fs than it allowed for the client's SETCLIENTID operation,
the PUTROOTFH in this compound fails with NFS4ERR_WRONGSEC.  Even
though the SETCLIENTID_CONFIRM succeeded, our client's trunking
detection logic interprets the failure of the compound as a failure
by the server to confirm the client ID.

As part of server trunking detection, the client thus begins another
SETCLIENTID pass with the same nfs4_client_id.  This fails with
NFS4ERR_CLID_INUSE because the first SETCLIENTID/SETCLIENTID_CONFIRM
already succeeded in confirming that client ID -- it was the
PUTROOTFH operation that caused the SETCLIENTID_CONFIRM compound to
fail.

This commit separates the "establish client ID" step from the
"accessing the server's pseudo-fs root" step.  The first access of
the server's pseudo-fs may require retrying the PUTROOTFH operation
with different security flavors.

That leaves the matter of how to retrieve the server's lease time.
Do this in nfs4_proc_get_rootfh() after we are certain that the
rpc_clnt's security flavor is correct for accessing the root FH.

Note that NFSv4.1 state recovery invokes nfs4_proc_get_lease_time()
using the lease management security flavor.  This may cause some
heartburn if that security flavor isn't the same as the security
flavor the server requires for accessing the pseudo-fs.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Cc: Bryan Schumaker <bjschuma@netapp.com>
---

 fs/nfs/nfs4proc.c |   68 +++++++++++++++++++++++++++++++++++++++++++++--------
 fs/nfs/nfs4xdr.c  |   18 ++------------
 2 files changed, 61 insertions(+), 25 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ad86cfa..6f1055b 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2449,6 +2449,62 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
 	return status;
 }
 
+static int _nfs4_get_lease_time(struct nfs_server *server,
+		struct nfs_fh *fhandle)
+{
+	const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
+	struct nfs_fsinfo info;
+	struct nfs4_fsinfo_arg args = {
+		.fh = fhandle,
+		.bitmask = lease_bitmap,
+	};
+	struct nfs4_fsinfo_res res = {
+		.fsinfo = &info,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO],
+		.rpc_argp = &args,
+		.rpc_resp = &res,
+	};
+	unsigned long now;
+	int status;
+
+	dprintk("NFS call  get_lease_time\n");
+
+	now = jiffies;
+	status = nfs4_call_sync(server->client, server, &msg,
+					&args.seq_args, &res.seq_res, 0);
+	if (status == 0) {
+		struct nfs_client *clp = server->nfs_client;
+
+		spin_lock(&clp->cl_lock);
+		clp->cl_lease_time = info.lease_time * HZ;
+		clp->cl_last_renewal = now;
+		spin_unlock(&clp->cl_lock);
+	}
+	dprintk("NFS reply get_lease_time: %d\n", status);
+	return status;
+}
+
+static int nfs4_get_lease_time(struct nfs_server *server,
+		struct nfs_fh *fhandle)
+{
+	struct nfs4_exception exception = { };
+	int err;
+	do {
+		err = _nfs4_get_lease_time(server, fhandle);
+		switch (err) {
+		case 0:
+		case -NFS4ERR_WRONGSEC:
+			goto out;
+		default:
+			err = nfs4_handle_exception(server, err, &exception);
+		}
+	} while (exception.retry);
+out:
+	return err;
+}
+
 static int nfs4_do_find_root_sec(struct nfs_server *server,
 		struct nfs_fh *fhandle, struct nfs_fsinfo *info)
 {
@@ -2475,6 +2531,8 @@ int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
 		status = nfs4_do_find_root_sec(server, fhandle, info);
 
 	if (status == 0)
+		status = nfs4_get_lease_time(server, fhandle);
+	if (status == 0)
 		status = nfs4_server_capabilities(server, fhandle);
 	if (status == 0)
 		status = nfs4_do_fsinfo(server, fhandle, info);
@@ -4120,27 +4178,17 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
 		struct nfs4_setclientid_res *arg,
 		struct rpc_cred *cred)
 {
-	struct nfs_fsinfo fsinfo;
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
 		.rpc_argp = arg,
-		.rpc_resp = &fsinfo,
 		.rpc_cred = cred,
 	};
-	unsigned long now;
 	int status;
 
 	dprintk("NFS call  setclientid_confirm auth=%s, (client ID %llx)\n",
 		clp->cl_rpcclient->cl_auth->au_ops->au_name,
 		clp->cl_clientid);
-	now = jiffies;
 	status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
-	if (status == 0) {
-		spin_lock(&clp->cl_lock);
-		clp->cl_lease_time = fsinfo.lease_time * HZ;
-		clp->cl_last_renewal = now;
-		spin_unlock(&clp->cl_lock);
-	}
 	dprintk("NFS reply setclientid_confirm: %d\n", status);
 	return status;
 }
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index c445b8c..66eafa5 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -530,14 +530,10 @@ static int nfs4_stat_to_errno(int);
 				decode_setclientid_maxsz)
 #define NFS4_enc_setclientid_confirm_sz \
 				(compound_encode_hdr_maxsz + \
-				encode_setclientid_confirm_maxsz + \
-				encode_putrootfh_maxsz + \
-				encode_fsinfo_maxsz)
+				encode_setclientid_confirm_maxsz)
 #define NFS4_dec_setclientid_confirm_sz \
 				(compound_decode_hdr_maxsz + \
-				decode_setclientid_confirm_maxsz + \
-				decode_putrootfh_maxsz + \
-				decode_fsinfo_maxsz)
+				decode_setclientid_confirm_maxsz)
 #define NFS4_enc_lock_sz        (compound_encode_hdr_maxsz + \
 				encode_sequence_maxsz + \
 				encode_putfh_maxsz + \
@@ -2609,12 +2605,9 @@ static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
 	struct compound_hdr hdr = {
 		.nops	= 0,
 	};
-	const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
 
 	encode_compound_hdr(xdr, req, &hdr);
 	encode_setclientid_confirm(xdr, arg, &hdr);
-	encode_putrootfh(xdr, &hdr);
-	encode_fsinfo(xdr, lease_bitmap, &hdr);
 	encode_nops(&hdr);
 }
 
@@ -6650,8 +6643,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req,
  * Decode SETCLIENTID_CONFIRM response
  */
 static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
-					    struct xdr_stream *xdr,
-					    struct nfs_fsinfo *fsinfo)
+					    struct xdr_stream *xdr)
 {
 	struct compound_hdr hdr;
 	int status;
@@ -6659,10 +6651,6 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
 	status = decode_compound_hdr(xdr, &hdr);
 	if (!status)
 		status = decode_setclientid_confirm(xdr);
-	if (!status)
-		status = decode_putrootfh(xdr);
-	if (!status)
-		status = decode_fsinfo(xdr, fsinfo);
 	return status;
 }
 


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v1 4/4] NFS: Use static list of security flavors during root FH lookup recovery
  2013-02-06 23:29 [PATCH v1 0/4] Improving WRONGSEC recovery during lookup_root Chuck Lever
                   ` (2 preceding siblings ...)
  2013-02-06 23:30 ` [PATCH v1 3/4] NFS: Avoid PUTROOTFH when managing leases Chuck Lever
@ 2013-02-06 23:30 ` Chuck Lever
  3 siblings, 0 replies; 5+ messages in thread
From: Chuck Lever @ 2013-02-06 23:30 UTC (permalink / raw)
  To: linux-nfs; +Cc: Chuck Lever, Bryan Schumaker

If the Linux NFS client receives an NFS4ERR_WRONGSEC error while
trying to look up an NFS server's root file handle, it retries the
lookup operation with various security flavors to see what flavor
the NFS server will accept for pseudo-fs access.

The list of flavors the client uses during retry consists only of
flavors that are currently registered in the kernel RPC client.
This list may exclude the GSS pseudoflavors if auth_rpcgss.ko has
not yet been loaded.

Let's instead use a static list of security flavors that the NFS
standard requires the server to implement (RFC 3530bis, section
3.2.1).  The RPC client should now be able to load support for
these dynamically; if not, they are skipped.

Recovery behavior here is prescribed by RFC 3530bis, section
15.33.5:

> For LOOKUPP, PUTROOTFH and PUTPUBFH, the client will be unable to
> use the SECINFO operation since SECINFO requires a current
> filehandle and none exist for these two [sic] operations.  Therefore,
> the client must iterate through the security triples available at
> the client and reattempt the PUTROOTFH or PUTPUBFH operation.  In
> the unfortunate event none of the MANDATORY security triples are
> supported by the client and server, the client SHOULD try using
> others that support integrity.  Failing that, the client can try
> using AUTH_NONE, but because such forms lack integrity checks,
> this puts the client at risk.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Cc: Bryan Schumaker <bjschuma@netapp.com>
---

 fs/nfs/nfs4proc.c |   32 ++++++++++++++++++++------------
 1 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 6f1055b..e0fe351f 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2416,27 +2416,35 @@ out:
 	return ret;
 }
 
+/*
+ * Retry pseudoroot lookup with various security flavors.  We do this when:
+ *
+ *   NFSv4.0: the PUTROOTFH operation returns NFS4ERR_WRONGSEC
+ *   NFSv4.1: the server does not support the SECINFO_NO_NAME operation
+ *
+ * Returns zero on success, or a negative NFS4ERR value, or a
+ * negative errno value.
+ */
 static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
 			      struct nfs_fsinfo *info)
 {
-	int i, len, status = 0;
-	rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];
-
-	len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array));
-	if (len < 0)
-		return len;
-
-	for (i = 0; i < len; i++) {
-		/* AUTH_UNIX is the default flavor if none was specified,
-		 * thus has already been tried. */
-		if (flav_array[i] == RPC_AUTH_UNIX)
-			continue;
+	/* Per 3530bis 15.33.5 */
+	static const rpc_authflavor_t flav_array[] = {
+		RPC_AUTH_GSS_KRB5P,
+		RPC_AUTH_GSS_KRB5I,
+		RPC_AUTH_GSS_KRB5,
+		RPC_AUTH_NULL,
+	};
+	int status = -EPERM;
+	size_t i;
 
+	for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
 		status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
 		if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
 			continue;
 		break;
 	}
+
 	/*
 	 * -EACCESS could mean that the user doesn't have correct permissions
 	 * to access the mount.  It could also mean that we tried to mount


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-02-06 23:30 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-06 23:29 [PATCH v1 0/4] Improving WRONGSEC recovery during lookup_root Chuck Lever
2013-02-06 23:30 ` [PATCH v1 1/4] NFS: Handle missing rpc.gssd when looking up root FH Chuck Lever
2013-02-06 23:30 ` [PATCH v1 2/4] NFS: Clean up nfs4_proc_get_rootfh Chuck Lever
2013-02-06 23:30 ` [PATCH v1 3/4] NFS: Avoid PUTROOTFH when managing leases Chuck Lever
2013-02-06 23:30 ` [PATCH v1 4/4] NFS: Use static list of security flavors during root FH lookup recovery Chuck Lever

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.