Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 28 Sep 2014 09:23:26 -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:  <542819DE.3050709@denninger.net>
In-Reply-To: <20140928131516.GE1620@garage.freebsd.pl>
References:  <54076871.5010405@denninger.net> <54076CFE.5010308@denninger.net> <20140928131516.GE1620@garage.freebsd.pl>

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

[-- Attachment #1 --]
Yes, I wrote a script to handle it in the meantime as well.  The way the
geli command is architected it is rather difficult to do properly in the
code itself....

On 9/28/2014 8:15 AM, Pawel Jakub Dawidek wrote:
> Hi Karl,
>
> I like the idea. I myself currently use a script which obtains the
> passphrase:
>
> 	echo -n "Enter passphrase: "
> 	stty -echo
> 	read pass
> 	stty echo
> 	echo
>
> And then iterates over all providers I want to attach and uses -j option
> to provide the key for the attach subcommand.
>
> To make it integral part of geli and to be complete we would need to add
> support for multiple providers to the following subcommands: init,
> attach, onetime, setkey, delkey and resume.
>
> On Wed, Sep 03, 2014 at 02:33:18PM -0500, Karl Denninger wrote:
>> 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
>>
>>
>
>

-- 
Karl Denninger
karl@denninger.net <mailto:karl@denninger.net>
/The Market Ticker/

[-- 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
140928142326Z0#	*H
	1pVS#^y*aouP*w'0l	*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

-{8=R$	<ѮdWjV~`Wi(Qu*m	U9ro:0cvUT^Hx&{6k&GhH;1Ql1"7xlo;KT~WY8ΫѷGL<q ,w>2	7j5]ܐؚYULDBGr?Gט;sZdy
<H՗BTͬL-$>wLKMxpÔ3Ӣpvo#qD_10%=[A-qE,)`ۏ/>Y% C_E47g2Q3FafZڙ}Bt-qGFV+B!zNx8fEԯw"}?:sSRkɴl!t09R}xwdg=Q**qPNN[\F$+,r/DW	6ɹ U"

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