mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-06 17:18:32 +00:00
Implement GELI (AES-XTS and AES-CBC only) in gptboot and gptzfsboot
Allows booting from a GELI encrypted root file system, via UFS or ZFS Reviewed by: gnn, smh (previous version), delphij (previous version) Relnotes: yes Sponsored by: ScaleEngine Inc. Differential Revision: https://reviews.freebsd.org/D4593
This commit is contained in:
parent
e33c2e6b06
commit
b996592c3e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=296963
|
@ -3,6 +3,7 @@
|
|||
SUBDIR+= efi
|
||||
SUBDIR+= libstand32
|
||||
SUBDIR+= zfs
|
||||
SUBDIR+= geli
|
||||
SUBDIR+= userboot
|
||||
|
||||
.if ${MK_FORTH} != "no"
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
SUBDIR+= efi
|
||||
SUBDIR+= libstand32
|
||||
SUBDIR+= zfs
|
||||
SUBDIR+= geli
|
||||
|
|
|
@ -170,7 +170,7 @@ display_size(uint64_t size, u_int sectorsize)
|
|||
return (buf);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
ptblread(void *d, void *buf, size_t blocks, off_t offset)
|
||||
{
|
||||
struct disk_devdesc *dev;
|
||||
|
|
|
@ -107,6 +107,7 @@ extern int disk_read(struct disk_devdesc *dev, void *buf, off_t offset,
|
|||
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.
|
||||
|
|
|
@ -39,8 +39,6 @@ __FBSDID("$FreeBSD$");
|
|||
#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];
|
||||
|
|
|
@ -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);
|
||||
|
|
52
sys/boot/geli/Makefile
Normal file
52
sys/boot/geli/Makefile
Normal file
|
@ -0,0 +1,52 @@
|
|||
# $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
|
||||
|
||||
# Our password input method
|
||||
SRCS+= pwgets.c
|
||||
|
||||
# sha256 and sha512 from sys/crypto
|
||||
.PATH: ${.CURDIR}/../../crypto/sha2
|
||||
CFLAGS+= -DWEAK_REFS
|
||||
SRCS+= sha256c.c sha512c.c
|
||||
|
||||
# md5 from libmd
|
||||
.PATH: ${.CURDIR}/../../../lib/libmd
|
||||
SRCS+= md5c.c
|
||||
|
||||
# AES implementation from sys/crypto
|
||||
.PATH: ${.CURDIR}/../../crypto/rijndael
|
||||
CFLAGS+= -I${.CURDIR}/../../
|
||||
# Remove asserts
|
||||
CFLAGS+= -DNDEBUG
|
||||
SRCS+= rijndael-alg-fst.c rijndael-api-fst.c rijndael-api.c
|
||||
|
||||
# local 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>
|
284
sys/boot/geli/geliboot.c
Normal file
284
sys/boot/geli/geliboot.c
Normal file
|
@ -0,0 +1,284 @@
|
|||
/*-
|
||||
* 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"
|
||||
|
||||
SLIST_HEAD(geli_list, geli_entry) geli_head = SLIST_HEAD_INITIALIZER(geli_head);
|
||||
struct geli_list *geli_headp;
|
||||
|
||||
static int
|
||||
geli_same_device(struct geli_entry *ge, struct dsk *dskp)
|
||||
{
|
||||
|
||||
if (geli_e->dsk->drive == dskp->drive &&
|
||||
dskp->part == 255 && geli_e->dsk->part == dskp->slice) {
|
||||
/*
|
||||
* Sometimes slice = slice, and sometimes part = slice
|
||||
* If the incoming struct dsk has part=255, it means look at
|
||||
* the slice instead of the part number
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Is this the same device? */
|
||||
if (geli_e->dsk->drive != dskp->drive ||
|
||||
geli_e->dsk->slice != dskp->slice ||
|
||||
geli_e->dsk->part != dskp->part) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
int
|
||||
geli_attach(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_same_device(geli_e, dskp) != 0) {
|
||||
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);
|
||||
bzero(&key, sizeof(key));
|
||||
if (error == -1) {
|
||||
bzero(&mkey, sizeof(mkey));
|
||||
printf("Bad GELI key: %d\n", error);
|
||||
return (error);
|
||||
} else if (error != 0) {
|
||||
bzero(&mkey, sizeof(mkey));
|
||||
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);
|
||||
}
|
||||
bzero(&mkey, sizeof(mkey));
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
int
|
||||
is_geli(struct dsk *dskp)
|
||||
{
|
||||
SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
|
||||
if (geli_same_device(geli_e, dskp) == 0) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes)
|
||||
{
|
||||
u_char iv[G_ELI_IVKEYLEN];
|
||||
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_same_device(geli_e, dskp) != 0) {
|
||||
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(&gkey, sizeof(gkey));
|
||||
printf("Failed to decrypt in geli_read()!");
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
bzero(&gkey, sizeof(gkey));
|
||||
return (0);
|
||||
}
|
||||
|
||||
printf("GELI provider not found\n");
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* TODO: Implement GELI keyfile(s) support */
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* Try cached passphrase */
|
||||
if (i == 0 && pw[0] != '\0') {
|
||||
if (geli_attach(dskp, pw) == 0) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
printf("GELI Passphrase for disk%d%c%d: ", disk, parttype, part);
|
||||
pwgets(pw, GELI_PW_MAXLEN);
|
||||
printf("\n");
|
||||
if (geli_attach(dskp, pw) == 0) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
86
sys/boot/geli/geliboot.h
Normal file
86
sys/boot/geli/geliboot.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*-
|
||||
* 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>
|
||||
#include <geom/eli/pkcs5v2.h>
|
||||
|
||||
/* Pull in the md5, sha256, and sha512 implementations */
|
||||
#include <md5.h>
|
||||
#include <crypto/sha2/sha256.h>
|
||||
#include <crypto/sha2/sha512.h>
|
||||
|
||||
/* Pull in AES implementation */
|
||||
#include <crypto/rijndael/rijndael-api-fst.h>
|
||||
|
||||
/* AES-XTS implementation */
|
||||
#define _STAND
|
||||
#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
|
||||
|
||||
#define GELI_PW_MAXLEN 256
|
||||
extern void pwgets(char *buf, int n);
|
||||
|
||||
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;
|
||||
|
||||
int geli_count;
|
||||
|
||||
void geli_init(void);
|
||||
int geli_taste(int read_func(void *vdev, void *priv, off_t off,
|
||||
void *buf, size_t bytes), struct dsk *dsk, daddr_t lastsector);
|
||||
int geli_attach(struct dsk *dskp, const char *passphrase);
|
||||
int is_geli(struct dsk *dsk);
|
||||
int geli_read(struct dsk *dsk, off_t offset, u_char *buf, size_t bytes);
|
||||
int geli_decrypt(u_int algo, u_char *data, size_t datasize,
|
||||
const u_char *key, size_t keysize, const uint8_t* iv);
|
||||
int geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp);
|
||||
|
||||
#endif /* _GELIBOOT_H_ */
|
135
sys/boot/geli/geliboot_crypto.c
Normal file
135
sys/boot/geli/geliboot_crypto.c
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*-
|
||||
* Copyright (c) 2005-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* 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);
|
||||
|
||||
enc_xform_aes_xts.reinit(ctxp, iv);
|
||||
|
||||
switch (enc) {
|
||||
case 0: /* decrypt */
|
||||
for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) {
|
||||
enc_xform_aes_xts.decrypt(ctxp, data + i);
|
||||
}
|
||||
break;
|
||||
case 1: /* encrypt */
|
||||
for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) {
|
||||
enc_xform_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));
|
||||
}
|
83
sys/boot/geli/pwgets.c
Normal file
83
sys/boot/geli/pwgets.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* $NetBSD: gets.c,v 1.6 1995/10/11 21:16:57 pk Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. 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.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
||||
*
|
||||
* @(#)gets.c 8.1 (Berkeley) 6/11/93
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "stand.h"
|
||||
|
||||
/* gets() with constrained input length, for passwords */
|
||||
|
||||
void
|
||||
pwgets(char *buf, int n)
|
||||
{
|
||||
int c;
|
||||
char *lp;
|
||||
|
||||
for (lp = buf;;)
|
||||
switch (c = getchar() & 0177) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
*lp = '\0';
|
||||
putchar('\n');
|
||||
return;
|
||||
case '\b':
|
||||
case '\177':
|
||||
if (lp > buf) {
|
||||
lp--;
|
||||
putchar('\b');
|
||||
putchar(' ');
|
||||
putchar('\b');
|
||||
}
|
||||
break;
|
||||
case 'r'&037: {
|
||||
char *p;
|
||||
|
||||
putchar('\n');
|
||||
for (p = buf; p < lp; ++p)
|
||||
putchar(*p);
|
||||
break;
|
||||
}
|
||||
case 'u'&037:
|
||||
case 'w'&037:
|
||||
lp = buf;
|
||||
putchar('\n');
|
||||
break;
|
||||
default:
|
||||
if ((n < 1) || ((lp - buf) < n - 1)) {
|
||||
*lp++ = c;
|
||||
putchar('*');
|
||||
}
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
|
@ -64,6 +64,12 @@ struct bootargs
|
|||
*/
|
||||
};
|
||||
|
||||
struct geli_boot_args
|
||||
{
|
||||
uint32_t size;
|
||||
char gelipw[256];
|
||||
};
|
||||
|
||||
#endif /*__ASSEMBLER__*/
|
||||
|
||||
#endif /* !_BOOT_I386_ARGS_H_ */
|
||||
|
|
|
@ -96,6 +96,13 @@ xgetc(int fn)
|
|||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int
|
||||
getchar(void)
|
||||
{
|
||||
|
||||
return (xgetc(0));
|
||||
}
|
||||
|
||||
int
|
||||
keyhit(unsigned int secs)
|
||||
{
|
||||
|
|
|
@ -29,7 +29,6 @@ __FBSDID("$FreeBSD$");
|
|||
#include "xreadorg.h"
|
||||
#endif
|
||||
|
||||
#ifdef GPT
|
||||
static struct edd_params params;
|
||||
|
||||
uint64_t
|
||||
|
@ -50,7 +49,6 @@ drvsize(struct dsk *dskp)
|
|||
}
|
||||
return (params.sectors);
|
||||
}
|
||||
#endif /* GPT */
|
||||
|
||||
#ifndef USE_XREAD
|
||||
static struct edd_packet packet;
|
||||
|
|
|
@ -42,7 +42,7 @@ struct dsk {
|
|||
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_ */
|
||||
|
|
|
@ -39,6 +39,14 @@ CFLAGS= -DBOOTPROG=\"gptboot\" \
|
|||
|
||||
CFLAGS.gcc+= --param max-inline-insns-single=100
|
||||
|
||||
.if !defined(LOADER_NO_GELI_SUPPORT)
|
||||
CFLAGS+= -DLOADER_GELI_SUPPORT
|
||||
CFLAGS+= -I${.CURDIR}/../../geli
|
||||
LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
|
||||
.PATH: ${.CURDIR}/../../../opencrypto
|
||||
OPENCRYPTO_XTS= xform_aes_xts.o
|
||||
.endif
|
||||
|
||||
LD_FLAGS=-static -N --gc-sections
|
||||
|
||||
LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a
|
||||
|
@ -60,14 +68,14 @@ gptldr.bin: gptldr.out
|
|||
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 ${OPENCRYPTO_XTS}
|
||||
|
||||
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 ${OPENCRYPTO_XTS}
|
||||
${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT}
|
||||
|
||||
gptboot.o: ${.CURDIR}/../../common/ufsread.c
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ __FBSDID("$FreeBSD$");
|
|||
|
||||
#include <machine/bootinfo.h>
|
||||
#include <machine/elf.h>
|
||||
#include <machine/pc/bios.h>
|
||||
#include <machine/psl.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
@ -31,6 +32,7 @@ __FBSDID("$FreeBSD$");
|
|||
|
||||
#include <btxv86.h>
|
||||
|
||||
#include "bootargs.h"
|
||||
#include "lib.h"
|
||||
#include "rbx.h"
|
||||
#include "drv.h"
|
||||
|
@ -82,14 +84,60 @@ static struct dsk dsk;
|
|||
static char kname[1024];
|
||||
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 LOADER_GELI_SUPPORT
|
||||
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 (;;)
|
||||
;
|
||||
/* NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
heap_next += n;
|
||||
return (p);
|
||||
}
|
||||
|
||||
void
|
||||
free(void *ptr)
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#include "ufsread.c"
|
||||
#include "gpt.c"
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.c"
|
||||
static char gelipw[GELI_PW_MAXLEN];
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
|
||||
|
@ -102,14 +150,90 @@ xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
|
|||
return (0);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
memsize(void)
|
||||
static void
|
||||
bios_getmem(void)
|
||||
{
|
||||
uint64_t size;
|
||||
|
||||
v86.addr = MEM_EXT;
|
||||
/* 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);
|
||||
|
||||
/* 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
|
||||
|
@ -124,6 +248,16 @@ gptinit(void)
|
|||
printf("%s: no UFS partition was found\n", BOOTPROG);
|
||||
return (-1);
|
||||
}
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
if (geli_taste(vdev_read, &dsk, (gpttable[curent].ent_lba_end -
|
||||
gpttable[curent].ent_lba_start)) == 0) {
|
||||
if (geli_passphrase(&gelipw, dsk.unit, 'p', curent + 1, &dsk) != 0) {
|
||||
printf("%s: unable to decrypt GELI key\n", BOOTPROG);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
dsk_meta = 0;
|
||||
return (0);
|
||||
}
|
||||
|
@ -137,6 +271,17 @@ main(void)
|
|||
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);
|
||||
|
@ -146,10 +291,14 @@ main(void)
|
|||
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 LOADER_GELI_SUPPORT
|
||||
geli_init();
|
||||
#endif
|
||||
/* Process configuration file */
|
||||
|
||||
if (gptinit() != 0)
|
||||
|
@ -327,9 +476,16 @@ load(void)
|
|||
bootinfo.bi_esymtab = VTOP(p);
|
||||
bootinfo.bi_kernelname = VTOP(kname);
|
||||
bootinfo.bi_bios_dev = dsk.drive;
|
||||
geliargs.size = sizeof(geliargs);
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
bcopy(gelipw, geliargs.gelipw, sizeof(geliargs.gelipw));
|
||||
bzero(gelipw, sizeof(gelipw));
|
||||
#else
|
||||
geliargs.gelipw[0] = '\0';
|
||||
#endif
|
||||
__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
|
||||
|
@ -430,6 +586,53 @@ parse(char *cmdstr, int *dskupdated)
|
|||
static int
|
||||
dskread(void *buf, daddr_t lba, unsigned nblk)
|
||||
{
|
||||
int err;
|
||||
|
||||
return drvread(&dsk, buf, lba + dsk.start, nblk);
|
||||
err = drvread(&dsk, buf, lba + dsk.start, nblk);
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
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 LOADER_GELI_SUPPORT
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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 /* LOADER_GELI_SUPPORT */
|
||||
|
|
|
@ -35,6 +35,14 @@ CFLAGS= -DBOOTPROG=\"gptzfsboot\" \
|
|||
-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \
|
||||
-Winline
|
||||
|
||||
.if !defined(LOADER_NO_GELI_SUPPORT)
|
||||
CFLAGS+= -DLOADER_GELI_SUPPORT
|
||||
CFLAGS+= -I${.CURDIR}/../../geli
|
||||
LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
|
||||
.PATH: ${.CURDIR}/../../../opencrypto
|
||||
OPENCRYPTO_XTS= xform_aes_xts.o
|
||||
.endif
|
||||
|
||||
CFLAGS.gcc+= --param max-inline-insns-single=100
|
||||
|
||||
LD_FLAGS=-static -N --gc-sections
|
||||
|
@ -59,13 +67,13 @@ gptldr.out: gptldr.o
|
|||
${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o
|
||||
|
||||
CLEANFILES+= gptzfsboot.bin gptzfsboot.out zfsboot.o sio.o cons.o \
|
||||
drv.o gpt.o util.o
|
||||
drv.o gpt.o util.o ${OPENCRYPTO_XTS}
|
||||
|
||||
gptzfsboot.bin: gptzfsboot.out
|
||||
${OBJCOPY} -S -O binary gptzfsboot.out ${.TARGET}
|
||||
|
||||
gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o util.o
|
||||
${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND}
|
||||
gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o util.o ${OPENCRYPTO_XTS}
|
||||
${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT}
|
||||
|
||||
zfsboot.o: ${.CURDIR}/../../zfs/zfsimpl.c
|
||||
|
||||
|
|
|
@ -30,6 +30,12 @@ CFLAGS+= -DCOMSPEED=${BOOT_COMCONSOLE_SPEED}
|
|||
CFLAGS+= -DDISK_DEBUG
|
||||
.endif
|
||||
|
||||
.if !defined(LOADER_NO_GELI_SUPPORT)
|
||||
# Decrypt encrypted drives
|
||||
CFLAGS+= -DLOADER_GELI_SUPPORT
|
||||
CFLAGS+= -I${.CURDIR}/../../geli
|
||||
.endif
|
||||
|
||||
.if !defined(BOOT_HIDE_SERIAL_NUMBERS)
|
||||
# Export serial numbers, UUID, and asset tag from loader.
|
||||
CFLAGS+= -DSMBIOS_SERIAL_NUMBERS
|
||||
|
|
|
@ -49,6 +49,34 @@ __FBSDID("$FreeBSD$");
|
|||
#include "disk.h"
|
||||
#include "libi386.h"
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#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 /* LOADER_GELI_SUPPORT */
|
||||
|
||||
CTASSERT(sizeof(struct i386_devdesc) >= sizeof(struct disk_devdesc));
|
||||
|
||||
#define BIOS_NUMDRIVES 0x475
|
||||
|
@ -108,6 +136,18 @@ static int bd_ioctl(struct open_file *f, u_long cmd, void *data);
|
|||
static void bd_print(int verbose);
|
||||
static void bd_cleanup(void);
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
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 /* LOADER_GELI_SUPPORT */
|
||||
|
||||
struct devsw biosdisk = {
|
||||
"disk",
|
||||
DEVT_DISK,
|
||||
|
@ -154,6 +194,9 @@ bd_init(void)
|
|||
{
|
||||
int base, unit, nfd = 0;
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
geli_init();
|
||||
#endif
|
||||
/* sequence 0, 0x80 */
|
||||
for (base = 0; base <= 0x80; base += 0x80) {
|
||||
for (unit = base; (nbdinfo < MAXBDDEV); unit++) {
|
||||
|
@ -299,7 +342,8 @@ bd_print(int verbose)
|
|||
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,83 @@ bd_open(struct open_file *f, ...)
|
|||
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 LOADER_GELI_SUPPORT
|
||||
static char gelipw[GELI_PW_MAXLEN];
|
||||
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) {
|
||||
if ((passphrase = getenv("kern.geom.eli.passphrase"))
|
||||
!= NULL) {
|
||||
/* Use the cached passphrase */
|
||||
bcopy(passphrase, &gelipw, GELI_PW_MAXLEN);
|
||||
}
|
||||
if (geli_passphrase(&gelipw, dskp.unit, 'p',
|
||||
(dskp.slice > 0 ? dskp.slice : dskp.part),
|
||||
&dskp) == 0) {
|
||||
setenv("kern.geom.eli.passphrase", &gelipw, 1);
|
||||
bzero(gelipw, sizeof(gelipw));
|
||||
geli_status[dev->d_unit][dskp.slice] = ISGELI_YES;
|
||||
geli_part++;
|
||||
}
|
||||
} 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 /* LOADER_GELI_SUPPORT */
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -586,6 +704,38 @@ bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write)
|
|||
static int
|
||||
bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest)
|
||||
{
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
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 /* LOADER_GELI_SUPPORT */
|
||||
|
||||
return (bd_io(dev, dblk, blks, dest, 0));
|
||||
}
|
||||
|
@ -682,3 +832,25 @@ bd_getdev(struct i386_devdesc *d)
|
|||
DEBUG("dev is 0x%x\n", rootdev);
|
||||
return(rootdev);
|
||||
}
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
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 /* LOADER_GELI_SUPPORT */
|
||||
|
|
|
@ -58,6 +58,13 @@ CFLAGS+= -DLOADER_GZIP_SUPPORT
|
|||
.if defined(LOADER_NANDFS_SUPPORT)
|
||||
CFLAGS+= -DLOADER_NANDFS_SUPPORT
|
||||
.endif
|
||||
.if !defined(LOADER_NO_GELI_SUPPORT)
|
||||
CFLAGS+= -DLOADER_GELI_SUPPORT
|
||||
LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
|
||||
.PATH: ${.CURDIR}/../../../opencrypto
|
||||
SRCS+= xform_aes_xts.c
|
||||
CFLAGS+= -I${.CURDIR}/../../.. -D_STAND
|
||||
.endif
|
||||
|
||||
# Always add MI sources
|
||||
.PATH: ${.CURDIR}/../../common
|
||||
|
@ -116,8 +123,8 @@ FILES+= loader.rc menu.rc
|
|||
# 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>
|
||||
|
||||
|
|
|
@ -68,7 +68,11 @@ static void extract_currdev(void);
|
|||
static int isa_inb(int port);
|
||||
static void isa_outb(int port, int value);
|
||||
void exit(int code);
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
struct geli_boot_args *gargs;
|
||||
#endif
|
||||
#ifdef LOADER_ZFS_SUPPORT
|
||||
struct zfs_boot_args *zargs;
|
||||
static void i386_zfs_probe(void);
|
||||
#endif
|
||||
|
||||
|
@ -164,7 +168,31 @@ main(void)
|
|||
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.
|
||||
|
@ -214,7 +242,6 @@ extract_currdev(void)
|
|||
struct i386_devdesc new_currdev;
|
||||
#ifdef LOADER_ZFS_SUPPORT
|
||||
char buf[20];
|
||||
struct zfs_boot_args *zargs;
|
||||
#endif
|
||||
int biosdev = -1;
|
||||
|
||||
|
|
|
@ -121,8 +121,10 @@ void exit(int);
|
|||
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;
|
||||
|
@ -130,10 +132,18 @@ malloc(size_t n)
|
|||
printf("malloc failure\n");
|
||||
for (;;)
|
||||
;
|
||||
return 0;
|
||||
/* NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
heap_next += n;
|
||||
return p;
|
||||
return (p);
|
||||
}
|
||||
|
||||
void
|
||||
free(void *ptr)
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static char *
|
||||
|
@ -141,9 +151,14 @@ strdup(const char *s)
|
|||
{
|
||||
char *p = malloc(strlen(s) + 1);
|
||||
strcpy(p, s);
|
||||
return p;
|
||||
return (p);
|
||||
}
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.c"
|
||||
static char gelipw[GELI_PW_MAXLEN];
|
||||
#endif
|
||||
|
||||
#include "zfsimpl.c"
|
||||
|
||||
/*
|
||||
|
@ -199,6 +214,14 @@ vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
|
|||
nb = READ_BUF_SIZE / DEV_BSIZE;
|
||||
if (drvread(dsk, dmadat->rdbuf, lba, nb))
|
||||
return -1;
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
/* decrypt */
|
||||
if (is_geli(dsk) == 0) {
|
||||
if (geli_read(dsk, ((lba - dsk->start) * DEV_BSIZE),
|
||||
dmadat->rdbuf, nb * DEV_BSIZE))
|
||||
return (-1);
|
||||
}
|
||||
#endif
|
||||
memcpy(p, dmadat->rdbuf, nb * DEV_BSIZE);
|
||||
p += nb * DEV_BSIZE;
|
||||
lba += nb;
|
||||
|
@ -302,7 +325,7 @@ bios_getmem(void)
|
|||
high_heap_size = HEAP_MIN;
|
||||
high_heap_base = bios_extmem + 0x100000 - HEAP_MIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to detect a device supported by the legacy int13 BIOS
|
||||
|
@ -346,21 +369,39 @@ probe_drive(struct dsk *dsk)
|
|||
#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;
|
||||
|
||||
/*
|
||||
* 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 LOADER_GELI_SUPPORT
|
||||
/*
|
||||
* 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) {
|
||||
if (geli_passphrase(&gelipw, dsk->unit, ':', 0, dsk) == 0) {
|
||||
if (vdev_probe(vdev_read, dsk, NULL) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LOADER_GELI_SUPPORT */
|
||||
|
||||
sec = dmadat->secbuf;
|
||||
dsk->start = 0;
|
||||
|
||||
|
@ -383,6 +424,8 @@ probe_drive(struct dsk *dsk)
|
|||
* 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;
|
||||
|
@ -396,6 +439,8 @@ probe_drive(struct dsk *dsk)
|
|||
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
|
||||
|
@ -403,13 +448,31 @@ probe_drive(struct dsk *dsk)
|
|||
*/
|
||||
dsk = copy_dsk(dsk);
|
||||
}
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
else if (geli_taste(vdev_read, dsk, ent->ent_lba_end -
|
||||
ent->ent_lba_start) == 0) {
|
||||
if (geli_passphrase(&gelipw, dsk->unit, 'p', dsk->slice, dsk) == 0) {
|
||||
/*
|
||||
* This slice has GELI, check it for ZFS.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* LOADER_GELI_SUPPORT */
|
||||
}
|
||||
}
|
||||
slba++;
|
||||
}
|
||||
return;
|
||||
trymbr:
|
||||
#endif
|
||||
#endif /* GPT */
|
||||
|
||||
if (drvread(dsk, sec, DOSBBSECTOR, 1))
|
||||
return;
|
||||
|
@ -419,13 +482,28 @@ probe_drive(struct dsk *dsk)
|
|||
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 LOADER_GELI_SUPPORT
|
||||
else if (geli_taste(vdev_read, dsk, dp[i].dp_size -
|
||||
dp[i].dp_start) == 0) {
|
||||
if (geli_passphrase(&gelipw, dsk->unit, 's', i, dsk) == 0) {
|
||||
/*
|
||||
* This slice has GELI, check it for ZFS.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* LOADER_GELI_SUPPORT */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,8 +523,8 @@ main(void)
|
|||
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));
|
||||
|
@ -472,6 +550,9 @@ main(void)
|
|||
|
||||
autoboot = 1;
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
geli_init();
|
||||
#endif
|
||||
zfs_init();
|
||||
|
||||
/*
|
||||
|
@ -690,6 +771,12 @@ load(void)
|
|||
zfsargs.pool = zfsmount.spa->spa_guid;
|
||||
zfsargs.root = zfsmount.rootobj;
|
||||
zfsargs.primary_pool = primary_spa->spa_guid;
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
bcopy(gelipw, zfsargs.gelipw, sizeof(zfsargs.gelipw));
|
||||
bzero(gelipw, sizeof(gelipw));
|
||||
#else
|
||||
zfsargs.gelipw[0] = '\0';
|
||||
#endif
|
||||
if (primary_vdev != NULL)
|
||||
zfsargs.primary_vdev = primary_vdev->v_guid;
|
||||
else
|
||||
|
|
|
@ -55,6 +55,7 @@ struct zfs_boot_args
|
|||
uint64_t root;
|
||||
uint64_t primary_pool;
|
||||
uint64_t primary_vdev;
|
||||
char gelipw[256];
|
||||
};
|
||||
|
||||
int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec,
|
||||
|
|
Loading…
Reference in a new issue