Module Name:    src
Committed By:   riastradh
Date:           Tue Aug 30 08:48:42 UTC 2022

Modified Files:
        src/sbin/cgdconfig: cgdconfig.c

Log Message:
cgdconfig(8): Gracefully handle failed verification with shared keys.

The first time each key is verified, if verification fails, we chuck
the failed key and try again with passphrase re-entry.

But if a key has already been verified, and verification fails,
assume something is wrong with the disk and fail.


To generate a diff of this commit:
cvs rdiff -u -r1.58 -r1.59 src/sbin/cgdconfig/cgdconfig.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sbin/cgdconfig/cgdconfig.c
diff -u src/sbin/cgdconfig/cgdconfig.c:1.58 src/sbin/cgdconfig/cgdconfig.c:1.59
--- src/sbin/cgdconfig/cgdconfig.c:1.58	Fri Aug 12 10:49:47 2022
+++ src/sbin/cgdconfig/cgdconfig.c	Tue Aug 30 08:48:41 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: cgdconfig.c,v 1.58 2022/08/12 10:49:47 riastradh Exp $ */
+/* $NetBSD: cgdconfig.c,v 1.59 2022/08/30 08:48:41 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@@ -33,7 +33,7 @@
 #ifndef lint
 __COPYRIGHT("@(#) Copyright (c) 2002, 2003\
  The NetBSD Foundation, Inc.  All rights reserved.");
-__RCSID("$NetBSD: cgdconfig.c,v 1.58 2022/08/12 10:49:47 riastradh Exp $");
+__RCSID("$NetBSD: cgdconfig.c,v 1.59 2022/08/30 08:48:41 riastradh Exp $");
 #endif
 
 #ifdef HAVE_ARGON2
@@ -114,7 +114,9 @@ int	pflag = PFLAG_GETPASS;
 
 /*
  * When configuring all cgds, save a cache of shared keys for key
- * derivation.
+ * derivation.  If the _first_ verification with a shared key fails, we
+ * chuck it and start over; if _subsequent_ verifications fail, we
+ * assume the disk is wrong and give up on it immediately.
  */
 
 struct sharedkey {
@@ -122,8 +124,11 @@ struct sharedkey {
 	string_t		*id;
 	bits_t			*key;
 	LIST_ENTRY(sharedkey)	 list;
+	SLIST_ENTRY(sharedkey)	 used;
+	int			 verified;
 };
 LIST_HEAD(, sharedkey) sharedkeys;
+SLIST_HEAD(sharedkeyhits, sharedkey);
 
 static int	configure(int, char **, struct params *, int);
 static int	configure_stdin(struct params *, int argc, char **);
@@ -146,7 +151,8 @@ static int	do_printkey(int, char **);
 static int	 configure_params(int, const char *, const char *,
 				  struct params *);
 static void	 eliminate_cores(void);
-static bits_t	*getkey(const char *, struct keygen *, size_t);
+static bits_t	*getkey(const char *, struct keygen *, size_t,
+		     struct sharedkeyhits *);
 static bits_t	*getkey_storedkey(const char *, struct keygen *, size_t);
 static bits_t	*getkey_randomkey(const char *, struct keygen *, size_t, int);
 #ifdef HAVE_ARGON2
@@ -429,7 +435,8 @@ getsubkey(int alg, bits_t *key, bits_t *
 }
 
 static bits_t *
-getkey(const char *dev, struct keygen *kg, size_t len0)
+getkey(const char *dev, struct keygen *kg, size_t len0,
+    struct sharedkeyhits *skh)
 {
 	bits_t	*ret = NULL;
 	bits_t	*tmp;
@@ -502,9 +509,11 @@ getkey(const char *dev, struct keygen *k
 			sk->id = string_dup(kg->kg_sharedid);
 			sk->key = tmp;
 			LIST_INSERT_HEAD(&sharedkeys, sk, list);
+			sk->verified = 0;
 		}
 
 derive:		if (kg->kg_sharedid) {
+			assert(sk != NULL);
 			/*
 			 * tmp holds the master key, owned by the
 			 * struct sharedkey record; replace it by the
@@ -517,6 +526,8 @@ derive:		if (kg->kg_sharedid) {
 					bits_free(ret);
 				return NULL;
 			}
+			if (skh)
+				SLIST_INSERT_HEAD(skh, sk, used);
 		}
 		if (ret)
 			ret = bits_xor_d(tmp, ret);
@@ -811,6 +822,12 @@ configure(int argc, char **argv, struct 
 		}
 
 	for (;;) {
+		struct sharedkeyhits skh;
+		struct sharedkey *sk, *sk1;
+		int all_verified;
+
+		SLIST_INIT(&skh);
+
 		fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
 		if (fd == -1)
 			return -1;
@@ -818,7 +835,7 @@ configure(int argc, char **argv, struct 
 		if (p->key)
 			bits_free(p->key);
 
-		p->key = getkey(argv[1], p->keygen, p->keylen);
+		p->key = getkey(argv[1], p->keygen, p->keylen, &skh);
 		if (!p->key)
 			goto bail_err;
 
@@ -831,12 +848,33 @@ configure(int argc, char **argv, struct 
 			(void)unconfigure_fd(fd);
 			goto bail_err;
 		}
-		if (ret == 0)		/* success */
+		if (ret == 0) {		/* success */
+			SLIST_FOREACH(sk, &skh, used)
+				sk->verified = 1;
 			break;
+		}
 
 		(void)unconfigure_fd(fd);
 		(void)prog_close(fd);
 
+		/*
+		 * If the shared keys were all verified already, assume
+		 * something is wrong with the disk and give up.  If
+		 * not, flush the cache of the ones that have not been
+		 * verified in case we can try again with passphrase
+		 * re-entry.
+		 */
+		all_verified = 1;
+		SLIST_FOREACH_SAFE(sk, &skh, used, sk1) {
+			all_verified &= sk->verified;
+			if (!sk->verified) {
+				LIST_REMOVE(sk, list);
+				free(sk);
+			}
+		}
+		if (all_verified)
+			loop = 0;
+
 		if (!loop) {
 			warnx("verification failed permanently");
 			goto bail_err;
@@ -1331,7 +1369,7 @@ generate_convert(struct params *p, int a
 		return -1;
 	}
 
-	oldp->key = getkey("old file", oldp->keygen, oldp->keylen);
+	oldp->key = getkey("old file", oldp->keygen, oldp->keylen, NULL);
 
 	/* we copy across the non-keygen info, here. */
 
@@ -1383,7 +1421,7 @@ generate_convert(struct params *p, int a
 			return ret;
 	}
 
-	p->key = getkey("new file", p->keygen, p->keylen);
+	p->key = getkey("new file", p->keygen, p->keylen, NULL);
 
 	kg = keygen_generate(KEYGEN_STOREDKEY);
 	kg->kg_key = bits_xor(p->key, oldp->key);
@@ -1569,7 +1607,7 @@ printkey(const char *dev, const char *pa
 		warnx("invalid parameters file \"%s\"", paramsfile);
 		return -1;
 	}
-	p->key = getkey(dev, p->keygen, p->keylen);
+	p->key = getkey(dev, p->keygen, p->keylen, NULL);
 	raw = bits_getbuf(p->key);
 	nbits = bits_len(p->key);
 	assert(nbits <= INT_MAX - 7);

Reply via email to