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/nfs/callback_proc.c | |
parent | 80f9642724af5dfab7d330481fa22e07fde084da (diff) |
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/nfs/callback_proc.c')
-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: | |||
354 | * a single outstanding callback request at a time. | 354 | * a single outstanding callback request at a time. |
355 | */ | 355 | */ |
356 | static __be32 | 356 | static __be32 |
357 | validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) | 357 | validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot, |
358 | const struct cb_sequenceargs * args) | ||
358 | { | 359 | { |
359 | struct nfs4_slot *slot; | 360 | dprintk("%s enter. slotid %u seqid %u, slot table seqid: %u\n", |
360 | 361 | __func__, args->csa_slotid, args->csa_sequenceid, slot->seq_nr); | |
361 | dprintk("%s enter. slotid %u seqid %u\n", | ||
362 | __func__, args->csa_slotid, args->csa_sequenceid); | ||
363 | 362 | ||
364 | if (args->csa_slotid > tbl->server_highest_slotid) | 363 | if (args->csa_slotid > tbl->server_highest_slotid) |
365 | return htonl(NFS4ERR_BADSLOT); | 364 | return htonl(NFS4ERR_BADSLOT); |
366 | 365 | ||
367 | slot = tbl->slots + args->csa_slotid; | ||
368 | dprintk("%s slot table seqid: %u\n", __func__, slot->seq_nr); | ||
369 | |||
370 | /* Normal */ | ||
371 | if (likely(args->csa_sequenceid == slot->seq_nr + 1)) | ||
372 | goto out_ok; | ||
373 | |||
374 | /* Replay */ | 366 | /* Replay */ |
375 | if (args->csa_sequenceid == slot->seq_nr) { | 367 | if (args->csa_sequenceid == slot->seq_nr) { |
376 | dprintk("%s seqid %u is a replay\n", | 368 | dprintk("%s seqid %u is a replay\n", |
@@ -386,16 +378,14 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) | |||
386 | } | 378 | } |
387 | 379 | ||
388 | /* Wraparound */ | 380 | /* Wraparound */ |
389 | if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) { | 381 | if (unlikely(slot->seq_nr == 0xFFFFFFFFU)) { |
390 | slot->seq_nr = 1; | 382 | if (args->csa_sequenceid == 1) |
391 | goto out_ok; | 383 | return htonl(NFS4_OK); |
392 | } | 384 | } else if (likely(args->csa_sequenceid == slot->seq_nr + 1)) |
385 | return htonl(NFS4_OK); | ||
393 | 386 | ||
394 | /* Misordered request */ | 387 | /* Misordered request */ |
395 | return htonl(NFS4ERR_SEQ_MISORDERED); | 388 | return htonl(NFS4ERR_SEQ_MISORDERED); |
396 | out_ok: | ||
397 | tbl->highest_used_slotid = args->csa_slotid; | ||
398 | return htonl(NFS4_OK); | ||
399 | } | 389 | } |
400 | 390 | ||
401 | /* | 391 | /* |
@@ -486,6 +476,13 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
486 | goto out_unlock; | 476 | goto out_unlock; |
487 | } | 477 | } |
488 | 478 | ||
479 | status = validate_seqid(tbl, slot, args); | ||
480 | if (status) | ||
481 | goto out_unlock; | ||
482 | |||
483 | cps->slotid = args->csa_slotid; | ||
484 | tbl->highest_used_slotid = args->csa_slotid; | ||
485 | |||
489 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | 486 | memcpy(&res->csr_sessionid, &args->csa_sessionid, |
490 | sizeof(res->csr_sessionid)); | 487 | sizeof(res->csr_sessionid)); |
491 | res->csr_sequenceid = args->csa_sequenceid; | 488 | res->csr_sequenceid = args->csa_sequenceid; |
@@ -493,12 +490,6 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
493 | res->csr_highestslotid = tbl->server_highest_slotid; | 490 | res->csr_highestslotid = tbl->server_highest_slotid; |
494 | res->csr_target_highestslotid = tbl->target_highest_slotid; | 491 | res->csr_target_highestslotid = tbl->target_highest_slotid; |
495 | 492 | ||
496 | status = validate_seqid(tbl, args); | ||
497 | if (status) | ||
498 | goto out_unlock; | ||
499 | |||
500 | cps->slotid = args->csa_slotid; | ||
501 | |||
502 | /* The ca_maxresponsesize_cached is 0 with no DRC */ | 493 | /* The ca_maxresponsesize_cached is 0 with no DRC */ |
503 | if (args->csa_cachethis != 0) | 494 | if (args->csa_cachethis != 0) |
504 | return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE); | 495 | return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE); |
@@ -518,7 +509,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
518 | * If CB_SEQUENCE returns an error, then the state of the slot | 509 | * If CB_SEQUENCE returns an error, then the state of the slot |
519 | * (sequence ID, cached reply) MUST NOT change. | 510 | * (sequence ID, cached reply) MUST NOT change. |
520 | */ | 511 | */ |
521 | slot->seq_nr++; | 512 | slot->seq_nr = args->csa_sequenceid; |
522 | out_unlock: | 513 | out_unlock: |
523 | spin_unlock(&tbl->slot_tbl_lock); | 514 | spin_unlock(&tbl->slot_tbl_lock); |
524 | 515 | ||