diff options
-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; |