]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 11 Feb 2019 13:44:04 +0000 (14:44 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 11 Feb 2019 13:44:04 +0000 (14:44 +0100)
added patches:
ib-hfi1-add-limit-test-for-rc-uc-send-via-loopback.patch
nfsd4-catch-some-false-session-retries.patch
nfsd4-fix-cached-replies-to-solo-sequence-compounds.patch

queue-4.14/ib-hfi1-add-limit-test-for-rc-uc-send-via-loopback.patch [new file with mode: 0644]
queue-4.14/nfsd4-catch-some-false-session-retries.patch [new file with mode: 0644]
queue-4.14/nfsd4-fix-cached-replies-to-solo-sequence-compounds.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/ib-hfi1-add-limit-test-for-rc-uc-send-via-loopback.patch b/queue-4.14/ib-hfi1-add-limit-test-for-rc-uc-send-via-loopback.patch
new file mode 100644 (file)
index 0000000..5c1a21f
--- /dev/null
@@ -0,0 +1,79 @@
+From 09ce351dff8e7636af0beb72cd4a86c3904a0500 Mon Sep 17 00:00:00 2001
+From: Mike Marciniszyn <mike.marciniszyn@intel.com>
+Date: Thu, 17 Jan 2019 12:42:16 -0800
+Subject: IB/hfi1: Add limit test for RC/UC send via loopback
+
+From: Mike Marciniszyn <mike.marciniszyn@intel.com>
+
+commit 09ce351dff8e7636af0beb72cd4a86c3904a0500 upstream.
+
+Fix potential memory corruption and panic in loopback for IB_WR_SEND
+variants.
+
+The code blindly assumes the posted length will fit in the fetched rwqe,
+which is not a valid assumption.
+
+Fix by adding a limit test, and triggering the appropriate send completion
+and putting the QP in an error state.  This mimics the handling for
+non-loopback QPs.
+
+Fixes: 15703461533a ("IB/{hfi1, qib, rdmavt}: Move ruc_loopback to rdmavt")
+Cc: <stable@vger.kernel.org> #v4.20+
+Reviewed-by: Michael J. Ruhl <michael.j.ruhl@intel.com>
+Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
+Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
+
+---
+ drivers/infiniband/hw/hfi1/ruc.c    |    7 ++++++-
+ drivers/infiniband/hw/qib/qib_ruc.c |    7 ++++++-
+ 2 files changed, 12 insertions(+), 2 deletions(-)
+
+--- a/drivers/infiniband/hw/hfi1/ruc.c
++++ b/drivers/infiniband/hw/hfi1/ruc.c
+@@ -440,6 +440,8 @@ send:
+                       goto op_err;
+               if (!ret)
+                       goto rnr_nak;
++              if (wqe->length > qp->r_len)
++                      goto inv_err;
+               break;
+       case IB_WR_RDMA_WRITE_WITH_IMM:
+@@ -607,7 +609,10 @@ op_err:
+       goto err;
+ inv_err:
+-      send_status = IB_WC_REM_INV_REQ_ERR;
++      send_status =
++              sqp->ibqp.qp_type == IB_QPT_RC ?
++                      IB_WC_REM_INV_REQ_ERR :
++                      IB_WC_SUCCESS;
+       wc.status = IB_WC_LOC_QP_OP_ERR;
+       goto err;
+--- a/drivers/infiniband/hw/qib/qib_ruc.c
++++ b/drivers/infiniband/hw/qib/qib_ruc.c
+@@ -425,6 +425,8 @@ again:
+                       goto op_err;
+               if (!ret)
+                       goto rnr_nak;
++              if (wqe->length > qp->r_len)
++                      goto inv_err;
+               break;
+       case IB_WR_RDMA_WRITE_WITH_IMM:
+@@ -585,7 +587,10 @@ op_err:
+       goto err;
+ inv_err:
+-      send_status = IB_WC_REM_INV_REQ_ERR;
++      send_status =
++              sqp->ibqp.qp_type == IB_QPT_RC ?
++                      IB_WC_REM_INV_REQ_ERR :
++                      IB_WC_SUCCESS;
+       wc.status = IB_WC_LOC_QP_OP_ERR;
+       goto err;
diff --git a/queue-4.14/nfsd4-catch-some-false-session-retries.patch b/queue-4.14/nfsd4-catch-some-false-session-retries.patch
new file mode 100644 (file)
index 0000000..ef4be86
--- /dev/null
@@ -0,0 +1,114 @@
+From 53da6a53e1d414e05759fa59b7032ee08f4e22d7 Mon Sep 17 00:00:00 2001
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Tue, 17 Oct 2017 20:38:49 -0400
+Subject: nfsd4: catch some false session retries
+
+From: J. Bruce Fields <bfields@redhat.com>
+
+commit 53da6a53e1d414e05759fa59b7032ee08f4e22d7 upstream.
+
+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.)
+
+Tested-by: Olga Kornievskaia <aglo@umich.edu>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Donald Buczek <buczek@molgen.mpg.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfsd/nfs4state.c |   37 ++++++++++++++++++++++++++++++++++++-
+ fs/nfsd/state.h     |    1 +
+ 2 files changed, 37 insertions(+), 1 deletion(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -1472,8 +1472,10 @@ free_session_slots(struct nfsd4_session
+ {
+       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]);
++      }
+ }
+ /*
+@@ -2334,6 +2336,8 @@ nfsd4_store_cache_entry(struct nfsd4_com
+       slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
+       slot->sl_opcnt = resp->opcnt;
+       slot->sl_status = resp->cstate.status;
++      free_svc_cred(&slot->sl_cred);
++      copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred);
+       if (!nfsd4_cache_this(resp)) {
+               slot->sl_flags &= ~NFSD4_SLOT_CACHED;
+@@ -3040,6 +3044,34 @@ static bool nfsd4_request_too_big(struct
+       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)
+@@ -3099,6 +3131,9 @@ nfsd4_sequence(struct svc_rqst *rqstp, s
+               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;
+--- a/fs/nfsd/state.h
++++ b/fs/nfsd/state.h
+@@ -169,6 +169,7 @@ static inline struct nfs4_delegation *de
+ 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)
diff --git a/queue-4.14/nfsd4-fix-cached-replies-to-solo-sequence-compounds.patch b/queue-4.14/nfsd4-fix-cached-replies-to-solo-sequence-compounds.patch
new file mode 100644 (file)
index 0000000..2345be8
--- /dev/null
@@ -0,0 +1,125 @@
+From 085def3ade52f2ffe3e31f42e98c27dcc222dd37 Mon Sep 17 00:00:00 2001
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Wed, 18 Oct 2017 16:17:18 -0400
+Subject: nfsd4: fix cached replies to solo SEQUENCE compounds
+
+From: J. Bruce Fields <bfields@redhat.com>
+
+commit 085def3ade52f2ffe3e31f42e98c27dcc222dd37 upstream.
+
+Currently our handling of 4.1+ requests without "cachethis" set is
+confusing and not quite correct.
+
+Suppose a client sends a compound consisting of only a single SEQUENCE
+op, and it matches the seqid in a session slot (so it's a retry), but
+the previous request with that seqid did not have "cachethis" set.
+
+The obvious thing to do might be to return NFS4ERR_RETRY_UNCACHED_REP,
+but the protocol only allows that to be returned on the op following the
+SEQUENCE, and there is no such op in this case.
+
+The protocol permits us to cache replies even if the client didn't ask
+us to.  And it's easy to do so in the case of solo SEQUENCE compounds.
+
+So, when we get a solo SEQUENCE, we can either return the previously
+cached reply or NFSERR_SEQ_FALSE_RETRY if we notice it differs in some
+way from the original call.
+
+Currently, we're returning a corrupt reply in the case a solo SEQUENCE
+matches a previous compound with more ops.  This actually matters
+because the Linux client recently started doing this as a way to recover
+from lost replies to idempotent operations in the case the process doing
+the original reply was killed: in that case it's difficult to keep the
+original arguments around to do a real retry, and the client no longer
+cares what the result is anyway, but it would like to make sure that the
+slot's sequence id has been incremented, and the solo SEQUENCE assures
+that: if the server never got the original reply, it will increment the
+sequence id.  If it did get the original reply, it won't increment, and
+nothing else that about the reply really matters much.  But we can at
+least attempt to return valid xdr!
+
+Tested-by: Olga Kornievskaia <aglo@umich.edu>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Donald Buczek <buczek@molgen.mpg.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfsd/nfs4state.c |   20 +++++++++++++++-----
+ fs/nfsd/state.h     |    1 +
+ fs/nfsd/xdr4.h      |   13 +++++++++++--
+ 3 files changed, 27 insertions(+), 7 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -2331,14 +2331,16 @@ nfsd4_store_cache_entry(struct nfsd4_com
+       dprintk("--> %s slot %p\n", __func__, slot);
++      slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
+       slot->sl_opcnt = resp->opcnt;
+       slot->sl_status = resp->cstate.status;
+-      slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
+-      if (nfsd4_not_cached(resp)) {
+-              slot->sl_datalen = 0;
++      if (!nfsd4_cache_this(resp)) {
++              slot->sl_flags &= ~NFSD4_SLOT_CACHED;
+               return;
+       }
++      slot->sl_flags |= NFSD4_SLOT_CACHED;
++
+       base = resp->cstate.data_offset;
+       slot->sl_datalen = buf->len - base;
+       if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
+@@ -2365,8 +2367,16 @@ nfsd4_enc_sequence_replay(struct nfsd4_c
+       op = &args->ops[resp->opcnt - 1];
+       nfsd4_encode_operation(resp, op);
+-      /* Return nfserr_retry_uncached_rep in next operation. */
+-      if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) {
++      if (slot->sl_flags & NFSD4_SLOT_CACHED)
++              return op->status;
++      if (args->opcnt == 1) {
++              /*
++               * The original operation wasn't a solo sequence--we
++               * always cache those--so this retry must not match the
++               * original:
++               */
++              op->status = nfserr_seq_false_retry;
++      } else {
+               op = &args->ops[resp->opcnt++];
+               op->status = nfserr_retry_uncached_rep;
+               nfsd4_encode_operation(resp, op);
+--- a/fs/nfsd/state.h
++++ b/fs/nfsd/state.h
+@@ -174,6 +174,7 @@ struct nfsd4_slot {
+ #define NFSD4_SLOT_INUSE      (1 << 0)
+ #define NFSD4_SLOT_CACHETHIS  (1 << 1)
+ #define NFSD4_SLOT_INITIALIZED        (1 << 2)
++#define NFSD4_SLOT_CACHED     (1 << 3)
+       u8      sl_flags;
+       char    sl_data[];
+ };
+--- a/fs/nfsd/xdr4.h
++++ b/fs/nfsd/xdr4.h
+@@ -651,9 +651,18 @@ static inline bool nfsd4_is_solo_sequenc
+       return resp->opcnt == 1 && args->ops[0].opnum == OP_SEQUENCE;
+ }
+-static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
++/*
++ * The session reply cache only needs to cache replies that the client
++ * actually asked us to.  But it's almost free for us to cache compounds
++ * consisting of only a SEQUENCE op, so we may as well cache those too.
++ * Also, the protocol doesn't give us a convenient response in the case
++ * of a replay of a solo SEQUENCE op that wasn't cached
++ * (RETRY_UNCACHED_REP can only be returned in the second op of a
++ * compound).
++ */
++static inline bool nfsd4_cache_this(struct nfsd4_compoundres *resp)
+ {
+-      return !(resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS)
++      return (resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS)
+               || nfsd4_is_solo_sequence(resp);
+ }
index cecc1172792dbf5667209036c3f74c67294913f8..b53a56954c5a435748f2a243e7cecbc74b2cd821 100644 (file)
@@ -199,3 +199,6 @@ perf-core-don-t-warn-for-impossible-ring-buffer-sizes.patch
 perf-tests-evsel-tp-sched-fix-bitwise-operator.patch
 serial-fix-race-between-flush_to_ldisc-and-tty_open.patch
 serial-8250_pci-make-pci-class-test-non-fatal.patch
+nfsd4-fix-cached-replies-to-solo-sequence-compounds.patch
+nfsd4-catch-some-false-session-retries.patch
+ib-hfi1-add-limit-test-for-rc-uc-send-via-loopback.patch