Attempt to add multiple device attachment to "geli attach"
Karl Denninger
karl at denninger.net
Wed Sep 3 19:15:35 UTC 2014
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/9a402fcc/attachment.bin>
More information about the freebsd-geom
mailing list