Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F136975971
D4593.id11656.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
56 KB
Referenced Files
None
Subscribers
None
D4593.id11656.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D4593: Implement a stripped down version of GELI (AES-XTS and AES-CBC only) in gptboot and gptzfsboot
Attached
Detach File
Event Timeline
Log In to Comment