Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F171445269
D10236.id26933.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
D10236.id26933.diff
View Options
Index: sys/boot/geli/geliboot.h
===================================================================
--- sys/boot/geli/geliboot.h
+++ sys/boot/geli/geliboot.h
@@ -53,7 +53,7 @@
void *buf, size_t bytes), struct dsk *dsk, daddr_t lastsector);
int geli_attach(struct dsk *dskp, const char *passphrase, const u_char *mkeyp);
int is_geli(struct dsk *dsk);
-int geli_read(struct dsk *dsk, off_t offset, u_char *buf, size_t bytes);
+int geli_io(struct dsk *dsk, int enc, 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);
Index: sys/boot/geli/geliboot.c
===================================================================
--- sys/boot/geli/geliboot.c
+++ sys/boot/geli/geliboot.c
@@ -334,7 +334,7 @@
}
int
-geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes)
+geli_io(struct dsk *dskp, int enc, off_t offset, u_char *buf, size_t bytes)
{
u_char iv[G_ELI_IVKEYLEN];
u_char *pbuf;
@@ -372,13 +372,14 @@
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,
+ error = geliboot_crypt(geli_e->sc.sc_ealgo, enc, 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()!");
+ printf("Failed to %s in geli_io()!",
+ enc ? "encrypt" : "decrypt");
return (error);
}
pbuf += secsize;
Index: sys/boot/i386/gptboot/gptboot.c
===================================================================
--- sys/boot/i386/gptboot/gptboot.c
+++ sys/boot/i386/gptboot/gptboot.c
@@ -603,7 +603,7 @@
#ifdef LOADER_GELI_SUPPORT
if (err == 0 && is_geli(&dsk) == 0) {
/* Decrypt */
- if (geli_read(&dsk, lba * DEV_BSIZE, buf, nblk * DEV_BSIZE))
+ if (geli_io(&dsk, 0, lba * DEV_BSIZE, buf, nblk * DEV_BSIZE))
return (err);
}
#endif
Index: sys/boot/i386/libi386/biosdisk.c
===================================================================
--- sys/boot/i386/libi386/biosdisk.c
+++ sys/boot/i386/libi386/biosdisk.c
@@ -834,10 +834,6 @@
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) {
/*
* Align reads to DEV_GELIBOOT_BSIZE bytes because partial
@@ -882,7 +878,7 @@
/* GELI needs the offset relative to the partition start */
p_off = alignlba - dskp.start;
- err = geli_read(&dskp, p_off * BD(dev).bd_sectorsize, tmpbuf,
+ err = geli_io(&dskp, 0, p_off * BD(dev).bd_sectorsize, tmpbuf,
alignblks * BD(dev).bd_sectorsize);
if (err)
return (err);
@@ -902,6 +898,78 @@
bd_write(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 (geli_status[dev->d_unit][dev->d_slice] == ISGELI_YES) {
+ dskp.drive = bd_unit2bios(dev->d_unit);
+ dskp.type = dev->d_type;
+ dskp.unit = dev->d_unit;
+ dskp.slice = dev->d_slice;
+ dskp.part = dev->d_partition;
+ dskp.start = dev->d_offset;
+ /*
+ * Align writes to DEV_GELIBOOT_BSIZE bytes because partial
+ * sectors cannot be encrypted. 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;
+ /* GELI needs the offset relative to the partition start */
+ p_off = alignlba - dskp.start;
+ /*
+ * 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);
+ }
+ /*
+ * Unaligned writes require read/modify/write.
+ */
+ err = bd_io(dev, alignlba, DEV_GELIBOOT_BSIZE, tmpbuf,
+ 0);
+ if (err)
+ return (err);
+ /* Decrypt */
+ err = geli_io(&dskp, 0, p_off * BD(dev).bd_sectorsize,
+ tmpbuf, DEV_GELIBOOT_BSIZE);
+ if (err)
+ return (err);
+ bcopy(dest, tmpbuf + diff, blks * BD(dev).bd_sectorsize);
+ }
+
+ err = geli_io(&dskp, 0, p_off * BD(dev).bd_sectorsize, tmpbuf,
+ alignblks * BD(dev).bd_sectorsize);
+ if (err)
+ return (err);
+
+ err = bd_io(dev, alignlba, alignblks, tmpbuf, 1);
+ if (err)
+ return (err);
+
+ if (tmpbuf != dest) {
+ free(tmpbuf);
+ }
+ return (0);
+ }
+#endif /* LOADER_GELI_SUPPORT */
return (bd_io(dev, dblk, blks, dest, 1));
}
Index: sys/boot/i386/zfsboot/zfsboot.c
===================================================================
--- sys/boot/i386/zfsboot/zfsboot.c
+++ sys/boot/i386/zfsboot/zfsboot.c
@@ -201,10 +201,14 @@
vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
{
char *p;
- daddr_t lba, alignlba;
- off_t diff;
- unsigned int nb, alignnb;
+ daddr_t lba;
+ unsigned int nb;
struct dsk *dsk = (struct dsk *) priv;
+#ifdef LOADER_GELI_SUPPORT
+ daddr_t alignlba;
+ off_t diff;
+ unsigned int alignnb;
+#endif
if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
return -1;
@@ -212,6 +216,7 @@
p = buf;
lba = off / DEV_BSIZE;
lba += dsk->start;
+#ifdef LOADER_GELI_SUPPORT
/*
* Align reads to 4k else 4k sector GELIs will not decrypt.
* Round LBA down to nearest multiple of DEV_GELIBOOT_BSIZE bytes.
@@ -223,9 +228,11 @@
*/
alignlba += dsk->start;
diff = (lba - alignlba) * DEV_BSIZE;
+#endif
while (bytes > 0) {
nb = bytes / DEV_BSIZE;
+#ifdef LOADER_GELI_SUPPORT
/*
* Ensure that the read size plus the leading offset does not
* exceed the size of the read buffer.
@@ -241,21 +248,26 @@
if (drvread(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 (geli_io(dsk, 0, ((alignlba - dsk->start) *
DEV_BSIZE), dmadat->rdbuf, alignnb * DEV_BSIZE))
return (-1);
}
-#endif
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;
+#else
+ if (nb > READ_BUF_SIZE / DEV_BSIZE)
+ nb = READ_BUF_SIZE / DEV_BSIZE;
+ if (drvread(dsk, dmadat->rdbuf, lba, nb))
+ return -1;
+ memcpy(p, dmadat->rdbuf, nb * DEV_BSIZE);
+#endif
+ p += nb * DEV_BSIZE;
+ lba += nb;
+ bytes -= nb * DEV_BSIZE;
}
return 0;
@@ -268,6 +280,11 @@
daddr_t lba;
unsigned int nb;
struct dsk *dsk = (struct dsk *) priv;
+#ifdef LOADER_GELI_SUPPORT
+ daddr_t alignlba;
+ off_t diff;
+ unsigned int alignnb;
+#endif
if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
return -1;
@@ -275,13 +292,68 @@
p = buf;
lba = off / DEV_BSIZE;
lba += dsk->start;
+#ifdef LOADER_GELI_SUPPORT
+ /*
+ * Align writes to 4k else 4k sector GELIs will not decrypt.
+ * Round LBA down to nearest multiple of DEV_GELIBOOT_BSIZE bytes.
+ */
+ alignlba = rounddown2(off, DEV_GELIBOOT_BSIZE) / 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;
+#endif
+
while (bytes > 0) {
nb = bytes / DEV_BSIZE;
+#ifdef LOADER_GELI_SUPPORT
+ /*
+ * Ensure that the write size plus the leading offset does not
+ * exceed the size of the buffer.
+ */
+ if (nb > (READ_BUF_SIZE - diff) / DEV_BSIZE)
+ nb = (READ_BUF_SIZE - diff) / DEV_BSIZE;
+ /*
+ * Round the number of blocks to read up to the nearest multiple
+ * of DEV_GELIBOOT_BSIZE.
+ */
+ alignnb = roundup2(nb * DEV_BSIZE + diff, DEV_GELIBOOT_BSIZE)
+ / DEV_BSIZE;
+
+ /*
+ * Unaligned writes require read/modify/write.
+ */
+ if (diff > 0) {
+ vdev_read(vdev, priv, alignlba * DEV_BSIZE,
+ dmadat->rdbuf, DEV_GELIBOOT_BSIZE);
+ if (is_geli(dsk) == 0) {
+ if (geli_io(dsk, 0, ((alignlba - dsk->start) *
+ DEV_BSIZE), dmadat->rdbuf,
+ DEV_GELIBOOT_BSIZE))
+ return (-1);
+ }
+ }
+ memcpy(dmadat->rdbuf + diff, p, nb * DEV_BSIZE);
+ /* encrypt */
+ if (is_geli(dsk) == 0) {
+ if (geli_io(dsk, 1, ((alignlba - dsk->start) *
+ DEV_BSIZE), dmadat->rdbuf, alignnb * DEV_BSIZE))
+ return (-1);
+ }
+ if (drvwrite(dsk, dmadat->rdbuf, alignlba, alignnb))
+ return -1;
+ alignlba += alignnb;
+ /* Don't need the leading offset after the first block. */
+ diff = 0;
+#else
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))
return -1;
+#endif
p += nb * DEV_BSIZE;
lba += nb;
bytes -= nb * DEV_BSIZE;
@@ -717,7 +789,7 @@
primary_vdev = spa_get_primary_vdev(spa);
nextboot = 0;
- rc = vdev_read_pad2(primary_vdev, cmd, sizeof(cmd));
+ rc = vdev_read_pad2(primary_vdev, cmd, sizeof(cmd));
if (vdev_clear_pad2(primary_vdev))
printf("failed to clear pad2 area of primary vdev\n");
if (rc == 0) {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Sep 12, 4:12 AM (15 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38763177
Default Alt Text
D10236.id26933.diff (9 KB)
Attached To
Mode
D10236: Implement the ability for GELIBoot to write encrypted data zfsbootcfg(8) depends on being able to write a valid block of zeros with the correct ZFS checksum to the PAD2 area of the first ZFS vdev label When the disk is encrypted with GELI...
Attached
Detach File
Event Timeline
Log In to Comment