aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/rbd.c
diff options
context:
space:
mode:
authorAlex Elder <elder@inktank.com>2012-07-10 21:30:10 -0400
committerSage Weil <sage@inktank.com>2012-07-30 21:21:46 -0400
commitccece235d3737221e7a1118fdbd8474112adac84 (patch)
tree0264778d098f540f48a1caf26a64048f4afdc153 /drivers/block/rbd.c
parent913d2fdcf60576cbbd82969fcb2bc78a4d59ba33 (diff)
rbd: fixes in rbd_header_from_disk()
This fixes a few issues in rbd_header_from_disk(): - There is a check intended to catch overflow, but it's wrong in two ways. - First, the type we don't want to overflow is size_t, not unsigned int, and there is now a SIZE_MAX we can use for use with that type. - Second, we're allocating the snapshot ids and snapshot image sizes separately (each has type u64; on disk they grouped together as a rbd_image_header_ondisk structure). So we can use the size of u64 in this overflow check. - If there are no snapshots, then there should be no snapshot names. Enforce this, and issue a warning if we encounter a header with no snapshots but a non-zero snap_names_len. - When saving the snapshot names into the header, be more direct in defining the offset in the on-disk structure from which they're being copied by using "snap_count" rather than "i" in the array index. - If an error occurs, the "snapc" and "snap_names" fields are freed at the end of the function. Make those fields be null pointers after they're freed, to be explicit that they are no longer valid. - Finally, move the definition of the local variable "i" to the innermost scope in which it's needed. Signed-off-by: Alex Elder <elder@inktank.com> Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
Diffstat (limited to 'drivers/block/rbd.c')
-rw-r--r--drivers/block/rbd.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 1222d583ac2c..34676937d2d2 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -494,14 +494,14 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
494 struct rbd_image_header_ondisk *ondisk, 494 struct rbd_image_header_ondisk *ondisk,
495 u32 allocated_snaps) 495 u32 allocated_snaps)
496{ 496{
497 u32 i, snap_count; 497 u32 snap_count;
498 498
499 if (!rbd_dev_ondisk_valid(ondisk)) 499 if (!rbd_dev_ondisk_valid(ondisk))
500 return -ENXIO; 500 return -ENXIO;
501 501
502 snap_count = le32_to_cpu(ondisk->snap_count); 502 snap_count = le32_to_cpu(ondisk->snap_count);
503 if (snap_count > (UINT_MAX - sizeof(struct ceph_snap_context)) 503 if (snap_count > (SIZE_MAX - sizeof(struct ceph_snap_context))
504 / sizeof (*ondisk)) 504 / sizeof (u64))
505 return -EINVAL; 505 return -EINVAL;
506 header->snapc = kmalloc(sizeof(struct ceph_snap_context) + 506 header->snapc = kmalloc(sizeof(struct ceph_snap_context) +
507 snap_count * sizeof(u64), 507 snap_count * sizeof(u64),
@@ -509,8 +509,8 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
509 if (!header->snapc) 509 if (!header->snapc)
510 return -ENOMEM; 510 return -ENOMEM;
511 511
512 header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
513 if (snap_count) { 512 if (snap_count) {
513 header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
514 header->snap_names = kmalloc(header->snap_names_len, 514 header->snap_names = kmalloc(header->snap_names_len,
515 GFP_KERNEL); 515 GFP_KERNEL);
516 if (!header->snap_names) 516 if (!header->snap_names)
@@ -520,6 +520,8 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
520 if (!header->snap_sizes) 520 if (!header->snap_sizes)
521 goto err_names; 521 goto err_names;
522 } else { 522 } else {
523 WARN_ON(ondisk->snap_names_len);
524 header->snap_names_len = 0;
523 header->snap_names = NULL; 525 header->snap_names = NULL;
524 header->snap_sizes = NULL; 526 header->snap_sizes = NULL;
525 } 527 }
@@ -544,6 +546,8 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
544 header->total_snaps = snap_count; 546 header->total_snaps = snap_count;
545 547
546 if (snap_count && allocated_snaps == snap_count) { 548 if (snap_count && allocated_snaps == snap_count) {
549 int i;
550
547 for (i = 0; i < snap_count; i++) { 551 for (i = 0; i < snap_count; i++) {
548 header->snapc->snaps[i] = 552 header->snapc->snaps[i] =
549 le64_to_cpu(ondisk->snaps[i].id); 553 le64_to_cpu(ondisk->snaps[i].id);
@@ -552,7 +556,7 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
552 } 556 }
553 557
554 /* copy snapshot names */ 558 /* copy snapshot names */
555 memcpy(header->snap_names, &ondisk->snaps[i], 559 memcpy(header->snap_names, &ondisk->snaps[snap_count],
556 header->snap_names_len); 560 header->snap_names_len);
557 } 561 }
558 562
@@ -560,10 +564,14 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
560 564
561err_sizes: 565err_sizes:
562 kfree(header->snap_sizes); 566 kfree(header->snap_sizes);
567 header->snap_sizes = NULL;
563err_names: 568err_names:
564 kfree(header->snap_names); 569 kfree(header->snap_names);
570 header->snap_names = NULL;
565err_snapc: 571err_snapc:
566 kfree(header->snapc); 572 kfree(header->snapc);
573 header->snapc = NULL;
574
567 return -ENOMEM; 575 return -ENOMEM;
568} 576}
569 577