Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 11 Jul 2020 06:51:42 +0000 (UTC)
From:      Toomas Soome <tsoome@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r363090 - in head/stand: i386/gptboot libsa/geli
Message-ID:  <202007110651.06B6pgca006405@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202007110651.06B6pgca006405>