Attempt to add multiple device attachment to "geli attach"
Karl Denninger
karl at denninger.net
Wed Sep 3 19:33:25 UTC 2014
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 at denninger.net
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 2711 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.freebsd.org/pipermail/freebsd-geom/attachments/20140903/819f34f8/attachment.bin>
More information about the freebsd-geom
mailing list