Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 03 Sep 2014 14:33:18 -0500
From:      Karl Denninger <karl@denninger.net>
To:        freebsd-geom@freebsd.org
Subject:   Re: Attempt to add multiple device attachment to "geli attach"
Message-ID:  <54076CFE.5010308@denninger.net>
In-Reply-To: <54076871.5010405@denninger.net>
References:  <54076871.5010405@denninger.net>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Never mind... I know what I missed -- the key generation that is passed 
in is dependent on the metadata read from the userspace.

More work to do here.... will have to pass a separate key structure for 
each disk and it will also require some more work in the userspace 
command area so it doesn't prompt a second time for a password.

I'll post the completed patch set once I have it if people here think it 
would be interesting.

On 9/3/2014 14:13, Karl Denninger wrote:
> I'm aware of the potential issues here in terms of keying risks, but 
> there are plenty of reasons to support this capability with the 
> largest one being ZFS volumes that you wish to run encrypted.
>
> Take the following:
>
> label/pool0
> label/pool1
> label/pool2
> label/pool3
>
> (all relative to /dev, of course)
>
> These are all gpt partitions on different devices (typically full 
> disks less labels.)  You "geli init" them and then attach them and 
> build a raidz2 pool on that.
>
> OK, now the system is rebooted.  If you use the rc.conf file's option 
> to request geli passwords during the boot you had better not screw up 
> three times for only ONE of these volumes or the pool WILL come up 
> degraded!  Needless to say that's not nice.  It's even worse if it's a 
> raidz pool, you blow it, you reattach that disk and allow it to 
> resilver *and take a disk error on the remaining drives during the 
> resilver* -- now you're completely hosed.
>
> So, here's the idea -- if you use the same password and/or keyfile for 
> ALL of the volumes then either they ALL mount (if you get it right) or 
> NONE of them mount (if you get it wrong.)  Now the pool won't import 
> if you get it wrong and you're safe from the risk of taking a forced 
> resilver and potential data loss.
>
> The geom subclass command has a simple "nargs" test (must be "1") in 
> the attach command; I replaced that with "nargs < 1" for the error 
> case.  Now I can pass multiple devices to the kernel's geom handler 
> and they get passed to the kernel ctl handler.
>
> The following patch should, I believe, work -- but it doesn't. The 
> first disk attaches but the second one that was init'd with the same 
> passphrase fails.
>
> As near as I can tell the key components are not picked up off the 
> metadata until the geom driver gets ahold of it -- and thus the second 
> decryption attempt should work since on the second iteration through 
> the code grabs the key parameters off the request a second time.
>
> But I'm obviously missing something because the second volume returns 
> "Wrong key for ...."
>
> Ideas?
>
> Patch is relative to /usr/src/sys/geom/eli:
>
> *** g_eli_ctl.c.orig    Wed Sep  3 13:11:52 2014
> --- g_eli_ctl.c    Wed Sep  3 13:19:15 2014
> ***************
> *** 60,65 ****
> --- 60,68 ----
>       int *nargs, *detach, *readonly;
>       int keysize, error;
>       u_int nkey;
> +     char param[16];
> +
> +     u_int count;
>
>       g_topology_assert();
>
> ***************
> *** 68,74 ****
>           gctl_error(req, "No '%s' argument.", "nargs");
>           return;
>       }
> !     if (*nargs != 1) {
>           gctl_error(req, "Invalid number of arguments.");
>           return;
>       }
> --- 71,77 ----
>           gctl_error(req, "No '%s' argument.", "nargs");
>           return;
>       }
> !     if (*nargs < 1) {
>           gctl_error(req, "Invalid number of arguments.");
>           return;
>       }
> ***************
> *** 84,147 ****
>           gctl_error(req, "No '%s' argument.", "readonly");
>           return;
>       }
>
> !     name = gctl_get_asciiparam(req, "arg0");
> !     if (name == NULL) {
> !         gctl_error(req, "No 'arg%u' argument.", 0);
> !         return;
> !     }
> !     if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
> !         name += strlen("/dev/");
> !     pp = g_provider_by_name(name);
> !     if (pp == NULL) {
> !         gctl_error(req, "Provider %s is invalid.", name);
> !         return;
> !     }
> !     error = g_eli_read_metadata(mp, pp, &md);
> !     if (error != 0) {
> !         gctl_error(req, "Cannot read metadata from %s (error=%d).",
> !             name, error);
> !         return;
> !     }
> !     if (md.md_keys == 0x00) {
> !         bzero(&md, sizeof(md));
> !         gctl_error(req, "No valid keys on %s.", pp->name);
> !         return;
> !     }
> !
> !     key = gctl_get_param(req, "key", &keysize);
> !     if (key == NULL || keysize != G_ELI_USERKEYLEN) {
> !         bzero(&md, sizeof(md));
> !         gctl_error(req, "No '%s' argument.", "key");
> !         return;
> !     }
> !
> !     error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
> !     bzero(key, keysize);
> !     if (error == -1) {
> !         bzero(&md, sizeof(md));
> !         gctl_error(req, "Wrong key for %s.", pp->name);
> !         return;
> !     } else if (error > 0) {
> !         bzero(&md, sizeof(md));
> !         gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
> !             pp->name, error);
> !         return;
> !     }
> !     G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
> !
> !     if (*detach && *readonly) {
>           bzero(&md, sizeof(md));
> -         gctl_error(req, "Options -d and -r are mutually exclusive.");
> -         return;
>       }
> -     if (*detach)
> -         md.md_flags |= G_ELI_FLAG_WO_DETACH;
> -     if (*readonly)
> -         md.md_flags |= G_ELI_FLAG_RO;
> -     g_eli_create(req, mp, pp, &md, mkey, nkey);
> -     bzero(mkey, sizeof(mkey));
> -     bzero(&md, sizeof(md));
>   }
>
>   static struct g_eli_softc *
> --- 87,152 ----
>           gctl_error(req, "No '%s' argument.", "readonly");
>           return;
>       }
> +     for (count = 0; count < *nargs; count++) {
> +         snprintf(param, sizeof(param), "arg%d", count);
> +         name = gctl_get_asciiparam(req, param);
> +         if (name == NULL) {
> +             gctl_error(req, "No 'arg%u' argument.", count);
> +             return;
> +         }
> +         if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
> +             name += strlen("/dev/");
> +         pp = g_provider_by_name(name);
> +         if (pp == NULL) {
> +             gctl_error(req, "Provider %s is invalid.", name);
> +             return;
> +         }
> +         error = g_eli_read_metadata(mp, pp, &md);
> +         if (error != 0) {
> +             gctl_error(req, "Cannot read metadata from %s (error=%d).",
> +                 name, error);
> +             return;
> +         }
> +         if (md.md_keys == 0x00) {
> +             bzero(&md, sizeof(md));
> +             gctl_error(req, "No valid keys on %s.", pp->name);
> +             return;
> +         }
> +
> +         key = gctl_get_param(req, "key", &keysize);
> +         if (key == NULL || keysize != G_ELI_USERKEYLEN) {
> +             bzero(&md, sizeof(md));
> +             gctl_error(req, "No '%s' argument.", "key");
> +             return;
> +         }
>
> !         error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
> !         bzero(key, keysize);
> !         if (error == -1) {
> !             bzero(&md, sizeof(md));
> !             gctl_error(req, "Wrong key for %s.", pp->name);
> !             return;
> !         } else if (error > 0) {
> !             bzero(&md, sizeof(md));
> !             gctl_error(req, "Cannot decrypt Master Key for %s 
> (error=%d).",
> !                 pp->name, error);
> !             return;
> !         }
> !         G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
> !
> !         if (*detach && *readonly) {
> !             bzero(&md, sizeof(md));
> !             gctl_error(req, "Options -d and -r are mutually 
> exclusive.");
> !             return;
> !         }
> !         if (*detach)
> !             md.md_flags |= G_ELI_FLAG_WO_DETACH;
> !         if (*readonly)
> !             md.md_flags |= G_ELI_FLAG_RO;
> !         g_eli_create(req, mp, pp, &md, mkey, nkey);
> !         bzero(mkey, sizeof(mkey));
>           bzero(&md, sizeof(md));
>       }
>   }
>
>   static struct g_eli_softc *
>
>
> ------------------------
>

