From: NeilBrown Date: Fri, 4 Mar 2011 01:47:30 +0000 (+1100) Subject: devblock: validate the addresses of the state blocks a bit better. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=9a1f75908b604482a18d6ec3e3d46fc6a569b48c;p=LaFS.git devblock: validate the addresses of the state blocks a bit better. Allow all to be at start or end, but ensure they don't overlap data. Signed-off-by: NeilBrown --- diff --git a/super.c b/super.c index 853ed7b..c68eb68 100644 --- a/super.c +++ b/super.c @@ -70,6 +70,10 @@ valid_devblock(struct lafs_dev *db, sector_t addr) * it was found at sector 'addr' */ u32 crc, crc2; + u64 byteaddr; + sector_t segsize; + int i; + if (strncmp(db->idtag, "LaFS-DeviceBlock", 16) != 0) return 0; if (strncmp(db->version, "AlphaDevel ", 16) != 0) @@ -85,18 +89,18 @@ valid_devblock(struct lafs_dev *db, sector_t addr) return 0; } - addr = addr << 9; /* convert to byte */ - if (le64_to_cpu(db->devaddr[0]) != addr && - le64_to_cpu(db->devaddr[1]) != addr) + byteaddr = (u64)addr << 9; /* convert to byte */ + if (le64_to_cpu(db->devaddr[0]) != byteaddr && + le64_to_cpu(db->devaddr[1]) != byteaddr) return 0; if (db->statebits < 10 || db->statebits > 16) return 0; if (db->blockbits < 9 || db->blockbits > 20) return 0; - if (db->width < 1 || db->width > 500) + if (le16_to_cpu(db->width) < 1 || le16_to_cpu(db->width) >= 512) return 0; - if (db->stride < 1) + if (le32_to_cpu(db->stride) < 1) return 0; /* devaddr[0] must be early, [1] must be late */ if (le64_to_cpu(db->devaddr[0]) >= @@ -107,15 +111,9 @@ valid_devblock(struct lafs_dev *db, sector_t addr) le64_to_cpu(db->segment_offset) + ((((sector_t)le32_to_cpu(db->segment_count) * le32_to_cpu(db->segment_size))) - << le32_to_cpu(db->blockbits))) + << db->blockbits)) return 0; - /* we should be fairly flexable about addresses of state blocks, - * we should probably allow more, and we should just make sure - * they do not overlap any true segments.... - * FIXME - */ - /* 2 is an absolute minimum segment size, a few hundred is more * likely. We'll put a lower limit of 8, and an upper of 800000 */ @@ -127,6 +125,31 @@ valid_devblock(struct lafs_dev *db, sector_t addr) (le32_to_cpu(db->segment_size)<blockbits) * 10) return 0; + /* The 4 state blocks live before the first or after the last segment. + * The distance from start of first to end of last is either: + * - segment_count * segment_size if width*stride <= segment_size + * - (width-1) * stride + segment_size / width * segment_count + * if width * stride > segment_size + */ + segsize = le32_to_cpu(db->segment_size); + segsize *= le32_to_cpu(db->segment_count); + if (le16_to_cpu(db->width) * le32_to_cpu(db->stride) + > le32_to_cpu(db->segment_size)) { + int stride = le32_to_cpu(db->stride); + int width = le16_to_cpu(db->width); + + sector_div(segsize, width); + segsize += (width - 1) * stride; + } + segsize <<= db->blockbits; + for (i = 0; i < 4; i++) { + sector_t addr = le64_to_cpu(db->stateaddr[i]); + int offset = le32_to_cpu(db->segment_offset); + if (addr + (1<statebits) > offset && + addr < offset + segsize) + return 0; + } + /* FIXME should range check segment_count, but need to know * size for that */ if (le32_to_cpu(db->level) > 10)