Page MenuHomeFreeBSD

D4593.id11656.diff
No OneTemporary

D4593.id11656.diff

Index: sys/boot/Makefile.amd64
===================================================================
--- sys/boot/Makefile.amd64
+++ sys/boot/Makefile.amd64
@@ -3,6 +3,7 @@
SUBDIR+= efi
SUBDIR+= libstand32
SUBDIR+= zfs
+SUBDIR+= geli
SUBDIR+= userboot
.if ${MK_FORTH} != "no"
Index: sys/boot/Makefile.i386
===================================================================
--- sys/boot/Makefile.i386
+++ sys/boot/Makefile.i386
@@ -3,3 +3,4 @@
SUBDIR+= efi
SUBDIR+= libstand32
SUBDIR+= zfs
+SUBDIR+= geli
Index: sys/boot/common/bootstrap.h
===================================================================
--- sys/boot/common/bootstrap.h
+++ sys/boot/common/bootstrap.h
@@ -121,6 +121,7 @@
};
extern struct console *consoles[];
void cons_probe(void);
+void getpwstr(char *pwstr, size_t pwstrsize);
/*
* Plug-and-play enumerator/configurator interface.
Index: sys/boot/common/console.c
===================================================================
--- sys/boot/common/console.c
+++ sys/boot/common/console.c
@@ -261,3 +261,36 @@
return(CMD_OK);
}
+
+void
+getpwstr(char *pwstr, size_t pwstrsize)
+{
+ char *s;
+ int c;
+
+ s = pwstr;
+ for (;;) {
+ switch (c = getchar()) {
+ case 0:
+ break;
+ case '\177':
+ case '\b':
+ if (s > pwstr) {
+ s--;
+ putchar('\b');
+ putchar(' ');
+ putchar('\b');
+ }
+ break;
+ case '\n':
+ case '\r':
+ *s = 0;
+ return;
+ default:
+ if (s - pwstr < pwstrsize - 1)
+ *s++ = c;
+ putchar('*');
+ break;
+ }
+ }
+}
Index: sys/boot/common/disk.h
===================================================================
--- sys/boot/common/disk.h
+++ sys/boot/common/disk.h
@@ -107,6 +107,7 @@
u_int blocks);
extern int disk_write(struct disk_devdesc *dev, void *buf, off_t offset,
u_int blocks);
+extern int ptblread(void *d, void *buf, size_t blocks, off_t offset);
/*
* Print information about slices on a disk.
Index: sys/boot/common/disk.c
===================================================================
--- sys/boot/common/disk.c
+++ sys/boot/common/disk.c
@@ -170,7 +170,7 @@
return (buf);
}
-static int
+int
ptblread(void *d, void *buf, size_t blocks, off_t offset)
{
struct disk_devdesc *dev;
Index: sys/boot/common/gpt.h
===================================================================
--- sys/boot/common/gpt.h
+++ sys/boot/common/gpt.h
@@ -32,6 +32,8 @@
#include <uuid.h>
#include <drv.h>
+#define MAXTBLENTS 128
+
int gptread(const uuid_t *uuid, struct dsk *dskp, char *buf);
int gptfind(const uuid_t *uuid, struct dsk *dskp, int part);
void gptbootfailed(struct dsk *dskp);
Index: sys/boot/common/gpt.c
===================================================================
--- sys/boot/common/gpt.c
+++ sys/boot/common/gpt.c
@@ -39,8 +39,6 @@
#include "util.h"
#include "gpt.h"
-#define MAXTBLENTS 128
-
static struct gpt_hdr hdr_primary, hdr_backup, *gpthdr;
static uint64_t hdr_primary_lba, hdr_backup_lba;
static struct gpt_ent table_primary[MAXTBLENTS], table_backup[MAXTBLENTS];
Index: sys/boot/geli/Makefile
===================================================================
--- /dev/null
+++ sys/boot/geli/Makefile
@@ -0,0 +1,49 @@
+# $FreeBSD$
+# libgeliboot
+
+MAN=
+
+.include <src.opts.mk>
+MK_SSP= no
+
+LIB= geliboot
+INTERNALLIB=
+MK_PROFILE= no
+NO_PIC=
+
+.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
+CFLAGS+= -march=i386
+.endif
+.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "powerpc64"
+CFLAGS+= -m32
+.endif
+
+WARNS?= 0
+
+# string functions from libc
+.PATH: ${.CURDIR}/../../../lib/libc/string
+SRCS+= bcmp.c bcopy.c bzero.c
+
+# sha256 functions from sys/crypto
+.PATH: ${.CURDIR}/../../crypto/sha2
+SRCS+= sha256c.c sha2.c
+
+# sha512 functions from libmd
+.PATH: ${.CURDIR}/../../../lib/libmd
+CFLAGS+= -DWEAK_REFS
+SRCS+= md5c.c sha512c.c
+
+# AES implementation
+.PATH: ${.CURDIR}/../../crypto/rijndael
+CFLAGS+= -I${.CURDIR}/../../
+# Remove asserts
+CFLAGS+= -DNDEBUG
+SRCS+= rijndael-alg-fst.c rijndael-api-fst.c rijndael-api.c
+
+# GELI Implementation
+.PATH: ${.CURDIR}/../../geom/eli
+CFLAGS+= -D_STAND
+SRCS+= geliboot_crypto.c g_eli_hmac.c g_eli_key.c g_eli_key_cache.c pkcs5v2.c
+
+.include <bsd.stand.mk>
+.include <bsd.lib.mk>
Index: sys/boot/geli/geli_hmac.c
===================================================================
--- /dev/null
+++ sys/boot/geli/geli_hmac.c
@@ -0,0 +1,238 @@
+/*-
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+static void geli_hmac_init(struct hmac_ctx *ctx, const uint8_t *hkey,
+ size_t hkeylen);
+static void geli_hmac_update(struct hmac_ctx *ctx, const uint8_t *data,
+ size_t datasize);
+static void geli_hmac_final(struct hmac_ctx *ctx, uint8_t *md, size_t mdsize);
+static void geli_hmac(const uint8_t *hkey, size_t hkeysize, const uint8_t *data,
+ size_t datasize, uint8_t *md, size_t mdsize);
+static int geli_mkey_verify(const unsigned char *mkey, const unsigned char *key);
+static int geli_mkey_decrypt(struct geli_entry *gep, const unsigned char *key,
+ unsigned char *mkey, unsigned *nkeyp);
+static void pkcs5v2_genkey(uint8_t *key, unsigned keylen, const uint8_t *salt,
+ size_t saltsize, const char *passphrase, u_int iterations);
+
+/* XXX: replace with g_eli_crypto.c */
+static void
+geli_hmac_init(struct hmac_ctx *ctx, const uint8_t *hkey,
+ size_t hkeylen)
+{
+ u_char k_ipad[128], key[128];
+ SHA512_CTX lctx;
+ u_int i;
+
+ bzero(key, sizeof(key));
+ if (hkeylen <= 128)
+ bcopy(hkey, key, hkeylen);
+ else {
+ /* If key is longer than 128 bytes reset it to key = SHA512(key). */
+ SHA512_Init(&lctx);
+ SHA512_Update(&lctx, hkey, hkeylen);
+ SHA512_Final(key, &lctx);
+ }
+
+ /* XOR key with ipad and opad values. */
+ for (i = 0; i < sizeof(key); i++) {
+ k_ipad[i] = key[i] ^ 0x36;
+ ctx->k_opad[i] = key[i] ^ 0x5c;
+ }
+ bzero(key, sizeof(key));
+ /* Perform inner SHA512. */
+ SHA512_Init(&ctx->shactx);
+ SHA512_Update(&ctx->shactx, k_ipad, sizeof(k_ipad));
+ bzero(k_ipad, sizeof(k_ipad));
+}
+
+/* XXX: replace with g_eli_crypto.c */
+static void
+geli_hmac_update(struct hmac_ctx *ctx, const uint8_t *data,
+ size_t datasize)
+{
+
+ SHA512_Update(&ctx->shactx, data, datasize);
+}
+
+/* XXX: replace with g_eli_crypto.c */
+static void
+geli_hmac_final(struct hmac_ctx *ctx, uint8_t *md, size_t mdsize)
+{
+ u_char digest[SHA512_MDLEN];
+ SHA512_CTX lctx;
+
+ SHA512_Final(digest, &ctx->shactx);
+ /* Perform outer SHA512. */
+ SHA512_Init(&lctx);
+ SHA512_Update(&lctx, ctx->k_opad, sizeof(ctx->k_opad));
+ bzero(ctx, sizeof(*ctx));
+ SHA512_Update(&lctx, digest, sizeof(digest));
+ SHA512_Final(digest, &lctx);
+ bzero(&lctx, sizeof(lctx));
+ /* mdsize == 0 means "Give me the whole hash!" */
+ if (mdsize == 0)
+ mdsize = SHA512_MDLEN;
+ bcopy(digest, md, mdsize);
+ bzero(digest, sizeof(digest));
+}
+
+/* XXX: replace with g_eli_crypto.c */
+static void
+geli_hmac(const uint8_t *hkey, size_t hkeysize, const uint8_t *data,
+ size_t datasize, uint8_t *md, size_t mdsize)
+{
+ struct hmac_ctx ctx;
+
+ geli_hmac_init(&ctx, hkey, hkeysize);
+ geli_hmac_update(&ctx, data, datasize);
+ geli_hmac_final(&ctx, md, mdsize);
+}
+
+/* XXX: replace with g_eli_key.c
+ * Verify if the given 'key' is correct.
+ * Return 1 if it is correct and 0 otherwise.
+ */
+static int
+geli_mkey_verify(const unsigned char *mkey, const unsigned char *key)
+{
+ const unsigned char *odhmac; /* On-disk HMAC. */
+ unsigned char chmac[SHA512_MDLEN]; /* Calculated HMAC. */
+ unsigned char hmkey[SHA512_MDLEN]; /* Key for HMAC. */
+
+ /*
+ * The key for HMAC calculations is: hmkey = HMAC_SHA512(Derived-Key, 0)
+ */
+ geli_hmac(key, G_ELI_USERKEYLEN, "\x00", 1, hmkey, 0);
+
+ odhmac = mkey + G_ELI_DATAIVKEYLEN;
+
+ /* Calculate HMAC from Data-Key and IV-Key. */
+ geli_hmac(hmkey, sizeof(hmkey), mkey, G_ELI_DATAIVKEYLEN, chmac, 0);
+
+ bzero(hmkey, sizeof(hmkey));
+
+ /*
+ * Compare calculated HMAC with HMAC from metadata.
+ * If two HMACs are equal, 'key' is correct.
+ */
+ return (!bcmp(odhmac, chmac, SHA512_MDLEN));
+}
+
+/* XXX: replace with g_eli_key.c
+ * Find and decrypt Master Key encrypted with 'key'.
+ * Return decrypted Master Key number in 'nkeyp' if not NULL.
+ * Return 0 on success, > 0 on failure, -1 on bad key.
+ */
+static int
+geli_mkey_decrypt(struct geli_entry *gep, const unsigned char *key,
+ unsigned char *mkey, unsigned *nkeyp)
+{
+ unsigned char tmpmkey[G_ELI_MKEYLEN];
+ unsigned char enckey[SHA512_MDLEN]; /* Key for encryption. */
+ unsigned char ivkey[G_ELI_IVKEYLEN];
+ const unsigned char *mmkey;
+ int bit, error, nkey;
+
+ if (nkeyp != NULL)
+ *nkeyp = -1;
+
+ /*
+ * The key for encryption is: enckey = HMAC_SHA512(Derived-Key, 1)
+ */
+ geli_hmac(key, G_ELI_USERKEYLEN, "\x01", 1, enckey, 0);
+
+ mmkey = gep->md.md_mkeys;
+ for (nkey = 0; nkey < G_ELI_MAXMKEYS; nkey++, mmkey += G_ELI_MKEYLEN) {
+ bit = (1 << nkey);
+ if (!(gep->md.md_keys & bit))
+ continue;
+ bcopy(mmkey, tmpmkey, G_ELI_MKEYLEN);
+ /* gep->md.md_ealgo */
+ error = geli_decrypt(CRYPTO_AES_CBC, tmpmkey,
+ G_ELI_MKEYLEN, enckey, gep->md.md_keylen, ivkey);
+ if (error != 0) {
+ bzero(tmpmkey, sizeof(tmpmkey));
+ bzero(enckey, sizeof(enckey));
+ return (error);
+ }
+ if (geli_mkey_verify(tmpmkey, key)) {
+ bcopy(tmpmkey, mkey, G_ELI_DATAIVKEYLEN);
+ bzero(tmpmkey, sizeof(tmpmkey));
+ bzero(enckey, sizeof(enckey));
+ if (nkeyp != NULL)
+ *nkeyp = nkey;
+ return (0);
+ }
+ }
+ bzero(enckey, sizeof(enckey));
+ bzero(tmpmkey, sizeof(tmpmkey));
+ return (-1);
+}
+
+/* XXX: replace with pkcs5v2.c */
+static __inline void
+xor(uint8_t *dst, const uint8_t *src, size_t size)
+{
+
+ for (; size > 0; size--)
+ *dst++ ^= *src++;
+}
+
+/* XXX: replace with pkcs5v2.c */
+static void
+pkcs5v2_genkey(uint8_t *key, unsigned keylen, const uint8_t *salt,
+ size_t saltsize, const char *passphrase, u_int iterations)
+{
+ uint8_t md[SHA512_MDLEN], saltcount[saltsize + sizeof(uint32_t)];
+ uint8_t *counter, *keyp;
+ u_int i, bsize, passlen;
+ uint32_t count;
+
+ passlen = strlen(passphrase);
+ bzero(key, keylen);
+ bcopy(salt, saltcount, saltsize);
+ counter = saltcount + saltsize;
+
+ keyp = key;
+ for (count = 1; keylen > 0; count++, keylen -= bsize, keyp += bsize) {
+ bsize = MIN(keylen, sizeof(md));
+
+ counter[0] = (count >> 24) & 0xff;
+ counter[1] = (count >> 16) & 0xff;
+ counter[2] = (count >> 8) & 0xff;
+ counter[3] = count & 0xff;
+ geli_hmac(passphrase, passlen, saltcount, sizeof(saltcount), md, 0);
+ xor(keyp, md, bsize);
+
+ for (i = 1; i < iterations; i++) {
+ geli_hmac(passphrase, passlen, md, sizeof(md),
+ md, 0);
+ xor(keyp, md, bsize);
+ }
+ }
+}
Index: sys/boot/geli/geliboot.h
===================================================================
--- /dev/null
+++ sys/boot/geli/geliboot.h
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/endian.h>
+#include <sys/queue.h>
+
+#ifndef _GELIBOOT_H_
+#define _GELIBOOT_H_
+
+#define _STRING_H_
+#define _STRINGS_H_
+#define _STDIO_H_
+#include <geom/eli/g_eli.h>
+
+/* Pull in the md5, sha256, and sha512 implementations */
+#include <md5.h>
+#include <crypto/sha2/sha2.h>
+
+/* Pull in AES implementation */
+#include <crypto/rijndael/rijndael-api-fst.h>
+
+/* AES-XTS implementation */
+#define _LOADER
+#define STAND_H /* We don't want stand.h in {gpt,zfs,gptzfs}boot */
+#include <opencrypto/xform_enc.h>
+
+#ifndef DEV_BSIZE
+#define DEV_BSIZE 512
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#if 0
+#define CRYPTO_AES_CBC 11
+#define CRYPTO_SHA2_512_HMAC 20
+#define CRYPTO_AES_XTS 22
+
+#define SHA256_DIGEST_LENGTH 32
+#endif
+
+static SLIST_HEAD(geli_list, geli_entry) geli_head = SLIST_HEAD_INITIALIZER(geli_head);
+static struct geli_list *geli_headp;
+static struct geli_entry {
+ struct dsk *dsk;
+ off_t part_end;
+ struct g_eli_softc sc;
+ struct g_eli_metadata md;
+ SLIST_ENTRY(geli_entry) entries;
+} *geli_e, *geli_e_tmp;
+
+static int geli_count;
+
+static void geli_init(void);
+static int geli_taste(int read_func(void *vdev, void *priv, off_t off,
+ void *buf, size_t bytes), struct dsk *dsk, daddr_t lastsector);
+static int geli_attach(int read_func(void *vdev, void *priv, off_t off,
+ void *buf, size_t bytes), struct dsk *dskp, const char *passphrase);
+static int is_geli(struct dsk *dsk);
+static int geli_read(struct dsk *dsk, off_t offset, u_char *buf, size_t bytes);
+static int geli_decrypt(u_int algo, u_char *data, size_t datasize,
+ const u_char *key, size_t keysize, const uint8_t* iv);
+
+#endif /* _GELIBOOT_H_ */
Index: sys/boot/geli/geliboot.c
===================================================================
--- /dev/null
+++ sys/boot/geli/geliboot.c
@@ -0,0 +1,271 @@
+/*-
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "geliboot.h"
+
+static void
+geli_init(void)
+{
+
+ geli_count = 0;
+ SLIST_INIT(&geli_head);
+}
+
+/*
+ * Read the last sector of the drive or partition pointed to by dsk and see
+ * if it is GELI encrypted
+ */
+static int
+geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf,
+ size_t bytes), struct dsk *dskp, daddr_t lastsector)
+{
+ struct g_eli_metadata md;
+ u_char buf[DEV_BSIZE];
+ int error;
+
+ error = read_func(NULL, dskp, (off_t) lastsector * DEV_BSIZE, &buf,
+ (size_t) DEV_BSIZE);
+ if (error != 0) {
+ return (error);
+ }
+ error = eli_metadata_decode(buf, &md);
+ if (error != 0) {
+ return (error);
+ }
+
+ if ((md.md_flags & G_ELI_FLAG_ONETIME)) {
+ /* Swap device, skip it */
+ return (1);
+ }
+ if (!(md.md_flags & G_ELI_FLAG_BOOT)) {
+ /* Disk is not GELI boot device, skip it */
+ return (1);
+ }
+ geli_e = malloc(sizeof(struct geli_entry));
+ if (geli_e == NULL)
+ return (2);
+
+ geli_e->dsk = malloc(sizeof(struct dsk));
+ if (geli_e->dsk == NULL)
+ return (2);
+ memcpy(geli_e->dsk, dskp, sizeof(struct dsk));
+ geli_e->part_end = lastsector;
+ if (dskp->part == 255) {
+ geli_e->dsk->part = dskp->slice;
+ }
+
+ geli_e->md = md;
+ eli_metadata_softc(&geli_e->sc, &md, DEV_BSIZE,
+ (lastsector + DEV_BSIZE) * DEV_BSIZE);
+
+ SLIST_INSERT_HEAD(&geli_head, geli_e, entries);
+ geli_count++;
+
+ return (0);
+}
+
+/*
+ * Attempt to decrypt the device
+ */
+static int
+geli_attach(int read_func(void *vdev, void *priv, off_t off, void *buf,
+ size_t bytes), struct dsk *dskp, const char *passphrase)
+{
+ u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp;
+ u_int keynum;
+ struct hmac_ctx ctx;
+ int error;
+
+ SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
+ if (geli_e->dsk->drive != dskp->drive) {
+ continue;
+ }
+ if (dskp->part == 255) {
+ if (geli_e->dsk->part != dskp->slice) {
+ /* Right disk, wrong partition */
+ continue;
+ }
+ } else {
+ if (geli_e->dsk->slice != dskp->slice) {
+ /* Right disk, wrong slice */
+ continue;
+ } else if (geli_e->dsk->part != dskp->part) {
+ /* Right disk, wrong partition */
+ continue;
+ }
+ }
+
+ g_eli_crypto_hmac_init(&ctx, NULL, 0);
+ /*
+ * Prepare Derived-Key from the user passphrase.
+ */
+ if (geli_e->md.md_iterations == 0) {
+ g_eli_crypto_hmac_update(&ctx, geli_e->md.md_salt,
+ sizeof(geli_e->md.md_salt));
+ g_eli_crypto_hmac_update(&ctx, passphrase,
+ strlen(passphrase));
+ } else if (geli_e->md.md_iterations > 0) {
+ printf("Calculating GELI Decryption Key disk%dp%d @ %lu "
+ "iterations...\n", dskp->unit,
+ (dskp->slice > 0 ? dskp->slice : dskp->part),
+ geli_e->md.md_iterations);
+ u_char dkey[G_ELI_USERKEYLEN];
+
+ pkcs5v2_genkey(dkey, sizeof(dkey), geli_e->md.md_salt,
+ sizeof(geli_e->md.md_salt), passphrase,
+ geli_e->md.md_iterations);
+ g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
+ bzero(dkey, sizeof(dkey));
+ }
+
+ g_eli_crypto_hmac_final(&ctx, key, 0);
+
+ error = g_eli_mkey_decrypt(&geli_e->md, key, mkey, &keynum);
+ if (error == -1) {
+ printf("Bad GELI key: %d\n", error);
+ return (error);
+ } else if (error != 0) {
+ printf("Failed to decrypt GELI master key: %d\n", error);
+ return (error);
+ }
+
+ /* Store the keys */
+ bcopy(mkey, geli_e->sc.sc_mkey, sizeof(geli_e->sc.sc_mkey));
+ bcopy(mkey, geli_e->sc.sc_ivkey, sizeof(geli_e->sc.sc_ivkey));
+ mkp = mkey + sizeof(geli_e->sc.sc_ivkey);
+ if ((geli_e->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) {
+ bcopy(mkp, geli_e->sc.sc_ekey, G_ELI_DATAKEYLEN);
+ } else {
+ /*
+ * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10)
+ */
+ g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, "\x10", 1,
+ geli_e->sc.sc_ekey, 0);
+ }
+
+ /* Initialize the per-sector IV */
+ switch (geli_e->sc.sc_ealgo) {
+ case CRYPTO_AES_XTS:
+ break;
+ default:
+ SHA256_Init(&geli_e->sc.sc_ivctx);
+ SHA256_Update(&geli_e->sc.sc_ivctx, geli_e->sc.sc_ivkey,
+ sizeof(geli_e->sc.sc_ivkey));
+ break;
+ }
+
+ return (0);
+ }
+
+ /* Disk not found */
+ return (2);
+}
+
+static int
+is_geli(struct dsk *dskp)
+{
+ SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
+ if (geli_e->dsk->drive != dskp->drive) {
+ continue;
+ }
+ if (dskp->part == 255 && geli_e->dsk->part == dskp->slice) {
+ /* Sometimes we track slice, sometimes part :( */
+ return (0);
+ }
+ if (geli_e->dsk->slice != dskp->slice) {
+ /* Right disk, wrong slice */
+ continue;
+ }
+ if (geli_e->dsk->part != dskp->part) {
+ /* Right disk, wrong partition */
+ continue;
+ }
+ return (0);
+ }
+
+ return (1);
+}
+
+static int
+geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes)
+{
+ u_char iv[G_ELI_IVKEYLEN], key[G_ELI_DATAKEYLEN];
+ u_char *pbuf;
+ int error;
+ off_t os;
+ uint64_t keyno;
+ size_t n, nb;
+ struct g_eli_key gkey;
+
+ SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
+ if (geli_e->dsk->drive != dskp->drive) {
+ continue;
+ }
+ if (dskp->part == 255) {
+ if (geli_e->dsk->part != dskp->slice) {
+ /* Right disk, wrong partition */
+ continue;
+ }
+ } else {
+ if (geli_e->dsk->slice != dskp->slice) {
+ /* Right disk, wrong partition */
+ continue;
+ } else if (geli_e->dsk->part != dskp->part) {
+ /* Right disk, wrong partition */
+ continue;
+ }
+ }
+
+ nb = bytes / DEV_BSIZE;
+ for (n = 0; n < nb; n++) {
+ os = offset + (n * DEV_BSIZE);
+ pbuf = buf + (n * DEV_BSIZE);
+
+ g_eli_crypto_ivgen(&geli_e->sc, os, iv, G_ELI_IVKEYLEN);
+
+ /* Get the key that corresponds to this offset */
+ keyno = (os >> G_ELI_KEY_SHIFT) / DEV_BSIZE;
+ g_eli_key_fill(&geli_e->sc, &gkey, keyno);
+
+ error = geliboot_crypt(geli_e->sc.sc_ealgo, 0, pbuf,
+ DEV_BSIZE, gkey.gek_key, geli_e->sc.sc_ekeylen, iv);
+
+ if (error != 0) {
+ bzero(key, sizeof(key));
+ printf("Failed to decrypt in geli_read()!");
+ return (error);
+ }
+ }
+ bzero(key, sizeof(key));
+ return (0);
+ }
+
+ printf("GELI provider not found\n");
+ return (1);
+}
Index: sys/boot/geli/geliboot_crypto.c
===================================================================
--- /dev/null
+++ sys/boot/geli/geliboot_crypto.c
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "geliboot.h"
+
+int
+geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
+ const u_char *key, size_t keysize, u_char *iv)
+{
+ keyInstance aeskey;
+ cipherInstance cipher;
+ struct aes_xts_ctx xtsctx, *ctxp;
+ size_t xts_len;
+ int err, blks, i;
+
+ switch (algo) {
+ case CRYPTO_AES_CBC:
+ err = rijndael_makeKey(&aeskey, !enc, keysize,
+ (const char *)key);
+ if (err < 0) {
+ printf("Failed to setup decryption keys: %d\n", err);
+ return (err);
+ }
+
+ err = rijndael_cipherInit(&cipher, MODE_CBC, iv);
+ if (err < 0) {
+ printf("Failed to setup IV: %d\n", err);
+ return (err);
+ }
+
+ switch (enc) {
+ case 0: /* decrypt */
+ blks = rijndael_blockDecrypt(&cipher, &aeskey, data,
+ datasize * 8, data);
+ break;
+ case 1: /* encrypt */
+ blks = rijndael_blockEncrypt(&cipher, &aeskey, data,
+ datasize * 8, data);
+ break;
+ }
+ if (datasize != (blks / 8)) {
+ printf("Failed to decrypt the entire input: "
+ "%u != %u\n", blks, datasize);
+ return (1);
+ }
+ break;
+ case CRYPTO_AES_XTS:
+ xts_len = keysize << 1;
+ ctxp = &xtsctx;
+
+ rijndael_set_key(&ctxp->key1, key, xts_len / 2);
+ rijndael_set_key(&ctxp->key2, key + (xts_len / 16), xts_len / 2);
+
+ aes_xts_reinit(ctxp, iv);
+
+ switch (enc) {
+ case 0: /* decrypt */
+ for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) {
+ aes_xts_decrypt(ctxp, data + i);
+ }
+ break;
+ case 1: /* encrypt */
+ for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) {
+ aes_xts_encrypt(ctxp, data + i);
+ }
+ break;
+ }
+ break;
+ default:
+ printf("Unsupported crypto algorithm #%d\n", algo);
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
+ const u_char *key, size_t keysize)
+{
+ u_char iv[keysize];
+
+ bzero(iv, sizeof(iv));
+ return (geliboot_crypt(algo, enc, data, datasize, key, keysize, iv));
+}
+
+int
+g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
+ const u_char *key, size_t keysize)
+{
+
+ /* We prefer AES-CBC for metadata protection. */
+ if (algo == CRYPTO_AES_XTS)
+ algo = CRYPTO_AES_CBC;
+
+ return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize));
+}
+
+int
+g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
+ const u_char *key, size_t keysize)
+{
+
+ /* We prefer AES-CBC for metadata protection. */
+ if (algo == CRYPTO_AES_XTS)
+ algo = CRYPTO_AES_CBC;
+
+ return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize));
+}
Index: sys/boot/i386/common/bootargs.h
===================================================================
--- sys/boot/i386/common/bootargs.h
+++ sys/boot/i386/common/bootargs.h
@@ -64,6 +64,12 @@
*/
};
+struct geli_boot_args
+{
+ uint32_t size;
+ char gelipw[256];
+};
+
#endif /*__ASSEMBLER__*/
#endif /* !_BOOT_I386_ARGS_H_ */
Index: sys/boot/i386/common/cons.h
===================================================================
--- sys/boot/i386/common/cons.h
+++ sys/boot/i386/common/cons.h
@@ -30,5 +30,6 @@
int xgetc(int fn);
int keyhit(unsigned int secs);
void getstr(char *cmdstr, size_t cmdstrsize);
+void getpwstr(char *cmdstr, size_t cmdstrsize);
#endif /* !_CONS_H_ */
Index: sys/boot/i386/common/cons.c
===================================================================
--- sys/boot/i386/common/cons.c
+++ sys/boot/i386/common/cons.c
@@ -149,3 +149,34 @@
}
}
}
+
+void
+getpwstr(char *pwstr, size_t pwstrsize)
+{
+ char *s;
+ int c;
+
+ s = pwstr;
+ for (;;) {
+ switch (c = xgetc(0)) {
+ case 0:
+ break;
+ case '\177':
+ case '\b':
+ if (s > pwstr) {
+ s--;
+ printf("\b \b");
+ }
+ break;
+ case '\n':
+ case '\r':
+ *s = 0;
+ return;
+ default:
+ if (s - pwstr < pwstrsize - 1)
+ *s++ = c;
+ putchar('*');
+ break;
+ }
+ }
+}
Index: sys/boot/i386/common/drv.h
===================================================================
--- sys/boot/i386/common/drv.h
+++ sys/boot/i386/common/drv.h
@@ -42,7 +42,7 @@
int drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk);
#ifdef GPT
int drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk);
-uint64_t drvsize(struct dsk *dskp);
#endif /* GPT */
+uint64_t drvsize(struct dsk *dskp);
#endif /* !_DRV_H_ */
Index: sys/boot/i386/common/drv.c
===================================================================
--- sys/boot/i386/common/drv.c
+++ sys/boot/i386/common/drv.c
@@ -29,7 +29,6 @@
#include "xreadorg.h"
#endif
-#ifdef GPT
static struct edd_params params;
uint64_t
@@ -50,7 +49,6 @@
}
return (params.sectors);
}
-#endif /* GPT */
#ifndef USE_XREAD
static struct edd_packet packet;
Index: sys/boot/i386/gptboot/Makefile
===================================================================
--- sys/boot/i386/gptboot/Makefile
+++ sys/boot/i386/gptboot/Makefile
@@ -39,6 +39,13 @@
CFLAGS.gcc+= --param max-inline-insns-single=100
+.if !defined(LOADER_NO_GELI_SUPPORT)
+CFLAGS+= -DGELI
+CFLAGS+= -I${.CURDIR}/../../geli
+LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
+.PATH: ${.CURDIR}/../../../opencrypto
+.endif
+
LD_FLAGS=-static -N --gc-sections
LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a
@@ -60,14 +67,14 @@
gptldr.out: gptldr.o
${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o
-CLEANFILES+= gptboot.bin gptboot.out gptboot.o sio.o gpt.o crc32.o drv.o \
- cons.o util.o
+CLEANFILES+= gptboot.bin gptboot.out gptboot.o sio.o crc32.o drv.o \
+ cons.o util.o xform_aes_xts.o
gptboot.bin: gptboot.out
${OBJCOPY} -S -O binary gptboot.out ${.TARGET}
-gptboot.out: ${BTXCRT} gptboot.o sio.o gpt.o crc32.o drv.o cons.o util.o
- ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND}
+gptboot.out: ${BTXCRT} gptboot.o sio.o crc32.o drv.o cons.o util.o xform_aes_xts.o
+ ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT}
gptboot.o: ${.CURDIR}/../../common/ufsread.c
Index: sys/boot/i386/gptboot/gptboot.c
===================================================================
--- sys/boot/i386/gptboot/gptboot.c
+++ sys/boot/i386/gptboot/gptboot.c
@@ -23,6 +23,7 @@
#include <machine/bootinfo.h>
#include <machine/elf.h>
+#include <machine/pc/bios.h>
#include <machine/psl.h>
#include <stdarg.h>
@@ -31,6 +32,7 @@
#include <btxv86.h>
+#include "bootargs.h"
#include "lib.h"
#include "rbx.h"
#include "drv.h"
@@ -84,16 +86,61 @@
static struct dsk dsk;
static char kname[1024];
+static char gelipw[256];
static int comspeed = SIOSPD;
static struct bootinfo bootinfo;
+static struct geli_boot_args geliargs;
+
+static vm_offset_t high_heap_base;
+static uint32_t bios_basemem, bios_extmem, high_heap_size;
+
+static struct bios_smap smap;
+
+/*
+ * The minimum amount of memory to reserve in bios_extmem for the heap.
+ */
+#define HEAP_MIN (3 * 1024 * 1024)
+
+static char *heap_next;
+static char *heap_end;
void exit(int);
static void load(void);
static int parse(char *, int *);
static int dskread(void *, daddr_t, unsigned);
-static uint32_t memsize(void);
+void *malloc(size_t n);
+void free(void *ptr);
+#ifdef GELI
+static int vdev_read(void *vdev __unused, void *priv, off_t off, void *buf,
+ size_t bytes);
+#endif
+
+void *
+malloc(size_t n)
+{
+ char *p = heap_next;
+ if (p + n > heap_end) {
+ printf("malloc failure\n");
+ for (;;)
+ ;
+ return (0);
+ }
+ heap_next += n;
+ return (p);
+}
+
+void
+free(void *ptr)
+{
+
+ return;
+}
#include "ufsread.c"
+#include "gpt.c"
+#ifdef GELI
+#include "geliboot.c"
+#endif
static inline int
xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
@@ -106,19 +153,96 @@
return (0);
}
-static inline uint32_t
-memsize(void)
+static void
+bios_getmem(void)
{
+ uint64_t size;
+
+ /* Parse system memory map */
+ v86.ebx = 0;
+ do {
+ v86.ctl = V86_FLAGS;
+ v86.addr = MEM_EXT; /* int 0x15 function 0xe820*/
+ v86.eax = 0xe820;
+ v86.ecx = sizeof(struct bios_smap);
+ v86.edx = SMAP_SIG;
+ v86.es = VTOPSEG(&smap);
+ v86.edi = VTOPOFF(&smap);
+ v86int();
+ if ((v86.efl & 1) || (v86.eax != SMAP_SIG))
+ break;
+ /* look for a low-memory segment that's large enough */
+ if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) &&
+ (smap.length >= (512 * 1024)))
+ bios_basemem = smap.length;
+ /* look for the first segment in 'extended' memory */
+ if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) {
+ bios_extmem = smap.length;
+ }
+
+ /*
+ * Look for the largest segment in 'extended' memory beyond
+ * 1MB but below 4GB.
+ */
+ if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) &&
+ (smap.base < 0x100000000ull)) {
+ size = smap.length;
+
+ /*
+ * If this segment crosses the 4GB boundary, truncate it.
+ */
+ if (smap.base + size > 0x100000000ull)
+ size = 0x100000000ull - smap.base;
+
+ if (size > high_heap_size) {
+ high_heap_size = size;
+ high_heap_base = smap.base;
+ }
+ }
+ } while (v86.ebx != 0);
- v86.addr = MEM_EXT;
+ /* Fall back to the old compatibility function for base memory */
+ if (bios_basemem == 0) {
+ v86.ctl = 0;
+ v86.addr = 0x12; /* int 0x12 */
+ v86int();
+
+ bios_basemem = (v86.eax & 0xffff) * 1024;
+ }
+
+ /* Fall back through several compatibility functions for extended memory */
+ if (bios_extmem == 0) {
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x15; /* int 0x15 function 0xe801*/
+ v86.eax = 0xe801;
+ v86int();
+ if (!(v86.efl & 1)) {
+ bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024;
+ }
+ }
+ if (bios_extmem == 0) {
+ v86.ctl = 0;
+ v86.addr = 0x15; /* int 0x15 function 0x88*/
v86.eax = 0x8800;
v86int();
- return (v86.eax);
+ bios_extmem = (v86.eax & 0xffff) * 1024;
+ }
+
+ /*
+ * If we have extended memory and did not find a suitable heap
+ * region in the SMAP, use the last 3MB of 'extended' memory as a
+ * high heap candidate.
+ */
+ if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) {
+ high_heap_size = HEAP_MIN;
+ high_heap_base = bios_extmem + 0x100000 - HEAP_MIN;
+ }
}
static int
gptinit(void)
{
+ int i;
if (gptread(&freebsd_ufs_uuid, &dsk, dmadat->secbuf) == -1) {
printf("%s: unable to load GPT\n", BOOTPROG);
@@ -128,6 +252,27 @@
printf("%s: no UFS partition was found\n", BOOTPROG);
return (-1);
}
+#ifdef GELI
+ if (geli_taste(vdev_read, &dsk, (gpttable[curent].ent_lba_end -
+ gpttable[curent].ent_lba_start)) == 0) {
+ for (i = 0; i < 3; i++) {
+ /* Try cached passphrase */
+ if (i == 0 && gelipw[0] != '\0') {
+ if (geli_attach(vdev_read, &dsk, &gelipw) == 0) {
+ break;
+ }
+ }
+ printf("GELI Password for disk%dp%d: ", dsk.unit,
+ curent + 1);
+ getpwstr(gelipw, sizeof(gelipw));
+ printf("\n");
+ if (geli_attach(vdev_read, &dsk, &gelipw) == 0) {
+ break;
+ }
+ }
+ }
+#endif
+
dsk_meta = 0;
return (0);
}
@@ -141,6 +286,17 @@
ufs_ino_t ino;
dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
+
+ bios_getmem();
+
+ if (high_heap_size > 0) {
+ heap_end = PTOV(high_heap_base + high_heap_size);
+ heap_next = PTOV(high_heap_base);
+ } else {
+ heap_next = (char *)dmadat + sizeof(*dmadat);
+ heap_end = (char *)PTOV(bios_basemem);
+ }
+
v86.ctl = V86_FLAGS;
v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
dsk.drive = *(uint8_t *)PTOV(ARGS);
@@ -150,10 +306,14 @@
dsk.start = 0;
bootinfo.bi_version = BOOTINFO_VERSION;
bootinfo.bi_size = sizeof(bootinfo);
- bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */
- bootinfo.bi_extmem = memsize();
+ bootinfo.bi_basemem = bios_basemem / 1024;
+ bootinfo.bi_extmem = bios_extmem / 1024;
bootinfo.bi_memsizes_valid++;
+ bootinfo.bi_bios_dev = dsk.drive;
+#ifdef GELI
+ geli_init();
+#endif
/* Process configuration file */
if (gptinit() != 0)
@@ -331,9 +491,12 @@
bootinfo.bi_esymtab = VTOP(p);
bootinfo.bi_kernelname = VTOP(kname);
bootinfo.bi_bios_dev = dsk.drive;
+ geliargs.size = sizeof(geliargs);
+ bcopy(gelipw, geliargs.gelipw, sizeof(geliargs.gelipw));
+ bzero(gelipw, sizeof(gelipw));
__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff),
- 0, 0, 0, VTOP(&bootinfo));
+ KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo), geliargs);
}
static int
@@ -434,6 +597,53 @@
static int
dskread(void *buf, daddr_t lba, unsigned nblk)
{
+ int err;
+
+ err = drvread(&dsk, buf, lba + dsk.start, nblk);
+
+#ifdef GELI
+ if (err == 0 && is_geli(&dsk) == 0) {
+ /* Decrypt */
+ if (geli_read(&dsk, lba * DEV_BSIZE, buf, nblk * DEV_BSIZE))
+ return (err);
+ }
+#endif
+
+ return (err);
+}
+
+#ifdef GELI
+/*
+ * Read function compartible with the ZFS callback, required to keep the GELI
+ * Implementation the same for both UFS and ZFS
+ */
+static int
+vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, size_t bytes)
+{
+ char *p;
+ daddr_t lba;
+ unsigned int nb;
+ struct dsk *dskp = (struct dsk *) priv;
+
+ if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
+ return (-1);
- return drvread(&dsk, buf, lba + dsk.start, nblk);
+ p = buf;
+ lba = off / DEV_BSIZE;
+ lba += dskp->start;
+
+ while (bytes > 0) {
+ nb = bytes / DEV_BSIZE;
+ if (nb > VBLKSIZE / DEV_BSIZE)
+ nb = VBLKSIZE / DEV_BSIZE;
+ if (drvread(dskp, dmadat->blkbuf, lba, nb))
+ return (-1);
+ memcpy(p, dmadat->blkbuf, nb * DEV_BSIZE);
+ p += nb * DEV_BSIZE;
+ lba += nb;
+ bytes -= nb * DEV_BSIZE;
+ }
+
+ return (0);
}
+#endif
Index: sys/boot/i386/gptzfsboot/Makefile
===================================================================
--- sys/boot/i386/gptzfsboot/Makefile
+++ sys/boot/i386/gptzfsboot/Makefile
@@ -35,6 +35,13 @@
-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \
-Winline
+.if !defined(LOADER_NO_GELI_SUPPORT)
+CFLAGS+= -DGELI
+CFLAGS+= -I${.CURDIR}/../../geli
+LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
+.PATH: ${.CURDIR}/../../../opencrypto
+.endif
+
CFLAGS.gcc+= --param max-inline-insns-single=100
LD_FLAGS=-static -N --gc-sections
@@ -59,13 +66,13 @@
${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
+ drv.o gpt.o util.o xform_aes_xts.o
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
- ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND}
+gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o util.o xform_aes_xts.o
+ ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT}
zfsboot.o: ${.CURDIR}/../../zfs/zfsimpl.c
Index: sys/boot/i386/libi386/Makefile
===================================================================
--- sys/boot/i386/libi386/Makefile
+++ sys/boot/i386/libi386/Makefile
@@ -30,6 +30,12 @@
CFLAGS+= -DDISK_DEBUG
.endif
+.if !defined(LOADER_NO_GELI_SUPPORT)
+# Decrypt encrypted drives
+CFLAGS+= -DGELI
+CFLAGS+= -I${.CURDIR}/../../geli
+.endif
+
.if !defined(BOOT_HIDE_SERIAL_NUMBERS)
# Export serial numbers, UUID, and asset tag from loader.
CFLAGS+= -DSMBIOS_SERIAL_NUMBERS
Index: sys/boot/i386/libi386/biosdisk.c
===================================================================
--- sys/boot/i386/libi386/biosdisk.c
+++ sys/boot/i386/libi386/biosdisk.c
@@ -49,6 +49,34 @@
#include "disk.h"
#include "libi386.h"
+#ifdef GELI
+#include "cons.h"
+#include "drv.h"
+#include "gpt.h"
+#include "part.h"
+#include <uuid.h>
+struct pentry {
+ struct ptable_entry part;
+ uint64_t flags;
+ union {
+ uint8_t bsd;
+ uint8_t mbr;
+ uuid_t gpt;
+ uint16_t vtoc8;
+ } type;
+ STAILQ_ENTRY(pentry) entry;
+};
+struct ptable {
+ enum ptable_type type;
+ uint16_t sectorsize;
+ uint64_t sectors;
+
+ STAILQ_HEAD(, pentry) entries;
+};
+
+#include "geliboot.c"
+#endif
+
CTASSERT(sizeof(struct i386_devdesc) >= sizeof(struct disk_devdesc));
#define BIOS_NUMDRIVES 0x475
@@ -108,6 +136,18 @@
static void bd_print(int verbose);
static void bd_cleanup(void);
+#ifdef GELI
+static enum isgeli {
+ ISGELI_UNKNOWN,
+ ISGELI_NO,
+ ISGELI_YES
+};
+static enum isgeli geli_status[MAXBDDEV][MAXTBLENTS];
+
+int bios_read(void *vdev __unused, struct dsk *priv, off_t off, char *buf,
+ size_t bytes);
+#endif
+
struct devsw biosdisk = {
"disk",
DEVT_DISK,
@@ -154,6 +194,9 @@
{
int base, unit, nfd = 0;
+#ifdef GELI
+ geli_init();
+#endif
/* sequence 0, 0x80 */
for (base = 0; base <= 0x80; base += 0x80) {
for (unit = base; (nbdinfo < MAXBDDEV); unit++) {
@@ -299,7 +342,8 @@
static int
bd_open(struct open_file *f, ...)
{
- struct disk_devdesc *dev;
+ struct disk_devdesc *dev, rdev;
+ int err, g_err;
va_list ap;
va_start(ap, f);
@@ -309,9 +353,95 @@
if (dev->d_unit < 0 || dev->d_unit >= nbdinfo)
return (EIO);
- return (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
+ err = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
BD(dev).bd_sectorsize, (BD(dev).bd_flags & BD_FLOPPY) ?
- DISK_F_NOCACHE: 0));
+ DISK_F_NOCACHE: 0);
+
+#ifdef GELI
+ int r;
+ static char gelipw[256];
+ char *passphrase;
+
+ if (err)
+ return (err);
+
+ /* if we already know there is no GELI, skip the rest */
+ if (geli_status[dev->d_unit][dev->d_slice] != ISGELI_UNKNOWN)
+ return (err);
+
+ struct dsk dskp;
+ struct ptable *table = NULL;
+ struct ptable_entry part;
+ struct pentry *entry;
+ int geli_part = 0;
+
+ dskp.drive = bd_unit2bios(dev->d_unit);
+ dskp.type = dev->d_type;
+ dskp.unit = dev->d_unit;
+ dskp.slice = dev->d_slice;
+ dskp.part = dev->d_partition;
+ dskp.start = dev->d_offset;
+
+ memcpy(&rdev, dev, sizeof(rdev));
+ /* to read the GPT table, we need to read the first sector */
+ rdev.d_offset = 0;
+ /* We need the LBA of the end of the partition */
+ table = ptable_open(&rdev, BD(dev).bd_sectors,
+ BD(dev).bd_sectorsize, ptblread);
+ if (table == NULL) {
+ DEBUG("Can't read partition table");
+ /* soft failure, return the exit status of disk_open */
+ return (err);
+ }
+
+ if (table->type == PTABLE_GPT)
+ dskp.part = 255;
+
+ STAILQ_FOREACH(entry, &table->entries, entry) {
+ dskp.slice = entry->part.index;
+ dskp.start = entry->part.start;
+ if (is_geli(&dskp) == 0) {
+ geli_status[dev->d_unit][dskp.slice] = ISGELI_YES;
+ return (0);
+ }
+ if (geli_taste(bios_read, &dskp,
+ entry->part.end - entry->part.start) == 0) {
+ for (r = 0; r < 3; r++) {
+ if (r == 0 && (passphrase =
+ getenv("kern.geom.eli.passphrase"))
+ != NULL) {
+ /* Use the cached passphrase */
+ } else {
+ printf("GELI Password for disk%dp%d: ",
+ dskp.unit, (dskp.slice > 0 ?
+ dskp.slice : dskp.part));
+ getpwstr(gelipw, sizeof(gelipw));
+ printf("\n");
+ passphrase = &gelipw;
+ }
+ if (geli_attach(bios_read, &dskp, passphrase)
+ == 0) {
+ setenv("kern.geom.eli.passphrase",
+ passphrase, 1);
+ bzero(gelipw, sizeof(gelipw));
+ geli_status[dev->d_unit][dskp.slice] =
+ ISGELI_YES;
+ geli_part++;
+ break;
+ }
+ }
+ } else
+ geli_status[dev->d_unit][dskp.slice] = ISGELI_NO;
+ }
+
+ /* none of the partitions on this disk have GELI */
+ if (geli_part == 0) {
+ /* found no GELI */
+ geli_status[dev->d_unit][dev->d_slice] = ISGELI_NO;
+ }
+#endif
+
+ return (err);
}
static int
@@ -586,6 +716,38 @@
static int
bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest)
{
+#ifdef GELI
+ struct dsk dskp;
+ off_t p_off;
+ int err, n;
+
+ /* if we already know there is no GELI, skip the rest */
+ if (geli_status[dev->d_unit][dev->d_slice] != ISGELI_YES)
+ return (bd_io(dev, dblk, blks, dest, 0));
+
+ if (geli_status[dev->d_unit][dev->d_slice] == ISGELI_YES) {
+ err = bd_io(dev, dblk, blks, dest, 0);
+ if (err)
+ return (err);
+
+ dskp.drive = bd_unit2bios(dev->d_unit);
+ dskp.type = dev->d_type;
+ dskp.unit = dev->d_unit;
+ dskp.slice = dev->d_slice;
+ dskp.part = dev->d_partition;
+ dskp.start = dev->d_offset;
+
+ /* GELI needs the offset relative to the partition start */
+ p_off = dblk - dskp.start;
+
+ err = geli_read(&dskp, p_off * BIOSDISK_SECSIZE, dest,
+ blks * BIOSDISK_SECSIZE);
+ if (err)
+ return (err);
+
+ return (0);
+ }
+#endif
return (bd_io(dev, dblk, blks, dest, 0));
}
@@ -682,3 +844,25 @@
DEBUG("dev is 0x%x\n", rootdev);
return(rootdev);
}
+
+#ifdef GELI
+int
+bios_read(void *vdev __unused, struct dsk *priv, off_t off, char *buf, size_t bytes)
+{
+ struct disk_devdesc dev;
+
+ dev.d_dev = &biosdisk;
+ dev.d_type = priv->type;
+ dev.d_unit = priv->unit;
+ dev.d_slice = priv->slice;
+ dev.d_partition = priv->part;
+ dev.d_offset = priv->start;
+
+ off = off / BIOSDISK_SECSIZE;
+ /* GELI gives us the offset relative to the partition start */
+ off += dev.d_offset;
+ bytes = bytes / BIOSDISK_SECSIZE;
+
+ return (bd_io(&dev, off, bytes, buf, 0));
+}
+#endif
Index: sys/boot/i386/loader/Makefile
===================================================================
--- sys/boot/i386/loader/Makefile
+++ sys/boot/i386/loader/Makefile
@@ -58,6 +58,13 @@
.if defined(LOADER_NANDFS_SUPPORT)
CFLAGS+= -DLOADER_NANDFS_SUPPORT
.endif
+.if !defined(LOADER_NO_GELI_SUPPORT)
+CFLAGS+= -DGELI -DLOADER_GELI_SUPPORT
+LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
+.PATH: ${.CURDIR}/../../../opencrypto
+SRCS+= xform_aes_xts.c
+CFLAGS+= -I${.CURDIR}/../../.. -D_LOADER
+.endif
# Always add MI sources
.PATH: ${.CURDIR}/../../common
@@ -116,8 +123,8 @@
# XXX crt0.o needs to be first for pxeboot(8) to work
OBJS= ${BTXCRT}
-DPADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND}
-LDADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND}
+DPADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND} ${LIBGELIBOOT}
+LDADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND} ${LIBGELIBOOT}
.include <bsd.prog.mk>
Index: sys/boot/i386/loader/main.c
===================================================================
--- sys/boot/i386/loader/main.c
+++ sys/boot/i386/loader/main.c
@@ -68,7 +68,9 @@
static int isa_inb(int port);
static void isa_outb(int port, int value);
void exit(int code);
+struct geli_boot_args *gargs;
#ifdef LOADER_ZFS_SUPPORT
+struct zfs_boot_args *zargs;
static void i386_zfs_probe(void);
#endif
@@ -164,7 +166,31 @@
archsw.arch_isaoutb = isa_outb;
#ifdef LOADER_ZFS_SUPPORT
archsw.arch_zfs_probe = i386_zfs_probe;
-#endif
+
+#ifdef LOADER_GELI_SUPPORT
+ if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) {
+ zargs = (struct zfs_boot_args *)(kargs + 1);
+ if (zargs != NULL && zargs->size >= offsetof(struct zfs_boot_args, gelipw)) {
+ if (zargs->gelipw[0] != '\0') {
+ setenv("kern.geom.eli.passphrase", zargs->gelipw, 1);
+ bzero(zargs->gelipw, sizeof(zargs->gelipw));
+ }
+ }
+ }
+#endif /* LOADER_GELI_SUPPORT */
+#else /* LOADER_ZFS_SUPPORT */
+#ifdef LOADER_GELI_SUPPORT
+ if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) {
+ gargs = (struct geli_boot_args *)(kargs + 1);
+ if (gargs != NULL && gargs->size >= offsetof(struct geli_boot_args, gelipw)) {
+ if (gargs->gelipw[0] != '\0') {
+ setenv("kern.geom.eli.passphrase", gargs->gelipw, 1);
+ bzero(gargs->gelipw, sizeof(gargs->gelipw));
+ }
+ }
+ }
+#endif /* LOADER_GELI_SUPPORT */
+#endif /* LOADER_ZFS_SUPPORT */
/*
* March through the device switch probing for things.
@@ -219,7 +245,6 @@
struct i386_devdesc new_currdev;
#ifdef LOADER_ZFS_SUPPORT
char buf[20];
- struct zfs_boot_args *zargs;
#endif
int biosdev = -1;
Index: sys/boot/i386/zfsboot/Makefile
===================================================================
--- sys/boot/i386/zfsboot/Makefile
+++ sys/boot/i386/zfsboot/Makefile
@@ -27,6 +27,7 @@
-I${.CURDIR}/../../../cddl/boot/zfs \
-I${.CURDIR}/../btx/lib -I. \
-I${.CURDIR}/../boot2 \
+ -I${.CURDIR}/../../.. \
-Wall -Waggregate-return -Wbad-function-cast -Wcast-align \
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \
@@ -34,6 +35,13 @@
CFLAGS.gcc+= --param max-inline-insns-single=100
+.if !defined(LOADER_NO_GELI_SUPPORT)
+CFLAGS+= -DGELI
+CFLAGS+= -I${.CURDIR}/../../geli
+LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
+.PATH: ${.CURDIR}/../../../opencrypto
+.endif
+
LD_FLAGS=-static -N --gc-sections
LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a
@@ -55,12 +63,13 @@
${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 xform_aes_xts.o
-# We currently allow 65536 bytes for zfsboot - in practice it could be
+# We currently allow 131072 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,8 +86,8 @@
zfsboot.bin: zfsboot.out
${OBJCOPY} -S -O binary zfsboot.out ${.TARGET}
-zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o util.o
- ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND}
+zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o util.o xform_aes_xts.o
+ ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT}
SRCS= zfsboot.c
Index: sys/boot/i386/zfsboot/zfsboot.c
===================================================================
--- sys/boot/i386/zfsboot/zfsboot.c
+++ sys/boot/i386/zfsboot/zfsboot.c
@@ -94,6 +94,7 @@
static char cmddup[512];
static char kname[1024];
static char rootname[256];
+static char gelipw[256];
static int comspeed = SIOSPD;
static struct bootinfo bootinfo;
static uint32_t bootdev;
@@ -125,8 +126,10 @@
static void load(void);
static int parse(void);
static void bios_getmem(void);
+void *malloc(size_t n);
+void free(void *ptr);
-static void *
+void *
malloc(size_t n)
{
char *p = heap_next;
@@ -134,10 +137,17 @@
printf("malloc failure\n");
for (;;)
;
- return 0;
+ return (0);
}
heap_next += n;
- return p;
+ return (p);
+}
+
+void
+free(void *ptr)
+{
+
+ return;
}
static char *
@@ -145,9 +155,50 @@
{
char *p = malloc(strlen(s) + 1);
strcpy(p, s);
- return p;
+ return (p);
}
+#ifdef GELI
+#include "geliboot.c"
+
+/*
+ * A wrapper for dskread that doesn't have to worry about whether the
+ * buffer pointer crosses a 64k boundary. Reads from an encrypted disk
+ */
+static int
+geli_vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, size_t bytes)
+{
+ char *p;
+ daddr_t lba;
+ unsigned int nb;
+ struct dsk *dsk = (struct dsk *) priv;
+
+ if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
+ return (-1);
+
+ p = buf;
+ lba = off / DEV_BSIZE;
+ lba += dsk->start;
+ while (bytes > 0) {
+ nb = bytes / DEV_BSIZE;
+ if (nb > READ_BUF_SIZE / DEV_BSIZE)
+ nb = READ_BUF_SIZE / DEV_BSIZE;
+ if (drvread(dsk, dmadat->rdbuf, lba, nb))
+ return (-1);
+ /* decrypt */
+ if (geli_read(dsk, ((lba - dsk->start) * DEV_BSIZE),
+ dmadat->rdbuf, nb * DEV_BSIZE))
+ return (-1);
+ memcpy(p, dmadat->rdbuf, nb * DEV_BSIZE);
+ p += nb * DEV_BSIZE;
+ lba += nb;
+ bytes -= nb * DEV_BSIZE;
+ }
+
+ return (0);
+}
+#endif
+
#include "zfsimpl.c"
/*
@@ -350,21 +401,52 @@
#ifdef GPT
struct gpt_hdr hdr;
struct gpt_ent *ent;
- daddr_t slba, elba;
unsigned part, entries_per_sec;
#endif
+ daddr_t slba, elba;
struct dos_partition *dp;
char *sec;
- unsigned i;
+ unsigned i, r;
/*
- * If we find a vdev on the whole disk, stop here. Otherwise dig
- * out the partition table and probe each slice/partition
- * in turn for a vdev.
+ * If we find a vdev on the whole disk, stop here.
*/
if (vdev_probe(vdev_read, dsk, NULL) == 0)
return;
+#ifdef GELI
+ /*
+ * Taste the disk, if it is GELI encrypted, decrypt it and check to see if
+ * it is a usable vdev then. Otherwise dig
+ * out the partition table and probe each slice/partition
+ * in turn for a vdev or GELI encrypted vdev.
+ */
+ elba = drvsize(dsk);
+ if (elba > 0) {
+ elba--;
+ }
+ if (geli_taste(vdev_read, dsk, elba) == 0) {
+ for (r = 0; r < 3; r++) {
+ /* Try cached passphrase */
+ if (r == 0 && gelipw[0] != '\0') {
+ if (geli_attach(vdev_read, dsk, &gelipw) == 0) {
+ if (vdev_probe(geli_vdev_read, dsk, NULL) == 0) {
+ return;
+ }
+ }
+ }
+ printf("GELI Password for disk%d: ", dsk->unit);
+ getpwstr(gelipw, sizeof(gelipw));
+ printf("\n");
+ if (geli_attach(vdev_read, dsk, &gelipw) == 0) {
+ if (vdev_probe(geli_vdev_read, dsk, NULL) == 0) {
+ return;
+ }
+ }
+ }
+ }
+#endif
+
sec = dmadat->secbuf;
dsk->start = 0;
@@ -387,6 +469,8 @@
* return the spa_t for the first we find (if requested). This
* will have the effect of booting from the first pool on the
* disk.
+ *
+ * If no vdev is found, GELI decrypting the device and try again
*/
entries_per_sec = DEV_BSIZE / hdr.hdr_entsz;
slba = hdr.hdr_lba_table;
@@ -400,6 +484,8 @@
if (memcmp(&ent->ent_type, &freebsd_zfs_uuid,
sizeof(uuid_t)) == 0) {
dsk->start = ent->ent_lba_start;
+ dsk->slice = part + 1;
+ dsk->part = 255;
if (vdev_probe(vdev_read, dsk, NULL) == 0) {
/*
* This slice had a vdev. We need a new dsk
@@ -407,6 +493,39 @@
*/
dsk = copy_dsk(dsk);
}
+#ifdef GELI
+ else if (geli_taste(vdev_read, dsk, ent->ent_lba_end -
+ ent->ent_lba_start) == 0) {
+ for (r = 0; r < 3; r++) {
+ /* Try cached passphrase */
+ if (r == 0 && gelipw[0] != '\0') {
+ if (geli_attach(vdev_read, dsk, &gelipw) == 0) {
+ if (vdev_probe(geli_vdev_read, dsk, NULL) == 0) {
+ dsk = copy_dsk(dsk);
+ }
+ break;
+ }
+ }
+ printf("GELI Password for disk%dp%d: ", dsk->unit,
+ dsk->slice);
+ getpwstr(gelipw, sizeof(gelipw));
+ printf("\n");
+ if (geli_attach(vdev_read, dsk, &gelipw) == 0) {
+ /*
+ * This slice has GELI, check it for ZFS.
+ */
+ if (vdev_probe(geli_vdev_read, dsk, NULL) == 0) {
+ /*
+ * This slice had a vdev. We need a new dsk
+ * structure now since the vdev now owns this one.
+ */
+ dsk = copy_dsk(dsk);
+ }
+ break;
+ }
+ }
+ }
+#endif
}
}
slba++;
@@ -423,13 +542,42 @@
if (!dp[i].dp_typ)
continue;
dsk->start = dp[i].dp_start;
+ dsk->slice = i + 1;
if (vdev_probe(vdev_read, dsk, NULL) == 0) {
- /*
- * This slice had a vdev. We need a new dsk structure now
- * since the vdev now owns this one.
- */
dsk = copy_dsk(dsk);
}
+#ifdef GELI
+ else if (geli_taste(vdev_read, dsk, dp[i].dp_size -
+ dp[i].dp_start) == 0) {
+ for (i = 0; i < 3; i++) {
+ /* Try cached passphrase */
+ if (r == 0 && gelipw[0] != '\0') {
+ if (geli_attach(vdev_read, dsk, &gelipw) == 0) {
+ if (vdev_probe(geli_vdev_read, dsk, NULL) == 0) {
+ dsk = copy_dsk(dsk);
+ }
+ break;
+ }
+ }
+ printf("GELI Password for disk%ds%d: ", dsk->unit, i);
+ getpwstr(gelipw, sizeof(gelipw));
+ printf("\n");
+ if (geli_attach(vdev_read, dsk, &gelipw) == 0) {
+ /*
+ * This slice has GELI, check it for ZFS.
+ */
+ if (vdev_probe(geli_vdev_read, dsk, NULL) == 0) {
+ /*
+ * This slice had a vdev. We need a new dsk
+ * structure now since the vdev now owns this one.
+ */
+ dsk = copy_dsk(dsk);
+ }
+ break;
+ }
+ }
+ }
+#endif
}
}
@@ -449,8 +597,8 @@
heap_end = PTOV(high_heap_base + high_heap_size);
heap_next = PTOV(high_heap_base);
} else {
- heap_next = (char *) dmadat + sizeof(*dmadat);
- heap_end = (char *) PTOV(bios_basemem);
+ heap_next = (char *)dmadat + sizeof(*dmadat);
+ heap_end = (char *)PTOV(bios_basemem);
}
dsk = malloc(sizeof(struct dsk));
@@ -476,6 +624,9 @@
autoboot = 1;
+#ifdef GELI
+ geli_init();
+#endif
zfs_init();
/*
@@ -694,6 +845,8 @@
zfsargs.pool = zfsmount.spa->spa_guid;
zfsargs.root = zfsmount.rootobj;
zfsargs.primary_pool = primary_spa->spa_guid;
+ bcopy(gelipw, zfsargs.gelipw, sizeof(zfsargs.gelipw));
+ bzero(gelipw, sizeof(gelipw));
if (primary_vdev != NULL)
zfsargs.primary_vdev = primary_vdev->v_guid;
else
Index: sys/boot/zfs/libzfs.h
===================================================================
--- sys/boot/zfs/libzfs.h
+++ sys/boot/zfs/libzfs.h
@@ -55,6 +55,7 @@
uint64_t root;
uint64_t primary_pool;
uint64_t primary_vdev;
+ char gelipw[256];
};
int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec,

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 21, 9:35 PM (1 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25749856
Default Alt Text
D4593.id11656.diff (56 KB)

Event Timeline