Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157015627
D16115.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D16115.diff
View Options
Index: head/lib/geom/eli/geli.8
===================================================================
--- head/lib/geom/eli/geli.8
+++ head/lib/geom/eli/geli.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 27, 2018
+.Dd July 24, 2018
.Dt GELI 8
.Os
.Sh NAME
@@ -61,7 +61,7 @@
.Op Fl l Ar keylen
.Op Fl s Ar sectorsize
.Op Fl V Ar version
-.Ar prov
+.Ar prov ...
.Nm
.Cm label - an alias for
.Cm init
@@ -233,10 +233,14 @@
indicates an action to be performed:
.Bl -tag -width ".Cm configure"
.It Cm init
-Initialize the provider which needs to be encrypted.
+Initialize providers which need to be encrypted.
+If multiple providers are listed as arguments, they will all be initialized
+with the same passphrase and/or User Key.
+A unique salt will be randomly generated for each provider to ensure the
+Master Key for each is unique.
Here you can set up the cryptographic algorithm to use, Data Key length,
etc.
-The last sector of the provider is used to store metadata.
+The last sector of the providers is used to store metadata.
The
.Cm init
subcommand also automatically writes metadata backups to
@@ -279,6 +283,16 @@
.Pa none
as the
.Ar backupfile .
+If multiple providers were initialized in the one command, you can use
+.Pa PROV
+(all upper-case) in the file name, and it will be replaced with the provider
+name.
+If
+.Pa PROV
+is not found in the file name and multiple providers were initialized in the
+one command,
+.Pa -<prov>
+will be appended to the end of the file name specified.
.It Fl d
When entering the passphrase to boot from this encrypted root filesystem, echo
.Ql *
Index: head/lib/geom/eli/geom_eli.c
===================================================================
--- head/lib/geom/eli/geom_eli.c
+++ head/lib/geom/eli/geom_eli.c
@@ -91,7 +91,7 @@
/*
* Available commands:
*
- * init [-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov
+ * init [-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov ...
* label - alias for 'init'
* attach [-Cdprv] [-n keyno] [-j passfile] [-k keyfile] prov ...
* detach [-fl] prov ...
@@ -129,7 +129,7 @@
{ 'V', "mdversion", "-1", G_TYPE_NUMBER },
G_OPT_SENTINEL
},
- "[-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov"
+ "[-bdgPTv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov ..."
},
{ "label", G_FLAG_VERBOSE, eli_main,
{
@@ -695,6 +695,7 @@
eli_init(struct gctl_req *req)
{
struct g_eli_metadata md;
+ struct gctl_req *r;
unsigned char sector[sizeof(struct g_eli_metadata)] __aligned(4);
unsigned char key[G_ELI_USERKEYLEN];
char backfile[MAXPATHLEN];
@@ -702,22 +703,16 @@
unsigned int secsize, version;
off_t mediasize;
intmax_t val;
- int error, nargs;
+ int error, i, nargs, nparams, param;
+ const int one = 1;
nargs = gctl_get_int(req, "nargs");
- if (nargs != 1) {
- gctl_error(req, "Invalid number of arguments.");
+ if (nargs <= 0) {
+ gctl_error(req, "Too few arguments.");
return;
}
- prov = gctl_get_ascii(req, "arg0");
- mediasize = g_get_mediasize(prov);
- secsize = g_get_sectorsize(prov);
- if (mediasize == 0 || secsize == 0) {
- gctl_error(req, "Cannot get informations about %s: %s.", prov,
- strerror(errno));
- return;
- }
+ /* Start generating metadata for provider(s) being initialized. */
explicit_bzero(&md, sizeof(md));
strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
val = gctl_get_intmax(req, "mdversion");
@@ -809,7 +804,6 @@
gctl_error(req, "Invalid key length.");
return;
}
- md.md_provsize = mediasize;
val = gctl_get_intmax(req, "iterations");
if (val != -1) {
@@ -829,78 +823,191 @@
md.md_iterations = val;
val = gctl_get_intmax(req, "sectorsize");
- if (val == 0)
- md.md_sectorsize = secsize;
- else {
- if (val < 0 || (val % secsize) != 0 || !powerof2(val)) {
- gctl_error(req, "Invalid sector size.");
- return;
- }
- if (val > sysconf(_SC_PAGE_SIZE)) {
- fprintf(stderr,
- "warning: Using sectorsize bigger than the page size!\n");
- }
- md.md_sectorsize = val;
+ if (val > sysconf(_SC_PAGE_SIZE)) {
+ fprintf(stderr,
+ "warning: Using sectorsize bigger than the page size!\n");
}
md.md_keys = 0x01;
- arc4random_buf(md.md_salt, sizeof(md.md_salt));
- arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys));
- /* Generate user key. */
- if (eli_genkey(req, &md, key, true) == NULL) {
+ /*
+ * Determine number of parameters in the parent geom request before the
+ * nargs parameter and list of providers.
+ */
+ nparams = req->narg - nargs - 1;
+
+ /* Create new child request for each provider and issue to kernel */
+ for (i = 0; i < nargs; i++) {
+ r = gctl_get_handle();
+
+ /* Copy each parameter from the parent request to the child */
+ for (param = 0; param < nparams; param++) {
+ gctl_ro_param(r, req->arg[param].name,
+ req->arg[param].len, req->arg[param].value);
+ }
+
+ /* Add a single provider to the parameter list of the child */
+ gctl_ro_param(r, "nargs", sizeof(one), &one);
+ prov = gctl_get_ascii(req, "arg%d", i);
+ gctl_ro_param(r, "arg0", -1, prov);
+
+ mediasize = g_get_mediasize(prov);
+ secsize = g_get_sectorsize(prov);
+ if (mediasize == 0 || secsize == 0) {
+ gctl_error(r, "Cannot get information about %s: %s.",
+ prov, strerror(errno));
+ goto out;
+ }
+
+ md.md_provsize = mediasize;
+
+ val = gctl_get_intmax(r, "sectorsize");
+ if (val == 0) {
+ md.md_sectorsize = secsize;
+ } else {
+ if (val < 0 || (val % secsize) != 0 || !powerof2(val)) {
+ gctl_error(r, "Invalid sector size.");
+ goto out;
+ }
+ md.md_sectorsize = val;
+ }
+
+ /* Use different salt and Master Key for each provider. */
+ arc4random_buf(md.md_salt, sizeof(md.md_salt));
+ arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys));
+
+ /* Generate user key. */
+ if (eli_genkey(r, &md, key, true) == NULL) {
+ /*
+ * Error generating key - details added to geom request
+ * by eli_genkey().
+ */
+ goto out;
+ }
+
+ /* Encrypt the first and the only Master Key. */
+ error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen,
+ md.md_mkeys);
explicit_bzero(key, sizeof(key));
- explicit_bzero(&md, sizeof(md));
- return;
- }
+ if (error != 0) {
+ gctl_error(r, "Cannot encrypt Master Key: %s.",
+ strerror(error));
+ goto out;
+ }
- /* Encrypt the first and the only Master Key. */
- error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
- explicit_bzero(key, sizeof(key));
- if (error != 0) {
- explicit_bzero(&md, sizeof(md));
- gctl_error(req, "Cannot encrypt Master Key: %s.",
- strerror(error));
- return;
- }
+ /*
+ * Convert metadata to on-disk format and then immediately erase
+ * sensitive data from the metadata struct.
+ */
+ eli_metadata_encode(&md, sector);
+ explicit_bzero(&md.md_provsize, sizeof(md.md_provsize));
+ explicit_bzero(&md.md_sectorsize, sizeof(md.md_sectorsize));
+ explicit_bzero(&md.md_salt, sizeof(md.md_salt));
+ explicit_bzero(&md.md_mkeys, sizeof(md.md_mkeys));
- eli_metadata_encode(&md, sector);
- explicit_bzero(&md, sizeof(md));
- error = g_metadata_store(prov, sector, sizeof(sector));
- explicit_bzero(sector, sizeof(sector));
- if (error != 0) {
- gctl_error(req, "Cannot store metadata on %s: %s.", prov,
- strerror(error));
- return;
- }
- if (verbose)
- printf("Metadata value stored on %s.\n", prov);
- /* Backup metadata to a file. */
- str = gctl_get_ascii(req, "backupfile");
- if (str[0] != '\0') {
- /* Backupfile given be the user, just copy it. */
- strlcpy(backfile, str, sizeof(backfile));
- } else {
- /* Generate file name automatically. */
+ /*
+ * Store metadata to disk and then immediately erase sensitive
+ * data from memory.
+ */
+ error = g_metadata_store(prov, sector, sizeof(sector));
+ explicit_bzero(sector, sizeof(sector));
+ if (error != 0) {
+ gctl_error(r, "Cannot store metadata on %s: %s.", prov,
+ strerror(error));
+ goto out;
+ }
+ if (verbose)
+ printf("Metadata value stored on %s.\n", prov);
+
+ /* Backup metadata to a file. */
const char *p = prov;
- unsigned int i;
+ unsigned int j;
- if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+ /*
+ * Check if provider string includes the devfs mountpoint
+ * (typically /dev/).
+ */
+ if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) {
+ /* Skip forward to the device filename only. */
p += sizeof(_PATH_DEV) - 1;
- snprintf(backfile, sizeof(backfile), "%s%s.eli",
- GELI_BACKUP_DIR, p);
- /* Replace all / with _. */
- for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) {
- if (backfile[i] == '/')
- backfile[i] = '_';
}
+
+ str = gctl_get_ascii(r, "backupfile");
+ if (str[0] != '\0') {
+ /* Backupfile given by the user, just copy it. */
+ strlcpy(backfile, str, sizeof(backfile));
+
+ /* Make the backup filename unique if multiple providers
+ * initialized in one command. */
+ if (nargs > 1) {
+ /*
+ * Replace first occurrence of "PROV" with
+ * provider name.
+ */
+ str = strnstr(backfile, "PROV",
+ sizeof(backfile));
+ if (str != NULL) {
+ char suffix[MAXPATHLEN];
+ j = str - backfile;
+ strlcpy(suffix, &backfile[j+4],
+ sizeof(suffix));
+ backfile[j] = '\0';
+ strlcat(backfile, p, sizeof(backfile));
+ strlcat(backfile, suffix,
+ sizeof(backfile));
+ } else {
+ /*
+ * "PROV" not found in backfile, append
+ * provider name.
+ */
+ strlcat(backfile, "-",
+ sizeof(backfile));
+ strlcat(backfile, p, sizeof(backfile));
+ }
+ }
+ } else {
+ /* Generate filename automatically. */
+ snprintf(backfile, sizeof(backfile), "%s%s.eli",
+ GELI_BACKUP_DIR, p);
+ /* Replace all / with _. */
+ for (j = strlen(GELI_BACKUP_DIR); backfile[j] != '\0';
+ j++) {
+ if (backfile[j] == '/')
+ backfile[j] = '_';
+ }
+ }
+ if (strcmp(backfile, "none") != 0 &&
+ eli_backup_create(r, prov, backfile) == 0) {
+ printf("\nMetadata backup for provider %s can be found "
+ "in %s\n", prov, backfile);
+ printf("and can be restored with the following "
+ "command:\n");
+ printf("\n\t# geli restore %s %s\n\n", backfile, prov);
+ }
+
+out:
+ /*
+ * Print error for this request, and set parent request error
+ * message.
+ */
+ if (r->error != NULL && r->error[0] != '\0') {
+ warnx("%s", r->error);
+ gctl_error(req, "There was an error with at least one "
+ "provider.");
+ }
+
+ gctl_free(r);
+
+ /*
+ * Erase sensitive data from memory, and ensure subsequent
+ * providers are initialized with unique metadata.
+ */
+ explicit_bzero(key, sizeof(key));
+ explicit_bzero(&md, sizeof(md));
}
- if (strcmp(backfile, "none") != 0 &&
- eli_backup_create(req, prov, backfile) == 0) {
- printf("\nMetadata backup can be found in %s and\n", backfile);
- printf("can be restored with the following command:\n");
- printf("\n\t# geli restore %s %s\n\n", backfile, prov);
- }
+
+ /* Clear the cached metadata, including keys. */
+ explicit_bzero(&md, sizeof(md));
}
static void
@@ -914,7 +1021,7 @@
const int one = 1;
nargs = gctl_get_int(req, "nargs");
- if (nargs == 0) {
+ if (nargs <= 0) {
gctl_error(req, "Too few arguments.");
return;
}
@@ -927,13 +1034,14 @@
*/
nparams = req->narg - nargs - 1;
- /* Create new child geom request for each provider and issue to kernel */
+ /* Create new child request for each provider and issue to kernel */
for (i = 0; i < nargs; i++) {
r = gctl_get_handle();
- /* Copy each parameter from the parent request to the child request */
+ /* Copy each parameter from the parent request to the child */
for (param = 0; param < nparams; param++) {
- gctl_ro_param(r, req->arg[param].name, req->arg[param].len, req->arg[param].value);
+ gctl_ro_param(r, req->arg[param].name,
+ req->arg[param].len, req->arg[param].value);
}
/* Add a single provider to the parameter list of the child */
@@ -971,10 +1079,14 @@
}
out:
- /* Print error for this request, and set parent request error message */
+ /*
+ * Print error for this request, and set parent request error
+ * message.
+ */
if (r->error != NULL && r->error[0] != '\0') {
warnx("%s", r->error);
- gctl_error(req, "There was an error with at least one provider.");
+ gctl_error(req, "There was an error with at least one "
+ "provider.");
}
gctl_free(r);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, May 18, 11:22 PM (12 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33275947
Default Alt Text
D16115.diff (12 KB)
Attached To
Mode
D16115: geli init multiple providers
Attached
Detach File
Event Timeline
Log In to Comment