From 2c55d0903d506fe90b5f2cb6608cba5a6672b3c2 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Thu, 18 Aug 2016 00:37:07 +0000 Subject: [PATCH] Add SHA512, skein, large blocks support for loader zfs. Updated sha512 from illumos. Using skein from freebsd crypto tree. Since loader itself is using 64MB memory for heap, updated zfsboot to use same, and this also allows to support zfs large blocks. Note, adding additional features does increate zfsboot code, therefore this update does increase zfsboot code to 128k, also I have ported gptldr.S update to zfsldr.S to support 64k+ code. With this update, boot1.efi has almost reached the current limit of the size set for it, so one of the future patches for boot1.efi will need to increase the limit. Currently known missing zfs features in boot loader are edonr and gzip support. Reviewed by: delphij, imp Approved by: imp (mentor) Obtained from: sha256.c update and skein_zfs.c stub from illumos. Differential Revision: https://reviews.freebsd.org/D7418 --- sys/boot/efi/boot1/Makefile | 5 + sys/boot/efi/loader/Makefile | 3 + sys/boot/i386/boot2/Makefile | 2 +- sys/boot/i386/gptboot/Makefile | 4 +- sys/boot/i386/gptboot/gptldr.S | 2 +- sys/boot/i386/gptzfsboot/Makefile | 12 +- sys/boot/i386/zfsboot/Makefile | 15 +- sys/boot/i386/zfsboot/zfsboot.c | 2 +- sys/boot/i386/zfsboot/zfsldr.S | 65 +++++--- sys/boot/userboot/ficl/Makefile | 3 + sys/boot/userboot/userboot/Makefile | 2 + sys/boot/userboot/zfs/Makefile | 5 +- sys/boot/zfs/Makefile | 4 + sys/boot/zfs/zfsimpl.c | 121 ++++++++++++-- sys/cddl/boot/zfs/fletcher.c | 14 +- sys/cddl/boot/zfs/sha256.c | 244 +++++++++++++++++++++++++--- sys/cddl/boot/zfs/skein_zfs.c | 92 +++++++++++ sys/cddl/boot/zfs/zfsimpl.h | 25 ++- sys/cddl/boot/zfs/zfssubr.c | 145 +++++++++++++---- 19 files changed, 640 insertions(+), 125 deletions(-) create mode 100644 sys/cddl/boot/zfs/skein_zfs.c diff --git a/sys/boot/efi/boot1/Makefile b/sys/boot/efi/boot1/Makefile index 0c2394524b0..12144786ed4 100644 --- a/sys/boot/efi/boot1/Makefile +++ b/sys/boot/efi/boot1/Makefile @@ -19,12 +19,16 @@ CWARNFLAGS.zfs_module.c += -Wno-missing-prototypes CWARNFLAGS.zfs_module.c += -Wno-sign-compare CWARNFLAGS.zfs_module.c += -Wno-unused-parameter CWARNFLAGS.zfs_module.c += -Wno-unused-function +CWARNFLAGS.skein.c += -Wno-cast-align +CWARNFLAGS.skein.c += -Wno-missing-variable-declarations .endif # architecture-specific loader code SRCS= boot1.c self_reloc.c start.S ufs_module.c .if ${MK_ZFS} != "no" SRCS+= zfs_module.c +SRCS+= skein.c skein_block.c +.PATH: ${.CURDIR}/../../../crypto/skein .endif CFLAGS+= -I. @@ -40,6 +44,7 @@ CFLAGS+= -DEFI_DEBUG .if ${MK_ZFS} != "no" CFLAGS+= -I${.CURDIR}/../../zfs/ CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs/ +CFLAGS+= -I${.CURDIR}/../../../crypto/skein CFLAGS+= -DEFI_ZFS_BOOT .endif diff --git a/sys/boot/efi/loader/Makefile b/sys/boot/efi/loader/Makefile index 2f54032cd05..07c7af17212 100644 --- a/sys/boot/efi/loader/Makefile +++ b/sys/boot/efi/loader/Makefile @@ -24,6 +24,8 @@ SRCS= autoload.c \ .if ${MK_ZFS} != "no" SRCS+= zfs.c .PATH: ${.CURDIR}/../../zfs +SRCS+= skein.c skein_block.c +.PATH: ${.CURDIR}/../../../crypto/skein # Disable warnings that are currently incompatible with the zfs boot code CWARNFLAGS.zfs.c+= -Wno-sign-compare @@ -53,6 +55,7 @@ CFLAGS+= -I${.CURDIR}/../../i386/libi386 .if ${MK_ZFS} != "no" CFLAGS+= -I${.CURDIR}/../../zfs CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs +CFLAGS+= -I${.CURDIR}/../../../crypto/skein CFLAGS+= -DEFI_ZFS_BOOT .endif CFLAGS+= -DNO_PCI -DEFI diff --git a/sys/boot/i386/boot2/Makefile b/sys/boot/i386/boot2/Makefile index 16ed40483f5..aac799335f1 100644 --- a/sys/boot/i386/boot2/Makefile +++ b/sys/boot/i386/boot2/Makefile @@ -33,7 +33,7 @@ CFLAGS= -fomit-frame-pointer \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ -I${.CURDIR}/../../common \ -I${.CURDIR}/../btx/lib -I. \ - -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \ + -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Winline diff --git a/sys/boot/i386/gptboot/Makefile b/sys/boot/i386/gptboot/Makefile index cc8251c9de6..b89a4727208 100644 --- a/sys/boot/i386/gptboot/Makefile +++ b/sys/boot/i386/gptboot/Makefile @@ -32,10 +32,10 @@ CFLAGS= -DBOOTPROG=\"gptboot\" \ -I${.CURDIR}/../btx/lib -I. \ -I${.CURDIR}/../boot2 \ -I${.CURDIR}/../../.. \ - -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \ + -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ - -Winline + -Winline -Wno-pointer-sign CFLAGS.gcc+= --param max-inline-insns-single=100 diff --git a/sys/boot/i386/gptboot/gptldr.S b/sys/boot/i386/gptboot/gptldr.S index bbd32ba3d29..088122f3b34 100644 --- a/sys/boot/i386/gptboot/gptldr.S +++ b/sys/boot/i386/gptboot/gptldr.S @@ -45,7 +45,7 @@ /* Misc. Constants */ .set SIZ_PAG,0x1000 # Page size .set SIZ_SEC,0x200 # Sector size - .set COPY_BLKS,0x4 # Number of blocks + .set COPY_BLKS,0x8 # Number of blocks # to copy for boot2 .set COPY_BLK_SZ,0x8000 # Copy in 32k blocks; must be # a multiple of 16 bytes diff --git a/sys/boot/i386/gptzfsboot/Makefile b/sys/boot/i386/gptzfsboot/Makefile index 97ddd39ae72..cd4eef81247 100644 --- a/sys/boot/i386/gptzfsboot/Makefile +++ b/sys/boot/i386/gptzfsboot/Makefile @@ -2,7 +2,7 @@ .PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../gptboot \ ${.CURDIR}/../zfsboot ${.CURDIR}/../common \ - ${.CURDIR}/../../common + ${.CURDIR}/../../common ${.CURDIR}/../../../crypto/skein FILES= gptzfsboot MAN= gptzfsboot.8 @@ -27,13 +27,14 @@ CFLAGS= -DBOOTPROG=\"gptzfsboot\" \ -I${.CURDIR}/../common \ -I${.CURDIR}/../../zfs \ -I${.CURDIR}/../../../cddl/boot/zfs \ + -I${.CURDIR}/../../../crypto/skein \ -I${.CURDIR}/../btx/lib -I. \ -I${.CURDIR}/../boot2 \ -I${.CURDIR}/../../.. \ - -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \ + -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ - -Winline + -Winline -Wno-tentative-definition-incomplete-type -Wno-pointer-sign .if !defined(LOADER_NO_GELI_SUPPORT) CFLAGS+= -DLOADER_GELI_SUPPORT @@ -67,12 +68,13 @@ gptldr.out: gptldr.o ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o CLEANFILES+= gptzfsboot.bin gptzfsboot.out zfsboot.o sio.o cons.o \ - drv.o gpt.o util.o ${OPENCRYPTO_XTS} + drv.o gpt.o util.o skein.o skein_block.o ${OPENCRYPTO_XTS} gptzfsboot.bin: gptzfsboot.out ${OBJCOPY} -S -O binary gptzfsboot.out ${.TARGET} -gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o util.o ${OPENCRYPTO_XTS} +gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o util.o \ + skein.o skein_block.o ${OPENCRYPTO_XTS} ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT} zfsboot.o: ${.CURDIR}/../../zfs/zfsimpl.c diff --git a/sys/boot/i386/zfsboot/Makefile b/sys/boot/i386/zfsboot/Makefile index 7f434a8459b..dadcecb915d 100644 --- a/sys/boot/i386/zfsboot/Makefile +++ b/sys/boot/i386/zfsboot/Makefile @@ -1,6 +1,7 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../common ${.CURDIR}/../../common +.PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../common \ + ${.CURDIR}/../../common ${.CURDIR}/../../../crypto/skein FILES= zfsboot MAN= zfsboot.8 @@ -25,9 +26,10 @@ CFLAGS= -DBOOTPROG=\"zfsboot\" \ -I${.CURDIR}/../common \ -I${.CURDIR}/../../zfs \ -I${.CURDIR}/../../../cddl/boot/zfs \ + -I${.CURDIR}/../../../crypto/skein \ -I${.CURDIR}/../btx/lib -I. \ -I${.CURDIR}/../boot2 \ - -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \ + -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Winline @@ -55,12 +57,13 @@ zfsldr.out: zfsldr.o ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} zfsldr.o CLEANFILES+= zfsboot2 zfsboot.ld zfsboot.ldr zfsboot.bin zfsboot.out \ - zfsboot.o zfsboot.s zfsboot.s.tmp sio.o cons.o drv.o util.o + zfsboot.o zfsboot.s zfsboot.s.tmp sio.o cons.o drv.o util.o \ + skein.o skein_block.o -# We currently allow 65536 bytes for zfsboot - in practice it could be +# We currently allow 128k bytes for zfsboot - in practice it could be # any size up to 3.5Mb but keeping it fixed size simplifies zfsldr. # -BOOT2SIZE= 65536 +BOOT2SIZE= 131072 zfsboot2: zfsboot.ld @set -- `ls -l zfsboot.ld`; x=$$((${BOOT2SIZE}-$$5)); \ @@ -77,7 +80,7 @@ zfsboot.ldr: zfsboot.bin: zfsboot.out ${OBJCOPY} -S -O binary zfsboot.out ${.TARGET} -zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o util.o +zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o util.o skein.o skein_block.o ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} SRCS= zfsboot.c diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c index 49140d13060..e372f14e731 100644 --- a/sys/boot/i386/zfsboot/zfsboot.c +++ b/sys/boot/i386/zfsboot/zfsboot.c @@ -105,7 +105,7 @@ static struct bios_smap smap; /* * The minimum amount of memory to reserve in bios_extmem for the heap. */ -#define HEAP_MIN (3 * 1024 * 1024) +#define HEAP_MIN (64 * 1024 * 1024) static char *heap_next; static char *heap_end; diff --git a/sys/boot/i386/zfsboot/zfsldr.S b/sys/boot/i386/zfsboot/zfsldr.S index b8be28265fc..3e85e27aa38 100644 --- a/sys/boot/i386/zfsboot/zfsldr.S +++ b/sys/boot/i386/zfsboot/zfsldr.S @@ -32,8 +32,11 @@ /* Misc. Constants */ .set SIZ_PAG,0x1000 # Page size .set SIZ_SEC,0x200 # Sector size - - .set NSECT,0x80 + .set COPY_BLKS,0x8 # Number of blocks + # to copy for boot2 + .set COPY_BLK_SZ,0x8000 # Copy in 32k blocks; must be + # a multiple of 16 bytes + .set NSECT,(COPY_BLK_SZ / SIZ_SEC * COPY_BLKS) .globl start .code16 @@ -88,12 +91,12 @@ main.3: add $0x10,%si # Next entry /* * Ok, we have a slice and drive in %dx now, so use that to locate and * load boot2. %si references the start of the slice we are looking - * for, so go ahead and load up the 128 sectors starting at sector 1024 - * (i.e. after the two vdev labels). We don't have do anything fancy - * here to allow for an extra copy of boot1 and a partition table - * (compare to this section of the UFS bootstrap) so we just load it - * all at 0x9000. The first part of boot2 is BTX, which wants to run - * at 0x9000. The boot2.bin binary starts right after the end of BTX, + * for, so go ahead and load up the COPY_BLKS*COPY_BLK_SZ/SIZ_SEC sectors + * starting at sector 1024 (i.e. after the two vdev labels). We don't + * have do anything fancy here to allow for an extra copy of boot1 and + * a partition table (compare to this section of the UFS bootstrap) so we + * just load it all at 0x9000. The first part of boot2 is BTX, which wants + * to run at 0x9000. The boot2.bin binary starts right after the end of BTX, * so we have to figure out where the start of it is and then move the * binary to 0xc000. Normally, BTX clients start at MEM_USR, or 0xa000, * but when we use btxld to create zfsboot2, we use an entry point of @@ -116,23 +119,37 @@ main.6: pushal # Save params incl %eax # Advance to add $SIZ_SEC,%ebx # next sector loop main.6 # If not last, read another - mov MEM_BTX+0xa,%bx # Get BTX length - mov $NSECT*SIZ_SEC-1,%di # Size of load area (less one) - mov %di,%si # End of load area, 0x9000 rel - sub %bx,%di # End of client, 0xc000 rel - mov %di,%cx # Size of - inc %cx # client - mov $(MEM_BTX)>>4,%dx # Segment - mov %dx,%ds # addressing 0x9000 - mov $(MEM_USR+2*SIZ_PAG)>>4,%dx # Segment - mov %dx,%es # addressing 0xc000 - std # Move with decrement - rep # Relocate - movsb # client + + mov $MEM_BTX,%bx # BTX + mov 0xa(%bx),%si # Get BTX length and set + add %bx,%si # %si to start of boot2 + dec %si # Set %ds:%si to point at the + mov %si,%ax # last byte we want to copy + shr $4,%ax # from boot2, with %si made as + add $(COPY_BLKS*COPY_BLK_SZ/16),%ax # small as possible. + and $0xf,%si # + mov %ax,%ds # + mov $(MEM_USR+2*SIZ_PAG)/16,%ax # Set %es:(-1) to point at + add $(COPY_BLKS*COPY_BLK_SZ/16),%ax # the last byte we + mov %ax,%es # want to copy boot2 into. + mov $COPY_BLKS,%bx # Copy COPY_BLKS 32k blocks +copyloop: + add $COPY_BLK_SZ,%si # Adjust %ds:%si to point at + mov %ds,%ax # the end of the next 32k to + sub $COPY_BLK_SZ/16,%ax # copy from boot2 + mov %ax,%ds + mov $COPY_BLK_SZ-1,%di # Adjust %es:%di to point at + mov %es,%ax # the end of the next 32k into + sub $COPY_BLK_SZ/16,%ax # which we want boot2 copied + mov %ax,%es + mov $COPY_BLK_SZ,%cx # Copy 32k + std + rep movsb + dec %bx + jnz copyloop + mov %cx,%ds # Reset %ds and %es + mov %cx,%es cld # Back to increment - xor %dx,%dx # Back - mov %ds,%dx # to zero - mov %dx,%es # segment /* * Enable A20 so we can access memory above 1 meg. diff --git a/sys/boot/userboot/ficl/Makefile b/sys/boot/userboot/ficl/Makefile index fd6c7f07056..927a504d8ce 100644 --- a/sys/boot/userboot/ficl/Makefile +++ b/sys/boot/userboot/ficl/Makefile @@ -10,6 +10,9 @@ BASE_SRCS= dict.c ficl.c fileaccess.c float.c loader.c math64.c \ SRCS= ${BASE_SRCS} sysdep.c softcore.c CLEANFILES= softcore.c testmain testmain.o + +CWARNFLAGS.loader.c.c += -Wno-implicit-function-declaration + .if HAVE_PNP CFLAGS+= -DHAVE_PNP .endif diff --git a/sys/boot/userboot/userboot/Makefile b/sys/boot/userboot/userboot/Makefile index b64bcc08ca9..cdc29d192d9 100644 --- a/sys/boot/userboot/userboot/Makefile +++ b/sys/boot/userboot/userboot/Makefile @@ -35,6 +35,8 @@ CFLAGS+= -I${.CURDIR}/../../.. CFLAGS+= -I${.CURDIR}/../../../../lib/libstand CFLAGS+= -ffreestanding -I. +CWARNFLAGS.main.c += -Wno-implicit-function-declaration + LDFLAGS+= -nostdlib -Wl,-Bsymbolic NEWVERSWHAT= "User boot" ${MACHINE_CPUARCH} diff --git a/sys/boot/userboot/zfs/Makefile b/sys/boot/userboot/zfs/Makefile index 8fe315b38ea..cc320a483d9 100644 --- a/sys/boot/userboot/zfs/Makefile +++ b/sys/boot/userboot/zfs/Makefile @@ -2,15 +2,16 @@ S= ${.CURDIR}/../../zfs -.PATH: ${S} +.PATH: ${S} ${.CURDIR}/../../../crypto/skein LIB= zfsboot INTERNALLIB= -SRCS+= zfs.c +SRCS+= zfs.c skein.c skein_block.c CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../../.. -I. CFLAGS+= -I${.CURDIR}/../../../../lib/libstand CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs +CFLAGS+= -I${.CURDIR}/../../../crypto/skein CFLAGS+= -ffreestanding -fPIC CFLAGS+= -Wformat -Wall diff --git a/sys/boot/zfs/Makefile b/sys/boot/zfs/Makefile index 3ab2251ddbe..db0f44a1d6a 100644 --- a/sys/boot/zfs/Makefile +++ b/sys/boot/zfs/Makefile @@ -5,10 +5,14 @@ INTERNALLIB= SRCS+= zfs.c +SRCS+= skein.c skein_block.c +.PATH: ${.CURDIR}/../../crypto/skein + CFLAGS+= -DBOOTPROG=\"zfsloader\" CFLAGS+= -I${.CURDIR}/../common -I${.CURDIR}/../.. -I. CFLAGS+= -I${.CURDIR}/../../../lib/libstand CFLAGS+= -I${.CURDIR}/../../cddl/boot/zfs +CFLAGS+= -I${.CURDIR}/../../crypto/skein .if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -march=i386 diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c index 73fe0b64b8f..85aeb765172 100644 --- a/sys/boot/zfs/zfsimpl.c +++ b/sys/boot/zfs/zfsimpl.c @@ -58,6 +58,8 @@ static const char *features_for_read[] = { "com.delphix:extensible_dataset", "com.delphix:embedded_data", "org.open-zfs:large_blocks", + "org.illumos:sha512", + "org.illumos:skein", NULL }; @@ -78,6 +80,9 @@ static char *zfs_temp_buf, *zfs_temp_end, *zfs_temp_ptr; static int zio_read(const spa_t *spa, const blkptr_t *bp, void *buf); static int zfs_get_root(const spa_t *spa, uint64_t *objid); static int zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result); +static int zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, + const char *name, uint64_t integer_size, uint64_t num_integers, + void *value); static void zfs_init(void) @@ -420,7 +425,7 @@ vdev_read_phys(vdev_t *vdev, const blkptr_t *bp, void *buf, rc = vdev->v_phys_read(vdev, vdev->v_read_priv, offset, buf, psize); if (rc) return (rc); - if (bp && zio_checksum_verify(bp, buf)) + if (bp && zio_checksum_verify(vdev->spa, bp, buf)) return (EIO); return (0); @@ -1074,6 +1079,7 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv, spa_t **spap) } zfs_free(upbuf, VDEV_UBERBLOCK_SIZE(vdev)); + vdev->spa = spa; if (spap) *spap = spa; return (0); @@ -1122,7 +1128,7 @@ zio_read_gang(const spa_t *spa, const blkptr_t *bp, void *buf) pbuf += BP_GET_PSIZE(gbp); } - if (zio_checksum_verify(bp, buf)) + if (zio_checksum_verify(spa, bp, buf)) return (EIO); return (0); } @@ -1224,7 +1230,8 @@ dnode_read(const spa_t *spa, const dnode_phys_t *dnode, off_t offset, void *buf, int i, rc; if (bsize > SPA_MAXBLOCKSIZE) { - printf("ZFS: I/O error - blocks larger than 128K are not supported\n"); + printf("ZFS: I/O error - blocks larger than %llu are not " + "supported\n", SPA_MAXBLOCKSIZE); return (EIO); } @@ -1364,12 +1371,73 @@ fzap_leaf_value(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc) return value; } +static void +stv(int len, void *addr, uint64_t value) +{ + switch (len) { + case 1: + *(uint8_t *)addr = value; + return; + case 2: + *(uint16_t *)addr = value; + return; + case 4: + *(uint32_t *)addr = value; + return; + case 8: + *(uint64_t *)addr = value; + return; + } +} + +/* + * Extract a array from a zap leaf entry. + */ +static void +fzap_leaf_array(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, + uint64_t integer_size, uint64_t num_integers, void *buf) +{ + uint64_t array_int_len = zc->l_entry.le_value_intlen; + uint64_t value = 0; + uint64_t *u64 = buf; + char *p = buf; + int len = MIN(zc->l_entry.le_value_numints, num_integers); + int chunk = zc->l_entry.le_value_chunk; + int byten = 0; + + if (integer_size == 8 && len == 1) { + *u64 = fzap_leaf_value(zl, zc); + return; + } + + while (len > 0) { + struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(zl, chunk).l_array; + int i; + + ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(zl)); + for (i = 0; i < ZAP_LEAF_ARRAY_BYTES && len > 0; i++) { + value = (value << 8) | la->la_array[i]; + byten++; + if (byten == array_int_len) { + stv(integer_size, p, value); + byten = 0; + len--; + if (len == 0) + return; + p += integer_size; + } + } + chunk = la->la_next; + } +} + /* * Lookup a value in a fatzap directory. Assumes that the zap scratch * buffer contains the directory header. */ static int -fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64_t *value) +fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, + uint64_t integer_size, uint64_t num_integers, void *value) { int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; zap_phys_t zh = *(zap_phys_t *) zap_scratch; @@ -1436,9 +1504,10 @@ fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint6 zc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_next); } if (fzap_name_equal(&zl, zc, name)) { - if (zc->l_entry.le_value_intlen * zc->l_entry.le_value_numints > 8) + if (zc->l_entry.le_value_intlen * zc->l_entry.le_value_numints > + integer_size * num_integers) return (E2BIG); - *value = fzap_leaf_value(&zl, zc); + fzap_leaf_array(&zl, zc, integer_size, num_integers, value); return (0); } @@ -1449,7 +1518,8 @@ fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint6 * Lookup a name in a zap object and return its value as a uint64_t. */ static int -zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64_t *value) +zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, + uint64_t integer_size, uint64_t num_integers, void *value) { int rc; uint64_t zap_type; @@ -1462,8 +1532,10 @@ zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64 zap_type = *(uint64_t *) zap_scratch; if (zap_type == ZBT_MICRO) return mzap_lookup(dnode, name, value); - else if (zap_type == ZBT_HEADER) - return fzap_lookup(spa, dnode, name, value); + else if (zap_type == ZBT_HEADER) { + return fzap_lookup(spa, dnode, name, integer_size, + num_integers, value); + } printf("ZFS: invalid zap_type=%d\n", (int)zap_type); return (EIO); } @@ -1802,7 +1874,8 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum) if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, &dir)) return (EIO); - if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, &dir_obj)) + if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (dir_obj), + 1, &dir_obj)) return (EIO); p = name; @@ -1832,7 +1905,8 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum) return (EIO); /* Actual loop condition #2. */ - if (zap_lookup(spa, &child_dir_zap, element, &dir_obj) != 0) + if (zap_lookup(spa, &child_dir_zap, element, sizeof (dir_obj), + 1, &dir_obj) != 0) return (ENOENT); } @@ -1962,9 +2036,9 @@ zfs_get_root(const spa_t *spa, uint64_t *objid) /* * Lookup the pool_props and see if we can find a bootfs. */ - if (zap_lookup(spa, &dir, DMU_POOL_PROPS, &props) == 0 + if (zap_lookup(spa, &dir, DMU_POOL_PROPS, sizeof (props), 1, &props) == 0 && objset_get_dnode(spa, &spa->spa_mos, props, &propdir) == 0 - && zap_lookup(spa, &propdir, "bootfs", &bootfs) == 0 + && zap_lookup(spa, &propdir, "bootfs", sizeof (bootfs), 1, &bootfs) == 0 && bootfs != 0) { *objid = bootfs; @@ -1973,7 +2047,7 @@ zfs_get_root(const spa_t *spa, uint64_t *objid) /* * Lookup the root dataset directory */ - if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, &root) + if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (root), 1, &root) || objset_get_dnode(spa, &spa->spa_mos, root, &dir)) { printf("ZFS: can't find root dsl_dir\n"); return (EIO); @@ -2047,7 +2121,8 @@ check_mos_features(const spa_t *spa) if ((rc = objset_get_dnode(spa, &spa->spa_mos, DMU_OT_OBJECT_DIRECTORY, &dir)) != 0) return (rc); - if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ, &objnum)) != 0) + if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ, + sizeof (objnum), 1, &objnum)) != 0) return (rc); if ((rc = objset_get_dnode(spa, &spa->spa_mos, objnum, &dir)) != 0) @@ -2072,6 +2147,7 @@ check_mos_features(const spa_t *spa) static int zfs_spa_init(spa_t *spa) { + dnode_phys_t dir; int rc; if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) { @@ -2083,6 +2159,17 @@ zfs_spa_init(spa_t *spa) return (EIO); } + if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, + &dir)) { + printf("ZFS: failed to read pool %s directory object\n", + spa->spa_name); + return (EIO); + } + /* this is allowed to fail, older pools do not have salt */ + rc = zap_lookup(spa, &dir, DMU_POOL_CHECKSUM_SALT, 1, + sizeof (spa->spa_cksum_salt.zcs_bytes), + spa->spa_cksum_salt.zcs_bytes); + rc = check_mos_features(spa); if (rc != 0) { printf("ZFS: pool %s is not supported\n", spa->spa_name); @@ -2173,7 +2260,7 @@ zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode) if (rc) return (rc); - rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, &rootnum); + rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, sizeof (rootnum), 1, &rootnum); if (rc) return (rc); @@ -2205,7 +2292,7 @@ zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode) return (ENOTDIR); parentnum = objnum; - rc = zap_lookup(spa, &dn, element, &objnum); + rc = zap_lookup(spa, &dn, element, sizeof (objnum), 1, &objnum); if (rc) return (rc); objnum = ZFS_DIRENT_OBJ(objnum); diff --git a/sys/cddl/boot/zfs/fletcher.c b/sys/cddl/boot/zfs/fletcher.c index 3c600360703..2aa381a9d9a 100644 --- a/sys/cddl/boot/zfs/fletcher.c +++ b/sys/cddl/boot/zfs/fletcher.c @@ -23,10 +23,9 @@ * Use is subject to license terms. */ -/*#pragma ident "%Z%%M% %I% %E% SMI"*/ - static void -fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp) +fletcher_2_native(const void *buf, uint64_t size, + const void *ctx_template __unused, zio_cksum_t *zcp) { const uint64_t *ip = buf; const uint64_t *ipend = ip + (size / sizeof (uint64_t)); @@ -43,7 +42,8 @@ fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp) } static void -fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp) +fletcher_2_byteswap(const void *buf, uint64_t size, + const void *ctx_template __unused, zio_cksum_t *zcp) { const uint64_t *ip = buf; const uint64_t *ipend = ip + (size / sizeof (uint64_t)); @@ -60,7 +60,8 @@ fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp) } static void -fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp) +fletcher_4_native(const void *buf, uint64_t size, + const void *ctx_template __unused, zio_cksum_t *zcp) { const uint32_t *ip = buf; const uint32_t *ipend = ip + (size / sizeof (uint32_t)); @@ -77,7 +78,8 @@ fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp) } static void -fletcher_4_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp) +fletcher_4_byteswap(const void *buf, uint64_t size, + const void *ctx_template __unused, zio_cksum_t *zcp) { const uint32_t *ip = buf; const uint32_t *ipend = ip + (size / sizeof (uint32_t)); diff --git a/sys/cddl/boot/zfs/sha256.c b/sys/cddl/boot/zfs/sha256.c index f0d83acf557..eee98e612a1 100644 --- a/sys/cddl/boot/zfs/sha256.c +++ b/sys/cddl/boot/zfs/sha256.c @@ -23,19 +23,21 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -/*#pragma ident "%Z%%M% %I% %E% SMI"*/ +/* + * Copyright 2013 Saso Kiselkov. All rights reserved. + * Copyright 2015 Toomas Soome + */ /* - * SHA-256 checksum, as specified in FIPS 180-2, available at: + * SHA-256 and SHA-512/256 hashes, as specified in FIPS 180-4, available at: * http://csrc.nist.gov/cryptval * - * This is a very compact implementation of SHA-256. + * This is a very compact implementation of SHA-256 and SHA-512/256. * It is designed to be simple and portable, not to be fast. */ /* - * The literal definitions according to FIPS180-2 would be: + * The literal definitions according to FIPS180-4 would be: * * Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) * Maj(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) @@ -44,12 +46,21 @@ */ #define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) #define Maj(x, y, z) (((x) & (y)) ^ ((z) & ((x) ^ (y)))) -#define Rot32(x, s) (((x) >> s) | ((x) << (32 - s))) -#define SIGMA0(x) (Rot32(x, 2) ^ Rot32(x, 13) ^ Rot32(x, 22)) -#define SIGMA1(x) (Rot32(x, 6) ^ Rot32(x, 11) ^ Rot32(x, 25)) -#define sigma0(x) (Rot32(x, 7) ^ Rot32(x, 18) ^ ((x) >> 3)) -#define sigma1(x) (Rot32(x, 17) ^ Rot32(x, 19) ^ ((x) >> 10)) +#define ROTR(x, n) (((x) >> (n)) | ((x) << ((sizeof (x) * NBBY)-(n)))) +/* SHA-224/256 operations */ +#define BIGSIGMA0_256(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define BIGSIGMA1_256(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define SIGMA0_256(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ ((x) >> 3)) +#define SIGMA1_256(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ ((x) >> 10)) + +/* SHA-384/512 operations */ +#define BIGSIGMA0_512(x) (ROTR((x), 28) ^ ROTR((x), 34) ^ ROTR((x), 39)) +#define BIGSIGMA1_512(x) (ROTR((x), 14) ^ ROTR((x), 18) ^ ROTR((x), 41)) +#define SIGMA0_512(x) (ROTR((x), 1) ^ ROTR((x), 8) ^ ((x) >> 7)) +#define SIGMA1_512(x) (ROTR((x), 19) ^ ROTR((x), 61) ^ ((x) >> 6)) + +/* SHA-256 round constants */ static const uint32_t SHA256_K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, @@ -69,46 +80,134 @@ static const uint32_t SHA256_K[64] = { 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; +/* SHA-512 round constants */ +static const uint64_t SHA512_K[80] = { + 0x428A2F98D728AE22ULL, 0x7137449123EF65CDULL, + 0xB5C0FBCFEC4D3B2FULL, 0xE9B5DBA58189DBBCULL, + 0x3956C25BF348B538ULL, 0x59F111F1B605D019ULL, + 0x923F82A4AF194F9BULL, 0xAB1C5ED5DA6D8118ULL, + 0xD807AA98A3030242ULL, 0x12835B0145706FBEULL, + 0x243185BE4EE4B28CULL, 0x550C7DC3D5FFB4E2ULL, + 0x72BE5D74F27B896FULL, 0x80DEB1FE3B1696B1ULL, + 0x9BDC06A725C71235ULL, 0xC19BF174CF692694ULL, + 0xE49B69C19EF14AD2ULL, 0xEFBE4786384F25E3ULL, + 0x0FC19DC68B8CD5B5ULL, 0x240CA1CC77AC9C65ULL, + 0x2DE92C6F592B0275ULL, 0x4A7484AA6EA6E483ULL, + 0x5CB0A9DCBD41FBD4ULL, 0x76F988DA831153B5ULL, + 0x983E5152EE66DFABULL, 0xA831C66D2DB43210ULL, + 0xB00327C898FB213FULL, 0xBF597FC7BEEF0EE4ULL, + 0xC6E00BF33DA88FC2ULL, 0xD5A79147930AA725ULL, + 0x06CA6351E003826FULL, 0x142929670A0E6E70ULL, + 0x27B70A8546D22FFCULL, 0x2E1B21385C26C926ULL, + 0x4D2C6DFC5AC42AEDULL, 0x53380D139D95B3DFULL, + 0x650A73548BAF63DEULL, 0x766A0ABB3C77B2A8ULL, + 0x81C2C92E47EDAEE6ULL, 0x92722C851482353BULL, + 0xA2BFE8A14CF10364ULL, 0xA81A664BBC423001ULL, + 0xC24B8B70D0F89791ULL, 0xC76C51A30654BE30ULL, + 0xD192E819D6EF5218ULL, 0xD69906245565A910ULL, + 0xF40E35855771202AULL, 0x106AA07032BBD1B8ULL, + 0x19A4C116B8D2D0C8ULL, 0x1E376C085141AB53ULL, + 0x2748774CDF8EEB99ULL, 0x34B0BCB5E19B48A8ULL, + 0x391C0CB3C5C95A63ULL, 0x4ED8AA4AE3418ACBULL, + 0x5B9CCA4F7763E373ULL, 0x682E6FF3D6B2B8A3ULL, + 0x748F82EE5DEFB2FCULL, 0x78A5636F43172F60ULL, + 0x84C87814A1F0AB72ULL, 0x8CC702081A6439ECULL, + 0x90BEFFFA23631E28ULL, 0xA4506CEBDE82BDE9ULL, + 0xBEF9A3F7B2C67915ULL, 0xC67178F2E372532BULL, + 0xCA273ECEEA26619CULL, 0xD186B8C721C0C207ULL, + 0xEADA7DD6CDE0EB1EULL, 0xF57D4F7FEE6ED178ULL, + 0x06F067AA72176FBAULL, 0x0A637DC5A2C898A6ULL, + 0x113F9804BEF90DAEULL, 0x1B710B35131C471BULL, + 0x28DB77F523047D84ULL, 0x32CAAB7B40C72493ULL, + 0x3C9EBE0A15C9BEBCULL, 0x431D67C49C100D4CULL, + 0x4CC5D4BECB3E42B6ULL, 0x597F299CFC657E2AULL, + 0x5FCB6FAB3AD6FAECULL, 0x6C44198C4A475817ULL +}; + static void SHA256Transform(uint32_t *H, const uint8_t *cp) { uint32_t a, b, c, d, e, f, g, h, t, T1, T2, W[64]; - for (t = 0; t < 16; t++, cp += 4) + /* copy chunk into the first 16 words of the message schedule */ + for (t = 0; t < 16; t++, cp += sizeof (uint32_t)) W[t] = (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | cp[3]; + /* extend the first 16 words into the remaining 48 words */ for (t = 16; t < 64; t++) - W[t] = sigma1(W[t - 2]) + W[t - 7] + - sigma0(W[t - 15]) + W[t - 16]; + W[t] = SIGMA1_256(W[t - 2]) + W[t - 7] + + SIGMA0_256(W[t - 15]) + W[t - 16]; + /* init working variables to the current hash value */ a = H[0]; b = H[1]; c = H[2]; d = H[3]; e = H[4]; f = H[5]; g = H[6]; h = H[7]; + /* iterate the compression function for all rounds of the hash */ for (t = 0; t < 64; t++) { - T1 = h + SIGMA1(e) + Ch(e, f, g) + SHA256_K[t] + W[t]; - T2 = SIGMA0(a) + Maj(a, b, c); + T1 = h + BIGSIGMA1_256(e) + Ch(e, f, g) + SHA256_K[t] + W[t]; + T2 = BIGSIGMA0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; } + /* add the compressed chunk to the current hash value */ H[0] += a; H[1] += b; H[2] += c; H[3] += d; H[4] += e; H[5] += f; H[6] += g; H[7] += h; } static void -zio_checksum_SHA256(const void *buf, uint64_t size, zio_cksum_t *zcp) +SHA512Transform(uint64_t *H, const uint8_t *cp) { - uint32_t H[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; - uint8_t pad[128]; - int padsize = size & 63; - int i; + uint64_t a, b, c, d, e, f, g, h, t, T1, T2, W[80]; + /* copy chunk into the first 16 words of the message schedule */ + for (t = 0; t < 16; t++, cp += sizeof (uint64_t)) + W[t] = ((uint64_t)cp[0] << 56) | ((uint64_t)cp[1] << 48) | + ((uint64_t)cp[2] << 40) | ((uint64_t)cp[3] << 32) | + ((uint64_t)cp[4] << 24) | ((uint64_t)cp[5] << 16) | + ((uint64_t)cp[6] << 8) | (uint64_t)cp[7]; + + /* extend the first 16 words into the remaining 64 words */ + for (t = 16; t < 80; t++) + W[t] = SIGMA1_512(W[t - 2]) + W[t - 7] + + SIGMA0_512(W[t - 15]) + W[t - 16]; + + /* init working variables to the current hash value */ + a = H[0]; b = H[1]; c = H[2]; d = H[3]; + e = H[4]; f = H[5]; g = H[6]; h = H[7]; + + /* iterate the compression function for all rounds of the hash */ + for (t = 0; t < 80; t++) { + T1 = h + BIGSIGMA1_512(e) + Ch(e, f, g) + SHA512_K[t] + W[t]; + T2 = BIGSIGMA0_512(a) + Maj(a, b, c); + h = g; g = f; f = e; e = d + T1; + d = c; c = b; b = a; a = T1 + T2; + } + + /* add the compressed chunk to the current hash value */ + H[0] += a; H[1] += b; H[2] += c; H[3] += d; + H[4] += e; H[5] += f; H[6] += g; H[7] += h; +} + +/* + * Implements the SHA-224 and SHA-256 hash algos - to select between them + * pass the appropriate initial values of 'H' and truncate the last 32 bits + * in case of SHA-224. + */ +static void +SHA256(uint32_t *H, const void *buf, uint64_t size, zio_cksum_t *zcp) +{ + uint8_t pad[128]; + unsigned padsize = size & 63; + unsigned i, k; + + /* process all blocks up to the last one */ for (i = 0; i < size - padsize; i += 64) SHA256Transform(H, (uint8_t *)buf + i); - for (i = 0; i < padsize; i++) - pad[i] = ((uint8_t *)buf)[i]; + /* process the last block and padding */ + for (k = 0; k < padsize; k++) + pad[k] = ((uint8_t *)buf)[k+i]; for (pad[padsize++] = 0x80; (padsize & 63) != 56; padsize++) pad[padsize] = 0; @@ -125,3 +224,102 @@ zio_checksum_SHA256(const void *buf, uint64_t size, zio_cksum_t *zcp) (uint64_t)H[4] << 32 | H[5], (uint64_t)H[6] << 32 | H[7]); } + +/* + * encode 64bit data in big-endian format. + */ +static void +Encode64(uint8_t *output, uint64_t *input, size_t len) +{ + size_t i, j; + for (i = 0, j = 0; j < len; i++, j += 8) { + output[j] = (input[i] >> 56) & 0xff; + output[j + 1] = (input[i] >> 48) & 0xff; + output[j + 2] = (input[i] >> 40) & 0xff; + output[j + 3] = (input[i] >> 32) & 0xff; + output[j + 4] = (input[i] >> 24) & 0xff; + output[j + 5] = (input[i] >> 16) & 0xff; + output[j + 6] = (input[i] >> 8) & 0xff; + output[j + 7] = input[i] & 0xff; + } +} + +/* + * Implements the SHA-384, SHA-512 and SHA-512/t hash algos - to select + * between them pass the appropriate initial values for 'H'. The output + * of this function is truncated to the first 256 bits that fit into 'zcp'. + */ +static void +SHA512(uint64_t *H, const void *buf, uint64_t size, zio_cksum_t *zcp) +{ + uint64_t c64[2]; + uint8_t pad[256]; + unsigned padsize = size & 127; + unsigned i, k; + + /* process all blocks up to the last one */ + for (i = 0; i < size - padsize; i += 128) + SHA512Transform(H, (uint8_t *)buf + i); + + /* process the last block and padding */ + for (k = 0; k < padsize; k++) + pad[k] = ((uint8_t *)buf)[k+i]; + + if (padsize < 112) { + for (pad[padsize++] = 0x80; padsize < 112; padsize++) + pad[padsize] = 0; + } else { + for (pad[padsize++] = 0x80; padsize < 240; padsize++) + pad[padsize] = 0; + } + + c64[0] = 0; + c64[1] = size << 3; + Encode64(pad+padsize, c64, sizeof (c64)); + padsize += sizeof (c64); + + for (i = 0; i < padsize; i += 128) + SHA512Transform(H, pad + i); + + /* truncate the output to the first 256 bits which fit into 'zcp' */ + Encode64((uint8_t *)zcp, H, sizeof (uint64_t) * 4); +} + +static void +zio_checksum_SHA256(const void *buf, uint64_t size, + const void *ctx_template __unused, zio_cksum_t *zcp) +{ + /* SHA-256 as per FIPS 180-4. */ + uint32_t H[] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + }; + SHA256(H, buf, size, zcp); +} + +static void +zio_checksum_SHA512_native(const void *buf, uint64_t size, + const void *ctx_template __unused, zio_cksum_t *zcp) +{ + /* SHA-512/256 as per FIPS 180-4. */ + uint64_t H[] = { + 0x22312194FC2BF72CULL, 0x9F555FA3C84C64C2ULL, + 0x2393B86B6F53B151ULL, 0x963877195940EABDULL, + 0x96283EE2A88EFFE3ULL, 0xBE5E1E2553863992ULL, + 0x2B0199FC2C85B8AAULL, 0x0EB72DDC81C52CA2ULL + }; + SHA512(H, buf, size, zcp); +} + +static void +zio_checksum_SHA512_byteswap(const void *buf, uint64_t size, + const void *ctx_template, zio_cksum_t *zcp) +{ + zio_cksum_t tmp; + + zio_checksum_SHA512_native(buf, size, ctx_template, &tmp); + zcp->zc_word[0] = BSWAP_64(tmp.zc_word[0]); + zcp->zc_word[1] = BSWAP_64(tmp.zc_word[1]); + zcp->zc_word[2] = BSWAP_64(tmp.zc_word[2]); + zcp->zc_word[3] = BSWAP_64(tmp.zc_word[3]); +} diff --git a/sys/cddl/boot/zfs/skein_zfs.c b/sys/cddl/boot/zfs/skein_zfs.c new file mode 100644 index 00000000000..5b424c7a8b2 --- /dev/null +++ b/sys/cddl/boot/zfs/skein_zfs.c @@ -0,0 +1,92 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * $FreeBSD$ + */ +/* + * Copyright 2013 Saso Kiselkov. All rights reserved. + */ +#include + +/* + * Computes a native 256-bit skein MAC checksum. Please note that this + * function requires the presence of a ctx_template that should be allocated + * using zio_checksum_skein_tmpl_init. + */ +/*ARGSUSED*/ +static void +zio_checksum_skein_native(const void *buf, uint64_t size, + const void *ctx_template, zio_cksum_t *zcp) +{ + Skein_512_Ctxt_t ctx; + + ASSERT(ctx_template != NULL); + bcopy(ctx_template, &ctx, sizeof (ctx)); + (void) Skein_512_Update(&ctx, buf, size); + (void) Skein_512_Final(&ctx, (uint8_t *)zcp); + bzero(&ctx, sizeof (ctx)); +} + +/* + * Byteswapped version of zio_checksum_skein_native. This just invokes + * the native checksum function and byteswaps the resulting checksum (since + * skein is internally endian-insensitive). + */ +static void +zio_checksum_skein_byteswap(const void *buf, uint64_t size, + const void *ctx_template, zio_cksum_t *zcp) +{ + zio_cksum_t tmp; + + zio_checksum_skein_native(buf, size, ctx_template, &tmp); + zcp->zc_word[0] = BSWAP_64(tmp.zc_word[0]); + zcp->zc_word[1] = BSWAP_64(tmp.zc_word[1]); + zcp->zc_word[2] = BSWAP_64(tmp.zc_word[2]); + zcp->zc_word[3] = BSWAP_64(tmp.zc_word[3]); +} + +/* + * Allocates a skein MAC template suitable for using in skein MAC checksum + * computations and returns a pointer to it. + */ +static void * +zio_checksum_skein_tmpl_init(const zio_cksum_salt_t *salt) +{ + Skein_512_Ctxt_t *ctx; + + ctx = malloc(sizeof (*ctx)); + bzero(ctx, sizeof (*ctx)); + (void) Skein_512_InitExt(ctx, sizeof (zio_cksum_t) * 8, 0, + salt->zcs_bytes, sizeof (salt->zcs_bytes)); + return (ctx); +} + +/* + * Frees a skein context template previously allocated using + * zio_checksum_skein_tmpl_init. + */ +static void +zio_checksum_skein_tmpl_free(void *ctx_template) +{ + Skein_512_Ctxt_t *ctx = ctx_template; + + bzero(ctx, sizeof (*ctx)); + free(ctx); +} diff --git a/sys/cddl/boot/zfs/zfsimpl.h b/sys/cddl/boot/zfs/zfsimpl.h index a18c2b0bbff..2ccec82ec48 100644 --- a/sys/cddl/boot/zfs/zfsimpl.h +++ b/sys/cddl/boot/zfs/zfsimpl.h @@ -114,13 +114,11 @@ typedef enum { B_FALSE, B_TRUE } boolean_t; #define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16)) #define BSWAP_64(x) ((BSWAP_32(x) << 32) | BSWAP_32((x) >> 32)) -/* - * Note: the boot loader can't actually read blocks larger than 128KB, - * due to lack of memory. Therefore its SPA_MAXBLOCKSIZE is still 128KB. - */ #define SPA_MINBLOCKSHIFT 9 -#define SPA_MAXBLOCKSHIFT 17 +#define SPA_OLDMAXBLOCKSHIFT 17 +#define SPA_MAXBLOCKSHIFT 24 #define SPA_MINBLOCKSIZE (1ULL << SPA_MINBLOCKSHIFT) +#define SPA_OLDMAXBLOCKSIZE (1ULL << SPA_OLDMAXBLOCKSHIFT) #define SPA_MAXBLOCKSIZE (1ULL << SPA_MAXBLOCKSHIFT) /* @@ -149,6 +147,14 @@ typedef struct zio_cksum { uint64_t zc_word[4]; } zio_cksum_t; +/* + * Some checksums/hashes need a 256-bit initialization salt. This salt is kept + * secret and is suitable for use in MAC algorithms as the key. + */ +typedef struct zio_cksum_salt { + uint8_t zcs_bytes[32]; +} zio_cksum_salt_t; + /* * Each block is described by its DVAs, time of birth, checksum, etc. * The word-by-word, bit-by-bit layout of the blkptr is as follows: @@ -528,6 +534,10 @@ enum zio_checksum { ZIO_CHECKSUM_FLETCHER_4, ZIO_CHECKSUM_SHA256, ZIO_CHECKSUM_ZILOG2, + ZIO_CHECKSUM_NOPARITY, + ZIO_CHECKSUM_SHA512, + ZIO_CHECKSUM_SKEIN, + ZIO_CHECKSUM_EDONR, ZIO_CHECKSUM_FUNCTIONS }; @@ -1157,6 +1167,7 @@ typedef struct dsl_dataset_phys { #define DMU_POOL_DEFLATE "deflate" #define DMU_POOL_HISTORY "history" #define DMU_POOL_PROPS "pool_props" +#define DMU_POOL_CHECKSUM_SALT "org.illumos:checksum_salt" #define ZAP_MAGIC 0x2F52AB2ABULL @@ -1462,6 +1473,7 @@ typedef struct znode_phys { * In-core vdev representation. */ struct vdev; +struct spa; typedef int vdev_phys_read_t(struct vdev *vdev, void *priv, off_t offset, void *buf, size_t bytes); typedef int vdev_read_t(struct vdev *vdev, const blkptr_t *bp, @@ -1484,6 +1496,7 @@ typedef struct vdev { vdev_phys_read_t *v_phys_read; /* read from raw leaf vdev */ vdev_read_t *v_read; /* read from vdev */ void *v_read_priv; /* private data for read function */ + struct spa *spa; /* link to spa */ } vdev_t; /* @@ -1499,6 +1512,8 @@ typedef struct spa { struct uberblock spa_uberblock; /* best uberblock so far */ vdev_list_t spa_vdevs; /* list of all toplevel vdevs */ objset_phys_t spa_mos; /* MOS for this pool */ + zio_cksum_salt_t spa_cksum_salt; /* secret salt for cksum */ + void *spa_cksum_tmpls[ZIO_CHECKSUM_FUNCTIONS]; int spa_inited; /* initialized */ } spa_t; diff --git a/sys/cddl/boot/zfs/zfssubr.c b/sys/cddl/boot/zfs/zfssubr.c index a64f065ad16..7ef866abdaa 100644 --- a/sys/cddl/boot/zfs/zfssubr.c +++ b/sys/cddl/boot/zfs/zfssubr.c @@ -63,7 +63,8 @@ zfs_init_crc(void) } static void -zio_checksum_off(const void *buf, uint64_t size, zio_cksum_t *zcp) +zio_checksum_off(const void *buf, uint64_t size, + const void *ctx_template, zio_cksum_t *zcp) { ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0); } @@ -71,38 +72,75 @@ zio_checksum_off(const void *buf, uint64_t size, zio_cksum_t *zcp) /* * Signature for checksum functions. */ -typedef void zio_checksum_t(const void *data, uint64_t size, zio_cksum_t *zcp); +typedef void zio_checksum_t(const void *data, uint64_t size, + const void *ctx_template, zio_cksum_t *zcp); +typedef void *zio_checksum_tmpl_init_t(const zio_cksum_salt_t *salt); +typedef void zio_checksum_tmpl_free_t(void *ctx_template); + +typedef enum zio_checksum_flags { + /* Strong enough for metadata? */ + ZCHECKSUM_FLAG_METADATA = (1 << 1), + /* ZIO embedded checksum */ + ZCHECKSUM_FLAG_EMBEDDED = (1 << 2), + /* Strong enough for dedup (without verification)? */ + ZCHECKSUM_FLAG_DEDUP = (1 << 3), + /* Uses salt value */ + ZCHECKSUM_FLAG_SALTED = (1 << 4), + /* Strong enough for nopwrite? */ + ZCHECKSUM_FLAG_NOPWRITE = (1 << 5) +} zio_checksum_flags_t; /* * Information about each checksum function. */ typedef struct zio_checksum_info { - zio_checksum_t *ci_func[2]; /* checksum function for each byteorder */ - int ci_correctable; /* number of correctable bits */ - int ci_eck; /* uses zio embedded checksum? */ - int ci_dedup; /* strong enough for dedup? */ - const char *ci_name; /* descriptive name */ + /* checksum function for each byteorder */ + zio_checksum_t *ci_func[2]; + zio_checksum_tmpl_init_t *ci_tmpl_init; + zio_checksum_tmpl_free_t *ci_tmpl_free; + zio_checksum_flags_t ci_flags; + const char *ci_name; /* descriptive name */ } zio_checksum_info_t; #include "blkptr.c" #include "fletcher.c" #include "sha256.c" +#include "skein_zfs.c" static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = { - {{NULL, NULL}, 0, 0, 0, "inherit"}, - {{NULL, NULL}, 0, 0, 0, "on"}, - {{zio_checksum_off, zio_checksum_off}, 0, 0, 0, "off"}, - {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, 0, "label"}, - {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, 0, "gang_header"}, - {{fletcher_2_native, fletcher_2_byteswap}, 0, 1, 0, "zilog"}, - {{fletcher_2_native, fletcher_2_byteswap}, 0, 0, 0, "fletcher2"}, - {{fletcher_4_native, fletcher_4_byteswap}, 1, 0, 0, "fletcher4"}, - {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 0, 1, "SHA256"}, - {{fletcher_4_native, fletcher_4_byteswap}, 0, 1, 0, "zillog2"}, + {{NULL, NULL}, NULL, NULL, 0, "inherit"}, + {{NULL, NULL}, NULL, NULL, 0, "on"}, + {{zio_checksum_off, zio_checksum_off}, NULL, NULL, 0, "off"}, + {{zio_checksum_SHA256, zio_checksum_SHA256}, NULL, NULL, + ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_EMBEDDED, "label"}, + {{zio_checksum_SHA256, zio_checksum_SHA256}, NULL, NULL, + ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_EMBEDDED, "gang_header"}, + {{fletcher_2_native, fletcher_2_byteswap}, NULL, NULL, + ZCHECKSUM_FLAG_EMBEDDED, "zilog"}, + {{fletcher_2_native, fletcher_2_byteswap}, NULL, NULL, + 0, "fletcher2"}, + {{fletcher_4_native, fletcher_4_byteswap}, NULL, NULL, + ZCHECKSUM_FLAG_METADATA, "fletcher4"}, + {{zio_checksum_SHA256, zio_checksum_SHA256}, NULL, NULL, + ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP | + ZCHECKSUM_FLAG_NOPWRITE, "SHA256"}, + {{fletcher_4_native, fletcher_4_byteswap}, NULL, NULL, + ZCHECKSUM_FLAG_EMBEDDED, "zillog2"}, + {{zio_checksum_off, zio_checksum_off}, NULL, NULL, + 0, "noparity"}, + {{zio_checksum_SHA512_native, zio_checksum_SHA512_byteswap}, + NULL, NULL, ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP | + ZCHECKSUM_FLAG_NOPWRITE, "SHA512"}, + {{zio_checksum_skein_native, zio_checksum_skein_byteswap}, + zio_checksum_skein_tmpl_init, zio_checksum_skein_tmpl_free, + ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP | + ZCHECKSUM_FLAG_SALTED | ZCHECKSUM_FLAG_NOPWRITE, "skein"}, + /* no edonr for now */ + {{NULL, NULL}, NULL, NULL, ZCHECKSUM_FLAG_METADATA | + ZCHECKSUM_FLAG_SALTED | ZCHECKSUM_FLAG_NOPWRITE, "edonr"} }; - /* * Common signature for all zio compress/decompress functions. */ @@ -186,8 +224,48 @@ zio_checksum_label_verifier(zio_cksum_t *zcp, uint64_t offset) ZIO_SET_CHECKSUM(zcp, offset, 0, 0, 0); } +/* + * Calls the template init function of a checksum which supports context + * templates and installs the template into the spa_t. + */ +static void +zio_checksum_template_init(enum zio_checksum checksum, spa_t *spa) +{ + zio_checksum_info_t *ci = &zio_checksum_table[checksum]; + + if (ci->ci_tmpl_init == NULL) + return; + + if (spa->spa_cksum_tmpls[checksum] != NULL) + return; + + if (spa->spa_cksum_tmpls[checksum] == NULL) { + spa->spa_cksum_tmpls[checksum] = + ci->ci_tmpl_init(&spa->spa_cksum_salt); + } +} + +/* + * Called by a spa_t that's about to be deallocated. This steps through + * all of the checksum context templates and deallocates any that were + * initialized using the algorithm-specific template init function. + */ +void +zio_checksum_templates_free(spa_t *spa) +{ + for (enum zio_checksum checksum = 0; + checksum < ZIO_CHECKSUM_FUNCTIONS; checksum++) { + if (spa->spa_cksum_tmpls[checksum] != NULL) { + zio_checksum_info_t *ci = &zio_checksum_table[checksum]; + + ci->ci_tmpl_free(spa->spa_cksum_tmpls[checksum]); + spa->spa_cksum_tmpls[checksum] = NULL; + } + } +} + static int -zio_checksum_verify(const blkptr_t *bp, void *data) +zio_checksum_verify(const spa_t *spa, const blkptr_t *bp, void *data) { uint64_t size; unsigned int checksum; @@ -204,7 +282,8 @@ zio_checksum_verify(const blkptr_t *bp, void *data) if (ci->ci_func[0] == NULL || ci->ci_func[1] == NULL) return (EINVAL); - if (ci->ci_eck) { + zio_checksum_template_init(checksum, (spa_t *) spa); + if (ci->ci_flags & ZCHECKSUM_FLAG_EMBEDDED) { zio_eck_t *eck; ASSERT(checksum == ZIO_CHECKSUM_GANG_HEADER || @@ -227,7 +306,8 @@ zio_checksum_verify(const blkptr_t *bp, void *data) expected_cksum = eck->zec_cksum; eck->zec_cksum = verifier; - ci->ci_func[byteswap](data, size, &actual_cksum); + ci->ci_func[byteswap](data, size, + spa->spa_cksum_tmpls[checksum], &actual_cksum); eck->zec_cksum = expected_cksum; if (byteswap) @@ -235,11 +315,12 @@ zio_checksum_verify(const blkptr_t *bp, void *data) sizeof (zio_cksum_t)); } else { expected_cksum = bp->blk_cksum; - ci->ci_func[0](data, size, &actual_cksum); + ci->ci_func[0](data, size, spa->spa_cksum_tmpls[checksum], + &actual_cksum); } if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum)) { - /*printf("ZFS: read checksum failed\n");*/ + /*printf("ZFS: read checksum %s failed\n", ci->ci_name);*/ return (EIO); } @@ -1249,10 +1330,10 @@ vdev_child(vdev_t *pvd, uint64_t devidx) * any ereports we generate can note it. */ static int -raidz_checksum_verify(const blkptr_t *bp, void *data, uint64_t size) +raidz_checksum_verify(const spa_t *spa, const blkptr_t *bp, void *data, + uint64_t size) { - - return (zio_checksum_verify(bp, data)); + return (zio_checksum_verify(spa, bp, data)); } /* @@ -1301,8 +1382,8 @@ raidz_parity_verify(raidz_map_t *rm) * cases we'd only use parity information in column 0. */ static int -vdev_raidz_combrec(raidz_map_t *rm, const blkptr_t *bp, void *data, - off_t offset, uint64_t bytes, int total_errors, int data_errors) +vdev_raidz_combrec(const spa_t *spa, raidz_map_t *rm, const blkptr_t *bp, + void *data, off_t offset, uint64_t bytes, int total_errors, int data_errors) { raidz_col_t *rc; void *orig[VDEV_RAIDZ_MAXPARITY]; @@ -1381,7 +1462,7 @@ vdev_raidz_combrec(raidz_map_t *rm, const blkptr_t *bp, void *data, * success. */ code = vdev_raidz_reconstruct(rm, tgts, n); - if (raidz_checksum_verify(bp, data, bytes) == 0) { + if (raidz_checksum_verify(spa, bp, data, bytes) == 0) { for (i = 0; i < n; i++) { c = tgts[i]; rc = &rm->rm_col[c]; @@ -1552,7 +1633,7 @@ reconstruct: */ if (total_errors <= rm->rm_firstdatacol - parity_untried) { if (data_errors == 0) { - if (raidz_checksum_verify(bp, data, bytes) == 0) { + if (raidz_checksum_verify(vd->spa, bp, data, bytes) == 0) { /* * If we read parity information (unnecessarily * as it happens since no reconstruction was @@ -1597,7 +1678,7 @@ reconstruct: code = vdev_raidz_reconstruct(rm, tgts, n); - if (raidz_checksum_verify(bp, data, bytes) == 0) { + if (raidz_checksum_verify(vd->spa, bp, data, bytes) == 0) { /* * If we read more parity disks than were used * for reconstruction, confirm that the other @@ -1671,7 +1752,7 @@ reconstruct: if (total_errors > rm->rm_firstdatacol) { error = EIO; } else if (total_errors < rm->rm_firstdatacol && - (code = vdev_raidz_combrec(rm, bp, data, offset, bytes, + (code = vdev_raidz_combrec(vd->spa, rm, bp, data, offset, bytes, total_errors, data_errors)) != 0) { /* * If we didn't use all the available parity for the