Page MenuHomeFreeBSD

D5820.id14851.diff
No OneTemporary

D5820.id14851.diff

Index: sys/boot/geli/geliboot.h
===================================================================
--- sys/boot/geli/geliboot.h
+++ sys/boot/geli/geliboot.h
@@ -55,6 +55,9 @@
#ifndef DEV_BSIZE
#define DEV_BSIZE 512
#endif
+#ifndef DEV_4KSEC
+#define DEV_4KSEC 4096
+#endif
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
Index: sys/boot/geli/geliboot.c
===================================================================
--- sys/boot/geli/geliboot.c
+++ sys/boot/geli/geliboot.c
@@ -73,14 +73,18 @@
size_t bytes), struct dsk *dskp, daddr_t lastsector)
{
struct g_eli_metadata md;
- u_char buf[DEV_BSIZE];
+ u_char buf[DEV_BSIZE], rawbuf[DEV_4KSEC];
int error;
+ off_t alignbyte;
- error = read_func(NULL, dskp, (off_t) lastsector * DEV_BSIZE, &buf,
- (size_t) DEV_BSIZE);
+ alignbyte = (off_t)(lastsector * DEV_BSIZE) & ~ (off_t)(DEV_4KSEC - 1);
+ error = read_func(NULL, dskp, alignbyte, &rawbuf, (size_t) DEV_4KSEC);
if (error != 0) {
return (error);
}
+ /* Extract the last 512 bytes from the 4k sector */
+ memcpy(&buf, rawbuf + (DEV_4KSEC - DEV_BSIZE), DEV_BSIZE);
+
error = eli_metadata_decode(buf, &md);
if (error != 0) {
return (error);
@@ -229,35 +233,47 @@
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 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;
+ 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: sys/boot/i386/libi386/biosdisk.c
===================================================================
--- sys/boot/i386/libi386/biosdisk.c
+++ sys/boot/i386/libi386/biosdisk.c
@@ -706,15 +706,29 @@
{
#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 4k else 4k sector GELIs will not decrypt */
+ /* Round LBA down to nearest multiple of 4096 bytes */
+ alignlba = dblk & ~ (daddr_t)(8 - 1);
+ /* Round number of blocks up to nearest multiple of 4096 */
+ alignblks = blks + (dblk - alignlba) + (8 - 1) & ~ (int)(8 - 1);
+ diff = (dblk - alignlba) * BIOSDISK_SECSIZE;
+ /*
+ * Use a temporary buffer here because the buffer provided by
+ * the caller may be too small, and we don't want to overflow it
+ */
+ tmpbuf = alloca(alignblks * BIOSDISK_SECSIZE);
+
+ err = bd_io(dev, alignlba, alignblks, tmpbuf, 0);
if (err)
return (err);
@@ -726,13 +740,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: sys/boot/i386/zfsboot/zfsboot.c
===================================================================
--- sys/boot/i386/zfsboot/zfsboot.c
+++ sys/boot/i386/zfsboot/zfsboot.c
@@ -59,6 +59,8 @@
#define TYPE_MAXHARD TYPE_DA
#define TYPE_FD 2
+#define DEV_4KSEC 4096
+
extern uint32_t _end;
#ifdef GPT
@@ -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,42 @@
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_4KSEC - 1);
+ /* Round LBA down to nearest multiple of 4096 bytes */
+ alignlba = alignoff / DEV_BSIZE;
+ /* The read must be 4k aligned to the GELI partition, not the 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))
+ /* Don't overflow the read buffer */
+ if (nb * DEV_BSIZE + diff > READ_BUF_SIZE)
+ nb -= diff / DEV_BSIZE;
+ /* Round number of blocks up to nearest multiple of 4096 */
+ alignnb = nb + (diff / DEV_BSIZE) + (DEV_4KSEC / DEV_BSIZE - 1)
+ & ~ (unsigned int)(DEV_4KSEC / 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 leadingg offset after the first block */
+ diff = 0;
}
return 0;

File Metadata

Mime Type
text/plain
Expires
Sun, May 24, 2:37 PM (3 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33474626
Default Alt Text
D5820.id14851.diff (6 KB)

Event Timeline