Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F150191422
D5820.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D5820.id.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D5820: Fix GELIBoot support if GELI sector size is > 512
Attached
Detach File
Event Timeline
Log In to Comment