mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 08:43:19 -04:00
MFC r199017,199228
Fix handling of GPT headers when size is > 92 bytes. This should address reading GPT headers written by opensolaris.
This commit is contained in:
parent
1c7de26f34
commit
4cb9493f3f
1 changed files with 95 additions and 67 deletions
|
|
@ -73,7 +73,7 @@ enum gpt_state {
|
|||
struct g_part_gpt_table {
|
||||
struct g_part_table base;
|
||||
u_char mbr[MBRSIZE];
|
||||
struct gpt_hdr hdr;
|
||||
struct gpt_hdr *hdr;
|
||||
quad_t lba[GPT_ELT_COUNT];
|
||||
enum gpt_state state[GPT_ELT_COUNT];
|
||||
};
|
||||
|
|
@ -143,13 +143,12 @@ static struct uuid gpt_uuid_linux_swap = GPT_ENT_TYPE_LINUX_SWAP;
|
|||
static struct uuid gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
|
||||
static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_UNUSED;
|
||||
|
||||
static void
|
||||
static struct gpt_hdr *
|
||||
gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp,
|
||||
enum gpt_elt elt, struct gpt_hdr *hdr)
|
||||
enum gpt_elt elt)
|
||||
{
|
||||
struct uuid uuid;
|
||||
struct gpt_hdr *buf, *hdr;
|
||||
struct g_provider *pp;
|
||||
char *buf;
|
||||
quad_t lba, last;
|
||||
int error;
|
||||
uint32_t crc, sz;
|
||||
|
|
@ -161,63 +160,75 @@ gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp,
|
|||
buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize,
|
||||
&error);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
bcopy(buf, hdr, sizeof(*hdr));
|
||||
if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0)
|
||||
return;
|
||||
return (NULL);
|
||||
hdr = NULL;
|
||||
if (memcmp(buf->hdr_sig, GPT_HDR_SIG, sizeof(buf->hdr_sig)) != 0)
|
||||
goto fail;
|
||||
|
||||
table->state[elt] = GPT_STATE_CORRUPT;
|
||||
sz = le32toh(hdr->hdr_size);
|
||||
sz = le32toh(buf->hdr_size);
|
||||
if (sz < 92 || sz > pp->sectorsize)
|
||||
return;
|
||||
crc = le32toh(hdr->hdr_crc_self);
|
||||
hdr->hdr_crc_self = 0;
|
||||
if (crc32(hdr, sz) != crc)
|
||||
return;
|
||||
goto fail;
|
||||
|
||||
hdr = g_malloc(sz, M_WAITOK | M_ZERO);
|
||||
bcopy(buf, hdr, sz);
|
||||
hdr->hdr_size = sz;
|
||||
|
||||
crc = le32toh(buf->hdr_crc_self);
|
||||
buf->hdr_crc_self = 0;
|
||||
if (crc32(buf, sz) != crc)
|
||||
goto fail;
|
||||
hdr->hdr_crc_self = crc;
|
||||
|
||||
table->state[elt] = GPT_STATE_INVALID;
|
||||
hdr->hdr_revision = le32toh(hdr->hdr_revision);
|
||||
hdr->hdr_revision = le32toh(buf->hdr_revision);
|
||||
if (hdr->hdr_revision < 0x00010000)
|
||||
return;
|
||||
hdr->hdr_lba_self = le64toh(hdr->hdr_lba_self);
|
||||
goto fail;
|
||||
hdr->hdr_lba_self = le64toh(buf->hdr_lba_self);
|
||||
if (hdr->hdr_lba_self != table->lba[elt])
|
||||
return;
|
||||
hdr->hdr_lba_alt = le64toh(hdr->hdr_lba_alt);
|
||||
goto fail;
|
||||
hdr->hdr_lba_alt = le64toh(buf->hdr_lba_alt);
|
||||
|
||||
/* Check the managed area. */
|
||||
hdr->hdr_lba_start = le64toh(hdr->hdr_lba_start);
|
||||
hdr->hdr_lba_start = le64toh(buf->hdr_lba_start);
|
||||
if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last)
|
||||
return;
|
||||
hdr->hdr_lba_end = le64toh(hdr->hdr_lba_end);
|
||||
goto fail;
|
||||
hdr->hdr_lba_end = le64toh(buf->hdr_lba_end);
|
||||
if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last)
|
||||
return;
|
||||
goto fail;
|
||||
|
||||
/* Check the table location and size of the table. */
|
||||
hdr->hdr_entries = le32toh(hdr->hdr_entries);
|
||||
hdr->hdr_entsz = le32toh(hdr->hdr_entsz);
|
||||
hdr->hdr_entries = le32toh(buf->hdr_entries);
|
||||
hdr->hdr_entsz = le32toh(buf->hdr_entsz);
|
||||
if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 ||
|
||||
(hdr->hdr_entsz & 7) != 0)
|
||||
return;
|
||||
hdr->hdr_lba_table = le64toh(hdr->hdr_lba_table);
|
||||
goto fail;
|
||||
hdr->hdr_lba_table = le64toh(buf->hdr_lba_table);
|
||||
if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last)
|
||||
return;
|
||||
goto fail;
|
||||
if (hdr->hdr_lba_table >= hdr->hdr_lba_start &&
|
||||
hdr->hdr_lba_table <= hdr->hdr_lba_end)
|
||||
return;
|
||||
goto fail;
|
||||
lba = hdr->hdr_lba_table +
|
||||
(hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) /
|
||||
pp->sectorsize - 1;
|
||||
if (lba >= last)
|
||||
return;
|
||||
goto fail;
|
||||
if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end)
|
||||
return;
|
||||
goto fail;
|
||||
|
||||
table->state[elt] = GPT_STATE_OK;
|
||||
le_uuid_dec(&hdr->hdr_uuid, &uuid);
|
||||
hdr->hdr_uuid = uuid;
|
||||
hdr->hdr_crc_table = le32toh(hdr->hdr_crc_table);
|
||||
le_uuid_dec(&buf->hdr_uuid, &hdr->hdr_uuid);
|
||||
hdr->hdr_crc_table = le32toh(buf->hdr_crc_table);
|
||||
|
||||
g_free(buf);
|
||||
return (hdr);
|
||||
|
||||
fail:
|
||||
if (hdr != NULL)
|
||||
g_free(hdr);
|
||||
g_free(buf);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static struct gpt_ent *
|
||||
|
|
@ -230,6 +241,9 @@ gpt_read_tbl(struct g_part_gpt_table *table, struct g_consumer *cp,
|
|||
unsigned int idx, sectors, tblsz;
|
||||
int error;
|
||||
|
||||
if (hdr == NULL)
|
||||
return (NULL);
|
||||
|
||||
pp = cp->provider;
|
||||
table->lba[elt] = hdr->hdr_lba_table;
|
||||
|
||||
|
|
@ -271,6 +285,9 @@ static int
|
|||
gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec)
|
||||
{
|
||||
|
||||
if (pri == NULL || sec == NULL)
|
||||
return (0);
|
||||
|
||||
if (!EQUUID(&pri->hdr_uuid, &sec->hdr_uuid))
|
||||
return (0);
|
||||
return ((pri->hdr_revision == sec->hdr_revision &&
|
||||
|
|
@ -427,17 +444,20 @@ g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp)
|
|||
table->lba[GPT_ELT_SECHDR] = last;
|
||||
table->lba[GPT_ELT_SECTBL] = last - tblsz;
|
||||
|
||||
bcopy(GPT_HDR_SIG, table->hdr.hdr_sig, sizeof(table->hdr.hdr_sig));
|
||||
table->hdr.hdr_revision = GPT_HDR_REVISION;
|
||||
table->hdr.hdr_size = offsetof(struct gpt_hdr, padding);
|
||||
table->hdr.hdr_lba_start = 2 + tblsz;
|
||||
table->hdr.hdr_lba_end = last - tblsz - 1;
|
||||
kern_uuidgen(&table->hdr.hdr_uuid, 1);
|
||||
table->hdr.hdr_entries = basetable->gpt_entries;
|
||||
table->hdr.hdr_entsz = sizeof(struct gpt_ent);
|
||||
/* Allocate space for the header */
|
||||
table->hdr = g_malloc(sizeof(struct gpt_hdr), M_WAITOK | M_ZERO);
|
||||
|
||||
basetable->gpt_first = table->hdr.hdr_lba_start;
|
||||
basetable->gpt_last = table->hdr.hdr_lba_end;
|
||||
bcopy(GPT_HDR_SIG, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
|
||||
table->hdr->hdr_revision = GPT_HDR_REVISION;
|
||||
table->hdr->hdr_size = offsetof(struct gpt_hdr, padding);
|
||||
table->hdr->hdr_lba_start = 2 + tblsz;
|
||||
table->hdr->hdr_lba_end = last - tblsz - 1;
|
||||
kern_uuidgen(&table->hdr->hdr_uuid, 1);
|
||||
table->hdr->hdr_entries = basetable->gpt_entries;
|
||||
table->hdr->hdr_entsz = sizeof(struct gpt_ent);
|
||||
|
||||
basetable->gpt_first = table->hdr->hdr_lba_start;
|
||||
basetable->gpt_last = table->hdr->hdr_lba_end;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -582,7 +602,7 @@ g_part_gpt_probe(struct g_part_table *table, struct g_consumer *cp)
|
|||
static int
|
||||
g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
|
||||
{
|
||||
struct gpt_hdr prihdr, sechdr;
|
||||
struct gpt_hdr *prihdr, *sechdr;
|
||||
struct gpt_ent *tbl, *pritbl, *sectbl;
|
||||
struct g_provider *pp;
|
||||
struct g_part_gpt_table *table;
|
||||
|
|
@ -601,18 +621,18 @@ g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
|
|||
g_free(buf);
|
||||
|
||||
/* Read the primary header and table. */
|
||||
gpt_read_hdr(table, cp, GPT_ELT_PRIHDR, &prihdr);
|
||||
prihdr = gpt_read_hdr(table, cp, GPT_ELT_PRIHDR);
|
||||
if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) {
|
||||
pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, &prihdr);
|
||||
pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, prihdr);
|
||||
} else {
|
||||
table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
|
||||
pritbl = NULL;
|
||||
}
|
||||
|
||||
/* Read the secondary header and table. */
|
||||
gpt_read_hdr(table, cp, GPT_ELT_SECHDR, &sechdr);
|
||||
sechdr = gpt_read_hdr(table, cp, GPT_ELT_SECHDR);
|
||||
if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK) {
|
||||
sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, &sechdr);
|
||||
sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, sechdr);
|
||||
} else {
|
||||
table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
|
||||
sectbl = NULL;
|
||||
|
|
@ -635,13 +655,17 @@ g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
|
|||
*/
|
||||
if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK &&
|
||||
table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
|
||||
!gpt_matched_hdrs(&prihdr, &sechdr)) {
|
||||
!gpt_matched_hdrs(prihdr, sechdr)) {
|
||||
if (table->state[GPT_ELT_PRITBL] == GPT_STATE_OK) {
|
||||
table->state[GPT_ELT_SECHDR] = GPT_STATE_INVALID;
|
||||
table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
|
||||
g_free(sechdr);
|
||||
sechdr = NULL;
|
||||
} else {
|
||||
table->state[GPT_ELT_PRIHDR] = GPT_STATE_INVALID;
|
||||
table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
|
||||
g_free(prihdr);
|
||||
prihdr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -651,6 +675,8 @@ g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
|
|||
printf("GEOM: %s: using the secondary instead -- recovery "
|
||||
"strongly advised.\n", pp->name);
|
||||
table->hdr = sechdr;
|
||||
if (prihdr != NULL)
|
||||
g_free(prihdr);
|
||||
tbl = sectbl;
|
||||
if (pritbl != NULL)
|
||||
g_free(pritbl);
|
||||
|
|
@ -662,14 +688,16 @@ g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
|
|||
"suggested.\n", pp->name);
|
||||
}
|
||||
table->hdr = prihdr;
|
||||
if (sechdr != NULL)
|
||||
g_free(sechdr);
|
||||
tbl = pritbl;
|
||||
if (sectbl != NULL)
|
||||
g_free(sectbl);
|
||||
}
|
||||
|
||||
basetable->gpt_first = table->hdr.hdr_lba_start;
|
||||
basetable->gpt_last = table->hdr.hdr_lba_end;
|
||||
basetable->gpt_entries = table->hdr.hdr_entries;
|
||||
basetable->gpt_first = table->hdr->hdr_lba_start;
|
||||
basetable->gpt_last = table->hdr->hdr_lba_end;
|
||||
basetable->gpt_entries = table->hdr->hdr_entries;
|
||||
|
||||
for (index = basetable->gpt_entries - 1; index >= 0; index--) {
|
||||
if (EQUUID(&tbl[index].ent_type, &gpt_uuid_unused))
|
||||
|
|
@ -729,7 +757,7 @@ g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
|
|||
|
||||
pp = cp->provider;
|
||||
table = (struct g_part_gpt_table *)basetable;
|
||||
tlbsz = (table->hdr.hdr_entries * table->hdr.hdr_entsz +
|
||||
tlbsz = (table->hdr->hdr_entries * table->hdr->hdr_entsz +
|
||||
pp->sectorsize - 1) / pp->sectorsize;
|
||||
|
||||
/* Write the PMBR */
|
||||
|
|
@ -743,21 +771,21 @@ g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
|
|||
/* Allocate space for the header and entries. */
|
||||
buf = g_malloc((tlbsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO);
|
||||
|
||||
memcpy(buf, table->hdr.hdr_sig, sizeof(table->hdr.hdr_sig));
|
||||
le32enc(buf + 8, table->hdr.hdr_revision);
|
||||
le32enc(buf + 12, table->hdr.hdr_size);
|
||||
le64enc(buf + 40, table->hdr.hdr_lba_start);
|
||||
le64enc(buf + 48, table->hdr.hdr_lba_end);
|
||||
le_uuid_enc(buf + 56, &table->hdr.hdr_uuid);
|
||||
le32enc(buf + 80, table->hdr.hdr_entries);
|
||||
le32enc(buf + 84, table->hdr.hdr_entsz);
|
||||
memcpy(buf, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
|
||||
le32enc(buf + 8, table->hdr->hdr_revision);
|
||||
le32enc(buf + 12, table->hdr->hdr_size);
|
||||
le64enc(buf + 40, table->hdr->hdr_lba_start);
|
||||
le64enc(buf + 48, table->hdr->hdr_lba_end);
|
||||
le_uuid_enc(buf + 56, &table->hdr->hdr_uuid);
|
||||
le32enc(buf + 80, table->hdr->hdr_entries);
|
||||
le32enc(buf + 84, table->hdr->hdr_entsz);
|
||||
|
||||
LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
|
||||
if (baseentry->gpe_deleted)
|
||||
continue;
|
||||
entry = (struct g_part_gpt_entry *)baseentry;
|
||||
index = baseentry->gpe_index - 1;
|
||||
bp = buf + pp->sectorsize + table->hdr.hdr_entsz * index;
|
||||
bp = buf + pp->sectorsize + table->hdr->hdr_entsz * index;
|
||||
le_uuid_enc(bp, &entry->ent.ent_type);
|
||||
le_uuid_enc(bp + 16, &entry->ent.ent_uuid);
|
||||
le64enc(bp + 32, entry->ent.ent_lba_start);
|
||||
|
|
@ -768,7 +796,7 @@ g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
|
|||
}
|
||||
|
||||
crc = crc32(buf + pp->sectorsize,
|
||||
table->hdr.hdr_entries * table->hdr.hdr_entsz);
|
||||
table->hdr->hdr_entries * table->hdr->hdr_entsz);
|
||||
le32enc(buf + 88, crc);
|
||||
|
||||
/* Write primary meta-data. */
|
||||
|
|
@ -776,7 +804,7 @@ g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
|
|||
le64enc(buf + 24, table->lba[GPT_ELT_PRIHDR]); /* hdr_lba_self. */
|
||||
le64enc(buf + 32, table->lba[GPT_ELT_SECHDR]); /* hdr_lba_alt. */
|
||||
le64enc(buf + 72, table->lba[GPT_ELT_PRITBL]); /* hdr_lba_table. */
|
||||
crc = crc32(buf, table->hdr.hdr_size);
|
||||
crc = crc32(buf, table->hdr->hdr_size);
|
||||
le32enc(buf + 16, crc);
|
||||
|
||||
error = g_write_data(cp, table->lba[GPT_ELT_PRITBL] * pp->sectorsize,
|
||||
|
|
@ -793,7 +821,7 @@ g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
|
|||
le64enc(buf + 24, table->lba[GPT_ELT_SECHDR]); /* hdr_lba_self. */
|
||||
le64enc(buf + 32, table->lba[GPT_ELT_PRIHDR]); /* hdr_lba_alt. */
|
||||
le64enc(buf + 72, table->lba[GPT_ELT_SECTBL]); /* hdr_lba_table. */
|
||||
crc = crc32(buf, table->hdr.hdr_size);
|
||||
crc = crc32(buf, table->hdr->hdr_size);
|
||||
le32enc(buf + 16, crc);
|
||||
|
||||
error = g_write_data(cp, table->lba[GPT_ELT_SECTBL] * pp->sectorsize,
|
||||
|
|
|
|||
Loading…
Reference in a new issue