Skip to content

Commit

Permalink
Create the luksmeta nuke command
Browse files Browse the repository at this point in the history
This command erases the entirety of the LUKSv1 header gap.

Additionally, we add the -n option to the luksmeta init command.
This option nukes the gap before initialization to ensure a new
initialization state.
  • Loading branch information
npmccallum committed Jun 24, 2017
1 parent 4fccbc3 commit ef306c2
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 22 deletions.
20 changes: 19 additions & 1 deletion libluksmeta.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,25 @@ luksmeta_test(struct crypt_device *cd)
return fd;
}

int
luksmeta_nuke(struct crypt_device *cd)
{
uint8_t zero[ALIGN(1, true)] = {};
uint32_t length = 0;
int fd = -1;
int r = 0;

fd = open_hole(cd, O_RDWR | O_SYNC, &length);
if (fd < 0)
return fd;

for (size_t i = 0; r >= 0 && i < length; i += sizeof(zero))
r = writeall(fd, zero, sizeof(zero));

close(fd);
return r < 0 ? r : 0;
}

int
luksmeta_init(struct crypt_device *cd)
{
Expand Down Expand Up @@ -482,4 +501,3 @@ luksmeta_wipe(struct crypt_device *cd, int slot, const luksmeta_uuid_t uuid)
close(fd);
return r < 0 ? r : 0;
}

42 changes: 37 additions & 5 deletions luksmeta.8
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
\fBluksmeta test\fR \-d DEVICE
.
.P
\fBluksmeta init\fR \-d DEVICE [\-f]
\fBluksmeta nuke\fR \-d DEVICE [\-f]
.
.P
\fBluksmeta init\fR \-d DEVICE [\-f] [\-n]
.
.P
\fBluksmeta show\fR \-d DEVICE [\-s SLOT]
Expand Down Expand Up @@ -49,13 +52,16 @@ UUIDs are large enough that collision is practically impossible\. So if your app
The easiest way to generate a UUID is to use \fBuuidgen\fR(1)\. However, any compliant UUID generator will suffice\.
.
.SH "INITIALIZATION"
Before reading or writing metadata, the LUKSv1 block device must be initialized for metadata storage\. Two commands help with this process: \fBluksmeta test\fR and \fBluksmeta init\fR\.
Before reading or writing metadata, the LUKSv1 block device must be initialized for metadata storage\. Three commands help with this process: \fBluksmeta test\fR, \fBluksmeta nuke\fR and \fBluksmeta init\fR\.
.
.P
The \fBluksmeta test\fR command simply checks an existing block device to see if it is initialized for metadata storage\. This command does not provide any output, so be sure to check its return code (see below)\.
.
.P
The \fBluksmeta init\fR command initializes the LUKSv1 block device for metadata storage\. This process will wipe out any data in the LUKSv1 header gap\. For this reason, this command will require user confirmation before any data is written, unless the \fB\-f\fR option is supplied\. Note that this command succeeds if the device is already initialized\.
The \fBluksmeta nuke\fR command will zero (erase) the entire LUKSv1 header gap\. Since this operation is destructive, user confirmation will be required before clearing the gap unless the \fB\-f\fR option is supplied\.
.
.P
The \fBluksmeta init\fR command initializes the LUKSv1 block device for metadata storage\. This process will wipe out any data in the LUKSv1 header gap\. For this reason, this command will require user confirmation before any data is written unless the \fB\-f\fR option is supplied\. Note that this command succeeds without any modification if the device is already initialized\. If you would like to force the creation of clean initialization state, you can specify the \fB\-n\fR option to nuke the LUKSv1 header gap before initialization (but after user confirmation)\.
.
.SH "METADATA STATE"
The \fBluksmeta show\fR command displays the current state of slots on the LUKSv1 block device\. If no slot is specified, it prints a table consisting of the slot number, the corresponding LUKSv1 slot state and the UUID of the data stored in the \fBluksmeta\fR slot (or "empty" if no data is stored)\. If a slot is specified, this command simply prints out the UUID of the data in the slot\. If the slot does not contain data, it prints nothing\.
Expand Down Expand Up @@ -138,13 +144,26 @@ This command uses the return values as defined by \fBsysexit\.h\fR\. The followi
Additionally, \fBluksmeta save\fR will return \fBEX_UNAVAILABLE\fR when you attempt to save data into a slot that is already used\. Likewise, \fBluksmeta load\fR will return \fBEX_UNAVAILABLE\fR when you attempt to read from an empty slot\.
.
.SH "EXAMPLES"
Ensure that a device is initialized:
Destroy all data (including LUKSMeta data) in the LUKSv1 header gap and initalize the gap for LUKSMeta storage:
.
.IP "" 4
.
.nf

$ luksmeta init \-n \-f \-d /dev/sdz
.
.fi
.
.IP "" 0
.
.P
If already initialized, do nothing\. Otherwise, destroy all non\-LUKSMeta data in the LUKSv1 header gap and initialize the gap for LUKSMeta storage:
.
.IP "" 4
.
.nf

