MFC GELI Loader Improvements: r336252, r336254, r336256, r336354,
r336532-r336534, r336537, r336626, r337326, r337349, r341071, r341160, r341420, r341473, r341651, r342793 Note that this MFC contains some seemingly unrelated zfsloader bits -- this was needed in order to pull in some later fixes for GELI hand-off w/ ZFS bits included. r336252: Extend loader(8) geli support to all architectures and all disk-like devices. This moves the bulk of the geli support from lib386/biosdisk.c into a new geli/gelidev.c which implements a devsw-type device whose dv_strategy() function handles geli decryption. Support for all arches comes from moving the taste-and-attach code to the devopen() function in libsa. After opening any DEVT_DISK device, devopen() calls the new function geli_probe_and_attach(), which will "attach" the geli code to the open_file struct by creating a geli_devdesc instance to replace the disk_devdesc instance in the open_file. That routes all IO for the device through the geli code. A new public geli_add_key() function is added, to allow arch/vendor-specific code to add keys obtained from custom hardware or other sources. With these changes, geli support will be compiled into all variations of loader(8) on all arches because the default is WITH_LOADER_GELI. r336254: Use if rather than case for a simple boolean. gcc thinks blks is undefined sometimes with the case, but enc is always 0 or 1, so and if / else is better anyway. r336256: Fix glitched indentation (and rewrap as needed due to deeper indent). No functional changes. r336354: zfsboot: fix build with WITHOUT_LOADER_GELI r336532: Collapse zfsloader functionality back down into loader. We no longer really need a separate zfsloader. It was useful when we were first supporting ZFS and had limited ability to properly boot off of ZFS without the special boot loader. Now that the boot loader has matured, go the way loader.efi pioneered and just build one binary. Change the name of the loader to load in the secondary boot blocks to be just /boot/loader. Provide a symbolic link from zfsloader to loader so people who have not upgraded their boot blocks are not affected. This has the happy benefit of making coexistence easier as well (fewer binaries in the matrix). r336533: Eliminate zfsloader man page. Remove all cross references to zfsloader.8 and /boot/zfsloader. Move ZFS specific info into loader.8. r336534: NM and OBJCOPY are already defined for all builds. There's no need to conditionally define them here. r336537: Mention zfsloader being folded into loader in UPDATING. r336626: Older zfs boot blocks don't support symlinks. install the link to zfsloader as a hard link. While newer ones do, the whole point of the link was to transition to the new world order smoothly. A hard link is less flexible, but it works and will result in fewer bumps. Adjust UPDATING entry to match. r337326: loader: biosdisk.c has leftover geli header. A small cleanup, remove unneeded #include. r337349: zfsboot: Fix startup crash On a FreeNAS mini XL, with geli encrypted drives the loader crashed in geli_read(). When we iterate over the list of disks and allocate the zfsdsk structures we don’t zero out the gdev pointer. In one case that resulted in geli_read() (called on the bogus pointer) dividing by zero. Use calloc() to ensure the zfsdsk structure is always zeroed, so the pointer is initialised to NULL. As a side benefit it gets rid of one #ifdef LOADER_GELI_SUPPORT. r341071: Restore the ability to override the disk unit/partition at the boot: prompt in gptboot. When arch-independent geli support was added, a new static 'gdsk' struct was added, but there was still a static 'dsk' struct, and when you typed in an alternate disk/partition, the string was parsed into that struct, which was then never used for anything. Now the string gets parsed into gdsk.dsk, the struct that's actually used. r341160: Add comments describing the bootargs handoff between loader(8) and gptboot or zfsboot, when loader(8) is the BTX loader. No functional changes. r341420: Eliminate duplicated code and struct member definitions in the handoff of args data between gptboot/zfsboot and loader(8). Despite what seems like a lot of changes here, there are no actual changes in behavior, or in the data layout in the structures involved. This is just eliminating identical code pasted into multiple locations. In detail, the changes are... - Move struct zfs_boot_args definition from libsa/zfs/libzfs.h to i386/common/bootargs.h because it is specific to x86 booting and the handoff between zfsboot and loader, and has no relation to the zfs library code in general. - The geli_boot_args and zfs_boot_args structs both contain an identical set of member variables containing geli information. Extract this out to a new geli_boot_data struct, and embed it in the arg-passing structs. - Provide new routines geli_import_boot_data() and geli_export_boot_data() that can be shared between gptboot, zfsboot, and loader instead of pasting identical code into several different .c files. - Remove some checks for a NULL pointer that can never be true because the pointer being tested was set using pointer math (kargs + 1) and that can never result in NULL in this code. r341473: Fix args cross-threading between gptboot(8) and loader(8) with zfs support. When loader(8) is built with zfs support enabled, it assumes that any extarg data present is a zfs_boot_args struct, but if the first-stage loader was gptboot(8) the extarg data is actually a geli_boot_args struct. Luckily, zfsboot(8) and gptzfsboot(8) have always passed KARGS_FLAGS_ZFS along with KARGS_FLAGS_EXTARG, so we can use KARGS_FLAGS_ZFS to decide whether the extarg data is a zfs_boot_args struct. To avoid similar problems in the future, gptboot(8) now passes a new KARGS_FLAGS_GELI to indicate that extarg data is geli_boot_args. In loader(8), if the neither KARGS_FLAGS_ZFS nor KARGS_FLAGS_GELI is set but extarg data is present (which will be the case for gptboot compiled before this change), we now check for the known size of the geli_boot_args struct passed by the older versions of gptboot as a way of confirming what type of extarg data is present. In a semi-related tidying up, since loader's main() has already decided what type of extarg data is present and set the global 'zargs' var accordingly, don't repeat the check in extract_currdev, just check whether zargs is NULL or not. r341651: Don't reference zfs-specific variables if LOADER_ZFS_SUPPORT is undefined because the variables will be undefined too. r342793: MK_ZFS -> {MK_ZFS|MK_LOADER_ZFS}, this is so we can diable userland / kernel ZFS but keep the boot-loaders when using ZoL port. Relnotes: yes (GELI support extended) Relnotes: yes (zfsloader has been collapsed into loader and may be removed after boot blocks have been updated)
This commit is contained in:
parent
c6edb746c3
commit
0a7dac1dfe
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -3,3 +3,4 @@
|
||||
*.cpp diff=cpp
|
||||
*.hpp diff=cpp
|
||||
*.py diff=python
|
||||
. svn-properties=svn:keywords=tools/build/options/WITHOUT_LOADER_ZFS
|
||||
|
8
UPDATING
8
UPDATING
@ -16,6 +16,14 @@ from older versions of FreeBSD, try WITHOUT_CLANG and WITH_GCC to bootstrap to
|
||||
the tip of head, and then rebuild without this option. The bootstrap process
|
||||
from older version of current across the gcc/clang cutover is a bit fragile.
|
||||
|
||||
20190220:
|
||||
zfsloader's functionality has now been folded into loader.
|
||||
zfsloader is no longer necesasary once you've updated your
|
||||
boot blocks. For a transition period, we will install a
|
||||
hardlink for zfsloader to loader to allow a smooth transition
|
||||
until the boot blocks can be updated (hard link because old
|
||||
zfs boot blocks don't understand symlinks).
|
||||
|
||||
20190216:
|
||||
Lualoader has been merged to facilitate testing on this branch. It's
|
||||
purely opt-in for now by building WITH_LOADER_LUA and WITHOUT_FORTH in
|
||||
|
@ -183,6 +183,7 @@ __DEFAULT_YES_OPTIONS = \
|
||||
WIRELESS \
|
||||
WPA_SUPPLICANT_EAPOL \
|
||||
ZFS \
|
||||
LOADER_ZFS \
|
||||
ZONEINFO
|
||||
|
||||
__DEFAULT_NO_OPTIONS = \
|
||||
@ -290,10 +291,6 @@ BROKEN_OPTIONS+=LIBSOFT
|
||||
${__T:Mriscv*}
|
||||
BROKEN_OPTIONS+=EFI
|
||||
.endif
|
||||
# GELI isn't supported on !x86
|
||||
.if ${__T} != "i386" && ${__T} != "amd64"
|
||||
BROKEN_OPTIONS+=LOADER_GELI
|
||||
.endif
|
||||
# OFW is only for powerpc and sparc64, exclude others
|
||||
.if ${__T:Mpowerpc*} == "" && ${__T:Msparc64} == ""
|
||||
BROKEN_OPTIONS+=LOADER_OFW
|
||||
@ -377,6 +374,7 @@ MK_SOURCELESS_UCODE:= no
|
||||
|
||||
.if ${MK_CDDL} == "no"
|
||||
MK_ZFS:= no
|
||||
MK_LOADER_ZFS:= no
|
||||
MK_CTF:= no
|
||||
.endif
|
||||
|
||||
|
@ -32,6 +32,10 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "bootstrap.h"
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.h"
|
||||
#endif
|
||||
|
||||
int
|
||||
devopen(struct open_file *f, const char *fname, const char **file)
|
||||
{
|
||||
@ -43,6 +47,7 @@ devopen(struct open_file *f, const char *fname, const char **file)
|
||||
return (result);
|
||||
|
||||
/* point to device-specific data so that device open can use it */
|
||||
f->f_dev = dev->d_dev;
|
||||
f->f_devdata = dev;
|
||||
result = dev->d_dev->dv_open(f, dev);
|
||||
if (result != 0) {
|
||||
@ -51,8 +56,17 @@ devopen(struct open_file *f, const char *fname, const char **file)
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* reference the devsw entry from the open_file structure */
|
||||
f->f_dev = dev->d_dev;
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
/*
|
||||
* If f->f_dev is geli-encrypted and we can decrypt it (will prompt for
|
||||
* pw if needed), this will attach the geli code to the open_file by
|
||||
* replacing f->f_dev and f_devdata with pointers to a geli_devdesc.
|
||||
*/
|
||||
if (f->f_dev->dv_type == DEVT_DISK) {
|
||||
geli_probe_and_attach(f);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,10 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "bootstrap.h"
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.h"
|
||||
#endif
|
||||
|
||||
#if defined(__sparc64__)
|
||||
#include <openfirm.h>
|
||||
|
||||
@ -355,7 +359,9 @@ md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64)
|
||||
#endif
|
||||
file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
|
||||
}
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
geli_export_key_metadata(kfp);
|
||||
#endif
|
||||
#if defined(__sparc64__)
|
||||
file_addmetadata(kfp, MODINFOMD_DTLB_SLOTS,
|
||||
sizeof dtlb_slot, &dtlb_slot);
|
||||
|
@ -33,7 +33,6 @@
|
||||
#define PATH_CONFIG "/boot/config"
|
||||
#define PATH_LOADER "/boot/loader"
|
||||
#define PATH_LOADER_EFI "/boot/loader.efi"
|
||||
#define PATH_LOADER_ZFS "/boot/zfsloader"
|
||||
#define PATH_KERNEL "/boot/kernel/kernel"
|
||||
|
||||
#endif /* _PATHS_H_ */
|
||||
|
@ -56,7 +56,6 @@ CFLAGS+= -Ddouble=jagged-little-pill -Dfloat=floaty-mcfloatface
|
||||
|
||||
|
||||
# GELI Support, with backward compat hooks (mostly)
|
||||
.if defined(HAVE_GELI)
|
||||
.if defined(LOADER_NO_GELI_SUPPORT)
|
||||
MK_LOADER_GELI=no
|
||||
.warning "Please move from LOADER_NO_GELI_SUPPORT to WITHOUT_LOADER_GELI"
|
||||
@ -69,7 +68,6 @@ MK_LOADER_GELI=yes
|
||||
CFLAGS+= -DLOADER_GELI_SUPPORT
|
||||
CFLAGS+= -I${SASRC}/geli
|
||||
.endif # MK_LOADER_GELI
|
||||
.endif # HAVE_GELI
|
||||
|
||||
# These should be confined to loader.mk, but can't because uboot/lib
|
||||
# also uses it. It's part of loader, but isn't a loader so we can't
|
||||
|
@ -24,7 +24,7 @@ CWARNFLAGS.zfs_module.c += -Wno-unused-function
|
||||
|
||||
# architecture-specific loader code
|
||||
SRCS= boot1.c self_reloc.c start.S ufs_module.c
|
||||
.if ${MK_ZFS} != "no"
|
||||
.if ${MK_LOADER_ZFS} != "no"
|
||||
SRCS+= zfs_module.c
|
||||
CFLAGS.zfs_module.c+= -I${ZFSSRC}
|
||||
CFLAGS.zfs_module.c+= -I${SYSDIR}/cddl/boot/zfs
|
||||
@ -76,9 +76,6 @@ LDADD+= ${LIBEFI} ${LIBSA}
|
||||
|
||||
DPADD+= ${LDSCRIPT}
|
||||
|
||||
NM?= nm
|
||||
OBJCOPY?= objcopy
|
||||
|
||||
.if ${MACHINE_CPUARCH} == "amd64"
|
||||
EFI_TARGET= efi-app-x86_64
|
||||
.elif ${MACHINE_CPUARCH} == "i386"
|
||||
|
@ -44,7 +44,7 @@ CFLAGS+= -fPIC -mno-red-zone
|
||||
.endif
|
||||
CFLAGS+= -I${EFIINC}
|
||||
CFLAGS+= -I${EFIINCMD}
|
||||
.if ${MK_ZFS} != "no"
|
||||
.if ${MK_LOADER_ZFS} != "no"
|
||||
CFLAGS+= -I${ZFSSRC}
|
||||
CFLAGS+= -DEFI_ZFS_BOOT
|
||||
.endif
|
||||
|
@ -24,7 +24,7 @@ SRCS= autoload.c \
|
||||
smbios.c \
|
||||
vers.c
|
||||
|
||||
.if ${MK_ZFS} != "no"
|
||||
.if ${MK_LOADER_ZFS} != "no"
|
||||
CFLAGS+= -I${ZFSSRC}
|
||||
CFLAGS+= -DEFI_ZFS_BOOT
|
||||
HAVE_ZFS= yes
|
||||
@ -91,9 +91,6 @@ CLEANFILES+= loader.efi
|
||||
|
||||
NEWVERSWHAT= "EFI loader" ${MACHINE}
|
||||
|
||||
NM?= nm
|
||||
OBJCOPY?= objcopy
|
||||
|
||||
.if ${MACHINE_CPUARCH} == "amd64"
|
||||
EFI_TARGET= efi-app-x86_64
|
||||
.elif ${MACHINE_CPUARCH} == "i386"
|
||||
|
@ -56,6 +56,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include <fdt_platform.h>
|
||||
#endif
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.h"
|
||||
#endif
|
||||
|
||||
int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp);
|
||||
|
||||
extern EFI_SYSTEM_TABLE *ST;
|
||||
@ -452,7 +456,9 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
|
||||
#endif
|
||||
file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
|
||||
file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof ST, &ST);
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
geli_export_key_metadata(kfp);
|
||||
#endif
|
||||
bi_load_efi_data(kfp);
|
||||
|
||||
/* Figure out the size and location of the metadata. */
|
||||
|
@ -18,6 +18,6 @@ SUBDIR.yes+= pxeldr
|
||||
SUBDIR.yes+= kgzldr
|
||||
.endif
|
||||
|
||||
SUBDIR.${MK_ZFS}+= zfsboot gptzfsboot zfsloader
|
||||
SUBDIR.${MK_LOADER_ZFS}+= zfsboot gptzfsboot
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
FILES= boot boot1 boot2
|
||||
|
||||
NM?= nm
|
||||
|
||||
# A value of 0x80 enables LBA support.
|
||||
BOOT_BOOT1_FLAGS?= 0x80
|
||||
|
||||
|
@ -18,10 +18,11 @@
|
||||
#ifndef _BOOT_I386_ARGS_H_
|
||||
#define _BOOT_I386_ARGS_H_
|
||||
|
||||
#define KARGS_FLAGS_CD 0x1
|
||||
#define KARGS_FLAGS_PXE 0x2
|
||||
#define KARGS_FLAGS_ZFS 0x4
|
||||
#define KARGS_FLAGS_EXTARG 0x8 /* variably sized extended argument */
|
||||
#define KARGS_FLAGS_CD 0x0001 /* .bootdev is a bios CD dev */
|
||||
#define KARGS_FLAGS_PXE 0x0002 /* .pxeinfo is valid */
|
||||
#define KARGS_FLAGS_ZFS 0x0004 /* .zfspool is valid, EXTARG is zfs_boot_args */
|
||||
#define KARGS_FLAGS_EXTARG 0x0008 /* variably sized extended argument */
|
||||
#define KARGS_FLAGS_GELI 0x0010 /* EXTARG is geli_boot_args */
|
||||
|
||||
#define BOOTARGS_SIZE 24 /* sizeof(struct bootargs) */
|
||||
#define BA_BOOTFLAGS 8 /* offsetof(struct bootargs, bootflags) */
|
||||
@ -43,6 +44,24 @@
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/*
|
||||
* This struct describes the contents of the stack on entry to btxldr.S. This
|
||||
* is the data that follows the return address, so it begins at 4(%esp). On
|
||||
* the sending side, this data is passed as individual args to __exec(). On the
|
||||
* receiving side, code in btxldr.S copies the data from the entry stack to a
|
||||
* known fixed location in the new address space. Then, btxcsu.S sets the
|
||||
* global variable __args to point to that known fixed location before calling
|
||||
* main(), which casts __args to a struct bootargs pointer to access the data.
|
||||
* The btxldr.S code is aware of KARGS_FLAGS_EXTARG, and if it's set, the extra
|
||||
* args data is copied along with the other bootargs from the entry stack to the
|
||||
* fixed location in the new address space.
|
||||
*
|
||||
* The bootinfo field is actually a pointer to a bootinfo struct that has been
|
||||
* converted to uint32_t using VTOP(). On the receiving side it must be
|
||||
* converted back to a pointer using PTOV(). Code in btxldr.S is aware of this
|
||||
* field and if it's non-NULL it copies the data it points to into another known
|
||||
* fixed location, and adjusts the bootinfo field to point to that new location.
|
||||
*/
|
||||
struct bootargs
|
||||
{
|
||||
uint32_t howto;
|
||||
@ -66,11 +85,15 @@ struct bootargs
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include <crypto/intake.h>
|
||||
#include "geliboot.h"
|
||||
#endif
|
||||
|
||||
struct geli_boot_args
|
||||
/*
|
||||
* geli_boot_data is embedded in geli_boot_args (passed from gptboot to loader)
|
||||
* and in zfs_boot_args (passed from zfsboot and gptzfsboot to loader).
|
||||
*/
|
||||
struct geli_boot_data
|
||||
{
|
||||
uint32_t size;
|
||||
union {
|
||||
char gelipw[256];
|
||||
struct {
|
||||
@ -88,6 +111,49 @@ struct geli_boot_args
|
||||
};
|
||||
};
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
|
||||
static inline void
|
||||
export_geli_boot_data(struct geli_boot_data *gbdata)
|
||||
{
|
||||
|
||||
gbdata->notapw = '\0';
|
||||
gbdata->keybuf_sentinel = KEYBUF_SENTINEL;
|
||||
gbdata->keybuf = malloc(sizeof(struct keybuf) +
|
||||
(GELI_MAX_KEYS * sizeof(struct keybuf_ent)));
|
||||
geli_export_key_buffer(gbdata->keybuf);
|
||||
}
|
||||
|
||||
static inline void
|
||||
import_geli_boot_data(struct geli_boot_data *gbdata)
|
||||
{
|
||||
|
||||
if (gbdata->gelipw[0] != '\0') {
|
||||
setenv("kern.geom.eli.passphrase", gbdata->gelipw, 1);
|
||||
explicit_bzero(gbdata->gelipw, sizeof(gbdata->gelipw));
|
||||
} else if (gbdata->keybuf_sentinel == KEYBUF_SENTINEL) {
|
||||
geli_import_key_buffer(gbdata->keybuf);
|
||||
}
|
||||
}
|
||||
#endif /* LOADER_GELI_SUPPORT */
|
||||
|
||||
struct geli_boot_args
|
||||
{
|
||||
uint32_t size;
|
||||
struct geli_boot_data gelidata;
|
||||
};
|
||||
|
||||
struct zfs_boot_args
|
||||
{
|
||||
uint32_t size;
|
||||
uint32_t reserved;
|
||||
uint64_t pool;
|
||||
uint64_t root;
|
||||
uint64_t primary_pool;
|
||||
uint64_t primary_vdev;
|
||||
struct geli_boot_data gelidata;
|
||||
};
|
||||
|
||||
#endif /*__ASSEMBLER__*/
|
||||
|
||||
#endif /* !_BOOT_I386_ARGS_H_ */
|
||||
|
@ -1,7 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
HAVE_GELI= yes
|
||||
|
||||
.include <bsd.init.mk>
|
||||
|
||||
.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${SASRC}
|
||||
@ -9,8 +7,6 @@ HAVE_GELI= yes
|
||||
FILES= gptboot
|
||||
MAN= gptboot.8
|
||||
|
||||
NM?= nm
|
||||
|
||||
BOOT_COMCONSOLE_PORT?= 0x3f8
|
||||
BOOT_COMCONSOLE_SPEED?= 9600
|
||||
B2SIOFMT?= 0x3
|
||||
|
@ -81,7 +81,6 @@ uint32_t opts;
|
||||
static const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
|
||||
static const unsigned char dev_maj[NDEV] = {30, 4, 2};
|
||||
|
||||
static struct dsk dsk;
|
||||
static char kname[1024];
|
||||
static int comspeed = SIOSPD;
|
||||
static struct bootinfo bootinfo;
|
||||
@ -113,11 +112,19 @@ static int vdev_read(void *vdev __unused, void *priv, off_t off, void *buf,
|
||||
#include "ufsread.c"
|
||||
#include "gpt.c"
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.c"
|
||||
#include "geliboot.h"
|
||||
static char gelipw[GELI_PW_MAXLEN];
|
||||
static struct keybuf *gelibuf;
|
||||
#endif
|
||||
|
||||
struct gptdsk {
|
||||
struct dsk dsk;
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
struct geli_dev *gdev;
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct gptdsk gdsk;
|
||||
|
||||
static inline int
|
||||
xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
|
||||
{
|
||||
@ -225,19 +232,21 @@ static int
|
||||
gptinit(void)
|
||||
{
|
||||
|
||||
if (gptread(&freebsd_ufs_uuid, &dsk, dmadat->secbuf) == -1) {
|
||||
if (gptread(&freebsd_ufs_uuid, &gdsk.dsk, dmadat->secbuf) == -1) {
|
||||
printf("%s: unable to load GPT\n", BOOTPROG);
|
||||
return (-1);
|
||||
}
|
||||
if (gptfind(&freebsd_ufs_uuid, &dsk, dsk.part) == -1) {
|
||||
if (gptfind(&freebsd_ufs_uuid, &gdsk.dsk, gdsk.dsk.part) == -1) {
|
||||
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_havekey(&dsk) != 0 && geli_passphrase(gelipw,
|
||||
dsk.unit, 'p', curent + 1, &dsk) != 0) {
|
||||
gdsk.gdev = geli_taste(vdev_read, &gdsk.dsk,
|
||||
(gpttable[curent].ent_lba_end - gpttable[curent].ent_lba_start),
|
||||
"disk%up%u:", gdsk.dsk.unit, curent + 1);
|
||||
if (gdsk.gdev != NULL) {
|
||||
if (geli_havekey(gdsk.gdev) != 0 &&
|
||||
geli_passphrase(gdsk.gdev, gelipw) != 0) {
|
||||
printf("%s: unable to decrypt GELI key\n", BOOTPROG);
|
||||
return (-1);
|
||||
}
|
||||
@ -273,21 +282,18 @@ main(void)
|
||||
|
||||
v86.ctl = V86_FLAGS;
|
||||
v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
|
||||
dsk.drive = *(uint8_t *)PTOV(ARGS);
|
||||
dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
|
||||
dsk.unit = dsk.drive & DRV_MASK;
|
||||
dsk.part = -1;
|
||||
dsk.start = 0;
|
||||
gdsk.dsk.drive = *(uint8_t *)PTOV(ARGS);
|
||||
gdsk.dsk.type = gdsk.dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
|
||||
gdsk.dsk.unit = gdsk.dsk.drive & DRV_MASK;
|
||||
gdsk.dsk.part = -1;
|
||||
gdsk.dsk.start = 0;
|
||||
bootinfo.bi_version = BOOTINFO_VERSION;
|
||||
bootinfo.bi_size = sizeof(bootinfo);
|
||||
bootinfo.bi_basemem = bios_basemem / 1024;
|
||||
bootinfo.bi_extmem = bios_extmem / 1024;
|
||||
bootinfo.bi_memsizes_valid++;
|
||||
bootinfo.bi_bios_dev = dsk.drive;
|
||||
bootinfo.bi_bios_dev = gdsk.dsk.drive;
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
geli_init();
|
||||
#endif
|
||||
/* Process configuration file */
|
||||
|
||||
if (gptinit() != 0)
|
||||
@ -332,8 +338,8 @@ main(void)
|
||||
load();
|
||||
memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
|
||||
load();
|
||||
gptbootfailed(&dsk);
|
||||
if (gptfind(&freebsd_ufs_uuid, &dsk, -1) == -1)
|
||||
gptbootfailed(&gdsk.dsk);
|
||||
if (gptfind(&freebsd_ufs_uuid, &gdsk.dsk, -1) == -1)
|
||||
break;
|
||||
dsk_meta = 0;
|
||||
}
|
||||
@ -345,8 +351,8 @@ main(void)
|
||||
printf("\nFreeBSD/x86 boot\n"
|
||||
"Default: %u:%s(%up%u)%s\n"
|
||||
"boot: ",
|
||||
dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
|
||||
dsk.part, kname);
|
||||
gdsk.dsk.drive & DRV_MASK, dev_nm[gdsk.dsk.type],
|
||||
gdsk.dsk.unit, gdsk.dsk.part, kname);
|
||||
}
|
||||
if (ioctrl & IO_SERIAL)
|
||||
sio_flush();
|
||||
@ -392,9 +398,9 @@ load(void)
|
||||
if (!(ino = lookup(kname))) {
|
||||
if (!ls) {
|
||||
printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG,
|
||||
kname, dsk.drive & DRV_MASK, dev_nm[dsk.type],
|
||||
dsk.unit,
|
||||
dsk.part);
|
||||
kname, gdsk.dsk.drive & DRV_MASK,
|
||||
dev_nm[gdsk.dsk.type], gdsk.dsk.unit,
|
||||
gdsk.dsk.part);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -469,21 +475,22 @@ load(void)
|
||||
}
|
||||
bootinfo.bi_esymtab = VTOP(p);
|
||||
bootinfo.bi_kernelname = VTOP(kname);
|
||||
bootinfo.bi_bios_dev = dsk.drive;
|
||||
bootinfo.bi_bios_dev = gdsk.dsk.drive;
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
geliargs.size = sizeof(geliargs);
|
||||
explicit_bzero(gelipw, sizeof(gelipw));
|
||||
gelibuf = malloc(sizeof(struct keybuf) +
|
||||
(GELI_MAX_KEYS * sizeof(struct keybuf_ent)));
|
||||
geli_fill_keybuf(gelibuf);
|
||||
geliargs.notapw = '\0';
|
||||
geliargs.keybuf_sentinel = KEYBUF_SENTINEL;
|
||||
geliargs.keybuf = gelibuf;
|
||||
export_geli_boot_data(&geliargs.gelidata);
|
||||
#endif
|
||||
/*
|
||||
* Note that the geliargs struct is passed by value, not by pointer.
|
||||
* Code in btxldr.S copies the values from the entry stack to a fixed
|
||||
* location within loader(8) at startup due to the presence of the
|
||||
* KARGS_FLAGS_EXTARG flag.
|
||||
*/
|
||||
__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
|
||||
MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff),
|
||||
MAKEBOOTDEV(dev_maj[gdsk.dsk.type], gdsk.dsk.part + 1, gdsk.dsk.unit, 0xff),
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo), geliargs
|
||||
KARGS_FLAGS_GELI | KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo), geliargs
|
||||
#else
|
||||
0, 0, 0, VTOP(&bootinfo)
|
||||
#endif
|
||||
@ -561,22 +568,22 @@ parse_cmds(char *cmdstr, int *dskupdated)
|
||||
arg[1] != dev_nm[i][1]; i++)
|
||||
if (i == NDEV - 1)
|
||||
return (-1);
|
||||
dsk.type = i;
|
||||
gdsk.dsk.type = i;
|
||||
arg += 3;
|
||||
dsk.unit = *arg - '0';
|
||||
if (arg[1] != 'p' || dsk.unit > 9)
|
||||
gdsk.dsk.unit = *arg - '0';
|
||||
if (arg[1] != 'p' || gdsk.dsk.unit > 9)
|
||||
return (-1);
|
||||
arg += 2;
|
||||
dsk.part = *arg - '0';
|
||||
if (dsk.part < 1 || dsk.part > 9)
|
||||
gdsk.dsk.part = *arg - '0';
|
||||
if (gdsk.dsk.part < 1 || gdsk.dsk.part > 9)
|
||||
return (-1);
|
||||
arg++;
|
||||
if (arg[0] != ')')
|
||||
return (-1);
|
||||
arg++;
|
||||
if (drv == -1)
|
||||
drv = dsk.unit;
|
||||
dsk.drive = (dsk.type <= TYPE_MAXHARD
|
||||
drv = gdsk.dsk.unit;
|
||||
gdsk.dsk.drive = (gdsk.dsk.type <= TYPE_MAXHARD
|
||||
? DRV_HARD : 0) + drv;
|
||||
*dskupdated = 1;
|
||||
}
|
||||
@ -596,12 +603,13 @@ dskread(void *buf, daddr_t lba, unsigned nblk)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = drvread(&dsk, buf, lba + dsk.start, nblk);
|
||||
err = drvread(&gdsk.dsk, buf, lba + gdsk.dsk.start, nblk);
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
if (err == 0 && is_geli(&dsk) == 0) {
|
||||
if (err == 0 && gdsk.gdev != NULL) {
|
||||
/* Decrypt */
|
||||
if (geli_read(&dsk, lba * DEV_BSIZE, buf, nblk * DEV_BSIZE))
|
||||
if (geli_read(gdsk.gdev, lba * DEV_BSIZE, buf,
|
||||
nblk * DEV_BSIZE))
|
||||
return (err);
|
||||
}
|
||||
#endif
|
||||
@ -611,8 +619,8 @@ dskread(void *buf, daddr_t lba, unsigned nblk)
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
/*
|
||||
* Read function compartible with the ZFS callback, required to keep the GELI
|
||||
* Implementation the same for both UFS and ZFS
|
||||
* Read function compatible 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)
|
||||
@ -620,22 +628,22 @@ 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 gptdsk *dskp;
|
||||
|
||||
dskp = (struct dsk *)priv;
|
||||
dskp = (struct gptdsk *)priv;
|
||||
|
||||
if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
|
||||
return (-1);
|
||||
|
||||
p = buf;
|
||||
lba = off / DEV_BSIZE;
|
||||
lba += dskp->start;
|
||||
lba += dskp->dsk.start;
|
||||
|
||||
while (bytes > 0) {
|
||||
nb = bytes / DEV_BSIZE;
|
||||
if (nb > VBLKSIZE / DEV_BSIZE)
|
||||
nb = VBLKSIZE / DEV_BSIZE;
|
||||
if (drvread(dskp, dmadat->blkbuf, lba, nb))
|
||||
if (drvread(&dskp->dsk, dmadat->blkbuf, lba, nb))
|
||||
return (-1);
|
||||
memcpy(p, dmadat->blkbuf, nb * DEV_BSIZE);
|
||||
p += nb * DEV_BSIZE;
|
||||
|
@ -1,7 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
HAVE_GELI= yes
|
||||
|
||||
.include <bsd.init.mk>
|
||||
|
||||
.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/gptboot \
|
||||
@ -11,8 +9,6 @@ HAVE_GELI= yes
|
||||
FILES= gptzfsboot
|
||||
MAN= gptzfsboot.8
|
||||
|
||||
NM?= nm
|
||||
|
||||
BOOT_COMCONSOLE_PORT?= 0x3f8
|
||||
BOOT_COMCONSOLE_SPEED?= 9600
|
||||
B2SIOFMT?= 0x3
|
||||
|
@ -71,7 +71,7 @@ If the
|
||||
.Cm bootfs
|
||||
property is not set, then the root filesystem of the pool is used as
|
||||
the default.
|
||||
.Xr zfsloader 8
|
||||
.Xr loader 8
|
||||
is loaded from the boot filesystem.
|
||||
If
|
||||
.Pa /boot.config
|
||||
@ -83,7 +83,7 @@ in the same way as
|
||||
.Pp
|
||||
The ZFS GUIDs of the first successfully probed device and the first
|
||||
detected pool are made available to
|
||||
.Xr zfsloader 8
|
||||
.Xr loader 8
|
||||
in the
|
||||
.Cm vfs.zfs.boot.primary_vdev
|
||||
and
|
||||
@ -104,7 +104,7 @@ accepts all the options that
|
||||
supports.
|
||||
.Pp
|
||||
The filesystem specification and the path to
|
||||
.Xr zfsloader 8
|
||||
.Xr loader 8
|
||||
are different from
|
||||
.Xr boot 8 .
|
||||
The format is
|
||||
@ -116,7 +116,7 @@ The format is
|
||||
Both the filesystem and the path can be specified.
|
||||
If only a path is specified, then the default filesystem is used.
|
||||
If only a pool and filesystem are specified, then
|
||||
.Pa /boot/zfsloader
|
||||
.Pa /boot/loader
|
||||
is used as a path.
|
||||
.Pp
|
||||
Additionally, the
|
||||
@ -128,7 +128,7 @@ The output format is similar to that of
|
||||
.Pp
|
||||
The configured or automatically determined ZFS boot filesystem is
|
||||
stored in the
|
||||
.Xr zfsloader 8
|
||||
.Xr loader 8
|
||||
.Cm loaddev
|
||||
variable, and also set as the initial value of the
|
||||
.Cm currdev
|
||||
@ -171,7 +171,6 @@ gpart bootcode -p /boot/gptzfsboot -i 1 ada0
|
||||
.Xr boot 8 ,
|
||||
.Xr gpart 8 ,
|
||||
.Xr loader 8 ,
|
||||
.Xr zfsloader 8 ,
|
||||
.Xr zpool 8
|
||||
.Sh HISTORY
|
||||
.Nm
|
||||
|
@ -1,7 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
HAVE_GELI= yes
|
||||
|
||||
.include <bsd.init.mk>
|
||||
|
||||
.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/gptboot \
|
||||
@ -10,8 +8,6 @@ HAVE_GELI= yes
|
||||
FILES= isoboot
|
||||
MAN= isoboot.8
|
||||
|
||||
NM?= nm
|
||||
|
||||
BOOT_COMCONSOLE_PORT?= 0x3f8
|
||||
BOOT_COMCONSOLE_SPEED?= 9600
|
||||
B2SIOFMT?= 0x3
|
||||
|
@ -1,7 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
HAVE_GELI= yes
|
||||
|
||||
.include <bsd.init.mk>
|
||||
|
||||
LIB= i386
|
||||
|
@ -50,34 +50,6 @@ __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 */
|
||||
|
||||
#define BIOS_NUMDRIVES 0x475
|
||||
#define BIOSDISK_SECSIZE 512
|
||||
#define BUFSIZE (1 * BIOSDISK_SECSIZE)
|
||||
@ -138,17 +110,6 @@ static int bd_close(struct open_file *f);
|
||||
static int bd_ioctl(struct open_file *f, u_long cmd, void *data);
|
||||
static int bd_print(int verbose);
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
enum isgeli {
|
||||
ISGELI_UNKNOWN,
|
||||
ISGELI_NO,
|
||||
ISGELI_YES
|
||||
};
|
||||
static enum isgeli geli_status[MAXBDDEV][MAXTBLENTS];
|
||||
|
||||
int bios_read(void *, void *, off_t off, void *buf, size_t bytes);
|
||||
#endif /* LOADER_GELI_SUPPORT */
|
||||
|
||||
struct devsw biosdisk = {
|
||||
"disk",
|
||||
DEVT_DISK,
|
||||
@ -195,9 +156,6 @@ 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++) {
|
||||
@ -379,7 +337,7 @@ bd_print(int verbose)
|
||||
static int
|
||||
bd_open(struct open_file *f, ...)
|
||||
{
|
||||
struct disk_devdesc *dev;
|
||||
struct disk_devdesc *dev, rdev;
|
||||
struct disk_devdesc disk;
|
||||
int err, g_err;
|
||||
va_list ap;
|
||||
@ -421,81 +379,6 @@ bd_open(struct open_file *f, ...)
|
||||
err = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
|
||||
BD(dev).bd_sectorsize);
|
||||
|
||||
#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->dd.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->dd.d_unit);
|
||||
dskp.type = dev->dd.d_dev->dv_type;
|
||||
dskp.unit = dev->dd.d_unit;
|
||||
dskp.slice = dev->d_slice;
|
||||
dskp.part = dev->d_partition;
|
||||
dskp.start = dev->d_offset;
|
||||
|
||||
/* We need the LBA of the end of the partition */
|
||||
table = ptable_open(&disk, 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->dd.d_unit][dskp.slice] = ISGELI_YES;
|
||||
return (0);
|
||||
}
|
||||
if (geli_taste(bios_read, &dskp,
|
||||
entry->part.end - entry->part.start) == 0) {
|
||||
if (geli_havekey(&dskp) == 0) {
|
||||
geli_status[dev->dd.d_unit][dskp.slice] = ISGELI_YES;
|
||||
geli_part++;
|
||||
continue;
|
||||
}
|
||||
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->dd.d_unit][dskp.slice] = ISGELI_YES;
|
||||
geli_part++;
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
geli_status[dev->dd.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->dd.d_unit][dev->d_slice] = ISGELI_NO;
|
||||
}
|
||||
#endif /* LOADER_GELI_SUPPORT */
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
@ -841,79 +724,6 @@ 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, diff;
|
||||
daddr_t alignlba;
|
||||
int err, n, alignblks;
|
||||
char *tmpbuf;
|
||||
|
||||
/* if we already know there is no GELI, skip the rest */
|
||||
if (geli_status[dev->dd.d_unit][dev->d_slice] != ISGELI_YES)
|
||||
return (bd_io(dev, dblk, blks, dest, 0));
|
||||
|
||||
if (geli_status[dev->dd.d_unit][dev->d_slice] == ISGELI_YES) {
|
||||
/*
|
||||
* Align reads to DEV_GELIBOOT_BSIZE bytes because partial
|
||||
* sectors cannot be decrypted. Round the requested LBA down to
|
||||
* nearest multiple of DEV_GELIBOOT_BSIZE bytes.
|
||||
*/
|
||||
alignlba = rounddown2(dblk * BD(dev).bd_sectorsize,
|
||||
DEV_GELIBOOT_BSIZE) / BD(dev).bd_sectorsize;
|
||||
/*
|
||||
* Round number of blocks to read up to nearest multiple of
|
||||
* DEV_GELIBOOT_BSIZE
|
||||
*/
|
||||
diff = (dblk - alignlba) * BD(dev).bd_sectorsize;
|
||||
alignblks = roundup2(blks * BD(dev).bd_sectorsize + diff,
|
||||
DEV_GELIBOOT_BSIZE) / BD(dev).bd_sectorsize;
|
||||
|
||||
/*
|
||||
* If the read is rounded up to a larger size, use a temporary
|
||||
* buffer here because the buffer provided by the caller may be
|
||||
* too small.
|
||||
*/
|
||||
if (diff == 0) {
|
||||
tmpbuf = dest;
|
||||
} else {
|
||||
tmpbuf = malloc(alignblks * BD(dev).bd_sectorsize);
|
||||
if (tmpbuf == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (alignlba + alignblks > BD(dev).bd_sectors) {
|
||||
DEBUG("Shorted read at %llu from %d to %llu blocks",
|
||||
alignlba, alignblks, BD(dev).bd_sectors - alignlba);
|
||||
alignblks = BD(dev).bd_sectors - alignlba;
|
||||
}
|
||||
|
||||
err = bd_io(dev, alignlba, alignblks, tmpbuf, 0);
|
||||
if (err)
|
||||
return (err);
|
||||
|
||||
dskp.drive = bd_unit2bios(dev->dd.d_unit);
|
||||
dskp.type = dev->dd.d_dev->dv_type;
|
||||
dskp.unit = dev->dd.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 = alignlba - dskp.start;
|
||||
|
||||
err = geli_read(&dskp, p_off * BD(dev).bd_sectorsize, (u_char *)tmpbuf,
|
||||
alignblks * BD(dev).bd_sectorsize);
|
||||
if (err)
|
||||
return (err);
|
||||
|
||||
if (tmpbuf != dest) {
|
||||
bcopy(tmpbuf + diff, dest, blks * BD(dev).bd_sectorsize);
|
||||
free(tmpbuf);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
#endif /* LOADER_GELI_SUPPORT */
|
||||
|
||||
return (bd_io(dev, dblk, blks, dest, 0));
|
||||
}
|
||||
@ -1009,25 +819,3 @@ 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, void *xpriv, off_t off, void *buf, size_t bytes)
|
||||
{
|
||||
struct disk_devdesc dev;
|
||||
struct dsk *priv = xpriv;
|
||||
|
||||
dev.dd.d_dev = &biosdisk;
|
||||
dev.dd.d_unit = priv->unit;
|
||||
dev.d_slice = priv->slice;
|
||||
dev.d_partition = priv->part;
|
||||
dev.d_offset = priv->start;
|
||||
|
||||
off = off / BD(&dev).bd_sectorsize;
|
||||
/* GELI gives us the offset relative to the partition start */
|
||||
off += dev.d_offset;
|
||||
bytes = bytes / BD(&dev).bd_sectorsize;
|
||||
|
||||
return (bd_io(&dev, off, bytes, buf, 0));
|
||||
}
|
||||
#endif /* LOADER_GELI_SUPPORT */
|
||||
|
@ -39,9 +39,6 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.h"
|
||||
|
||||
static const size_t keybuf_size = sizeof(struct keybuf) +
|
||||
(GELI_MAX_KEYS * sizeof(struct keybuf_ent));
|
||||
#endif
|
||||
|
||||
static struct bootinfo bi;
|
||||
@ -154,10 +151,6 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t
|
||||
int bootdevnr, i, howto;
|
||||
char *kernelname;
|
||||
const char *kernelpath;
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
char buf[keybuf_size];
|
||||
struct keybuf *keybuf = (struct keybuf *)buf;
|
||||
#endif
|
||||
|
||||
howto = bi_getboothowto(args);
|
||||
|
||||
@ -235,9 +228,7 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t
|
||||
file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
|
||||
bios_addsmapdata(kfp);
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
geli_fill_keybuf(keybuf);
|
||||
file_addmetadata(kfp, MODINFOMD_KEYBUF, keybuf_size, buf);
|
||||
bzero(buf, sizeof(buf));
|
||||
geli_export_key_metadata(kfp);
|
||||
#endif
|
||||
|
||||
/* Figure out the size and location of the metadata */
|
||||
|
@ -42,9 +42,6 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.h"
|
||||
|
||||
static const size_t keybuf_size = sizeof(struct keybuf) +
|
||||
(GELI_MAX_KEYS * sizeof(struct keybuf_ent));
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -196,10 +193,6 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep,
|
||||
vm_offset_t size;
|
||||
char *rootdevname;
|
||||
int howto;
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
char buf[keybuf_size];
|
||||
struct keybuf *keybuf = (struct keybuf *)buf;
|
||||
#endif
|
||||
|
||||
if (!bi_checkcpu()) {
|
||||
printf("CPU doesn't support long mode\n");
|
||||
@ -248,11 +241,8 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep,
|
||||
file_addmetadata(kfp, MODINFOMD_MODULEP, sizeof module, &module);
|
||||
if (add_smap != 0)
|
||||
bios_addsmapdata(kfp);
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
geli_fill_keybuf(keybuf);
|
||||
file_addmetadata(kfp, MODINFOMD_KEYBUF, keybuf_size, buf);
|
||||
bzero(buf, sizeof(buf));
|
||||
geli_export_key_metadata(kfp);
|
||||
#endif
|
||||
|
||||
size = bi_copymodules64(0);
|
||||
|
@ -1,6 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
HAVE_GELI= yes
|
||||
HAVE_ZFS= ${MK_LOADER_ZFS}
|
||||
|
||||
LOADER_NET_SUPPORT?= yes
|
||||
LOADER_NFS_SUPPORT?= yes
|
||||
@ -64,6 +64,10 @@ ${LOADER}: ${LOADER}.bin ${BTXLDR} ${BTXKERN}
|
||||
${LOADER}.bin: ${LOADER}.sym
|
||||
strip -R .comment -R .note -o ${.TARGET} ${.ALLSRC}
|
||||
|
||||
# XXX TODO: Fix this when coexistence comes in
|
||||
.if ${MK_LOADER_ZFS} == "yes" # && ${LOADER_INTERP} == ${LOADER_DEFAULT_INTERP}
|
||||
LINKS+= ${BINDIR}/${LOADER} ${BINDIR}/zfsloader
|
||||
.endif
|
||||
FILES+= ${LOADER}
|
||||
# XXX INSTALLFLAGS_loader= -b
|
||||
FILESMODE_${LOADER}= ${BINMODE} -b
|
||||
|
@ -73,6 +73,7 @@ void exit(int code);
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.h"
|
||||
struct geli_boot_args *gargs;
|
||||
struct geli_boot_data *gbdata;
|
||||
#endif
|
||||
#ifdef LOADER_ZFS_SUPPORT
|
||||
struct zfs_boot_args *zargs;
|
||||
@ -169,38 +170,50 @@ main(void)
|
||||
#ifdef LOADER_ZFS_SUPPORT
|
||||
archsw.arch_zfs_probe = i386_zfs_probe;
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) {
|
||||
/*
|
||||
* zfsboot and gptzfsboot have always passed KARGS_FLAGS_ZFS, so if that is
|
||||
* set along with KARGS_FLAGS_EXTARG we know we can interpret the extarg
|
||||
* data as a struct zfs_boot_args.
|
||||
*/
|
||||
#define KARGS_EXTARGS_ZFS (KARGS_FLAGS_EXTARG | KARGS_FLAGS_ZFS)
|
||||
|
||||
if ((kargs->bootflags & KARGS_EXTARGS_ZFS) == KARGS_EXTARGS_ZFS) {
|
||||
zargs = (struct zfs_boot_args *)(kargs + 1);
|
||||
if (zargs != NULL && zargs->size >= offsetof(struct zfs_boot_args, gelipw)) {
|
||||
if (zargs->size >= offsetof(struct zfs_boot_args, keybuf_sentinel) &&
|
||||
zargs->keybuf_sentinel == KEYBUF_SENTINEL) {
|
||||
geli_save_keybuf(zargs->keybuf);
|
||||
}
|
||||
if (zargs->gelipw[0] != '\0') {
|
||||
setenv("kern.geom.eli.passphrase", zargs->gelipw, 1);
|
||||
explicit_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->keybuf_sentinel == KEYBUF_SENTINEL) {
|
||||
geli_save_keybuf(gargs->keybuf);
|
||||
}
|
||||
if (gargs->gelipw[0] != '\0') {
|
||||
setenv("kern.geom.eli.passphrase", gargs->gelipw, 1);
|
||||
explicit_bzero(gargs->gelipw, sizeof(gargs->gelipw));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LOADER_GELI_SUPPORT */
|
||||
#endif /* LOADER_ZFS_SUPPORT */
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
/*
|
||||
* If we decided earlier that we have zfs_boot_args extarg data, and it is
|
||||
* big enough to contain the embedded geli data (the early zfs_boot_args
|
||||
* structs weren't), then init the gbdata pointer accordingly. If there is
|
||||
* extarg data which isn't zfs_boot_args data, determine whether it is
|
||||
* geli_boot_args data. Recent versions of gptboot set KARGS_FLAGS_GELI to
|
||||
* indicate that. Earlier versions didn't, but we presume that's what we
|
||||
* have if the extarg size exactly matches the size of the geli_boot_args
|
||||
* struct during that pre-flag era.
|
||||
*/
|
||||
#define LEGACY_GELI_ARGS_SIZE 260 /* This can never change */
|
||||
|
||||
#ifdef LOADER_ZFS_SUPPORT
|
||||
if (zargs != NULL) {
|
||||
if (zargs->size > offsetof(struct zfs_boot_args, gelidata)) {
|
||||
gbdata = &zargs->gelidata;
|
||||
}
|
||||
} else
|
||||
#endif /* LOADER_ZFS_SUPPORT */
|
||||
if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) {
|
||||
gargs = (struct geli_boot_args *)(kargs + 1);
|
||||
if ((kargs->bootflags & KARGS_FLAGS_GELI) ||
|
||||
gargs->size == LEGACY_GELI_ARGS_SIZE) {
|
||||
gbdata = &gargs->gelidata;
|
||||
}
|
||||
}
|
||||
|
||||
if (gbdata != NULL)
|
||||
import_geli_boot_data(gbdata);
|
||||
#endif /* LOADER_GELI_SUPPORT */
|
||||
|
||||
/*
|
||||
* March through the device switch probing for things.
|
||||
*/
|
||||
@ -271,11 +284,7 @@ extract_currdev(void)
|
||||
}
|
||||
#ifdef LOADER_ZFS_SUPPORT
|
||||
} else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) {
|
||||
zargs = NULL;
|
||||
/* check for new style extended argument */
|
||||
if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0)
|
||||
zargs = (struct zfs_boot_args *)(kargs + 1);
|
||||
|
||||
/* zargs was set in main() if we have new style extended argument */
|
||||
if (zargs != NULL &&
|
||||
zargs->size >= offsetof(struct zfs_boot_args, primary_pool)) {
|
||||
/* sufficient data is provided */
|
||||
|
@ -1,7 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
HAVE_GELI=yes
|
||||
|
||||
.include <bsd.init.mk>
|
||||
|
||||
.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${SASRC}
|
||||
@ -9,8 +7,6 @@ HAVE_GELI=yes
|
||||
FILES= zfsboot
|
||||
MAN= zfsboot.8
|
||||
|
||||
NM?= nm
|
||||
|
||||
BOOT_COMCONSOLE_PORT?= 0x3f8
|
||||
BOOT_COMCONSOLE_SPEED?= 9600
|
||||
B2SIOFMT?= 0x3
|
||||
|
@ -114,7 +114,6 @@ in the example above.
|
||||
.Xr boot 8 ,
|
||||
.Xr gptzfsboot 8 ,
|
||||
.Xr loader 8 ,
|
||||
.Xr zfsloader 8 ,
|
||||
.Xr zpool 8
|
||||
.Sh HISTORY
|
||||
.Nm
|
||||
|
@ -127,11 +127,17 @@ static void bios_getmem(void);
|
||||
int main(void);
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.c"
|
||||
#include "geliboot.h"
|
||||
static char gelipw[GELI_PW_MAXLEN];
|
||||
static struct keybuf *gelibuf;
|
||||
#endif
|
||||
|
||||
struct zfsdsk {
|
||||
struct dsk dsk;
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
struct geli_dev *gdev;
|
||||
#endif
|
||||
};
|
||||
|
||||
#include "zfsimpl.c"
|
||||
|
||||
/*
|
||||
@ -174,14 +180,14 @@ vdev_read(void *xvdev, void *priv, off_t off, void *buf, size_t bytes)
|
||||
daddr_t lba, alignlba;
|
||||
off_t diff;
|
||||
unsigned int nb, alignnb;
|
||||
struct dsk *dsk = (struct dsk *) priv;
|
||||
struct zfsdsk *zdsk = (struct zfsdsk *) priv;
|
||||
|
||||
if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
|
||||
return -1;
|
||||
|
||||
p = buf;
|
||||
lba = off / DEV_BSIZE;
|
||||
lba += dsk->start;
|
||||
lba += zdsk->dsk.start;
|
||||
/*
|
||||
* Align reads to 4k else 4k sector GELIs will not decrypt.
|
||||
* Round LBA down to nearest multiple of DEV_GELIBOOT_BSIZE bytes.
|
||||
@ -191,7 +197,7 @@ vdev_read(void *xvdev, void *priv, off_t off, void *buf, size_t bytes)
|
||||
* The read must be aligned to DEV_GELIBOOT_BSIZE bytes relative to the
|
||||
* start of the GELI partition, not the start of the actual disk.
|
||||
*/
|
||||
alignlba += dsk->start;
|
||||
alignlba += zdsk->dsk.start;
|
||||
diff = (lba - alignlba) * DEV_BSIZE;
|
||||
|
||||
while (bytes > 0) {
|
||||
@ -209,18 +215,20 @@ vdev_read(void *xvdev, void *priv, off_t off, void *buf, size_t bytes)
|
||||
alignnb = roundup2(nb * DEV_BSIZE + diff, DEV_GELIBOOT_BSIZE)
|
||||
/ DEV_BSIZE;
|
||||
|
||||
if (dsk->size > 0 && alignlba + alignnb > dsk->size + dsk->start) {
|
||||
printf("Shortening read at %lld from %d to %lld\n", alignlba,
|
||||
alignnb, (dsk->size + dsk->start) - alignlba);
|
||||
alignnb = (dsk->size + dsk->start) - alignlba;
|
||||
if (zdsk->dsk.size > 0 && alignlba + alignnb >
|
||||
zdsk->dsk.size + zdsk->dsk.start) {
|
||||
printf("Shortening read at %lld from %d to %lld\n",
|
||||
alignlba, alignnb,
|
||||
(zdsk->dsk.size + zdsk->dsk.start) - alignlba);
|
||||
alignnb = (zdsk->dsk.size + zdsk->dsk.start) - alignlba;
|
||||
}
|
||||
|
||||
if (drvread(dsk, dmadat->rdbuf, alignlba, alignnb))
|
||||
if (drvread(&zdsk->dsk, dmadat->rdbuf, alignlba, alignnb))
|
||||
return -1;
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
/* decrypt */
|
||||
if (is_geli(dsk) == 0) {
|
||||
if (geli_read(dsk, ((alignlba - dsk->start) *
|
||||
if (zdsk->gdev != NULL) {
|
||||
if (geli_read(zdsk->gdev, ((alignlba - zdsk->dsk.start) *
|
||||
DEV_BSIZE), dmadat->rdbuf, alignnb * DEV_BSIZE))
|
||||
return (-1);
|
||||
}
|
||||
@ -250,20 +258,20 @@ vdev_write(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
|
||||
char *p;
|
||||
daddr_t lba;
|
||||
unsigned int nb;
|
||||
struct dsk *dsk = (struct dsk *) priv;
|
||||
struct zfsdsk *zdsk = (struct zfsdsk *) priv;
|
||||
|
||||
if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
|
||||
return -1;
|
||||
|
||||
p = buf;
|
||||
lba = off / DEV_BSIZE;
|
||||
lba += dsk->start;
|
||||
lba += zdsk->dsk.start;
|
||||
while (bytes > 0) {
|
||||
nb = bytes / DEV_BSIZE;
|
||||
if (nb > READ_BUF_SIZE / DEV_BSIZE)
|
||||
nb = READ_BUF_SIZE / DEV_BSIZE;
|
||||
memcpy(dmadat->rdbuf, p, nb * DEV_BSIZE);
|
||||
if (drvwrite(dsk, dmadat->rdbuf, lba, nb))
|
||||
if (drvwrite(&zdsk->dsk, dmadat->rdbuf, lba, nb))
|
||||
return -1;
|
||||
p += nb * DEV_BSIZE;
|
||||
lba += nb;
|
||||
@ -441,13 +449,13 @@ int13probe(int drive)
|
||||
* We call this when we find a ZFS vdev - ZFS consumes the dsk
|
||||
* structure so we must make a new one.
|
||||
*/
|
||||
static struct dsk *
|
||||
copy_dsk(struct dsk *dsk)
|
||||
static struct zfsdsk *
|
||||
copy_dsk(struct zfsdsk *zdsk)
|
||||
{
|
||||
struct dsk *newdsk;
|
||||
struct zfsdsk *newdsk;
|
||||
|
||||
newdsk = malloc(sizeof(struct dsk));
|
||||
*newdsk = *dsk;
|
||||
newdsk = malloc(sizeof(struct zfsdsk));
|
||||
*newdsk = *zdsk;
|
||||
return (newdsk);
|
||||
}
|
||||
|
||||
@ -459,11 +467,14 @@ copy_dsk(struct dsk *dsk)
|
||||
* with boot2 and we can not afford to grow that code.
|
||||
*/
|
||||
static uint64_t
|
||||
drvsize_ext(struct dsk *dskp)
|
||||
drvsize_ext(struct zfsdsk *zdsk)
|
||||
{
|
||||
struct dsk *dskp;
|
||||
uint64_t size, tmp;
|
||||
int cyl, hds, sec;
|
||||
|
||||
dskp = &zdsk->dsk;
|
||||
|
||||
v86.ctl = V86_FLAGS;
|
||||
v86.addr = 0x13;
|
||||
v86.eax = 0x800;
|
||||
@ -508,17 +519,17 @@ drvsize_ext(struct dsk *dskp)
|
||||
uint64_t
|
||||
ldi_get_size(void *priv)
|
||||
{
|
||||
struct dsk *dskp = priv;
|
||||
uint64_t size = dskp->size;
|
||||
struct zfsdsk *zdsk = priv;
|
||||
uint64_t size = zdsk->dsk.size;
|
||||
|
||||
if (dskp->start == 0)
|
||||
size = drvsize_ext(dskp);
|
||||
if (zdsk->dsk.start == 0)
|
||||
size = drvsize_ext(zdsk);
|
||||
|
||||
return (size * DEV_BSIZE);
|
||||
}
|
||||
|
||||
static void
|
||||
probe_drive(struct dsk *dsk)
|
||||
probe_drive(struct zfsdsk *zdsk)
|
||||
{
|
||||
#ifdef GPT
|
||||
struct gpt_hdr hdr;
|
||||
@ -537,7 +548,7 @@ probe_drive(struct dsk *dsk)
|
||||
/*
|
||||
* If we find a vdev on the whole disk, stop here.
|
||||
*/
|
||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0)
|
||||
if (vdev_probe(vdev_read2, zdsk, NULL) == 0)
|
||||
return;
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
@ -547,14 +558,15 @@ probe_drive(struct dsk *dsk)
|
||||
* out the partition table and probe each slice/partition
|
||||
* in turn for a vdev or GELI encrypted vdev.
|
||||
*/
|
||||
elba = drvsize_ext(dsk);
|
||||
elba = drvsize_ext(zdsk);
|
||||
if (elba > 0) {
|
||||
elba--;
|
||||
}
|
||||
if (geli_taste(vdev_read, dsk, elba) == 0) {
|
||||
if (geli_havekey(dsk) == 0 || geli_passphrase(gelipw, dsk->unit,
|
||||
':', 0, dsk) == 0) {
|
||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0) {
|
||||
zdsk->gdev = geli_taste(vdev_read, zdsk, elba, "disk%u:0:");
|
||||
if (zdsk->gdev != NULL) {
|
||||
if (geli_havekey(zdsk->gdev) == 0 ||
|
||||
geli_passphrase(zdsk->gdev, gelipw) == 0) {
|
||||
if (vdev_probe(vdev_read2, zdsk, NULL) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -562,13 +574,13 @@ probe_drive(struct dsk *dsk)
|
||||
#endif /* LOADER_GELI_SUPPORT */
|
||||
|
||||
sec = dmadat->secbuf;
|
||||
dsk->start = 0;
|
||||
zdsk->dsk.start = 0;
|
||||
|
||||
#ifdef GPT
|
||||
/*
|
||||
* First check for GPT.
|
||||
*/
|
||||
if (drvread(dsk, sec, 1, 1)) {
|
||||
if (drvread(&zdsk->dsk, sec, 1, 1)) {
|
||||
return;
|
||||
}
|
||||
memcpy(&hdr, sec, sizeof(hdr));
|
||||
@ -590,38 +602,39 @@ probe_drive(struct dsk *dsk)
|
||||
slba = hdr.hdr_lba_table;
|
||||
elba = slba + hdr.hdr_entries / entries_per_sec;
|
||||
while (slba < elba) {
|
||||
dsk->start = 0;
|
||||
if (drvread(dsk, sec, slba, 1))
|
||||
zdsk->dsk.start = 0;
|
||||
if (drvread(&zdsk->dsk, sec, slba, 1))
|
||||
return;
|
||||
for (part = 0; part < entries_per_sec; part++) {
|
||||
ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz);
|
||||
if (memcmp(&ent->ent_type, &freebsd_zfs_uuid,
|
||||
sizeof(uuid_t)) == 0) {
|
||||
dsk->start = ent->ent_lba_start;
|
||||
dsk->size = ent->ent_lba_end - ent->ent_lba_start + 1;
|
||||
dsk->slice = part + 1;
|
||||
dsk->part = 255;
|
||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0) {
|
||||
zdsk->dsk.start = ent->ent_lba_start;
|
||||
zdsk->dsk.size = ent->ent_lba_end - ent->ent_lba_start + 1;
|
||||
zdsk->dsk.slice = part + 1;
|
||||
zdsk->dsk.part = 255;
|
||||
if (vdev_probe(vdev_read2, zdsk, 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);
|
||||
zdsk = copy_dsk(zdsk);
|
||||
}
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
else if (geli_taste(vdev_read, dsk, ent->ent_lba_end -
|
||||
ent->ent_lba_start) == 0) {
|
||||
if (geli_havekey(dsk) == 0 || geli_passphrase(gelipw,
|
||||
dsk->unit, 'p', dsk->slice, dsk) == 0) {
|
||||
else if ((zdsk->gdev = geli_taste(vdev_read, zdsk,
|
||||
ent->ent_lba_end - ent->ent_lba_start, "disk%up%u:",
|
||||
zdsk->dsk.unit, zdsk->dsk.slice)) != NULL) {
|
||||
if (geli_havekey(zdsk->gdev) == 0 ||
|
||||
geli_passphrase(zdsk->gdev, gelipw) == 0) {
|
||||
/*
|
||||
* This slice has GELI, check it for ZFS.
|
||||
*/
|
||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0) {
|
||||
if (vdev_probe(vdev_read2, zdsk, 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);
|
||||
zdsk = copy_dsk(zdsk);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -635,33 +648,33 @@ probe_drive(struct dsk *dsk)
|
||||
trymbr:
|
||||
#endif /* GPT */
|
||||
|
||||
if (drvread(dsk, sec, DOSBBSECTOR, 1))
|
||||
if (drvread(&zdsk->dsk, sec, DOSBBSECTOR, 1))
|
||||
return;
|
||||
dp = (void *)(sec + DOSPARTOFF);
|
||||
|
||||
for (i = 0; i < NDOSPART; i++) {
|
||||
if (!dp[i].dp_typ)
|
||||
continue;
|
||||
dsk->start = dp[i].dp_start;
|
||||
dsk->size = dp[i].dp_size;
|
||||
dsk->slice = i + 1;
|
||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0) {
|
||||
dsk = copy_dsk(dsk);
|
||||
zdsk->dsk.start = dp[i].dp_start;
|
||||
zdsk->dsk.size = dp[i].dp_size;
|
||||
zdsk->dsk.slice = i + 1;
|
||||
if (vdev_probe(vdev_read2, zdsk, NULL) == 0) {
|
||||
zdsk = copy_dsk(zdsk);
|
||||
}
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
else if (geli_taste(vdev_read, dsk, dp[i].dp_size -
|
||||
dp[i].dp_start) == 0) {
|
||||
if (geli_havekey(dsk) == 0 || geli_passphrase(gelipw, dsk->unit,
|
||||
's', i, dsk) == 0) {
|
||||
else if ((zdsk->gdev = geli_taste(vdev_read, zdsk, dp[i].dp_size -
|
||||
dp[i].dp_start, "disk%us%u:")) != NULL) {
|
||||
if (geli_havekey(zdsk->gdev) == 0 ||
|
||||
geli_passphrase(zdsk->gdev, gelipw) == 0) {
|
||||
/*
|
||||
* This slice has GELI, check it for ZFS.
|
||||
*/
|
||||
if (vdev_probe(vdev_read2, dsk, NULL) == 0) {
|
||||
if (vdev_probe(vdev_read2, zdsk, 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);
|
||||
zdsk = copy_dsk(zdsk);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -675,7 +688,7 @@ main(void)
|
||||
{
|
||||
dnode_phys_t dn;
|
||||
off_t off;
|
||||
struct dsk *dsk;
|
||||
struct zfsdsk *zdsk;
|
||||
int autoboot, i;
|
||||
int nextboot;
|
||||
int rc;
|
||||
@ -693,39 +706,36 @@ main(void)
|
||||
}
|
||||
setheap(heap_next, heap_end);
|
||||
|
||||
dsk = malloc(sizeof(struct dsk));
|
||||
dsk->drive = *(uint8_t *)PTOV(ARGS);
|
||||
dsk->type = dsk->drive & DRV_HARD ? TYPE_AD : TYPE_FD;
|
||||
dsk->unit = dsk->drive & DRV_MASK;
|
||||
dsk->slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
|
||||
dsk->part = 0;
|
||||
dsk->start = 0;
|
||||
dsk->size = drvsize_ext(dsk);
|
||||
zdsk = calloc(1, sizeof(struct zfsdsk));
|
||||
zdsk->dsk.drive = *(uint8_t *)PTOV(ARGS);
|
||||
zdsk->dsk.type = zdsk->dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
|
||||
zdsk->dsk.unit = zdsk->dsk.drive & DRV_MASK;
|
||||
zdsk->dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
|
||||
zdsk->dsk.part = 0;
|
||||
zdsk->dsk.start = 0;
|
||||
zdsk->dsk.size = drvsize_ext(zdsk);
|
||||
|
||||
bootinfo.bi_version = BOOTINFO_VERSION;
|
||||
bootinfo.bi_size = sizeof(bootinfo);
|
||||
bootinfo.bi_basemem = bios_basemem / 1024;
|
||||
bootinfo.bi_extmem = bios_extmem / 1024;
|
||||
bootinfo.bi_memsizes_valid++;
|
||||
bootinfo.bi_bios_dev = dsk->drive;
|
||||
bootinfo.bi_bios_dev = zdsk->dsk.drive;
|
||||
|
||||
bootdev = MAKEBOOTDEV(dev_maj[dsk->type],
|
||||
dsk->slice, dsk->unit, dsk->part);
|
||||
bootdev = MAKEBOOTDEV(dev_maj[zdsk->dsk.type],
|
||||
zdsk->dsk.slice, zdsk->dsk.unit, zdsk->dsk.part);
|
||||
|
||||
/* Process configuration file */
|
||||
|
||||
autoboot = 1;
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
geli_init();
|
||||
#endif
|
||||
zfs_init();
|
||||
|
||||
/*
|
||||
* Probe the boot drive first - we will try to boot from whatever
|
||||
* pool we find on that drive.
|
||||
*/
|
||||
probe_drive(dsk);
|
||||
probe_drive(zdsk);
|
||||
|
||||
/*
|
||||
* Probe the rest of the drives that the bios knows about. This
|
||||
@ -744,15 +754,15 @@ main(void)
|
||||
if (!int13probe(i | DRV_HARD))
|
||||
break;
|
||||
|
||||
dsk = malloc(sizeof(struct dsk));
|
||||
dsk->drive = i | DRV_HARD;
|
||||
dsk->type = dsk->drive & TYPE_AD;
|
||||
dsk->unit = i;
|
||||
dsk->slice = 0;
|
||||
dsk->part = 0;
|
||||
dsk->start = 0;
|
||||
dsk->size = drvsize_ext(dsk);
|
||||
probe_drive(dsk);
|
||||
zdsk = calloc(1, sizeof(struct zfsdsk));
|
||||
zdsk->dsk.drive = i | DRV_HARD;
|
||||
zdsk->dsk.type = zdsk->dsk.drive & TYPE_AD;
|
||||
zdsk->dsk.unit = i;
|
||||
zdsk->dsk.slice = 0;
|
||||
zdsk->dsk.part = 0;
|
||||
zdsk->dsk.start = 0;
|
||||
zdsk->dsk.size = drvsize_ext(zdsk);
|
||||
probe_drive(zdsk);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -834,7 +844,7 @@ main(void)
|
||||
*/
|
||||
|
||||
if (autoboot && !*kname) {
|
||||
memcpy(kname, PATH_LOADER_ZFS, sizeof(PATH_LOADER_ZFS));
|
||||
memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER));
|
||||
if (!keyhit(3)) {
|
||||
load();
|
||||
memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
|
||||
@ -982,18 +992,17 @@ load(void)
|
||||
zfsargs.primary_pool = primary_spa->spa_guid;
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
explicit_bzero(gelipw, sizeof(gelipw));
|
||||
gelibuf = malloc(sizeof(struct keybuf) + (GELI_MAX_KEYS * sizeof(struct keybuf_ent)));
|
||||
geli_fill_keybuf(gelibuf);
|
||||
zfsargs.notapw = '\0';
|
||||
zfsargs.keybuf_sentinel = KEYBUF_SENTINEL;
|
||||
zfsargs.keybuf = gelibuf;
|
||||
#else
|
||||
zfsargs.gelipw[0] = '\0';
|
||||
export_geli_boot_data(&zfsargs.gelidata);
|
||||
#endif
|
||||
if (primary_vdev != NULL)
|
||||
zfsargs.primary_vdev = primary_vdev->v_guid;
|
||||
else
|
||||
printf("failed to detect primary vdev\n");
|
||||
/*
|
||||
* Note that the zfsargs struct is passed by value, not by pointer. Code in
|
||||
* btxldr.S copies the values from the entry stack to a fixed location
|
||||
* within loader(8) at startup due to the presence of KARGS_FLAGS_EXTARG.
|
||||
*/
|
||||
__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
|
||||
bootdev,
|
||||
KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG,
|
||||
|
@ -1,8 +0,0 @@
|
||||
# $FreeBSD$
|
||||
|
||||
LOADER= zfsloader
|
||||
NEWVERSWHAT= "ZFS enabled bootstrap loader" x86
|
||||
HAVE_ZFS= yes
|
||||
CFLAGS+= -DBOOTPROG=\"zfsloader\"
|
||||
|
||||
.include "${.CURDIR}/../loader/Makefile"
|
@ -156,7 +156,7 @@ SRCS+= explicit_bzero.c
|
||||
.endif
|
||||
|
||||
# Maybe ZFS
|
||||
.if ${MK_ZFS} == "yes"
|
||||
.if ${MK_LOADER_ZFS} == "yes"
|
||||
.include "${SASRC}/zfs/Makefile.inc"
|
||||
.endif
|
||||
|
||||
|
@ -27,7 +27,15 @@ SRCS+= ${i}
|
||||
|
||||
# local GELI Implementation
|
||||
.PATH: ${SYSDIR}/geom/eli
|
||||
SRCS+= geliboot_crypto.c g_eli_hmac.c g_eli_key.c g_eli_key_cache.c pkcs5v2.c
|
||||
SRCS+= \
|
||||
geliboot.c \
|
||||
geliboot_crypto.c \
|
||||
gelidev.c \
|
||||
geli_metadata.c \
|
||||
g_eli_hmac.c \
|
||||
g_eli_key.c \
|
||||
g_eli_key_cache.c \
|
||||
pkcs5v2.c \
|
||||
|
||||
# aes
|
||||
.PATH: ${SYSDIR}/opencrypto
|
||||
|
52
stand/libsa/geli/geli_metadata.c
Normal file
52
stand/libsa/geli/geli_metadata.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2018 Ian Lepore <ian@FreeBSD.org>
|
||||
*
|
||||
* 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 <stand.h>
|
||||
#include <bootstrap.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker.h>
|
||||
#include "geliboot.h"
|
||||
|
||||
/*
|
||||
* Export a keybuf as metadata attached to a kernel module. This is separate
|
||||
* from the lower-level key management functions to avoid creating a linker
|
||||
* dependency on the libsa metadata routines when the geli code is linked into
|
||||
* early-stage bootloaders such as gptboot. Only loader(8) variants call this.
|
||||
*/
|
||||
void
|
||||
geli_export_key_metadata(struct preloaded_file *kfp)
|
||||
{
|
||||
struct keybuf *keybuf;
|
||||
|
||||
keybuf = malloc(GELI_KEYBUF_SIZE);
|
||||
geli_export_key_buffer(keybuf);
|
||||
file_addmetadata(kfp, MODINFOMD_KEYBUF, GELI_KEYBUF_SIZE, keybuf);
|
||||
explicit_bzero(keybuf, GELI_KEYBUF_SIZE);
|
||||
free(keybuf);
|
||||
}
|
@ -27,13 +27,19 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "geliboot_internal.h"
|
||||
#include <stand.h>
|
||||
#include <stdarg.h>
|
||||
#include "geliboot.h"
|
||||
#include "geliboot_internal.h"
|
||||
|
||||
SLIST_HEAD(geli_list, geli_entry) geli_head = SLIST_HEAD_INITIALIZER(geli_head);
|
||||
struct geli_list *geli_headp;
|
||||
struct known_dev {
|
||||
char name[GELIDEV_NAMELEN];
|
||||
struct geli_dev *gdev;
|
||||
SLIST_ENTRY(known_dev) entries;
|
||||
};
|
||||
|
||||
typedef u_char geli_ukey[G_ELI_USERKEYLEN];
|
||||
SLIST_HEAD(known_dev_list, known_dev) known_devs_head =
|
||||
SLIST_HEAD_INITIALIZER(known_devs_head);
|
||||
|
||||
static geli_ukey saved_keys[GELI_MAX_KEYS];
|
||||
static unsigned int nsaved_keys = 0;
|
||||
@ -43,7 +49,7 @@ static unsigned int nsaved_keys = 0;
|
||||
* Destroy the local storage when finished.
|
||||
*/
|
||||
void
|
||||
geli_fill_keybuf(struct keybuf *fkeybuf)
|
||||
geli_export_key_buffer(struct keybuf *fkeybuf)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@ -61,7 +67,7 @@ geli_fill_keybuf(struct keybuf *fkeybuf)
|
||||
* Zero out the keybuf.
|
||||
*/
|
||||
void
|
||||
geli_save_keybuf(struct keybuf *skeybuf)
|
||||
geli_import_key_buffer(struct keybuf *skeybuf)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@ -76,8 +82,8 @@ geli_save_keybuf(struct keybuf *skeybuf)
|
||||
skeybuf->kb_nents = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
save_key(geli_ukey key)
|
||||
void
|
||||
geli_add_key(geli_ukey key)
|
||||
{
|
||||
|
||||
/*
|
||||
@ -91,46 +97,22 @@ save_key(geli_ukey key)
|
||||
}
|
||||
|
||||
static int
|
||||
geli_same_device(struct geli_entry *ge, struct dsk *dskp)
|
||||
{
|
||||
|
||||
if (ge->dsk->drive == dskp->drive &&
|
||||
dskp->part == 255 && ge->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 (ge->dsk->drive != dskp->drive ||
|
||||
ge->dsk->slice != dskp->slice ||
|
||||
ge->dsk->part != dskp->part) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
geli_findkey(struct geli_entry *ge, struct dsk *dskp, u_char *mkey)
|
||||
geli_findkey(struct geli_dev *gdev, u_char *mkey)
|
||||
{
|
||||
u_int keynum;
|
||||
int i;
|
||||
|
||||
if (ge->keybuf_slot >= 0) {
|
||||
if (g_eli_mkey_decrypt_any(&ge->md, saved_keys[ge->keybuf_slot],
|
||||
if (gdev->keybuf_slot >= 0) {
|
||||
if (g_eli_mkey_decrypt_any(&gdev->md, saved_keys[gdev->keybuf_slot],
|
||||
mkey, &keynum) == 0) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < nsaved_keys; i++) {
|
||||
if (g_eli_mkey_decrypt_any(&ge->md, saved_keys[i], mkey,
|
||||
if (g_eli_mkey_decrypt_any(&gdev->md, saved_keys[i], mkey,
|
||||
&keynum) == 0) {
|
||||
ge->keybuf_slot = i;
|
||||
gdev->keybuf_slot = i;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
@ -138,37 +120,59 @@ geli_findkey(struct geli_entry *ge, struct dsk *dskp, u_char *mkey)
|
||||
return (1);
|
||||
}
|
||||
|
||||
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
|
||||
* Read the last sector of a drive or partition 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 geli_dev *
|
||||
geli_taste(geli_readfunc readfunc, void *readpriv, daddr_t lastsector,
|
||||
const char *namefmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
struct g_eli_metadata md;
|
||||
u_char buf[DEV_GELIBOOT_BSIZE];
|
||||
struct known_dev *kdev;
|
||||
struct geli_dev *gdev;
|
||||
u_char *buf;
|
||||
char devname[GELIDEV_NAMELEN];
|
||||
int error;
|
||||
off_t alignsector;
|
||||
|
||||
/*
|
||||
* Format the name into a temp buffer and use that to search for an
|
||||
* existing known_dev instance. If not found, this has the side effect
|
||||
* of initializing kdev to NULL.
|
||||
*/
|
||||
va_start(args, namefmt);
|
||||
vsnprintf(devname, sizeof(devname), namefmt, args);
|
||||
va_end(args);
|
||||
SLIST_FOREACH(kdev, &known_devs_head, entries) {
|
||||
if (strcmp(kdev->name, devname) == 0)
|
||||
return (kdev->gdev);
|
||||
}
|
||||
|
||||
/* Determine whether the new device is geli-encrypted... */
|
||||
if ((buf = malloc(DEV_GELIBOOT_BSIZE)) == NULL)
|
||||
goto out;
|
||||
alignsector = rounddown2(lastsector * DEV_BSIZE, DEV_GELIBOOT_BSIZE);
|
||||
if (alignsector + DEV_GELIBOOT_BSIZE > ((lastsector + 1) * DEV_BSIZE)) {
|
||||
/* Don't read past the end of the disk */
|
||||
alignsector = (lastsector * DEV_BSIZE) + DEV_BSIZE
|
||||
- DEV_GELIBOOT_BSIZE;
|
||||
alignsector = (lastsector * DEV_BSIZE) + DEV_BSIZE -
|
||||
DEV_GELIBOOT_BSIZE;
|
||||
}
|
||||
error = read_func(NULL, dskp, alignsector, &buf, DEV_GELIBOOT_BSIZE);
|
||||
error = readfunc(NULL, readpriv, alignsector, buf, DEV_GELIBOOT_BSIZE);
|
||||
if (error != 0) {
|
||||
return (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a new known_device. Whether it's geli-encrypted or not,
|
||||
* record its existance so we can avoid doing IO to probe it next time.
|
||||
*/
|
||||
if ((kdev = malloc(sizeof(*kdev))) == NULL)
|
||||
goto out;
|
||||
strlcpy(kdev->name, devname, sizeof(kdev->name));
|
||||
kdev->gdev = NULL;
|
||||
SLIST_INSERT_HEAD(&known_devs_head, kdev, entries);
|
||||
|
||||
/* Extract the last 4k sector of the disk. */
|
||||
error = eli_metadata_decode(buf, &md);
|
||||
if (error != 0) {
|
||||
@ -176,53 +180,46 @@ geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf,
|
||||
error = eli_metadata_decode(buf +
|
||||
(DEV_GELIBOOT_BSIZE - DEV_BSIZE), &md);
|
||||
if (error != 0) {
|
||||
return (error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(md.md_flags & G_ELI_FLAG_GELIBOOT)) {
|
||||
/* The GELIBOOT feature is not activated */
|
||||
return (1);
|
||||
goto out;
|
||||
}
|
||||
if ((md.md_flags & G_ELI_FLAG_ONETIME)) {
|
||||
/* Swap device, skip it. */
|
||||
return (1);
|
||||
goto out;
|
||||
}
|
||||
if (md.md_iterations < 0) {
|
||||
/* XXX TODO: Support loading key files. */
|
||||
/* Disk does not have a passphrase, 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->keybuf_slot = -1;
|
||||
|
||||
geli_e->md = md;
|
||||
eli_metadata_softc(&geli_e->sc, &md, DEV_BSIZE,
|
||||
/*
|
||||
* It's geli-encrypted, create a geli_dev for it and link it into the
|
||||
* known_dev instance.
|
||||
*/
|
||||
gdev = malloc(sizeof(struct geli_dev));
|
||||
if (gdev == NULL)
|
||||
goto out;
|
||||
gdev->part_end = lastsector;
|
||||
gdev->keybuf_slot = -1;
|
||||
gdev->md = md;
|
||||
gdev->name = kdev->name;
|
||||
eli_metadata_softc(&gdev->sc, &md, DEV_BSIZE,
|
||||
(lastsector + DEV_BSIZE) * DEV_BSIZE);
|
||||
|
||||
SLIST_INSERT_HEAD(&geli_head, geli_e, entries);
|
||||
geli_count++;
|
||||
|
||||
return (0);
|
||||
kdev->gdev = gdev;
|
||||
out:
|
||||
free(buf);
|
||||
if (kdev == NULL)
|
||||
return (NULL);
|
||||
return (kdev->gdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to decrypt the device
|
||||
* Attempt to decrypt the device. This will try existing keys first, then will
|
||||
* prompt for a passphrase if there are no existing keys that work.
|
||||
*/
|
||||
static int
|
||||
geli_attach(struct geli_entry *ge, struct dsk *dskp, const char *passphrase,
|
||||
u_char *mkeyp)
|
||||
geli_probe(struct geli_dev *gdev, const char *passphrase, u_char *mkeyp)
|
||||
{
|
||||
u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp;
|
||||
u_int keynum;
|
||||
@ -232,9 +229,10 @@ geli_attach(struct geli_entry *ge, struct dsk *dskp, const char *passphrase,
|
||||
if (mkeyp != NULL) {
|
||||
memcpy(&mkey, mkeyp, G_ELI_DATAIVKEYLEN);
|
||||
explicit_bzero(mkeyp, G_ELI_DATAIVKEYLEN);
|
||||
goto found_key;
|
||||
}
|
||||
|
||||
if (mkeyp != NULL || geli_findkey(ge, dskp, mkey) == 0) {
|
||||
if (geli_findkey(gdev, mkey) == 0) {
|
||||
goto found_key;
|
||||
}
|
||||
|
||||
@ -242,31 +240,29 @@ geli_attach(struct geli_entry *ge, struct dsk *dskp, const char *passphrase,
|
||||
/*
|
||||
* Prepare Derived-Key from the user passphrase.
|
||||
*/
|
||||
if (geli_e->md.md_iterations < 0) {
|
||||
if (gdev->md.md_iterations < 0) {
|
||||
/* XXX TODO: Support loading key files. */
|
||||
return (1);
|
||||
} else if (geli_e->md.md_iterations == 0) {
|
||||
g_eli_crypto_hmac_update(&ctx, geli_e->md.md_salt,
|
||||
sizeof(geli_e->md.md_salt));
|
||||
} else if (gdev->md.md_iterations == 0) {
|
||||
g_eli_crypto_hmac_update(&ctx, gdev->md.md_salt,
|
||||
sizeof(gdev->md.md_salt));
|
||||
g_eli_crypto_hmac_update(&ctx, (const uint8_t *)passphrase,
|
||||
strlen(passphrase));
|
||||
} else if (geli_e->md.md_iterations > 0) {
|
||||
printf("Calculating GELI Decryption Key disk%dp%d @ %d"
|
||||
" iterations...\n", dskp->unit,
|
||||
(dskp->slice > 0 ? dskp->slice : dskp->part),
|
||||
geli_e->md.md_iterations);
|
||||
} else if (gdev->md.md_iterations > 0) {
|
||||
printf("Calculating GELI Decryption Key for %s %d"
|
||||
" iterations...\n", gdev->name, gdev->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);
|
||||
pkcs5v2_genkey(dkey, sizeof(dkey), gdev->md.md_salt,
|
||||
sizeof(gdev->md.md_salt), passphrase,
|
||||
gdev->md.md_iterations);
|
||||
g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
|
||||
explicit_bzero(dkey, sizeof(dkey));
|
||||
}
|
||||
|
||||
g_eli_crypto_hmac_final(&ctx, key, 0);
|
||||
|
||||
error = g_eli_mkey_decrypt_any(&geli_e->md, key, mkey, &keynum);
|
||||
error = g_eli_mkey_decrypt_any(&gdev->md, key, mkey, &keynum);
|
||||
if (error == -1) {
|
||||
explicit_bzero(mkey, sizeof(mkey));
|
||||
explicit_bzero(key, sizeof(key));
|
||||
@ -279,34 +275,34 @@ geli_attach(struct geli_entry *ge, struct dsk *dskp, const char *passphrase,
|
||||
return (error);
|
||||
} else {
|
||||
/* Add key to keychain */
|
||||
save_key(key);
|
||||
geli_add_key(key);
|
||||
explicit_bzero(&key, sizeof(key));
|
||||
}
|
||||
|
||||
found_key:
|
||||
/* 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);
|
||||
bcopy(mkey, gdev->sc.sc_mkey, sizeof(gdev->sc.sc_mkey));
|
||||
bcopy(mkey, gdev->sc.sc_ivkey, sizeof(gdev->sc.sc_ivkey));
|
||||
mkp = mkey + sizeof(gdev->sc.sc_ivkey);
|
||||
if ((gdev->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) {
|
||||
bcopy(mkp, gdev->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, (const uint8_t *)"\x10", 1,
|
||||
geli_e->sc.sc_ekey, 0);
|
||||
gdev->sc.sc_ekey, 0);
|
||||
}
|
||||
explicit_bzero(mkey, sizeof(mkey));
|
||||
|
||||
/* Initialize the per-sector IV. */
|
||||
switch (geli_e->sc.sc_ealgo) {
|
||||
switch (gdev->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));
|
||||
SHA256_Init(&gdev->sc.sc_ivctx);
|
||||
SHA256_Update(&gdev->sc.sc_ivctx, gdev->sc.sc_ivkey,
|
||||
sizeof(gdev->sc.sc_ivkey));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -314,19 +310,7 @@ found_key:
|
||||
}
|
||||
|
||||
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)
|
||||
geli_read(struct geli_dev *gdev, off_t offset, u_char *buf, size_t bytes)
|
||||
{
|
||||
u_char iv[G_ELI_IVKEYLEN];
|
||||
u_char *pbuf;
|
||||
@ -337,100 +321,77 @@ geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes)
|
||||
struct g_eli_key gkey;
|
||||
|
||||
pbuf = buf;
|
||||
SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
|
||||
if (geli_same_device(geli_e, dskp) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
secsize = geli_e->sc.sc_sectorsize;
|
||||
nsec = bytes / secsize;
|
||||
if (nsec == 0) {
|
||||
/*
|
||||
* A read of less than the GELI sector size has been
|
||||
* requested. The caller provided destination buffer may
|
||||
* not be big enough to boost the read to a full sector,
|
||||
* so just attempt to decrypt the truncated sector.
|
||||
*/
|
||||
secsize = bytes;
|
||||
nsec = 1;
|
||||
}
|
||||
|
||||
for (n = 0, dstoff = offset; n < nsec; n++, dstoff += secsize) {
|
||||
|
||||
g_eli_crypto_ivgen(&geli_e->sc, dstoff, iv,
|
||||
G_ELI_IVKEYLEN);
|
||||
|
||||
/* Get the key that corresponds to this offset. */
|
||||
keyno = (dstoff >> G_ELI_KEY_SHIFT) / secsize;
|
||||
g_eli_key_fill(&geli_e->sc, &gkey, keyno);
|
||||
|
||||
error = geliboot_crypt(geli_e->sc.sc_ealgo, 0, pbuf,
|
||||
secsize, gkey.gek_key,
|
||||
geli_e->sc.sc_ekeylen, iv);
|
||||
|
||||
if (error != 0) {
|
||||
explicit_bzero(&gkey, sizeof(gkey));
|
||||
printf("Failed to decrypt in geli_read()!");
|
||||
return (error);
|
||||
}
|
||||
pbuf += secsize;
|
||||
}
|
||||
explicit_bzero(&gkey, sizeof(gkey));
|
||||
return (0);
|
||||
secsize = gdev->sc.sc_sectorsize;
|
||||
nsec = bytes / secsize;
|
||||
if (nsec == 0) {
|
||||
/*
|
||||
* A read of less than the GELI sector size has been
|
||||
* requested. The caller provided destination buffer may
|
||||
* not be big enough to boost the read to a full sector,
|
||||
* so just attempt to decrypt the truncated sector.
|
||||
*/
|
||||
secsize = bytes;
|
||||
nsec = 1;
|
||||
}
|
||||
|
||||
printf("GELI provider not found\n");
|
||||
return (1);
|
||||
for (n = 0, dstoff = offset; n < nsec; n++, dstoff += secsize) {
|
||||
|
||||
g_eli_crypto_ivgen(&gdev->sc, dstoff, iv, G_ELI_IVKEYLEN);
|
||||
|
||||
/* Get the key that corresponds to this offset. */
|
||||
keyno = (dstoff >> G_ELI_KEY_SHIFT) / secsize;
|
||||
g_eli_key_fill(&gdev->sc, &gkey, keyno);
|
||||
|
||||
error = geliboot_crypt(gdev->sc.sc_ealgo, 0, pbuf, secsize,
|
||||
gkey.gek_key, gdev->sc.sc_ekeylen, iv);
|
||||
|
||||
if (error != 0) {
|
||||
explicit_bzero(&gkey, sizeof(gkey));
|
||||
printf("Failed to decrypt in geli_read()!");
|
||||
return (error);
|
||||
}
|
||||
pbuf += secsize;
|
||||
}
|
||||
explicit_bzero(&gkey, sizeof(gkey));
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
geli_havekey(struct dsk *dskp)
|
||||
geli_havekey(struct geli_dev *gdev)
|
||||
{
|
||||
u_char mkey[G_ELI_DATAIVKEYLEN];
|
||||
int err;
|
||||
|
||||
SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
|
||||
if (geli_same_device(geli_e, dskp) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (geli_findkey(geli_e, dskp, mkey) == 0) {
|
||||
if (geli_attach(geli_e, dskp, NULL, mkey) == 0) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
err = ENOENT;
|
||||
if (geli_findkey(gdev, mkey) == 0) {
|
||||
if (geli_probe(gdev, NULL, mkey) == 0)
|
||||
err = 0;
|
||||
explicit_bzero(mkey, sizeof(mkey));
|
||||
}
|
||||
explicit_bzero(mkey, sizeof(mkey));
|
||||
|
||||
return (1);
|
||||
return (err);
|
||||
}
|
||||
|
||||
int
|
||||
geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp)
|
||||
geli_passphrase(struct geli_dev *gdev, char *pw)
|
||||
{
|
||||
int i;
|
||||
|
||||
SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
|
||||
if (geli_same_device(geli_e, dskp) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* TODO: Implement GELI keyfile(s) support */
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* Try cached passphrase */
|
||||
if (i == 0 && pw[0] != '\0') {
|
||||
if (geli_attach(geli_e, dskp, pw, NULL) == 0) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
printf("GELI Passphrase for disk%d%c%d: ", disk,
|
||||
parttype, part);
|
||||
pwgets(pw, GELI_PW_MAXLEN,
|
||||
(geli_e->md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS) == 0);
|
||||
printf("\n");
|
||||
if (geli_attach(geli_e, dskp, pw, NULL) == 0) {
|
||||
/* TODO: Implement GELI keyfile(s) support */
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* Try cached passphrase */
|
||||
if (i == 0 && pw[0] != '\0') {
|
||||
if (geli_probe(gdev, pw, NULL) == 0) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
printf("GELI Passphrase for %s ", gdev->name);
|
||||
pwgets(pw, GELI_PW_MAXLEN,
|
||||
(gdev->md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS) == 0);
|
||||
printf("\n");
|
||||
if (geli_probe(gdev, pw, NULL) == 0) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (1);
|
||||
|
@ -32,6 +32,8 @@
|
||||
#ifndef _GELIBOOT_H_
|
||||
#define _GELIBOOT_H_
|
||||
|
||||
#include <geom/eli/g_eli.h>
|
||||
|
||||
#ifndef DEV_BSIZE
|
||||
#define DEV_BSIZE 512
|
||||
#endif
|
||||
@ -44,26 +46,50 @@
|
||||
#endif
|
||||
|
||||
#define GELI_MAX_KEYS 64
|
||||
#define GELI_PW_MAXLEN 256
|
||||
#define GELI_PW_MAXLEN 256
|
||||
#define GELI_KEYBUF_SIZE (sizeof(struct keybuf) + \
|
||||
(GELI_MAX_KEYS * sizeof(struct keybuf_ent)))
|
||||
|
||||
extern void pwgets(char *buf, int n, int hide);
|
||||
|
||||
struct dsk;
|
||||
typedef u_char geli_ukey[G_ELI_USERKEYLEN];
|
||||
|
||||
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 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_havekey(struct dsk *dskp);
|
||||
int geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp);
|
||||
/*
|
||||
* An opaque struct used internally by geliboot functions. Returned by
|
||||
* geli_taste(), a pointer to one of these is essentially a device handle. There
|
||||
* is no need to release or free or "give back" the pointer.
|
||||
*/
|
||||
struct geli_dev;
|
||||
|
||||
int geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
|
||||
const u_char *key, size_t keysize, u_char *iv);
|
||||
/* Forward decls. */
|
||||
struct open_file;
|
||||
struct preloaded_file;
|
||||
|
||||
void geli_fill_keybuf(struct keybuf *keybuf);
|
||||
void geli_save_keybuf(struct keybuf *keybuf);
|
||||
/*
|
||||
* Low-level interface, used by early-stage bootloaders...
|
||||
*/
|
||||
|
||||
/* Read callback function type for geli_taste(). */
|
||||
typedef int (*geli_readfunc)(void *vdev, void *readpriv, off_t offbytes,
|
||||
void *buf, size_t sizebytes);
|
||||
|
||||
struct geli_dev * geli_taste(geli_readfunc readfunc, void *readpriv,
|
||||
daddr_t lastsector, const char *namefmt, ...);
|
||||
int geli_read(struct geli_dev *gdev, off_t offset, u_char *buf, size_t bytes);
|
||||
int geli_havekey(struct geli_dev *gdev);
|
||||
int geli_passphrase(struct geli_dev *gdev, char *pw);
|
||||
|
||||
/*
|
||||
* Libsa device-and-file-level interface.
|
||||
*/
|
||||
void geli_probe_and_attach(struct open_file *f);
|
||||
|
||||
/*
|
||||
* Manage key data.
|
||||
*/
|
||||
void geli_add_key(geli_ukey key);
|
||||
void geli_import_key_buffer(struct keybuf *keybuf);
|
||||
void geli_export_key_buffer(struct keybuf *keybuf);
|
||||
void geli_export_key_metadata(struct preloaded_file *kfp);
|
||||
|
||||
#endif /* _GELIBOOT_H_ */
|
||||
|
@ -59,15 +59,14 @@ geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
|
||||
return (err);
|
||||
}
|
||||
|
||||
switch (enc) {
|
||||
case 0: /* decrypt */
|
||||
if (enc == 0) {
|
||||
/* decrypt */
|
||||
blks = rijndael_blockDecrypt(&cipher, &aeskey, data,
|
||||
datasize * 8, data);
|
||||
break;
|
||||
case 1: /* encrypt */
|
||||
} else {
|
||||
/* encrypt */
|
||||
blks = rijndael_blockEncrypt(&cipher, &aeskey, data,
|
||||
datasize * 8, data);
|
||||
break;
|
||||
}
|
||||
if (datasize != (blks / 8)) {
|
||||
printf("Failed to decrypt the entire input: "
|
||||
|
@ -55,15 +55,17 @@
|
||||
#define STAND_H /* We don't want stand.h in {gpt,zfs,gptzfs}boot */
|
||||
#include <opencrypto/xform_enc.h>
|
||||
|
||||
struct geli_entry {
|
||||
struct dsk *dsk;
|
||||
#define GELIDEV_NAMELEN 32
|
||||
|
||||
struct geli_dev {
|
||||
off_t part_end;
|
||||
struct g_eli_softc sc;
|
||||
struct g_eli_metadata md;
|
||||
int keybuf_slot;
|
||||
SLIST_ENTRY(geli_entry) entries;
|
||||
} *geli_e, *geli_e_tmp;
|
||||
char *name; /* for prompting; it ends in ':' */
|
||||
};
|
||||
|
||||
static int geli_count;
|
||||
int geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
|
||||
const u_char *key, size_t keysize, u_char *iv);
|
||||
|
||||
#endif /* _GELIBOOT_INTERNAL_H_ */
|
||||
|
323
stand/libsa/geli/gelidev.c
Normal file
323
stand/libsa/geli/gelidev.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2018 Ian Lepore <ian@FreeBSD.org>
|
||||
*
|
||||
* 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 <stand.h>
|
||||
#include <stdarg.h>
|
||||
#include <uuid.h>
|
||||
#include <sys/disk.h>
|
||||
#include "disk.h"
|
||||
#include "geliboot.h"
|
||||
#include "geliboot_internal.h"
|
||||
|
||||
static int geli_dev_init(void);
|
||||
static int geli_dev_strategy(void *, int, daddr_t, size_t, char *, size_t *);
|
||||
static int geli_dev_open(struct open_file *f, ...);
|
||||
static int geli_dev_close(struct open_file *f);
|
||||
static int geli_dev_ioctl(struct open_file *, u_long, void *);
|
||||
static int geli_dev_print(int);
|
||||
static void geli_dev_cleanup(void);
|
||||
|
||||
/*
|
||||
* geli_devsw is static because it never appears in any arch's global devsw
|
||||
* array. Instead, when devopen() opens a DEVT_DISK device, it then calls
|
||||
* geli_probe_and_attach(), and if we find that the disk_devdesc describes a
|
||||
* geli-encrypted partition, we create a geli_devdesc which references this
|
||||
* devsw and has a pointer to the original disk_devdesc of the underlying host
|
||||
* disk. Then we manipulate the open_file struct to reference the new
|
||||
* geli_devdesc, effectively routing all IO operations through our code.
|
||||
*/
|
||||
static struct devsw geli_devsw = {
|
||||
.dv_name = "gelidisk",
|
||||
.dv_type = DEVT_DISK,
|
||||
.dv_init = geli_dev_init,
|
||||
.dv_strategy = geli_dev_strategy,
|
||||
.dv_open = geli_dev_open,
|
||||
.dv_close = geli_dev_close,
|
||||
.dv_ioctl = geli_dev_ioctl,
|
||||
.dv_print = geli_dev_print,
|
||||
.dv_cleanup = geli_dev_cleanup,
|
||||
};
|
||||
|
||||
/*
|
||||
* geli_devdesc instances replace the disk_devdesc in an open_file struct when
|
||||
* the partition is encrypted. We keep a reference to the original host
|
||||
* disk_devdesc so that we can read the raw encrypted data using it.
|
||||
*/
|
||||
struct geli_devdesc {
|
||||
struct disk_devdesc ddd; /* Must be first. */
|
||||
struct disk_devdesc *hdesc; /* disk/slice/part hosting geli vol */
|
||||
struct geli_dev *gdev; /* geli_dev entry */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* A geli_readfunc that reads via a disk_devdesc passed in readpriv. This is
|
||||
* used to read the underlying host disk data when probing/tasting to see if the
|
||||
* host provider is geli-encrypted.
|
||||
*/
|
||||
static int
|
||||
diskdev_read(void *vdev, void *readpriv, off_t offbytes,
|
||||
void *buf, size_t sizebytes)
|
||||
{
|
||||
struct disk_devdesc *ddev;
|
||||
|
||||
ddev = (struct disk_devdesc *)readpriv;
|
||||
|
||||
return (ddev->dd.d_dev->dv_strategy(ddev, F_READ, offbytes / DEV_BSIZE,
|
||||
sizebytes, buf, NULL));
|
||||
}
|
||||
|
||||
static int
|
||||
geli_dev_init(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Since geli_devsw never gets referenced in any arch's global devsw
|
||||
* table, this function should never get called.
|
||||
*/
|
||||
panic("%s: should never be called", __func__);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
static int
|
||||
geli_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf,
|
||||
size_t *rsize)
|
||||
{
|
||||
struct geli_devdesc *gdesc;
|
||||
off_t alnend, alnstart, reqend, reqstart;
|
||||
size_t alnsize;
|
||||
char *iobuf;
|
||||
int rc;
|
||||
|
||||
/* We only handle reading; no write support. */
|
||||
if ((rw & F_MASK) != F_READ)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
gdesc = (struct geli_devdesc *)devdata;
|
||||
|
||||
/*
|
||||
* We can only decrypt full geli blocks. The blk arg is expressed in
|
||||
* units of DEV_BSIZE blocks, while size is in bytes. Convert
|
||||
* everything to bytes, and calculate the geli-blocksize-aligned start
|
||||
* and end points.
|
||||
*
|
||||
* Note: md_sectorsize must be cast to a signed type for the round2
|
||||
* macros to work correctly (otherwise they get zero-extended to 64 bits
|
||||
* and mask off the high order 32 bits of the requested start/end).
|
||||
*/
|
||||
|
||||
reqstart = blk * DEV_BSIZE;
|
||||
reqend = reqstart + size;
|
||||
alnstart = rounddown2(reqstart, (int)gdesc->gdev->md.md_sectorsize);
|
||||
alnend = roundup2(reqend, (int)gdesc->gdev->md.md_sectorsize);
|
||||
alnsize = alnend - alnstart;
|
||||
|
||||
/*
|
||||
* If alignment requires us to read more than the size of the provided
|
||||
* buffer, allocate a temporary buffer.
|
||||
*/
|
||||
if (alnsize <= size)
|
||||
iobuf = buf;
|
||||
else if ((iobuf = malloc(alnsize)) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/*
|
||||
* Read the encrypted data using the host provider, then decrypt it.
|
||||
*/
|
||||
rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc, rw,
|
||||
alnstart / DEV_BSIZE, alnsize, iobuf, NULL);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
rc = geli_read(gdesc->gdev, alnstart, iobuf, alnsize);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If we had to use a temporary buffer, copy the requested part of the
|
||||
* data to the caller's buffer.
|
||||
*/
|
||||
if (iobuf != buf)
|
||||
memcpy(buf, iobuf + (reqstart - alnstart), size);
|
||||
|
||||
if (rsize != NULL)
|
||||
*rsize = size;
|
||||
out:
|
||||
if (iobuf != buf)
|
||||
free(iobuf);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static int
|
||||
geli_dev_open(struct open_file *f, ...)
|
||||
{
|
||||
|
||||
/*
|
||||
* Since geli_devsw never gets referenced in any arch's global devsw
|
||||
* table, this function should never get called.
|
||||
*/
|
||||
panic("%s: should never be called", __func__);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
static int
|
||||
geli_dev_close(struct open_file *f)
|
||||
{
|
||||
struct geli_devdesc *gdesc;
|
||||
|
||||
/*
|
||||
* Detach the geli_devdesc from the open_file and reattach the
|
||||
* underlying host provider's disk_devdesc; this undoes the work done at
|
||||
* the end of geli_probe_and_attach(). Call the host provider's
|
||||
* dv_close() (because that's what our caller thought it was doing).
|
||||
*/
|
||||
gdesc = (struct geli_devdesc *)f->f_devdata;
|
||||
f->f_devdata = gdesc->hdesc;
|
||||
f->f_dev = gdesc->hdesc->dd.d_dev;
|
||||
free(gdesc);
|
||||
f->f_dev->dv_close(f);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
geli_dev_ioctl(struct open_file *f, u_long cmd, void *data)
|
||||
{
|
||||
struct geli_devdesc *gdesc;
|
||||
struct g_eli_metadata *md;
|
||||
|
||||
gdesc = (struct geli_devdesc *)f->f_devdata;
|
||||
md = &gdesc->gdev->md;
|
||||
|
||||
switch (cmd) {
|
||||
case DIOCGSECTORSIZE:
|
||||
*(u_int *)data = md->md_sectorsize;
|
||||
break;
|
||||
case DIOCGMEDIASIZE:
|
||||
*(uint64_t *)data = md->md_sectorsize * md->md_provsize;
|
||||
break;
|
||||
default:
|
||||
return (ENOTTY);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
geli_dev_print(int verbose)
|
||||
{
|
||||
|
||||
/*
|
||||
* Since geli_devsw never gets referenced in any arch's global devsw
|
||||
* table, this function should never get called.
|
||||
*/
|
||||
panic("%s: should never be called", __func__);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
static void
|
||||
geli_dev_cleanup(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Since geli_devsw never gets referenced in any arch's global devsw
|
||||
* table, this function should never get called.
|
||||
*/
|
||||
panic("%s: should never be called", __func__);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* geli_probe_and_attach() is called from devopen() after it successfully calls
|
||||
* the dv_open() method of a DEVT_DISK device. We taste the partition described
|
||||
* by the disk_devdesc, and if it's geli-encrypted and we can decrypt it, we
|
||||
* create a geli_devdesc and store it into the open_file struct in place of the
|
||||
* underlying provider's disk_devdesc, effectively attaching our code to all IO
|
||||
* processing for the partition. Not quite the elegant stacking provided by
|
||||
* geom in the kernel, but it gets the job done.
|
||||
*/
|
||||
void
|
||||
geli_probe_and_attach(struct open_file *f)
|
||||
{
|
||||
static char gelipw[GELI_PW_MAXLEN];
|
||||
const char *envpw;
|
||||
struct geli_dev *gdev;
|
||||
struct geli_devdesc *gdesc;
|
||||
struct disk_devdesc *hdesc;
|
||||
uint64_t hmediasize;
|
||||
daddr_t hlastblk;
|
||||
int rc;
|
||||
|
||||
hdesc = (struct disk_devdesc *)(f->f_devdata);
|
||||
|
||||
/* Get the last block number for the host provider. */
|
||||
hdesc->dd.d_dev->dv_ioctl(f, DIOCGMEDIASIZE, &hmediasize);
|
||||
hlastblk = (hmediasize / DEV_BSIZE) - 1;
|
||||
|
||||
/* Taste the host provider. If it's not geli-encrypted just return. */
|
||||
gdev = geli_taste(diskdev_read, hdesc, hlastblk, disk_fmtdev(hdesc));
|
||||
if (gdev == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* It's geli, try to decrypt it with existing keys, or prompt for a
|
||||
* passphrase if we don't yet have a cached key for it.
|
||||
*/
|
||||
if ((rc = geli_havekey(gdev)) != 0) {
|
||||
envpw = getenv("kern.geom.eli.passphrase");
|
||||
if (envpw != NULL) {
|
||||
/* Use the cached passphrase */
|
||||
bcopy(envpw, &gelipw, GELI_PW_MAXLEN);
|
||||
}
|
||||
if ((rc = geli_passphrase(gdev, gelipw)) == 0) {
|
||||
/* Passphrase is good, cache it. */
|
||||
setenv("kern.geom.eli.passphrase", gelipw, 1);
|
||||
}
|
||||
explicit_bzero(gelipw, sizeof(gelipw));
|
||||
if (rc != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's geli-encrypted and we can decrypt it. Create a geli_devdesc,
|
||||
* store a reference to the underlying provider's disk_devdesc in it,
|
||||
* then attach it to the openfile struct in place of the host provider.
|
||||
*/
|
||||
if ((gdesc = malloc(sizeof(*gdesc))) == NULL)
|
||||
return;
|
||||
gdesc->ddd.dd.d_dev = &geli_devsw;
|
||||
gdesc->ddd.dd.d_opendata = NULL;
|
||||
gdesc->ddd.dd.d_unit = hdesc->dd.d_unit;
|
||||
gdesc->ddd.d_offset = hdesc->d_offset;
|
||||
gdesc->ddd.d_partition = hdesc->d_partition;
|
||||
gdesc->ddd.d_slice = hdesc->d_slice;
|
||||
gdesc->hdesc = hdesc;
|
||||
gdesc->gdev = gdev;
|
||||
f->f_dev = gdesc->ddd.dd.d_dev;
|
||||
f->f_devdata = gdesc;
|
||||
}
|
@ -44,31 +44,6 @@ struct zfs_devdesc {
|
||||
#include <crypto/intake.h>
|
||||
#endif
|
||||
|
||||
struct zfs_boot_args
|
||||
{
|
||||
uint32_t size;
|
||||
uint32_t reserved;
|
||||
uint64_t pool;
|
||||
uint64_t root;
|
||||
uint64_t primary_pool;
|
||||
uint64_t primary_vdev;
|
||||
union {
|
||||
char gelipw[256];
|
||||
struct {
|
||||
char notapw; /*
|
||||
* single null byte to stop keybuf
|
||||
* being interpreted as a password
|
||||
*/
|
||||
uint32_t keybuf_sentinel;
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
struct keybuf *keybuf;
|
||||
#else
|
||||
void *keybuf;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec,
|
||||
const char **path);
|
||||
char *zfs_fmtdev(void *vdev);
|
||||
|
@ -126,7 +126,7 @@ CFLAGS+= -DLOADER_GPT_SUPPORT
|
||||
CFLAGS+= -DLOADER_MBR_SUPPORT
|
||||
.endif
|
||||
|
||||
.if defined(HAVE_ZFS)
|
||||
.if ${HAVE_ZFS:Uno} == "yes"
|
||||
CFLAGS+= -DLOADER_ZFS_SUPPORT
|
||||
CFLAGS+= -I${ZFSSRC}
|
||||
CFLAGS+= -I${SYSDIR}/cddl/boot/zfs
|
||||
|
@ -170,7 +170,7 @@ These will be picked up using the
|
||||
and
|
||||
.Ev bootenvs_count
|
||||
variables set by
|
||||
.Xr zfsloader 8 .
|
||||
.Xr loader 8 .
|
||||
.It Fn core.setDefaults
|
||||
Resets ACPI, safe mode, single user, and verbose settings to their system
|
||||
defauilts.
|
||||
|
@ -3,8 +3,5 @@
|
||||
.include <bsd.init.mk>
|
||||
|
||||
MAN+= loader.8
|
||||
.if ${MK_ZFS} != "no"
|
||||
MAN+= zfsloader.8
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -1042,6 +1042,52 @@ executed.
|
||||
.It -259
|
||||
Unspecified error.
|
||||
.El
|
||||
.Sh ZFS FEATURES
|
||||
.Nm
|
||||
supports the following format for specifying ZFS filesystems which
|
||||
can be used wherever
|
||||
.Xr loader 8
|
||||
refers to a device specification:
|
||||
.Pp
|
||||
.Ar zfs:pool/filesystem:
|
||||
.Pp
|
||||
where
|
||||
.Pa pool/filesystem
|
||||
is a ZFS filesystem name as described in
|
||||
.Xr zfs 8 .
|
||||
.Pp
|
||||
If
|
||||
.Pa /etc/fstab
|
||||
does not have an entry for the root filesystem and
|
||||
.Va vfs.root.mountfrom
|
||||
is not set, but
|
||||
.Va currdev
|
||||
refers to a ZFS filesystem, then
|
||||
.Nm
|
||||
will instruct kernel to use that filesystem as the root filesystem.
|
||||
.Sh ZFS COMMAND EXTENSIONS
|
||||
.Bl -tag -width Ds -compact
|
||||
.It Ic lsdev Op Fl v
|
||||
Lists ZFS pools in addition to disks and partitions.
|
||||
Adding
|
||||
.Fl v
|
||||
shows more ZFS pool details in a format that resembles
|
||||
.Nm zpool Cm status
|
||||
output.
|
||||
.Pp
|
||||
.It Ic lszfs Ar filesystem
|
||||
A ZFS extended command that can be used to explore the ZFS filesystem
|
||||
hierarchy in a pool.
|
||||
Lists the immediate children of the
|
||||
.Ar filesystem .
|
||||
The filesystem hierarchy is rooted at a filesystem with the same name
|
||||
as the pool.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
Set the default device used for loading a kernel from a ZFS filesystem:
|
||||
.Bd -literal -offset indent
|
||||
set currdev=zfs:tank/ROOT/knowngood:
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr libstand 3 ,
|
||||
.Xr loader.conf 5 ,
|
||||
|
@ -1,106 +0,0 @@
|
||||
.\" Copyright (c) 2014 Andriy Gapon <avg@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 AUTHOR 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 AUTHOR 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$
|
||||
.\"
|
||||
.Dd September 15, 2014
|
||||
.Dt ZFSLOADER 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm zfsloader
|
||||
.Nd kernel bootstrapping final stage
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is an extended variant of
|
||||
.Xr loader 8
|
||||
with added support for booting from ZFS.
|
||||
This document describes only differences from
|
||||
.Xr loader 8 .
|
||||
.Sh ZFS FEATURES
|
||||
.Nm
|
||||
supports the following format for specifying ZFS filesystems which
|
||||
can be used wherever
|
||||
.Xr loader 8
|
||||
refers to a device specification:
|
||||
.Pp
|
||||
.Ar zfs:pool/filesystem:
|
||||
.Pp
|
||||
where
|
||||
.Pa pool/filesystem
|
||||
is a ZFS filesystem name as described in
|
||||
.Xr zfs 8 .
|
||||
.Pp
|
||||
If
|
||||
.Pa /etc/fstab
|
||||
does not have an entry for the root filesystem and
|
||||
.Va vfs.root.mountfrom
|
||||
is not set, but
|
||||
.Va currdev
|
||||
refers to a ZFS filesystem, then
|
||||
.Nm
|
||||
will instruct kernel to use that filesystem as the root filesystem.
|
||||
.Sh ZFS COMMAND EXTENSIONS
|
||||
.Bl -tag -width Ds -compact
|
||||
.It Ic lsdev Op Fl v
|
||||
Lists ZFS pools in addition to disks and partitions.
|
||||
Adding
|
||||
.Fl v
|
||||
shows more ZFS pool details in a format that resembles
|
||||
.Nm zpool Cm status
|
||||
output.
|
||||
.Pp
|
||||
.It Ic lszfs Ar filesystem
|
||||
A ZFS extended command that can be used to explore the ZFS filesystem
|
||||
hierarchy in a pool.
|
||||
Lists the immediate children of the
|
||||
.Ar filesystem .
|
||||
The filesystem hierarchy is rooted at a filesystem with the same name
|
||||
as the pool.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width /boot/zfsloader -compact
|
||||
.It Pa /boot/zfsloader
|
||||
.Nm
|
||||
itself.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
Set the default device used for loading a kernel from a ZFS filesystem:
|
||||
.Bd -literal -offset indent
|
||||
set currdev=zfs:tank/ROOT/knowngood:
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr gptzfsboot 8 ,
|
||||
.Xr loader 8 ,
|
||||
.Xr zfs 8 ,
|
||||
.Xr zfsboot 8 ,
|
||||
.Xr zfsloader 8 ,
|
||||
.Xr zpool 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
first appeared in
|
||||
.Fx 7.3 .
|
||||
.Sh AUTHORS
|
||||
This manual page was written by
|
||||
.An Andriy Gapon Aq avg@FreeBSD.org .
|
@ -5,6 +5,6 @@ NO_OBJ=t
|
||||
.include <bsd.init.mk>
|
||||
|
||||
SUBDIR.yes= boot1 loader
|
||||
SUBDIR.${MK_ZFS}+=zfsboot zfsloader
|
||||
SUBDIR.${MK_LOADER_ZFS}+=zfsboot
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
@ -1,5 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
HAVE_ZFS= ${MK_LOADER_ZFS}
|
||||
|
||||
LOADER_DISK_SUPPORT?= yes
|
||||
LOADER_UFS_SUPPORT?= yes
|
||||
LOADER_CD9660_SUPPORT?= yes
|
||||
@ -19,7 +21,7 @@ NEWVERSWHAT?= "bootstrap loader" sparc64
|
||||
VERSION_FILE= ${.CURDIR}/../loader/version
|
||||
INSTALLFLAGS= -b
|
||||
|
||||
.if ${MK_ZFS} != "no"
|
||||
.if ${MK_LOADER_ZFS} != "no"
|
||||
HAVE_ZFS= yes
|
||||
.endif
|
||||
|
||||
@ -40,6 +42,10 @@ HELP_FILES= ${.CURDIR}/help.sparc64
|
||||
|
||||
LDFLAGS+= -static
|
||||
|
||||
.if ${MK_LOADER_ZFS} == "yes"
|
||||
LINKS= ${BINDIR}/loader ${BINDIR}/zfsloader
|
||||
.endif
|
||||
|
||||
# Open Firmware standalone support library
|
||||
LIBOFW= ${BOOTOBJ}/ofw/libofw/libofw.a
|
||||
CFLAGS+= -I${BOOTSRC}/ofw/libofw/
|
||||
|
@ -1,8 +0,0 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= zfsloader
|
||||
NEWVERSWHAT= "ZFS enabled bootstrap loader" sparc64
|
||||
HAVE_ZFS= yes
|
||||
CFLAGS+= -DBOOTPROG=\"zfsloader\"
|
||||
|
||||
.include "${.CURDIR}/../loader/Makefile"
|
@ -39,7 +39,7 @@ LDFLAGS+= -nostdlib -Wl,-Bsymbolic
|
||||
|
||||
NEWVERSWHAT= "User boot" ${MACHINE_CPUARCH}
|
||||
|
||||
.if ${MK_ZFS} != "no"
|
||||
.if ${MK_LOADER_ZFS} != "no"
|
||||
CFLAGS+= -DUSERBOOT_ZFS_SUPPORT
|
||||
HAVE_ZFS=yes
|
||||
.endif
|
||||
|
@ -36,6 +36,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include "bootstrap.h"
|
||||
#include "libuserboot.h"
|
||||
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
#include "geliboot.h"
|
||||
#endif
|
||||
|
||||
static struct bootinfo bi;
|
||||
|
||||
/*
|
||||
@ -200,6 +204,9 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t
|
||||
file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
|
||||
file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
|
||||
bios_addsmapdata(kfp);
|
||||
#ifdef LOADER_GELI_SUPPORT
|
||||
geli_export_key_metadata(kfp);
|
||||
#endif
|
||||
|
||||
/* Figure out the size and location of the metadata */
|
||||
*modulep = addr;
|
||||
|
2
tools/build/options/WITHOUT_LOADER_ZFS
Normal file
2
tools/build/options/WITHOUT_LOADER_ZFS
Normal file
@ -0,0 +1,2 @@
|
||||
.\" $FreeBSD$
|
||||
Set to not build ZFS file system boot loader support.
|
@ -1,2 +1,2 @@
|
||||
.\" $FreeBSD$
|
||||
Set to not build ZFS file system.
|
||||
Set to not build ZFS file system kernel module, libraries, and user commands.
|
||||
|
Loading…
x
Reference in New Issue
Block a user