Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f83d86c authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent 80f96427
Loading
Loading
Loading
Loading
+17 −26
Original line number Original line Diff line number Diff line
@@ -354,23 +354,15 @@ __be32 nfs4_callback_devicenotify(struct cb_devicenotifyargs *args,
 * a single outstanding callback request at a time.
 * a single outstanding callback request at a time.
 */
 */
static __be32
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, slot table seqid: %u\n",

		__func__, args->csa_slotid, args->csa_sequenceid, slot->seq_nr);
	dprintk("%s enter. slotid %u seqid %u\n",
		__func__, args->csa_slotid, args->csa_sequenceid);


	if (args->csa_slotid > tbl->server_highest_slotid)
	if (args->csa_slotid > tbl->server_highest_slotid)
		return htonl(NFS4ERR_BADSLOT);
		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 */
	/* Replay */
	if (args->csa_sequenceid == slot->seq_nr) {
	if (args->csa_sequenceid == slot->seq_nr) {
		dprintk("%s seqid %u is a replay\n",
		dprintk("%s seqid %u is a replay\n",
@@ -386,16 +378,14 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
	}
	}


	/* Wraparound */
	/* Wraparound */
	if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) {
	if (unlikely(slot->seq_nr == 0xFFFFFFFFU)) {
		slot->seq_nr = 1;
		if (args->csa_sequenceid == 1)
		goto out_ok;
			return htonl(NFS4_OK);
	}
	} else if (likely(args->csa_sequenceid == slot->seq_nr + 1))
		return htonl(NFS4_OK);


	/* Misordered request */
	/* Misordered request */
	return htonl(NFS4ERR_SEQ_MISORDERED);
	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;
		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,
	memcpy(&res->csr_sessionid, &args->csa_sessionid,
	       sizeof(res->csr_sessionid));
	       sizeof(res->csr_sessionid));
	res->csr_sequenceid = args->csa_sequenceid;
	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_highestslotid = tbl->server_highest_slotid;
	res->csr_target_highestslotid = tbl->target_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 */
	/* The ca_maxresponsesize_cached is 0 with no DRC */
	if (args->csa_cachethis != 0)
	if (args->csa_cachethis != 0)
		return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE);
		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
	 * If CB_SEQUENCE returns an error, then the state of the slot
	 * (sequence ID, cached reply) MUST NOT change.
	 * (sequence ID, cached reply) MUST NOT change.
	 */
	 */
	slot->seq_nr++;
	slot->seq_nr = args->csa_sequenceid;
out_unlock:
out_unlock:
	spin_unlock(&tbl->slot_tbl_lock);
	spin_unlock(&tbl->slot_tbl_lock);