$ luksmeta test \-d /dev/sdz || luksmeta init \-f \-d /dev/sdz
$ luksmeta init \-f \-d /dev/sdz
.
.fi
.
Expand Down Expand Up @@ -193,6 +212,19 @@ $ luksmeta wipe \-d /dev/sdz \-s 0 \-u $UUID
.
.IP "" 0
.
.P
Erase all trace of LUKSMeta:
.
.IP "" 4
.
.nf

$ luksmeta nuke \-f \-d /dev/sdz
.
.fi
.
.IP "" 0
.
.SH "AUTHOR"
Nathaniel McCallum <npmccallum@redhat\.com>
.
Expand Down
33 changes: 26 additions & 7 deletions luksmeta.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ luksmeta(1) -- Utility for storing metadata in a LUKSv1 header

`luksmeta test` -d DEVICE

`luksmeta init` -d DEVICE [-f]
`luksmeta nuke` -d DEVICE [-f]

`luksmeta init` -d DEVICE [-f] [-n]

`luksmeta show` -d DEVICE [-s SLOT]

Expand Down Expand Up @@ -59,18 +61,25 @@ compliant UUID generator will suffice.
## INITIALIZATION

Before reading or writing metadata, the LUKSv1 block device must be
initialized for metadata storage. Two commands help with this process:
`luksmeta test` and `luksmeta init`.
initialized for metadata storage. Three commands help with this process:
`luksmeta test`, `luksmeta nuke` and `luksmeta init`.

The `luksmeta test` command simply checks an existing block device to see
if it is initialized for metadata storage. This command does not provide any
output, so be sure to check its return code (see below).

The `luksmeta nuke` command will zero (erase) the entire LUKSv1 header gap.
Since this operation is destructive, user confirmation will be required before
clearing the gap unless the `-f` option is supplied.

The `luksmeta init` command initializes the LUKSv1 block device for metadata
storage. This process will wipe out any data in the LUKSv1 header gap. For
this reason, this command will require user confirmation before any data is
written, unless the `-f` option is supplied. Note that this command succeeds
if the device is already initialized.
written unless the `-f` option is supplied. Note that this command succeeds
without any modification if the device is already initialized. If you would
like to force the creation of clean initialization state, you can specify the
`-n` option to nuke the LUKSv1 header gap before initialization (but after
user confirmation).

## METADATA STATE

Expand Down Expand Up @@ -173,9 +182,15 @@ return `EX_UNAVAILABLE` when you attempt to read from an empty slot.

## EXAMPLES

Ensure that a device is initialized:
Destroy all data (including LUKSMeta data) in the LUKSv1 header gap and
initalize the gap for LUKSMeta storage:

$ luksmeta init -n -f -d /dev/sdz

$ luksmeta test -d /dev/sdz || luksmeta init -f -d /dev/sdz
If already initialized, do nothing. Otherwise, destroy all non-LUKSMeta data
in the LUKSv1 header gap and initialize the gap for LUKSMeta storage:

$ luksmeta init -f -d /dev/sdz

Write some data to a slot:

Expand All @@ -193,6 +208,10 @@ Wipe the data from the slot:

$ luksmeta wipe -d /dev/sdz -s 0 -u $UUID

Erase all trace of LUKSMeta:

$ luksmeta nuke -f -d /dev/sdz

## AUTHOR

Nathaniel McCallum &lt;[email protected]&gt;
Expand Down
64 changes: 55 additions & 9 deletions luksmeta.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct options {
luksmeta_uuid_t uuid;
bool have_uuid;
bool force;
bool nuke;
int slot;
};

Expand All @@ -50,6 +51,40 @@ cmd_test(const struct options *opts, struct crypt_device *cd)
return luksmeta_test(cd) == 0 ? EX_OK : EX_OSFILE;
}

static int
cmd_nuke(const struct options *opts, struct crypt_device *cd)
{
int r = 0;

if (!opts->force) {
int c = 'X';

fprintf(stderr,
"You are about to erase all data in the LUKSMeta storage area.\n"
"A backup is advised before erasure is performed.\n\n");

while (!strchr("YyNn", c)) {
fprintf(stderr, "Do you wish to nuke %s? [yn] ",
crypt_get_device_name(cd));
c = getc(stdin);
}

if (strchr("Nn", c))
return EX_NOPERM;
}

r = luksmeta_nuke(cd);
switch (r) {
case 0:
return EX_OK;

default:
fprintf(stderr, "Error while erasing device (%s): %s\n",
opts->device, strerror(-r));
return EX_OSERR;
}
}

static int
cmd_init(const struct options *opts, struct crypt_device *cd)
{
Expand All @@ -74,6 +109,13 @@ cmd_init(const struct options *opts, struct crypt_device *cd)
return EX_NOPERM;
}

