diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2011-09-18 19:40:50 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2011-09-18 19:40:50 +0000 |
commit | a90403265684a6d9f1dd328d59cc29d76b0122de (patch) | |
tree | 7dc5782481b9f249ecf9acccfde33006a16a7d2e /sys | |
parent | 1ade2fc38cdb72cd6688c476cf27f596315fa65e (diff) |
Add support for variable length optional metadata in softraid(4). This
will allow new optional metadata types to be added without needing to
change the softraid metadata version.
Note that this commit changes the softraid metadata version, however
an upgrade from older metadata is handled automatically. A full backup
prior to upgrading is still strongly recommended.
With feedback from stsp@ and marco.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/softraid.c | 142 | ||||
-rw-r--r-- | sys/dev/softraid_crypto.c | 63 | ||||
-rw-r--r-- | sys/dev/softraidvar.h | 45 |
3 files changed, 174 insertions, 76 deletions
diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c index de95e4460db..33654c730bf 100644 --- a/sys/dev/softraid.c +++ b/sys/dev/softraid.c @@ -1,4 +1,4 @@ -/* $OpenBSD: softraid.c,v 1.247 2011/09/18 13:11:08 jsing Exp $ */ +/* $OpenBSD: softraid.c,v 1.248 2011/09/18 19:40:49 jsing Exp $ */ /* * Copyright (c) 2007, 2008, 2009 Marco Peereboom <marco@peereboom.us> * Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org> @@ -150,7 +150,7 @@ void sr_meta_chunks_create(struct sr_softc *, void sr_meta_init(struct sr_discipline *, struct sr_chunk_head *); void sr_meta_opt_handler(struct sr_discipline *, - struct sr_meta_opt *); + struct sr_meta_opt_hdr *); /* hotplug magic */ void sr_disk_attach(struct disk *, int); @@ -605,9 +605,9 @@ sr_meta_init(struct sr_discipline *sd, struct sr_chunk_head *cl) } void -sr_meta_opt_handler(struct sr_discipline *sd, struct sr_meta_opt *om) +sr_meta_opt_handler(struct sr_discipline *sd, struct sr_meta_opt_hdr *om) { - if (om->somi.som_type != SR_OPT_BOOT) + if (om->som_type != SR_OPT_BOOT) panic("unknown optional metadata type"); } @@ -636,8 +636,8 @@ sr_meta_save(struct sr_discipline *sd, u_int32_t flags) struct sr_chunk *src; struct sr_meta_chunk *cm; struct sr_workunit wu; + struct sr_meta_opt_hdr *omh; struct sr_meta_opt_item *omi; - struct sr_meta_opt *om; int i; DNPRINTF(SR_D_META, "%s: sr_meta_save %s\n", @@ -672,12 +672,17 @@ restart: } /* Optional metadata. */ - om = (struct sr_meta_opt *)(cm); + omh = (struct sr_meta_opt_hdr *)(cm); SLIST_FOREACH(omi, &sd->sd_meta_opt, omi_link) { - bcopy(&omi->omi_om, om, sizeof(*om)); - sr_checksum(sc, om, &om->som_checksum, - sizeof(struct sr_meta_opt_invariant)); - om++; + DNPRINTF(SR_D_META, "%s: saving optional metadata type %u with " + "length %u\n", DEVNAME(sc), omi->omi_som->som_type, + omi->omi_som->som_length); + bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH); + sr_checksum(sc, omi->omi_som, &omi->omi_som->som_checksum, + omi->omi_som->som_length); + bcopy(omi->omi_som, omh, omi->omi_som->som_length); + omh = (struct sr_meta_opt_hdr *)((u_int8_t *)omh + + omi->omi_som->som_length); } for (i = 0; i < sm->ssdi.ssd_chunk_no; i++) { @@ -793,8 +798,8 @@ sr_meta_read(struct sr_discipline *sd) sr_meta_opt_load(sc, sm, &sd->sd_meta_opt); SLIST_FOREACH(omi, &sd->sd_meta_opt, omi_link) if (sd->sd_meta_opt_handler == NULL || - sd->sd_meta_opt_handler(sd, &omi->omi_om) != 0) - sr_meta_opt_handler(sd, &omi->omi_om); + sd->sd_meta_opt_handler(sd, omi->omi_som) != 0) + sr_meta_opt_handler(sd, omi->omi_som); cp++; no_disk++; @@ -814,21 +819,85 @@ void sr_meta_opt_load(struct sr_softc *sc, struct sr_metadata *sm, struct sr_meta_opt_head *som) { + struct sr_meta_opt_hdr *omh; struct sr_meta_opt_item *omi; - struct sr_meta_opt *om; + u_int8_t checksum[MD5_DIGEST_LENGTH]; int i; /* Process optional metadata. */ - om = (struct sr_meta_opt *)((u_int8_t *)(sm + 1) + + omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) + sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no); for (i = 0; i < sm->ssdi.ssd_opt_no; i++) { omi = malloc(sizeof(struct sr_meta_opt_item), M_DEVBUF, M_WAITOK | M_ZERO); - bcopy(om, &omi->omi_om, sizeof(struct sr_meta_opt)); SLIST_INSERT_HEAD(som, omi, omi_link); - om++; + if (omh->som_length == 0) { + + /* Load old fixed length optional metadata. */ + DNPRINTF(SR_D_META, "%s: old optional metadata of type " + "%u\n", DEVNAME(sc), omh->som_type); + + /* Validate checksum. */ + sr_checksum(sc, (void *)omh, &checksum, + SR_OLD_META_OPT_SIZE - MD5_DIGEST_LENGTH); + if (bcmp(&checksum, (void *)omh + SR_OLD_META_OPT_MD5, + sizeof(checksum))) + panic("%s: invalid optional metadata " + "checksum", DEVNAME(sc)); + + /* Determine correct length. */ + switch (omh->som_type) { + case SR_OPT_CRYPTO: + omh->som_length = sizeof(struct sr_meta_crypto); + break; + case SR_OPT_BOOT: + omh->som_length = sizeof(struct sr_meta_boot); + break; + case SR_OPT_KEYDISK: + omh->som_length = + sizeof(struct sr_meta_keydisk); + break; + default: + panic("unknown old optional metadata " + "type %u\n", omh->som_type); + } + + omi->omi_som = malloc(omh->som_length, M_DEVBUF, + M_WAITOK | M_ZERO); + bcopy((u_int8_t *)omh + SR_OLD_META_OPT_OFFSET, + (u_int8_t *)omi->omi_som + sizeof(*omi->omi_som), + omh->som_length - sizeof(*omi->omi_som)); + omi->omi_som->som_type = omh->som_type; + omi->omi_som->som_length = omh->som_length; + + omh = (struct sr_meta_opt_hdr *)((void *)omh + + SR_OLD_META_OPT_SIZE); + } else { + + /* Load variable length optional metadata. */ + DNPRINTF(SR_D_META, "%s: optional metadata of type %u, " + "length %u\n", DEVNAME(sc), omh->som_type, + omh->som_length); + omi->omi_som = malloc(omh->som_length, M_DEVBUF, + M_WAITOK | M_ZERO); + bcopy(omh, omi->omi_som, omh->som_length); + + /* Validate checksum. */ + bcopy(&omi->omi_som->som_checksum, &checksum, + MD5_DIGEST_LENGTH); + bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH); + sr_checksum(sc, omi->omi_som, + &omi->omi_som->som_checksum, omh->som_length); + if (bcmp(&checksum, &omi->omi_som->som_checksum, + sizeof(checksum))) + panic("%s: invalid optional metadata checksum", + DEVNAME(sc)); + + omh = (struct sr_meta_opt_hdr *)((void *)omh + + omh->som_length); + } } } @@ -841,9 +910,9 @@ sr_meta_validate(struct sr_discipline *sd, dev_t dev, struct sr_metadata *sm, #ifdef SR_DEBUG struct sr_meta_chunk *mc; #endif + u_int8_t checksum[MD5_DIGEST_LENGTH]; char devname[32]; int rv = 1; - u_int8_t checksum[MD5_DIGEST_LENGTH]; DNPRINTF(SR_D_META, "%s: sr_meta_validate(%p)\n", DEVNAME(sc), sm); @@ -880,13 +949,10 @@ sr_meta_validate(struct sr_discipline *sd, dev_t dev, struct sr_metadata *sm, * Version 3 - update metadata version and fix up data offset * value since this did not exist in version 3. */ - sm->ssdi.ssd_version = SR_META_VERSION; - snprintf(sm->ssdi.ssd_revision, sizeof(sm->ssdi.ssd_revision), - "%03d", SR_META_VERSION); if (sm->ssd_data_offset == 0) sm->ssd_data_offset = SR_META_V3_DATA_OFFSET; - } else if (sm->ssdi.ssd_version == SR_META_VERSION) { + } else if (sm->ssdi.ssd_version == 4) { /* * Version 4 - original metadata format did not store @@ -895,6 +961,14 @@ sr_meta_validate(struct sr_discipline *sd, dev_t dev, struct sr_metadata *sm, if (sm->ssd_data_offset == 0) sm->ssd_data_offset = SR_DATA_OFFSET; + } else if (sm->ssdi.ssd_version == SR_META_VERSION) { + + /* + * Version 5 - variable length optional metadata. Migration + * from earlier fixed length optional metadata is handled + * in sr_meta_read(). + */ + } else { printf("%s: %s can not read metadata version %u, expected %u\n", @@ -904,6 +978,11 @@ sr_meta_validate(struct sr_discipline *sd, dev_t dev, struct sr_metadata *sm, } + /* Update version number and revision string. */ + sm->ssdi.ssd_version = SR_META_VERSION; + snprintf(sm->ssdi.ssd_revision, sizeof(sm->ssdi.ssd_revision), + "%03d", SR_META_VERSION); + #ifdef SR_DEBUG /* warn if disk changed order */ mc = (struct sr_meta_chunk *)(sm + 1); @@ -3377,7 +3456,7 @@ void sr_discipline_free(struct sr_discipline *sd) { struct sr_softc *sc; - struct sr_meta_opt_head *omh; + struct sr_meta_opt_head *som; struct sr_meta_opt_item *omi, *omi_next; if (!sd) @@ -3397,9 +3476,11 @@ sr_discipline_free(struct sr_discipline *sd) if (sd->sd_meta_foreign) free(sd->sd_meta_foreign, M_DEVBUF); - omh = &sd->sd_meta_opt; - for (omi = SLIST_FIRST(omh); omi != SLIST_END(omh); omi = omi_next) { + som = &sd->sd_meta_opt; + for (omi = SLIST_FIRST(som); omi != SLIST_END(som); omi = omi_next) { omi_next = SLIST_NEXT(omi, omi_link); + if (omi->omi_som) + free(omi->omi_som, M_DEVBUF); free(omi, M_DEVBUF); } @@ -4217,7 +4298,7 @@ sr_meta_print(struct sr_metadata *m) { int i; struct sr_meta_chunk *mc; - struct sr_meta_opt *mo; + struct sr_meta_opt_hdr *omh; if (!(sr_debug & SR_D_META)) return; @@ -4259,12 +4340,15 @@ sr_meta_print(struct sr_metadata *m) printf("\t\tscm_status %d\n", mc->scm_status); } - mo = (struct sr_meta_opt *)(mc); - for (i = 0; i < m->ssdi.ssd_opt_no; i++, mo++) { - printf("\t\t\tsom_type %d\n", mo->somi.som_type); + omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(m + 1) + + sizeof(struct sr_meta_chunk) * m->ssdi.ssd_chunk_no); + for (i = 0; i < m->ssdi.ssd_opt_no; i++) { + printf("\t\t\tsom_type %d\n", omh->som_type); printf("\t\t\tsom_checksum "); - sr_checksum_print(mo->som_checksum); + sr_checksum_print(omh->som_checksum); printf("\n"); + omh = (struct sr_meta_opt_hdr *)((void *)omh + + omh->som_length); } } diff --git a/sys/dev/softraid_crypto.c b/sys/dev/softraid_crypto.c index 73ae5efc3da..80a1983ddeb 100644 --- a/sys/dev/softraid_crypto.c +++ b/sys/dev/softraid_crypto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: softraid_crypto.c,v 1.72 2011/09/18 13:11:08 jsing Exp $ */ +/* $OpenBSD: softraid_crypto.c,v 1.73 2011/09/18 19:40:49 jsing Exp $ */ /* * Copyright (c) 2007 Marco Peereboom <marco@peereboom.us> * Copyright (c) 2008 Hans-Joerg Hoexer <hshoexer@openbsd.org> @@ -92,7 +92,7 @@ int sr_crypto_free_resources(struct sr_discipline *); int sr_crypto_ioctl(struct sr_discipline *, struct bioc_discipline *); int sr_crypto_meta_opt_handler(struct sr_discipline *, - struct sr_meta_opt *); + struct sr_meta_opt_hdr *); int sr_crypto_write(struct cryptop *); int sr_crypto_rw(struct sr_workunit *); int sr_crypto_rw2(struct sr_workunit *, struct sr_crypto_wu *); @@ -154,9 +154,12 @@ sr_crypto_create(struct sr_discipline *sd, struct bioc_createraid *bc, /* Create crypto optional metadata. */ omi = malloc(sizeof(struct sr_meta_opt_item), M_DEVBUF, M_WAITOK | M_ZERO); - omi->omi_om.somi.som_type = SR_OPT_CRYPTO; + omi->omi_som = malloc(sizeof(struct sr_meta_crypto), M_DEVBUF, + M_WAITOK | M_ZERO); + omi->omi_som->som_type = SR_OPT_CRYPTO; + omi->omi_som->som_length = sizeof(struct sr_meta_crypto); SLIST_INSERT_HEAD(&sd->sd_meta_opt, omi, omi_link); - sd->mds.mdd_crypto.scr_meta = &omi->omi_om.somi.som_meta.smm_crypto; + sd->mds.mdd_crypto.scr_meta = (struct sr_meta_crypto *)omi->omi_som; sd->sd_meta->ssdi.ssd_opt_no++; sd->mds.mdd_crypto.key_disk = NULL; @@ -676,6 +679,7 @@ sr_crypto_create_key_disk(struct sr_discipline *sd, dev_t dev) struct sr_metadata *sm = NULL; struct sr_meta_chunk *km; struct sr_meta_opt_item *omi = NULL; + struct sr_meta_keydisk *skm; struct sr_chunk *key_disk = NULL; struct disklabel label; struct vnode *vn; @@ -793,14 +797,17 @@ sr_crypto_create_key_disk(struct sr_discipline *sd, dev_t dev) sizeof(sd->mds.mdd_crypto.scr_maskkey)); /* Copy mask key to optional metadata area. */ - sm->ssdi.ssd_opt_no = 1; omi = malloc(sizeof(struct sr_meta_opt_item), M_DEVBUF, M_WAITOK | M_ZERO); - omi->omi_om.somi.som_type = SR_OPT_KEYDISK; - bcopy(sd->mds.mdd_crypto.scr_maskkey, - omi->omi_om.somi.som_meta.smm_keydisk.skm_maskkey, - sizeof(omi->omi_om.somi.som_meta.smm_keydisk.skm_maskkey)); + omi->omi_som = malloc(sizeof(struct sr_meta_keydisk), M_DEVBUF, + M_WAITOK | M_ZERO); + omi->omi_som->som_type = SR_OPT_KEYDISK; + omi->omi_som->som_length = sizeof(struct sr_meta_keydisk); + skm = (struct sr_meta_keydisk *)omi->omi_som; + bcopy(sd->mds.mdd_crypto.scr_maskkey, &skm->skm_maskkey, + sizeof(skm->skm_maskkey)); SLIST_INSERT_HEAD(&fakesd->sd_meta_opt, omi, omi_link); + fakesd->sd_meta->ssdi.ssd_opt_no++; /* Save metadata. */ if (sr_meta_save(fakesd, SR_META_DIRTY)) { @@ -838,7 +845,10 @@ sr_crypto_read_key_disk(struct sr_discipline *sd, dev_t dev) { struct sr_softc *sc = sd->sd_sc; struct sr_metadata *sm = NULL; - struct sr_meta_opt *om; + struct sr_meta_opt_item *omi, *omi_next; + struct sr_meta_opt_hdr *omh; + struct sr_meta_keydisk *skm; + struct sr_meta_opt_head som; struct sr_chunk *key_disk = NULL; struct disklabel label; struct vnode *vn = NULL; @@ -920,26 +930,33 @@ sr_crypto_read_key_disk(struct sr_discipline *sd, dev_t dev) sizeof(key_disk->src_meta)); /* Read mask key from optional metadata. */ - om = (struct sr_meta_opt *)((u_int8_t *)(sm + 1) + - sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no); - for (c = 0; c < sm->ssdi.ssd_opt_no; c++) { - if (om->somi.som_type == SR_OPT_KEYDISK) { - bcopy(&om->somi.som_meta.smm_keydisk.skm_maskkey, + SLIST_INIT(&som); + sr_meta_opt_load(sc, sm, &som); + SLIST_FOREACH(omi, &som, omi_link) { + omh = omi->omi_som; + if (omh->som_type == SR_OPT_KEYDISK) { + skm = (struct sr_meta_keydisk *)omh; + bcopy(&skm->skm_maskkey, sd->mds.mdd_crypto.scr_maskkey, sizeof(sd->mds.mdd_crypto.scr_maskkey)); - break; - } else if (om->somi.som_type == SR_OPT_CRYPTO) { - bcopy(&om->somi.som_meta.smm_crypto, + } else if (omh->som_type == SR_OPT_CRYPTO) { + /* Original keydisk format with key in crypto area. */ + bcopy(omh + sizeof(struct sr_meta_opt_hdr), sd->mds.mdd_crypto.scr_maskkey, sizeof(sd->mds.mdd_crypto.scr_maskkey)); - break; } - om++; } open = 0; done: + for (omi = SLIST_FIRST(&som); omi != SLIST_END(&som); omi = omi_next) { + omi_next = SLIST_NEXT(omi, omi_link); + if (omi->omi_som) + free(omi->omi_som, M_DEVBUF); + free(omi, M_DEVBUF); + } + if (sm) free(sm, M_DEVBUF); @@ -1150,12 +1167,12 @@ bad: } int -sr_crypto_meta_opt_handler(struct sr_discipline *sd, struct sr_meta_opt *om) +sr_crypto_meta_opt_handler(struct sr_discipline *sd, struct sr_meta_opt_hdr *om) { int rv = EINVAL; - if (om->somi.som_type == SR_OPT_CRYPTO) { - sd->mds.mdd_crypto.scr_meta = &om->somi.som_meta.smm_crypto; + if (om->som_type == SR_OPT_CRYPTO) { + sd->mds.mdd_crypto.scr_meta = (struct sr_meta_crypto *)om; rv = 0; } diff --git a/sys/dev/softraidvar.h b/sys/dev/softraidvar.h index 0b27906da56..a53f55adada 100644 --- a/sys/dev/softraidvar.h +++ b/sys/dev/softraidvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: softraidvar.h,v 1.107 2011/09/18 13:11:08 jsing Exp $ */ +/* $OpenBSD: softraidvar.h,v 1.108 2011/09/18 19:40:49 jsing Exp $ */ /* * Copyright (c) 2006 Marco Peereboom <marco@peereboom.us> * Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org> @@ -28,7 +28,7 @@ #include <crypto/md5.h> -#define SR_META_VERSION 4 /* bump when sr_metadata changes */ +#define SR_META_VERSION 5 /* bump when sr_metadata changes */ #define SR_META_SIZE 64 /* save space at chunk beginning */ #define SR_META_OFFSET 16 /* skip 8192 bytes at chunk beginning */ @@ -134,7 +134,19 @@ struct sr_crypto_chk_hmac_sha1 { u_int8_t sch_mac[20]; } __packed; +#define SR_OPT_INVALID 0x00 +#define SR_OPT_CRYPTO 0x01 +#define SR_OPT_BOOT 0x02 +#define SR_OPT_KEYDISK 0x03 + +struct sr_meta_opt_hdr { + u_int32_t som_type; /* optional metadata type. */ + u_int32_t som_length; /* optional metadata length. */ + u_int8_t som_checksum[MD5_DIGEST_LENGTH]; +} __packed; + struct sr_meta_crypto { + struct sr_meta_opt_hdr scm_hdr; u_int32_t scm_alg; /* vol crypto algorithm */ #define SR_CRYPTOA_AES_XTS_128 1 #define SR_CRYPTOA_AES_XTS_256 2 @@ -163,38 +175,23 @@ struct sr_meta_crypto { } __packed; struct sr_meta_boot { + struct sr_meta_opt_hdr sbm_hdr; u_int64_t sbm_root_uid; u_int32_t sbm_bootblk_size; u_int32_t sbm_bootldr_size; } __packed; struct sr_meta_keydisk { + struct sr_meta_opt_hdr skm_hdr; u_int8_t skm_maskkey[SR_CRYPTO_MAXKEYBYTES]; } __packed; -struct sr_meta_opt { - struct sr_meta_opt_invariant { - u_int32_t som_type; /* optional type */ -#define SR_OPT_INVALID 0x00 -#define SR_OPT_CRYPTO 0x01 -#define SR_OPT_BOOT 0x02 -#define SR_OPT_KEYDISK 0x03 - u_int32_t som_pad; - union { - struct sr_meta_crypto smm_crypto; - struct sr_meta_boot smm_boot; - struct sr_meta_keydisk smm_keydisk; - } som_meta; - } _som_invariant; -#define somi _som_invariant -#define somi_crypto _som_invariant.smm_crypto -#define somi_boot _som_invariant.smm_boot - /* MD5 of invariant optional metadata */ - u_int8_t som_checksum[MD5_DIGEST_LENGTH]; -} __packed; +#define SR_OLD_META_OPT_SIZE 2480 +#define SR_OLD_META_OPT_OFFSET 8 +#define SR_OLD_META_OPT_MD5 (SR_OLD_META_OPT_SIZE - MD5_DIGEST_LENGTH) struct sr_meta_opt_item { - struct sr_meta_opt omi_om; + struct sr_meta_opt_hdr *omi_som; SLIST_ENTRY(sr_meta_opt_item) omi_link; }; @@ -560,7 +557,7 @@ struct sr_discipline { void (*sd_set_vol_state)(struct sr_discipline *); int (*sd_openings)(struct sr_discipline *); int (*sd_meta_opt_handler)(struct sr_discipline *, - struct sr_meta_opt *); + struct sr_meta_opt_hdr *); /* SCSI emulation */ struct scsi_sense_data sd_scsi_sense; |