Page MenuHomeFreeBSD

D5820.id.diff
No OneTemporary

D5820.id.diff

Index: head/sys/boot/geli/geliboot.h
===================================================================
--- head/sys/boot/geli/geliboot.h
+++ head/sys/boot/geli/geliboot.h
@@ -55,6 +55,9 @@
#ifndef DEV_BSIZE
#define DEV_BSIZE 512
#endif
+#ifndef DEV_GELIBOOT_BSIZE
+#define DEV_GELIBOOT_BSIZE 4096
+#endif
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
Index: head/sys/boot/geli/geliboot.c
===================================================================
--- head/sys/boot/geli/geliboot.c
+++ head/sys/boot/geli/geliboot.c
@@ -73,30 +73,34 @@
size_t bytes), struct dsk *dskp, daddr_t lastsector)
{
struct g_eli_metadata md;
- u_char buf[DEV_BSIZE];
+ u_char buf[DEV_GELIBOOT_BSIZE];
int error;
+ off_t alignsector;
- error = read_func(NULL, dskp, (off_t) lastsector * DEV_BSIZE, &buf,
- (size_t) DEV_BSIZE);
+ alignsector = (lastsector * DEV_BSIZE) &
+ ~(off_t)(DEV_GELIBOOT_BSIZE - 1);
+ error = read_func(NULL, dskp, alignsector, &buf, DEV_GELIBOOT_BSIZE);
if (error != 0) {
return (error);
}
- error = eli_metadata_decode(buf, &md);
+ /* Extract the last DEV_BSIZE bytes from the block. */
+ error = eli_metadata_decode(buf + (DEV_GELIBOOT_BSIZE - DEV_BSIZE),
+ &md);
if (error != 0) {
return (error);
}
if ((md.md_flags & G_ELI_FLAG_ONETIME)) {
- /* Swap device, skip it */
+ /* Swap device, skip it. */
return (1);
}
if (!(md.md_flags & G_ELI_FLAG_BOOT)) {
- /* Disk is not GELI boot device, skip it */
+ /* Disk is not GELI boot device, skip it. */
return (1);
}
if (md.md_iterations < 0) {
- /* XXX TODO: Support loading key files */
- /* Disk does not have a passphrase, skip it */
+ /* XXX TODO: Support loading key files. */
+ /* Disk does not have a passphrase, skip it. */
return (1);
}
geli_e = malloc(sizeof(struct geli_entry));
@@ -143,7 +147,7 @@
* Prepare Derived-Key from the user passphrase.
*/
if (geli_e->md.md_iterations < 0) {
- /* XXX TODO: Support loading key files */
+ /* 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,
@@ -151,8 +155,8 @@
g_eli_crypto_hmac_update(&ctx, passphrase,
strlen(passphrase));
} else if (geli_e->md.md_iterations > 0) {
- printf("Calculating GELI Decryption Key disk%dp%d @ %lu "
- "iterations...\n", dskp->unit,
+ printf("Calculating GELI Decryption Key disk%dp%d @ %lu"
+ " iterations...\n", dskp->unit,
(dskp->slice > 0 ? dskp->slice : dskp->part),
geli_e->md.md_iterations);
u_char dkey[G_ELI_USERKEYLEN];
@@ -193,7 +197,7 @@
}
bzero(&mkey, sizeof(mkey));
- /* Initialize the per-sector IV */
+ /* Initialize the per-sector IV. */
switch (geli_e->sc.sc_ealgo) {
case CRYPTO_AES_XTS:
break;
@@ -207,7 +211,7 @@
return (0);
}
- /* Disk not found */
+ /* Disk not found. */
return (2);
}
@@ -229,35 +233,49 @@
u_char iv[G_ELI_IVKEYLEN];
u_char *pbuf;
int error;
- off_t os;
+ off_t dstoff;
uint64_t keyno;
- size_t n, nb;
+ size_t n, nsec, secsize;
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;
}
- nb = bytes / DEV_BSIZE;
- for (n = 0; n < nb; n++) {
- os = offset + (n * DEV_BSIZE);
- pbuf = buf + (n * DEV_BSIZE);
+ 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, os, iv, G_ELI_IVKEYLEN);
+ g_eli_crypto_ivgen(&geli_e->sc, dstoff, iv,
+ G_ELI_IVKEYLEN);
- /* Get the key that corresponds to this offset */
- keyno = (os >> G_ELI_KEY_SHIFT) / DEV_BSIZE;
+ /* 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,
- DEV_BSIZE, gkey.gek_key, geli_e->sc.sc_ekeylen, iv);
+ secsize, gkey.gek_key,
+ geli_e->sc.sc_ekeylen, iv);
if (error != 0) {
bzero(&gkey, sizeof(gkey));
printf("Failed to decrypt in geli_read()!");
return (error);
}
+ pbuf += secsize;
}
bzero(&gkey, sizeof(gkey));
return (0);
Index: head/sys/boot/i386/libi386/biosdisk.c
===================================================================
--- head/sys/boot/i386/libi386/biosdisk.c
+++ head/sys/boot/i386/libi386/biosdisk.c
@@ -706,15 +706,38 @@
{
#ifdef LOADER_GELI_SUPPORT
struct dsk dskp;
- off_t p_off;
- int err, n;
+ 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->d_unit][dev->d_slice] != ISGELI_YES)
return (bd_io(dev, dblk, blks, dest, 0));
if (geli_status[dev->d_unit][dev->d_slice] == ISGELI_YES) {
- err = bd_io(dev, dblk, blks, dest, 0);
+ /*
+ * 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 = dblk &
+ ~(daddr_t)((DEV_GELIBOOT_BSIZE / BIOSDISK_SECSIZE) - 1);
+ /*
+ * Round number of blocks to read up to nearest multiple of
+ * DEV_GELIBOOT_BSIZE
+ */
+ alignblks = blks + (dblk - alignlba) +
+ ((DEV_GELIBOOT_BSIZE / BIOSDISK_SECSIZE) - 1) &
+ ~(int)((DEV_GELIBOOT_BSIZE / BIOSDISK_SECSIZE) - 1);
+ diff = (dblk - alignlba) * BIOSDISK_SECSIZE;
+ /*
+ * Use a temporary buffer here because the buffer provided by
+ * the caller may be too small.
+ */
+ tmpbuf = alloca(alignblks * BIOSDISK_SECSIZE);
+
+ err = bd_io(dev, alignlba, alignblks, tmpbuf, 0);
if (err)
return (err);
@@ -726,13 +749,14 @@
dskp.start = dev->d_offset;
/* GELI needs the offset relative to the partition start */
- p_off = dblk - dskp.start;
+ p_off = alignlba - dskp.start;
- err = geli_read(&dskp, p_off * BIOSDISK_SECSIZE, dest,
- blks * BIOSDISK_SECSIZE);
+ err = geli_read(&dskp, p_off * BIOSDISK_SECSIZE, tmpbuf,
+ alignblks * BIOSDISK_SECSIZE);
if (err)
return (err);
+ bcopy(tmpbuf + diff, dest, blks * BIOSDISK_SECSIZE);
return (0);
}
#endif /* LOADER_GELI_SUPPORT */
Index: head/sys/boot/i386/zfsboot/zfsboot.c
===================================================================
--- head/sys/boot/i386/zfsboot/zfsboot.c
+++ head/sys/boot/i386/zfsboot/zfsboot.c
@@ -46,18 +46,20 @@
#include "libzfs.h"
-#define ARGS 0x900
-#define NOPT 14
-#define NDEV 3
-
-#define BIOS_NUMDRIVES 0x475
-#define DRV_HARD 0x80
-#define DRV_MASK 0x7f
-
-#define TYPE_AD 0
-#define TYPE_DA 1
-#define TYPE_MAXHARD TYPE_DA
-#define TYPE_FD 2
+#define ARGS 0x900
+#define NOPT 14
+#define NDEV 3
+
+#define BIOS_NUMDRIVES 0x475
+#define DRV_HARD 0x80
+#define DRV_MASK 0x7f
+
+#define TYPE_AD 0
+#define TYPE_DA 1
+#define TYPE_MAXHARD TYPE_DA
+#define TYPE_FD 2
+
+#define DEV_GELIBOOT_BSIZE 4096
extern uint32_t _end;
@@ -104,13 +106,13 @@
/*
* The minimum amount of memory to reserve in bios_extmem for the heap.
*/
-#define HEAP_MIN (3 * 1024 * 1024)
+#define HEAP_MIN (3 * 1024 * 1024)
static char *heap_next;
static char *heap_end;
/* Buffers that must not span a 64k boundary. */
-#define READ_BUF_SIZE 8192
+#define READ_BUF_SIZE 8192
struct dmadat {
char rdbuf[READ_BUF_SIZE]; /* for reading large things */
char secbuf[READ_BUF_SIZE]; /* for MBR/disklabel */
@@ -198,8 +200,9 @@
vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
{
char *p;
- daddr_t lba;
- unsigned int nb;
+ daddr_t lba, alignlba;
+ off_t alignoff, diff;
+ unsigned int nb, alignnb;
struct dsk *dsk = (struct dsk *) priv;
if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
@@ -208,24 +211,52 @@
p = buf;
lba = off / DEV_BSIZE;
lba += dsk->start;
+ /* Align reads to 4k else 4k sector GELIs will not decrypt. */
+ alignoff = off & ~ (off_t)(DEV_GELIBOOT_BSIZE - 1);
+ /* Round LBA down to nearest multiple of DEV_GELIBOOT_BSIZE bytes. */
+ alignlba = alignoff / DEV_BSIZE;
+ /*
+ * 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;
+ diff = (lba - alignlba) * DEV_BSIZE;
+
while (bytes > 0) {
nb = bytes / DEV_BSIZE;
if (nb > READ_BUF_SIZE / DEV_BSIZE)
nb = READ_BUF_SIZE / DEV_BSIZE;
- if (drvread(dsk, dmadat->rdbuf, lba, nb))
+ /*
+ * Ensure that the read size plus the leading offset does not
+ * exceed the size of the read buffer.
+ */
+ if (nb * DEV_BSIZE + diff > READ_BUF_SIZE)
+ nb -= diff / DEV_BSIZE;
+ /*
+ * Round the number of blocks to read up to the nearest multiple
+ * of DEV_GELIBOOT_BSIZE.
+ */
+ alignnb = nb + (diff / DEV_BSIZE) +
+ (DEV_GELIBOOT_BSIZE / DEV_BSIZE - 1) & ~
+ (unsigned int)(DEV_GELIBOOT_BSIZE / DEV_BSIZE - 1);
+
+ if (drvread(dsk, dmadat->rdbuf, alignlba, alignnb))
return -1;
#ifdef LOADER_GELI_SUPPORT
/* decrypt */
if (is_geli(dsk) == 0) {
- if (geli_read(dsk, ((lba - dsk->start) * DEV_BSIZE),
- dmadat->rdbuf, nb * DEV_BSIZE))
- return (-1);
+ if (geli_read(dsk, ((alignlba - dsk->start) *
+ DEV_BSIZE), dmadat->rdbuf, alignnb * DEV_BSIZE))
+ return (-1);
}
#endif
- memcpy(p, dmadat->rdbuf, nb * DEV_BSIZE);
+ memcpy(p, dmadat->rdbuf + diff, nb * DEV_BSIZE);
p += nb * DEV_BSIZE;
lba += nb;
+ alignlba += alignnb;
bytes -= nb * DEV_BSIZE;
+ /* Don't need the leading offset after the first block. */
+ diff = 0;
}
return 0;

File Metadata

Mime Type
text/plain
Expires
Tue, Mar 31, 3:56 AM (6 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30617927
Default Alt Text
D5820.id.diff (9 KB)

Event Timeline