-- 
-- Karl
karl@denninger.net



[-- Attachment #2 --]
0	*H
010	+0	*H
O0K030
	*H
010	UUS10UFlorida10U	Niceville10U
Cuda Systems LLC10UCuda Systems LLC CA1/0-	*H
	 customer-service@cudasystems.net0
130824190344Z
180823190344Z0[10	UUS10UFlorida10UKarl Denninger1!0	*H
	karl@denninger.net0"0
	*H
0
bi՞]MNԿawx?`)'ҴcWgR@BlWh+	u}ApdCFJVй~FOL}EW^bچYp3K&ׂ(R
lxڝ.xz?6&nsJ+1v9v/(kqĪp[vjcK%fϻe?iq]z
lyzFO'ppdX//Lw(3JIA*S#՟H[f|CGqJKooy.oEuOw$/섀$삻J9b|AP~8]D1YI<"""Y^T2iQ2b	yH)]	Ƶ0y$_N6XqMC 9՘	XgώjGTP"#nˋ"Bk100	U00	`HB0U0,	`HB
OpenSSL Generated Certificate0U|8˴d[20U#0]Af4U3x&^"408	`HB+)https://cudasystems.net:11443/revoked.crl0
	*H
gBwH]j\x`(&gW32"Uf^.^Iϱ
k!DQAg{(w/)\N'[oRW@CHO>)XrTNɘ!u`xt5(=f\-l3<@C6mnhv##1ŃbH͍_Nq
aʷ?rk$^9TIa!kh,D-ct1
00010	UUS10UFlorida10U	Niceville10U
Cuda Systems LLC10UCuda Systems LLC CA1/0-	*H
	 customer-service@cudasystems.net0	+;0	*H
	1	*H
0	*H
	1
140903193318Z0#	*H
	1p""!+E놆f0l	*H
	1_0]0	`He*0	`He0
*H
0*H
0
*H
@0+0
*H
(0	+710010	UUS10UFlorida10U	Niceville10U
Cuda Systems LLC10UCuda Systems LLC CA1/0-	*H
	 customer-service@cudasystems.net0*H
	1010	UUS10UFlorida10U	Niceville10U
Cuda Systems LLC10UCuda Systems LLC CA1/0-	*H
	 customer-service@cudasystems.net0
	*H
-ZYgLO}R&Hc+m>%",u!78Ckdv'ۊ_P8aἺ+urS\׼Lޙ?	>;LD;pXg4|v`M0
	Y/Y^*Qe807z@>~ոǶw+lfj[snu%bHK+_T1-Pfr"U~B9-g?fJKZ֛O͕پW'8QMlD
9▅pXed
΍_!{Mw"4yScUyno,<4L+d|-z,N=IgDVL4*?\<\(G=)Tɽ1.[vN(gQǍ`P6u=8FE
<pQDp~"4N+Ȧls*R<Ҝ5jQ

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