From: Greg Kroah-Hartman Date: Mon, 11 Feb 2019 13:44:04 +0000 (+0100) Subject: 4.14-stable patches X-Git-Tag: v4.9.156~19 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=326645df74c3e05f05eea76ec48fa48be34aa2d0;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches 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 --- 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 index 00000000000..5c1a21f8324 --- /dev/null +++ b/queue-4.14/ib-hfi1-add-limit-test-for-rc-uc-send-via-loopback.patch @@ -0,0 +1,79 @@ +From 09ce351dff8e7636af0beb72cd4a86c3904a0500 Mon Sep 17 00:00:00 2001 +From: Mike Marciniszyn +Date: Thu, 17 Jan 2019 12:42:16 -0800 +Subject: IB/hfi1: Add limit test for RC/UC send via loopback + +From: Mike Marciniszyn + +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: #v4.20+ +Reviewed-by: Michael J. Ruhl +Signed-off-by: Mike Marciniszyn +Signed-off-by: Dennis Dalessandro +Signed-off-by: Jason Gunthorpe +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Mike Marciniszyn + +--- + 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 index 00000000000..ef4be86df63 --- /dev/null +++ b/queue-4.14/nfsd4-catch-some-false-session-retries.patch @@ -0,0 +1,114 @@ +From 53da6a53e1d414e05759fa59b7032ee08f4e22d7 Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" +Date: Tue, 17 Oct 2017 20:38:49 -0400 +Subject: nfsd4: catch some false session retries + +From: J. Bruce Fields + +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 +Signed-off-by: J. Bruce Fields +Signed-off-by: Donald Buczek +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..2345be831c9 --- /dev/null +++ b/queue-4.14/nfsd4-fix-cached-replies-to-solo-sequence-compounds.patch @@ -0,0 +1,125 @@ +From 085def3ade52f2ffe3e31f42e98c27dcc222dd37 Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" +Date: Wed, 18 Oct 2017 16:17:18 -0400 +Subject: nfsd4: fix cached replies to solo SEQUENCE compounds + +From: J. Bruce Fields + +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 +Signed-off-by: J. Bruce Fields +Signed-off-by: Donald Buczek +Signed-off-by: Greg Kroah-Hartman + +--- + 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); + } + diff --git a/queue-4.14/series b/queue-4.14/series index cecc1172792..b53a56954c5 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -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