diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-01-23 16:57:58 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-01-24 17:12:49 -0500 |
commit | 5f83d86cf531d737ba2ca9c3cc500ff331fbd43e (patch) | |
tree | b0bdc28e27e7e3136c0752c8b35bc836f2c4a0b4 /fs | |
parent | 80f9642724af5dfab7d330481fa22e07fde084da (diff) | |
download | linux-5f83d86cf531d737ba2ca9c3cc500ff331fbd43e.tar.bz2 |
NFSv4.x: Fix wraparound issues when validing the callback sequence id
We need to make sure that we don't allow args->csa_sequenceid == 0.
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/callback_proc.c | 43 |
1 files changed, 17 insertions, 26 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 345df6309017..79c93b3bbfec 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -354,23 +354,15 @@ out: * a single outstanding callback request at a time. */ static __be32 -validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) +validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot, + const struct cb_sequenceargs * args) { - struct nfs4_slot *slot; - - dprintk("%s enter. slotid %u seqid %u\n", - __func__, args->csa_slotid, args->csa_sequenceid); + dprintk("%s enter. slotid %u seqid %u, slot table seqid: %u\n", + __func__, args->csa_slotid, args->csa_sequenceid, slot->seq_nr); if (args->csa_slotid > tbl->server_highest_slotid) return htonl(NFS4ERR_BADSLOT); - slot = tbl->slots + args->csa_slotid; - dprintk("%s slot table seqid: %u\n", __func__, slot->seq_nr); - - /* Normal */ - if (likely(args->csa_sequenceid == slot->seq_nr + 1)) - goto out_ok; - /* Replay */ if (args->csa_sequenceid == slot->seq_nr) { dprintk("%s seqid %u is a replay\n", @@ -386,16 +378,14 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) } /* Wraparound */ - if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) { - slot->seq_nr = 1; - goto out_ok; - } + if (unlikely(slot->seq_nr == 0xFFFFFFFFU)) { + if (args->csa_sequenceid == 1) + return htonl(NFS4_OK); + } else if (likely(args->csa_sequenceid == slot->seq_nr + 1)) + return htonl(NFS4_OK); /* Misordered request */ return htonl(NFS4ERR_SEQ_MISORDERED); -out_ok: - tbl->highest_used_slotid = args->csa_slotid; - return htonl(NFS4_OK); } /* @@ -486,6 +476,13 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, goto out_unlock; } + status = validate_seqid(tbl, slot, args); + if (status) + goto out_unlock; + + cps->slotid = args->csa_slotid; + tbl->highest_used_slotid = args->csa_slotid; + memcpy(&res->csr_sessionid, &args->csa_sessionid, sizeof(res->csr_sessionid)); res->csr_sequenceid = args->csa_sequenceid; @@ -493,12 +490,6 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, res->csr_highestslotid = tbl->server_highest_slotid; res->csr_target_highestslotid = tbl->target_highest_slotid; - status = validate_seqid(tbl, args); - if (status) - goto out_unlock; - - cps->slotid = args->csa_slotid; - /* The ca_maxresponsesize_cached is 0 with no DRC */ if (args->csa_cachethis != 0) return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE); @@ -518,7 +509,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, * If CB_SEQUENCE returns an error, then the state of the slot * (sequence ID, cached reply) MUST NOT change. */ - slot->seq_nr++; + slot->seq_nr = args->csa_sequenceid; out_unlock: spin_unlock(&tbl->slot_tbl_lock); |