linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "J. Bruce Fields" <bfields@redhat.com>
To: Olga Kornievskaia <aglo@umich.edu>
Cc: Trond Myklebust <trond.myklebust@primarydata.com>,
	linux-nfs <linux-nfs@vger.kernel.org>,
	"J. Bruce Fields" <bfields@redhat.com>
Subject: [PATCH 2/2] nfsd4: catch some false session retries
Date: Wed, 18 Oct 2017 17:25:19 -0400	[thread overview]
Message-ID: <1508361919-30495-2-git-send-email-bfields@redhat.com> (raw)
In-Reply-To: <1508361919-30495-1-git-send-email-bfields@redhat.com>

From: "J. Bruce Fields" <bfields@redhat.com>

The spec allows us to return NFS4ERR_SEQ_FALSE_RETRY if we notice that
the client is making a call that matches a previous (slot, seqid) pair
but that *isn't* actually a replay, because some detail of the call
doesn't actually match the previous one.

Catching every such case is difficult, but we may as well catch a few
easy ones.  This also handles the case described in the previous patch,
in a different way.

The spec does however require us to catch the case where the difference
is in the rpc credentials.  This prevents somebody from snooping another
user's replies by fabricating retries.

(But the practical value of the attack is limited by the fact that the
replies with the most sensitive data are READ replies, which are not
normally cached.)

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
 fs/nfsd/nfs4state.c | 37 ++++++++++++++++++++++++++++++++++++-
 fs/nfsd/state.h     |  1 +
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 7bd3ad88b85c..a9efdfe5e62f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1439,8 +1439,10 @@ free_session_slots(struct nfsd4_session *ses)
 {
 	int i;
 
-	for (i = 0; i < ses->se_fchannel.maxreqs; i++)
+	for (i = 0; i < ses->se_fchannel.maxreqs; i++) {
+		free_svc_cred(&ses->se_slots[i]->sl_cred);
 		kfree(ses->se_slots[i]);
+	}
 }
 
 /*
@@ -2293,11 +2295,13 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
 	dprintk("--> %s slot %p\n", __func__, slot);
 
 	slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
+	free_svc_cred(&slot->sl_cred);
 	if (!nfsd4_cache_this(resp)) {
 		slot->sl_flags &= !NFSD4_SLOT_CACHED;
 		return;
 	}
 	slot->sl_flags |= NFSD4_SLOT_CACHED;
+	copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred);
 	slot->sl_opcnt = resp->opcnt;
 	slot->sl_status = resp->cstate.status;
 
@@ -3000,6 +3004,34 @@ static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
 	return xb->len > session->se_fchannel.maxreq_sz;
 }
 
+static bool replay_matches_cache(struct svc_rqst *rqstp,
+		 struct nfsd4_sequence *seq, struct nfsd4_slot *slot)
+{
+	struct nfsd4_compoundargs *argp = rqstp->rq_argp;
+
+	if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) !=
+	    (bool)seq->cachethis)
+		return false;
+	/*
+	 * If there's an error than the reply can have fewer ops than
+	 * the call.  But if we cached a reply with *more* ops than the
+	 * call you're sending us now, then this new call is clearly not
+	 * really a replay of the old one:
+	 */
+	if (slot->sl_opcnt < argp->opcnt)
+		return false;
+	/* This is the only check explicitly called by spec: */
+	if (!same_creds(&rqstp->rq_cred, &slot->sl_cred))
+		return false;
+	/*
+	 * There may be more comparisons we could actually do, but the
+	 * spec doesn't require us to catch every case where the calls
+	 * don't match (that would require caching the call as well as
+	 * the reply), so we don't bother.
+	 */
+	return true;
+}
+
 __be32
 nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		union nfsd4_op_u *u)
@@ -3059,6 +3091,9 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		status = nfserr_seq_misordered;
 		if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
 			goto out_put_session;
+		status = nfserr_seq_false_retry;
+		if (!replay_matches_cache(rqstp, seq, slot))
+			goto out_put_session;
 		cstate->slot = slot;
 		cstate->session = session;
 		cstate->clp = clp;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 2488b7df1b35..86aa92d200e1 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -169,6 +169,7 @@ static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s)
 struct nfsd4_slot {
 	u32	sl_seqid;
 	__be32	sl_status;
+	struct svc_cred sl_cred;
 	u32	sl_datalen;
 	u16	sl_opcnt;
 #define NFSD4_SLOT_INUSE	(1 << 0)
-- 
2.13.5


  reply	other threads:[~2017-10-18 21:25 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-11 17:07 [PATCH v2] NFSv4.1: Fix up replays of interrupted requests Trond Myklebust
2017-10-16 16:37 ` Olga Kornievskaia
2017-10-16 17:07   ` Olga Kornievskaia
2017-10-16 18:36     ` J. Bruce Fields
2017-10-16 19:20       ` Olga Kornievskaia
2017-10-18 21:23       ` J. Bruce Fields
2017-10-19 17:07         ` Olga Kornievskaia
2017-10-18 21:25     ` [PATCH 1/2] nfsd4: fix cached replies to solo SEQUENCE compounds J. Bruce Fields
2017-10-18 21:25       ` J. Bruce Fields [this message]
2017-10-19 17:21       ` Olga Kornievskaia
2017-10-19 18:17         ` J. Bruce Fields
2017-10-19 18:34           ` Olga Kornievskaia
2017-10-19 20:20             ` J. Bruce Fields
2017-10-19 21:04               ` Olga Kornievskaia
2017-10-19 21:19                 ` Olga Kornievskaia
2017-10-20 17:47                   ` J. Bruce Fields
2017-10-20 18:55                     ` Olga Kornievskaia
2017-10-20 20:44                       ` J. Bruce Fields
2017-10-19 18:33 ` [PATCH v2] NFSv4.1: Fix up replays of interrupted requests Olga Kornievskaia
2017-10-19 18:52   ` Trond Myklebust
2018-05-22 21:28 ` Olga Kornievskaia

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=1508361919-30495-2-git-send-email-bfields@redhat.com \
    --to=bfields@redhat.com \
    --cc=aglo@umich.edu \
    --cc=linux-nfs@vger.kernel.org \
    --cc=trond.myklebust@primarydata.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).