if (opts->nuke) {
struct options o = { .force = true, .device = opts->device };
r = cmd_nuke(&o, cd);
if (r != EX_OK)
return r;
}

r = luksmeta_init(cd);
switch (r) {
case 0: /* fallthrough */
Expand Down Expand Up @@ -366,8 +408,10 @@ cmd_wipe(const struct options *opts, struct crypt_device *cd)
}
}

static const struct option opts[] = {
static const char *sopts = "hfnd:u:s:";
static const struct option lopts[] = {
{ "help", .val = 'h' },
{ "nuke", no_argument, .val = 'n' },
{ "force", no_argument, .val = 'f' },
{ "device", required_argument, .val = 'd' },
{ "uuid", required_argument, .val = 'u' },
Expand All @@ -380,6 +424,7 @@ static const struct {
const char *name;
} commands[] = {
{ cmd_test, "test", },
{ cmd_nuke, "nuke", },
{ cmd_init, "init", },
{ cmd_show, "show", },
{ cmd_save, "save", },
Expand All @@ -393,10 +438,11 @@ main(int argc, char *argv[])
{
struct options o = { .slot = CRYPT_ANY_SLOT };

for (int c; (c = getopt_long(argc, argv, "hfd:u:s:", opts, NULL)) != -1; ) {
for (int c; (c = getopt_long(argc, argv, sopts, lopts, NULL)) != -1; ) {
switch (c) {
case 'h': goto usage;
case 'd': o.device = optarg; break;
case 'n': o.nuke = true; break;
case 'f': o.force = true; break;
case 'u':
if (sscanf(optarg, UUID_TMPL, UUID_ARGS(&o.uuid)) != 16) {
Expand Down Expand Up @@ -470,12 +516,12 @@ main(int argc, char *argv[])

usage:
fprintf(stderr,
"Usage: %s test -d DEVICE\n"
" or: %s init -d DEVICE [-f]\n"
" or: %s show -d DEVICE [-s SLOT]\n"
" or: %s save -d DEVICE [-s SLOT] -u UUID < DATA\n"
" or: %s load -d DEVICE -s SLOT [-u UUID] > DATA\n"
" or: %s wipe -d DEVICE -s SLOT [-u UUID] [-f]\n",
argv[0], argv[0], argv[0], argv[0], argv[0], argv[0]);
"Usage: luksmeta test -d DEVICE\n"
" or: luksmeta nuke -d DEVICE [-f]\n"
" or: luksmeta init -d DEVICE [-f] [-n]\n"
" or: luksmeta show -d DEVICE [-s SLOT]\n"
" or: luksmeta save -d DEVICE [-s SLOT] -u UUID < DATA\n"
" or: luksmeta load -d DEVICE -s SLOT [-u UUID] > DATA\n"
" or: luksmeta wipe -d DEVICE -s SLOT [-u UUID] [-f]\n");
return EX_USAGE;
}
9 changes: 9 additions & 0 deletions luksmeta.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ typedef uint8_t luksmeta_uuid_t[16];
int
luksmeta_test(struct crypt_device *cd);

/**
* Zeroes the entire LUKSMeta storage space.
*
* @param cd crypt device handle
* @return Zero on success or negative errno value otherwise.
*/
int
luksmeta_nuke(struct crypt_device *cd);

/**
* Initializes metadata storage on a LUKSv1 device
*
Expand Down
11 changes: 11 additions & 0 deletions test-lm-init.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ main(int argc, char *argv[])
assert(luksmeta_load(cd, 2, uuid, data, sizeof(data)) == -EINVAL);
assert(luksmeta_wipe(cd, 2, UUID) == -EINVAL);

/* Test nuking */
assert(luksmeta_init(cd) == 0);
assert(luksmeta_test(cd) == 0);
assert(luksmeta_nuke(cd) == 0);
assert(luksmeta_test(cd) == -ENOENT);
assert(test_layout((range_t[]) {
{ 0, 1024 }, /* LUKS header */
{ 1024, offset - 1024, true }, /* Keyslot Area */
END(offset), /* Rest of the file */
}));

crypt_free(cd);
unlink(filename);
return 0;
Expand Down
13 changes: 13 additions & 0 deletions test-luksmeta
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,16 @@ for slot in `seq 0 7`; do
./luksmeta wipe -f -s $slot -d $tmp
! ./luksmeta load -s $slot -d $tmp
done

# Test nuking
./luksmeta test -d $tmp
./luksmeta init -f -d $tmp
./luksmeta nuke -f -d $tmp
! ./luksmeta test -d $tmp

# Test implicit nuking
./luksmeta init -f -d $tmp
echo hi | ./luksmeta save -s 0 -u 23149359-1b61-4803-b818-774ab730fbec -d $tmp
test "`./luksmeta load -s 0 -d $tmp`" == "hi"
./luksmeta init -n -f -d $tmp
! ./luksmeta load -s 0 -d $tmp

0 comments on commit ef306c2

Please sign in to comment.