From 1c97028d69164abca37a0f85c3ec780c5415b654 Mon Sep 17 00:00:00 2001 From: marcel Date: Fri, 29 Feb 2008 22:41:36 +0000 Subject: [PATCH] Follow-up improvements to the handling of false positives: If the partition table is empty, check to see if we have something that looks sufficiently like a BPB. On non-i386 machines, the boot sector typically doesn't contain boot code; the end of the boot sector is all zeroes. This is also where the partition table is for MBRs. We only check the sector size and cluster size, as that seems to be the most reliable across implementations, BPB versions and platforms. --- sys/geom/part/g_part_mbr.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/sys/geom/part/g_part_mbr.c b/sys/geom/part/g_part_mbr.c index 9e6b56ea7c2e..c12bf24b362c 100644 --- a/sys/geom/part/g_part_mbr.c +++ b/sys/geom/part/g_part_mbr.c @@ -118,6 +118,24 @@ mbr_parse_type(const char *type, u_char *dp_typ) return (EINVAL); } +static int +mbr_probe_bpb(u_char *bpb) +{ + uint16_t secsz; + uint8_t clstsz; + +#define PO2(x) ((x & (x - 1)) == 0) + secsz = le16dec(bpb); + if (secsz < 512 || secsz > 4096 || !PO2(secsz)) + return (0); + clstsz = bpb[2]; + if (clstsz < 1 || clstsz > 128 || !PO2(clstsz)) + return (0); +#undef PO2 + + return (1); +} + static void mbr_set_chs(struct g_part_table *table, uint32_t lba, u_char *cylp, u_char *hdp, u_char *secp) @@ -253,7 +271,7 @@ g_part_mbr_probe(struct g_part_table *table, struct g_consumer *cp) { struct g_provider *pp; u_char *buf, *p; - int error, index, res; + int error, index, res, sum; uint16_t magic; pp = cp->provider; @@ -282,8 +300,19 @@ g_part_mbr_probe(struct g_part_table *table, struct g_consumer *cp) goto out; } - /* Match. */ - res = G_PART_PROBE_PRI_NORM; + /* + * If the partition table does not consist of all zeroes, + * assume we have a MBR. If it's all zeroes, we could have + * a boot sector. For example, a boot sector that doesn't + * have boot code -- common on non-i386 hardware. In that + * case we check if we have a possible BPB. If so, then we + * assume we have a boot sector instead. + */ + sum = 0; + for (index = 0; index < NDOSPART * DOSPARTSIZE; index++) + sum += buf[DOSPARTOFF + index]; + if (sum != 0 || !mbr_probe_bpb(buf + 0x0b)) + res = G_PART_PROBE_PRI_NORM; out: g_free(buf);