summaryrefslogtreecommitdiff
path: root/stand
diff options
context:
space:
mode:
authorToomas Soome <tsoome@FreeBSD.org>2020-07-11 06:51:42 +0000
committerToomas Soome <tsoome@FreeBSD.org>2020-07-11 06:51:42 +0000
commitde776da3239ee3edc5f77bd0e48d0bb15262024b (patch)
tree1eafb95a729e033fce791c26cb18e46b999fb253 /stand
parenta0b083fbda682edb11b8dab28063967eba0ccc11 (diff)
downloadsrc-test-de776da3239ee3edc5f77bd0e48d0bb15262024b.tar.gz
src-test-de776da3239ee3edc5f77bd0e48d0bb15262024b.zip
loader: implement GELI writes
Bug: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=247482 This patch is based on initial work from allanjude. PR: 247482 Obtained from: https://reviews.freebsd.org/D10236 Differential Revision: https://reviews.freebsd.org/D25605
Notes
Notes: svn path=/head/; revision=363090
Diffstat (limited to 'stand')
-rw-r--r--stand/i386/gptboot/gptboot.c2
-rw-r--r--stand/libsa/geli/geliboot.c8
-rw-r--r--stand/libsa/geli/geliboot.h10
-rw-r--r--stand/libsa/geli/geliboot_crypto.c32
-rw-r--r--stand/libsa/geli/geliboot_internal.h4
-rw-r--r--stand/libsa/geli/gelidev.c75
6 files changed, 85 insertions, 46 deletions
diff --git a/stand/i386/gptboot/gptboot.c b/stand/i386/gptboot/gptboot.c
index 7b5423ede6d89..78d876554c86c 100644
--- a/stand/i386/gptboot/gptboot.c
+++ b/stand/i386/gptboot/gptboot.c
@@ -610,7 +610,7 @@ dskread(void *buf, daddr_t lba, unsigned nblk)
#ifdef LOADER_GELI_SUPPORT
if (err == 0 && gdsk.gdev != NULL) {
/* Decrypt */
- if (geli_read(gdsk.gdev, lba * DEV_BSIZE, buf,
+ if (geli_io(gdsk.gdev, GELI_DECRYPT, lba * DEV_BSIZE, buf,
nblk * DEV_BSIZE))
return (err);
}
diff --git a/stand/libsa/geli/geliboot.c b/stand/libsa/geli/geliboot.c
index 00b9af93573a2..954a3ec340448 100644
--- a/stand/libsa/geli/geliboot.c
+++ b/stand/libsa/geli/geliboot.c
@@ -310,7 +310,8 @@ found_key:
}
int
-geli_read(struct geli_dev *gdev, off_t offset, u_char *buf, size_t bytes)
+geli_io(struct geli_dev *gdev, geli_op_t enc, off_t offset, u_char *buf,
+ size_t bytes)
{
u_char iv[G_ELI_IVKEYLEN];
u_char *pbuf;
@@ -343,12 +344,13 @@ geli_read(struct geli_dev *gdev, off_t offset, u_char *buf, size_t bytes)
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,
+ error = geliboot_crypt(gdev->sc.sc_ealgo, enc, 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()!");
+ printf("%s: Failed to %s!", __func__,
+ enc ? "encrypt" : "decrypt");
return (error);
}
pbuf += secsize;
diff --git a/stand/libsa/geli/geliboot.h b/stand/libsa/geli/geliboot.h
index aeebde4b0a2ed..0c2ef817e97d0 100644
--- a/stand/libsa/geli/geliboot.h
+++ b/stand/libsa/geli/geliboot.h
@@ -50,6 +50,11 @@
#define GELI_KEYBUF_SIZE (sizeof(struct keybuf) + \
(GELI_MAX_KEYS * sizeof(struct keybuf_ent)))
+typedef enum geli_op {
+ GELI_DECRYPT,
+ GELI_ENCRYPT
+} geli_op_t;
+
extern void pwgets(char *buf, int n, int hide);
typedef u_char geli_ukey[G_ELI_USERKEYLEN];
@@ -73,9 +78,10 @@ struct preloaded_file;
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,
+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_io(struct geli_dev *gdev, geli_op_t, 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);
diff --git a/stand/libsa/geli/geliboot_crypto.c b/stand/libsa/geli/geliboot_crypto.c
index e2de7bba4cf58..8478d2754d6f4 100644
--- a/stand/libsa/geli/geliboot_crypto.c
+++ b/stand/libsa/geli/geliboot_crypto.c
@@ -35,7 +35,7 @@
#include "geliboot.h"
int
-geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
+geliboot_crypt(u_int algo, geli_op_t enc, u_char *data, size_t datasize,
const u_char *key, size_t keysize, u_char *iv)
{
keyInstance aeskey;
@@ -49,7 +49,7 @@ geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
err = rijndael_makeKey(&aeskey, !enc, keysize,
(const char *)key);
if (err < 0) {
- printf("Failed to setup decryption keys: %d\n", err);
+ printf("Failed to setup crypo keys: %d\n", err);
return (err);
}
@@ -59,18 +59,20 @@ geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
return (err);
}
- if (enc == 0) {
- /* decrypt */
+ switch (enc) {
+ case GELI_DECRYPT:
blks = rijndael_blockDecrypt(&cipher, &aeskey, data,
datasize * 8, data);
- } else {
- /* encrypt */
+ break;
+ case GELI_ENCRYPT:
blks = rijndael_blockEncrypt(&cipher, &aeskey, data,
datasize * 8, data);
+ break;
}
if (datasize != (blks / 8)) {
- printf("Failed to decrypt the entire input: "
- "%u != %zu\n", blks, datasize);
+ printf("Failed to %s the entire input: %u != %zu\n",
+ enc ? "decrypt" : "encrypt",
+ blks, datasize);
return (1);
}
break;
@@ -82,16 +84,16 @@ geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
enc_xform_aes_xts.reinit(ctxp, iv);
switch (enc) {
- case 0: /* decrypt */
+ case GELI_DECRYPT:
for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) {
enc_xform_aes_xts.decrypt(ctxp, data + i,
data + i);
}
break;
- case 1: /* encrypt */
+ case GELI_ENCRYPT:
for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) {
enc_xform_aes_xts.encrypt(ctxp, data + i,
- data + 1);
+ data + i);
}
break;
}
@@ -105,7 +107,7 @@ geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
}
static int
-g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
+g_eli_crypto_cipher(u_int algo, geli_op_t enc, u_char *data, size_t datasize,
const u_char *key, size_t keysize)
{
u_char iv[keysize];
@@ -123,7 +125,8 @@ g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
if (algo == CRYPTO_AES_XTS)
algo = CRYPTO_AES_CBC;
- return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize));
+ return (g_eli_crypto_cipher(algo, GELI_ENCRYPT, data, datasize, key,
+ keysize));
}
int
@@ -135,5 +138,6 @@ g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
if (algo == CRYPTO_AES_XTS)
algo = CRYPTO_AES_CBC;
- return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize));
+ return (g_eli_crypto_cipher(algo, GELI_DECRYPT, data, datasize, key,
+ keysize));
}
diff --git a/stand/libsa/geli/geliboot_internal.h b/stand/libsa/geli/geliboot_internal.h
index 2352a844f7ddf..2af74466179fe 100644
--- a/stand/libsa/geli/geliboot_internal.h
+++ b/stand/libsa/geli/geliboot_internal.h
@@ -55,6 +55,8 @@
#define STAND_H /* We don't want stand.h in {gpt,zfs,gptzfs}boot */
#include <opencrypto/xform_enc.h>
+#include "geliboot.h"
+
#define GELIDEV_NAMELEN 32
struct geli_dev {
@@ -65,7 +67,7 @@ struct geli_dev {
char *name; /* for prompting; it ends in ':' */
};
-int geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
+int geliboot_crypt(u_int algo, geli_op_t enc, u_char *data, size_t datasize,
const u_char *key, size_t keysize, u_char *iv);
#endif /* _GELIBOOT_INTERNAL_H_ */
diff --git a/stand/libsa/geli/gelidev.c b/stand/libsa/geli/gelidev.c
index 751255636112f..e1444c9b7fcd4 100644
--- a/stand/libsa/geli/gelidev.c
+++ b/stand/libsa/geli/gelidev.c
@@ -115,10 +115,6 @@ geli_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf,
char *iobuf;
int rc;
- /* We only handle reading; no write support. */
- if ((rw & F_MASK) != F_READ)
- return (EOPNOTSUPP);
-
gdesc = (struct geli_devdesc *)devdata;
/*
@@ -139,34 +135,63 @@ geli_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf,
alnsize = alnend - alnstart;
/*
- * If alignment requires us to read more than the size of the provided
- * buffer, allocate a temporary buffer.
+ * If alignment requires us to read/write more than the size of the
+ * provided buffer, allocate a temporary buffer.
+ * The writes will always get temporary buffer because of encryption.
*/
- if (alnsize <= size)
+ if (alnsize <= size && (rw & F_MASK) == F_READ)
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;
+ switch (rw & F_MASK) {
+ case F_READ:
+ /*
+ * 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_io(gdesc->gdev, GELI_DECRYPT, 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 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;
+ break;
+ case F_WRITE:
+ if (iobuf != buf) {
+ /* Read, decrypt, then modify. */
+ rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc,
+ F_READ, alnstart / DEV_BSIZE, alnsize, iobuf, NULL);
+ if (rc != 0)
+ goto out;
+ rc = geli_io(gdesc->gdev, GELI_DECRYPT, alnstart, iobuf,
+ alnsize);
+ if (rc != 0)
+ goto out;
+ /* Copy data to iobuf */
+ memcpy(iobuf + (reqstart - alnstart), buf, size);
+ }
- if (rsize != NULL)
- *rsize = size;
+ /* Encrypt and write it. */
+ rc = geli_io(gdesc->gdev, GELI_ENCRYPT, alnstart, iobuf,
+ alnsize);
+ if (rc != 0)
+ goto out;
+ rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc,
+ rw, alnstart / DEV_BSIZE, alnsize, iobuf, NULL);
+ }
out:
if (iobuf != buf)
free(iobuf);