Author: tsoome
Date: Sat Jul 11 06:51:42 2020
New Revision: 363090
URL: https://svnweb.freebsd.org/changeset/base/363090

Log:
  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

Modified:
  head/stand/i386/gptboot/gptboot.c
  head/stand/libsa/geli/geliboot.c
  head/stand/libsa/geli/geliboot.h
  head/stand/libsa/geli/geliboot_crypto.c
  head/stand/libsa/geli/geliboot_internal.h
  head/stand/libsa/geli/gelidev.c

Modified: head/stand/i386/gptboot/gptboot.c
==============================================================================
--- head/stand/i386/gptboot/gptboot.c   Sat Jul 11 03:39:44 2020        
(r363089)
+++ head/stand/i386/gptboot/gptboot.c   Sat Jul 11 06:51:42 2020        
(r363090)
@@ -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);
        }

Modified: head/stand/libsa/geli/geliboot.c
==============================================================================
--- head/stand/libsa/geli/geliboot.c    Sat Jul 11 03:39:44 2020        
(r363089)
+++ head/stand/libsa/geli/geliboot.c    Sat Jul 11 06:51:42 2020        
(r363090)
@@ -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 
                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;

Modified: head/stand/libsa/geli/geliboot.h
==============================================================================
--- head/stand/libsa/geli/geliboot.h    Sat Jul 11 03:39:44 2020        
(r363089)
+++ head/stand/libsa/geli/geliboot.h    Sat Jul 11 06:51:42 2020        
(r363090)
@@ -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);
 

Modified: head/stand/libsa/geli/geliboot_crypto.c
==============================================================================
--- head/stand/libsa/geli/geliboot_crypto.c     Sat Jul 11 03:39:44 2020        
(r363089)
+++ head/stand/libsa/geli/geliboot_crypto.c     Sat Jul 11 06:51:42 2020        
(r363090)
@@ -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
                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
                        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
                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
 }
 
 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 
        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 
        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));
 }

Modified: head/stand/libsa/geli/geliboot_internal.h
==============================================================================
--- head/stand/libsa/geli/geliboot_internal.h   Sat Jul 11 03:39:44 2020        
(r363089)
+++ head/stand/libsa/geli/geliboot_internal.h   Sat Jul 11 06:51:42 2020        
(r363090)
@@ -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_ */

Modified: head/stand/libsa/geli/gelidev.c
==============================================================================
--- head/stand/libsa/geli/gelidev.c     Sat Jul 11 03:39:44 2020        
(r363089)
+++ head/stand/libsa/geli/gelidev.c     Sat Jul 11 06:51:42 2020        
(r363090)
@@ -115,10 +115,6 @@ geli_dev_strategy(void *devdata, int rw, daddr_t blk, 
        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, 
        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;
+               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);
+               }
+
+               /* 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);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to