summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan Cantrill <bryan@joyent.com>2019-06-29 18:17:08 +0000
committerJoshua M. Clulow <jmc@joyent.com>2019-06-29 21:53:45 +0000
commitd2cb459496a9ba43c051f163b6233046ccb5bcdf (patch)
tree5551d1e4587b4b047866d5b0f925f00decfa01ac
parente9686f2048541f02e63b97976f385b6efa0f4831 (diff)
downloadillumos-joyent-d2cb459496a9ba43c051f163b6233046ccb5bcdf.tar.gz
OS-7828 add support for kernel crash dump encryption
Reviewed by: Robert Mustacchi <robert.mustacchi@joyent.com> Approved by: Joshua M. Clulow <jmc@joyent.com>
-rw-r--r--usr/src/cmd/dumpadm/dconf.c40
-rw-r--r--usr/src/cmd/dumpadm/dconf.h2
-rw-r--r--usr/src/cmd/dumpadm/main.c14
-rw-r--r--usr/src/cmd/savecore/Makefile.com13
-rw-r--r--usr/src/cmd/savecore/savecore.c172
-rw-r--r--usr/src/common/crypto/chacha/chacha.c24
-rw-r--r--usr/src/common/crypto/chacha/chacha.h6
-rw-r--r--usr/src/lib/libc/port/gen/arc4random.c4
-rw-r--r--usr/src/man/man1m/dumpadm.1m40
-rw-r--r--usr/src/man/man1m/savecore.1m27
-rw-r--r--usr/src/test/libc-tests/tests/random/chacha_tv.c4
-rw-r--r--usr/src/uts/common/Makefile.files1
-rw-r--r--usr/src/uts/common/Makefile.rules4
-rw-r--r--usr/src/uts/common/io/dump.c30
-rw-r--r--usr/src/uts/common/os/dumpsubr.c107
-rw-r--r--usr/src/uts/common/sys/dumpadm.h3
-rw-r--r--usr/src/uts/common/sys/dumphdr.h29
17 files changed, 467 insertions, 53 deletions
diff --git a/usr/src/cmd/dumpadm/dconf.c b/usr/src/cmd/dumpadm/dconf.c
index 440004eac5..5a1da87148 100644
--- a/usr/src/cmd/dumpadm/dconf.c
+++ b/usr/src/cmd/dumpadm/dconf.c
@@ -21,12 +21,14 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/swap.h>
#include <sys/dumpadm.h>
+#include <sys/dumphdr.h>
#include <sys/utsname.h>
#include <unistd.h>
@@ -537,6 +539,42 @@ dconf_get_dumpsize(dumpconf_t *dcp)
return (0);
}
+int
+dconf_set_crypt(dumpconf_t *dcp, const char *keyfile)
+{
+ int fd;
+ uint8_t key[DUMP_CRYPT_KEYLEN];
+
+ if ((fd = open(keyfile, O_RDONLY)) == -1) {
+ warn(gettext("failed to open %s"), keyfile);
+ return (-1);
+ }
+
+ if (read(fd, key, sizeof (key)) != sizeof (key)) {
+ warn(gettext("failed to read %d byte key from %s"),
+ DUMP_CRYPT_KEYLEN, keyfile);
+ (void) close(fd);
+ return (-1);
+ }
+
+ (void) close(fd);
+
+ if (ioctl(dcp->dc_dump_fd, DIOCSCRYPTKEY, key) == -1) {
+ warn(gettext("failed to set encryption key"));
+ return (-1);
+ }
+
+ /*
+ * Reload our config flags as they may have changed.
+ */
+ if ((dcp->dc_cflags = ioctl(dcp->dc_dump_fd, DIOCGETCONF, 0)) == -1) {
+ warn(gettext("failed to get kernel dump settings"));
+ return (-1);
+ }
+
+ return (0);
+}
+
void
dconf_print(dumpconf_t *dcp, FILE *fp)
{
@@ -578,6 +616,8 @@ dconf_print(dumpconf_t *dcp, FILE *fp)
(void) fprintf(fp, gettext(" Save compressed: %s\n"),
(dcp->dc_csave == DC_UNCOMPRESSED) ? gettext("off") :
gettext("on"));
+ (void) fprintf(fp, gettext(" Dump encrypted: %s\n"),
+ (dcp->dc_cflags & DUMP_ENCRYPT) ? gettext("yes") : gettext("no"));
}
int
diff --git a/usr/src/cmd/dumpadm/dconf.h b/usr/src/cmd/dumpadm/dconf.h
index 74920f0def..e2f609cee7 100644
--- a/usr/src/cmd/dumpadm/dconf.h
+++ b/usr/src/cmd/dumpadm/dconf.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _DCONF_H
@@ -73,6 +74,7 @@ extern int dconf_update(dumpconf_t *, int);
extern void dconf_print(dumpconf_t *, FILE *);
extern int dconf_write_uuid(dumpconf_t *);
extern int dconf_get_dumpsize(dumpconf_t *);
+extern int dconf_set_crypt(dumpconf_t *, const char *);
extern int dconf_str2device(dumpconf_t *, char *);
extern int dconf_str2savdir(dumpconf_t *, char *);
diff --git a/usr/src/cmd/dumpadm/main.c b/usr/src/cmd/dumpadm/main.c
index 07a7dd5207..dccafbba33 100644
--- a/usr/src/cmd/dumpadm/main.c
+++ b/usr/src/cmd/dumpadm/main.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/stat.h>
@@ -36,10 +37,10 @@
static const char USAGE[] = "\
Usage: %s [-enuy] [-c kernel | curproc | all ]\n\
- [-d dump-device | swap | none ] [-m min {k|m|%%} ] [-s savecore-dir]\n\
- [-r root-dir] [-z on|off]\n";
+ [-d dump-device | swap | none ] [-k key-file] [-m min {k|m|%%} ]\n\
+ [-s savecore-dir] [-r root-dir] [-z on|off]\n";
-static const char OPTS[] = "einuyc:d:m:s:r:z:";
+static const char OPTS[] = "einuyc:d:m:s:r:z:k:";
static const char PATH_DEVICE[] = "/dev/dump";
static const char PATH_CONFIG[] = "/etc/dumpadm.conf";
@@ -57,6 +58,7 @@ main(int argc, char *argv[])
int dcmode = DC_CURRENT; /* kernel settings override unless -u */
int modified = 0; /* have we modified the dump config? */
char *minfstr = NULL; /* string value of -m argument */
+ char *keyfile = NULL; /* key file for -k argument */
dumpconf_t dc; /* current configuration */
int chrooted = 0;
int douuid = 0;
@@ -136,6 +138,9 @@ main(int argc, char *argv[])
}
douuid++;
break;
+ case 'k':
+ keyfile = optarg;
+ break;
case 'm':
minfstr = optarg;
@@ -191,6 +196,9 @@ main(int argc, char *argv[])
return (E_ERROR);
}
+ if (keyfile != NULL && dconf_set_crypt(&dc, keyfile) == -1)
+ return (E_ERROR);
+
if (dcmode == DC_OVERRIDE) {
/*
* In override mode, we try to force an update. If this
diff --git a/usr/src/cmd/savecore/Makefile.com b/usr/src/cmd/savecore/Makefile.com
index 1f6e09b231..c4ba4f89f0 100644
--- a/usr/src/cmd/savecore/Makefile.com
+++ b/usr/src/cmd/savecore/Makefile.com
@@ -21,7 +21,7 @@
#
# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
#
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
PROG= savecore
SRCS= ../savecore.c ../../../uts/common/os/compress.c
@@ -54,12 +54,14 @@ BZIP2OBJS = bz2blocksort.o \
bz2crctable.o \
bz2huffman.o
+CHACHAOBJ = chacha.o
+
.KEEP_STATE:
all: $(PROG)
-$(PROG): $(OBJS) $(BZIP2OBJS)
- $(LINK.c) -o $(PROG) $(OBJS) $(BZIP2OBJS) $(LDLIBS)
+$(PROG): $(OBJS) $(BZIP2OBJS) $(CHACHAOBJ)
+ $(LINK.c) -o $(PROG) $(OBJS) $(BZIP2OBJS) $(CHACHAOBJ) $(LDLIBS)
$(POST_PROCESS)
clean:
@@ -95,3 +97,8 @@ include ../../Makefile.targ
bz2%.o: ../../../common/bzip2/%.c
$(COMPILE.c) -o $@ -I$(SRC)/common -I$(SRC)/common/bzip2 $<
$(POST_PROCESS_O)
+
+%.o: ../../../common/crypto/chacha/%.c
+ $(COMPILE.c) -o $@ -I$(SRC)/common -I$(SRC)/common/crypto/chacha $<
+ $(POST_PROCESS_O)
+
diff --git a/usr/src/cmd/savecore/savecore.c b/usr/src/cmd/savecore/savecore.c
index 9b8e43e488..e0e281f61e 100644
--- a/usr/src/cmd/savecore/savecore.c
+++ b/usr/src/cmd/savecore/savecore.c
@@ -42,6 +42,8 @@
#include <atomic.h>
#include <libnvpair.h>
#include <libintl.h>
+#include <assert.h>
+#include <strings.h>
#include <sys/mem.h>
#include <sys/statvfs.h>
#include <sys/dumphdr.h>
@@ -55,6 +57,7 @@
#include <sys/fm/util.h>
#include <fm/libfmevent.h>
#include <sys/int_fmtio.h>
+#include <crypto/chacha/chacha.h>
/* fread/fwrite buffer size */
@@ -74,6 +77,8 @@ static long pagesize; /* dump pagesize */
static int dumpfd = -1; /* dumpfile descriptor */
static boolean_t have_dumpfile = B_TRUE; /* dumpfile existence */
static dumphdr_t corehdr, dumphdr; /* initial and terminal dumphdrs */
+static dump_crypt_t dcrypt; /* dump encryption header */
+static size_t dumphdr_size; /* size of dump header */
static boolean_t dump_incomplete; /* dumphdr indicates incomplete */
static boolean_t fm_panic; /* dump is the result of fm_panic */
static offset_t endoff; /* offset of end-of-dump header */
@@ -165,7 +170,8 @@ static void
usage(void)
{
(void) fprintf(stderr,
- "usage: %s [-L | -r] [-vd] [-f dumpfile] [dirname]\n", progname);
+ "usage: %s [-L | -r] [-vd] [-k keyfile] [-f dumpfile] [dirname]\n",
+ progname);
exit(1);
}
@@ -329,6 +335,19 @@ Pwrite(int fd, void *buf, size_t size, off64_t off)
strerror(errno));
}
+static void
+Read(int fd, void *buf, size_t size)
+{
+ ssize_t sz = read(fd, buf, size);
+
+ if (sz < 0)
+ logprint(SC_SL_ERR | SC_EXIT_ERR,
+ "read: %s", strerror(errno));
+ else if (sz != size)
+ logprint(SC_SL_ERR | SC_EXIT_ERR,
+ "read: size %ld != %ld", sz, size);
+}
+
static void *
Zalloc(size_t size)
{
@@ -362,9 +381,9 @@ read_dumphdr(void)
dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
endoff = llseek(dumpfd, -DUMP_OFFSET, SEEK_END) & -DUMP_OFFSET;
Pread(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
- Pread(dumpfd, &datahdr, sizeof (datahdr), endoff + sizeof (dumphdr));
pagesize = dumphdr.dump_pagesize;
+ dumphdr_size = sizeof (dumphdr);
if (dumphdr.dump_magic != DUMP_MAGIC)
logprint(SC_SL_NONE | SC_EXIT_PEND, "bad magic number %x",
@@ -384,6 +403,20 @@ read_dumphdr(void)
"dump is from %u-bit kernel - cannot save on %u-bit kernel",
dumphdr.dump_wordsize, DUMP_WORDSIZE);
+ if (dumphdr.dump_flags & DF_ENCRYPTED) {
+ /*
+ * If our dump is encrypted, our encryption header follows
+ * our dump header. Read it, and then increment our
+ * dumphdr_size to assure that reads of data following the
+ * encryption header account for it.
+ */
+ Pread(dumpfd, &dcrypt, sizeof (dcrypt),
+ endoff + sizeof (dumphdr));
+ dumphdr_size += sizeof (dcrypt);
+ }
+
+ Pread(dumpfd, &datahdr, sizeof (datahdr), endoff + dumphdr_size);
+
if (datahdr.dump_datahdr_magic == DUMP_DATAHDR_MAGIC) {
if (datahdr.dump_datahdr_version != DUMP_DATAHDR_VERSION)
logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_PEND,
@@ -500,19 +533,76 @@ build_dump_map(int corefd, const pfn_t *pfn_table)
free(inbuf);
}
+static void
+Decrypt(offset_t dumpoff, len_t nb, char *buf, size_t sz, uint8_t *key)
+{
+ size_t nelems = nb / sizeof (uint64_t), i;
+ uint64_t *clear = (uint64_t *)buf;
+ uint64_t *stream = (uint64_t *)(buf + sz);
+ uint64_t *crypt = (uint64_t *)(buf + (2 * sz));
+ uint64_t ctr = dumpoff >> DUMP_CRYPT_BLOCKSHIFT;
+ chacha_ctx_t ctx;
+
+ /*
+ * If our size is not 8-byte aligned, prepare our ciphertext to the
+ * next 8-byte boundary.
+ */
+ if (nb & (sizeof (uint64_t) - 1)) {
+ assert(nb < sz);
+ nelems++;
+ }
+
+ chacha_keysetup(&ctx, key, DUMP_CRYPT_KEYLEN * 8, 0);
+ chacha_ivsetup(&ctx, dcrypt.dump_crypt_nonce, (uint8_t *)&ctr);
+
+ for (i = 0; i < nelems; i++) {
+ stream[i] = dumpoff;
+ dumpoff += sizeof (uint64_t);
+ }
+
+ chacha_encrypt_bytes(&ctx, (uint8_t *)stream, (uint8_t *)crypt, nb);
+
+ for (i = 0; i < nelems; i++)
+ clear[i] ^= crypt[i];
+}
+
+static void
+Verify(uint8_t *key)
+{
+ chacha_ctx_t ctx;
+ uint8_t hmac[DUMP_CRYPT_HMACLEN];
+
+ chacha_keysetup(&ctx, key, DUMP_CRYPT_KEYLEN * 8, 0);
+ chacha_ivsetup(&ctx, dcrypt.dump_crypt_nonce, NULL);
+
+ chacha_encrypt_bytes(&ctx, (uint8_t *)&dumphdr.dump_utsname,
+ (uint8_t *)hmac, DUMP_CRYPT_HMACLEN);
+
+ if (bcmp(hmac, &dcrypt.dump_crypt_hmac, DUMP_CRYPT_HMACLEN) == 0)
+ return;
+
+ logprint(SC_SL_NONE | SC_EXIT_ERR,
+ "provided key does not match encryption key");
+}
+
/*
* Copy whole sections of the dump device to the file.
*/
static void
Copy(offset_t dumpoff, len_t nb, offset_t *offp, int fd, char *buf,
- size_t sz)
+ size_t sz, uint8_t *key)
{
size_t nr;
offset_t off = *offp;
while (nb > 0) {
nr = sz < nb ? sz : (size_t)nb;
+
Pread(dumpfd, buf, nr, dumpoff);
+
+ if (dumphdr.dump_flags & DF_ENCRYPTED)
+ Decrypt(dumpoff, nr, buf, sz, key);
+
Pwrite(fd, buf, nr, off);
off += nr;
dumpoff += nr;
@@ -567,21 +657,56 @@ CopyPages(offset_t *offp, int fd, char *buf, size_t sz)
* Update corehdr with new offsets.
*/
static void
-copy_crashfile(const char *corefile)
+copy_crashfile(const char *corefile, const char *keyfile)
{
int corefd = Open(corefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ uint8_t keybuf[DUMP_CRYPT_KEYLEN];
size_t bufsz = FBUFSIZE;
- char *inbuf = Zalloc(bufsz);
+ char *inbuf;
offset_t coreoff;
size_t nb;
+ uint8_t *key = NULL;
+
+ if (dumphdr.dump_flags & DF_ENCRYPTED) {
+ int keyfd;
+
+ if (dcrypt.dump_crypt_algo != DUMP_CRYPT_ALGO_CHACHA20) {
+ logprint(SC_SL_NONE | SC_EXIT_ERR, "unrecognized dump "
+ "encryption algorithm %u", dcrypt.dump_crypt_algo);
+ }
+
+ if (keyfile == NULL) {
+ logprint(SC_SL_NONE | SC_EXIT_ERR, "dump is encrypted; "
+ "key must be provided");
+ }
- logprint(SC_SL_ERR | SC_IF_VERBOSE,
- "Copying %s to %s/%s\n", dumpfile, savedir, corefile);
+ keyfd = Open(keyfile, O_RDONLY, 0600);
+ Read(keyfd, keybuf, sizeof (keybuf));
+ (void) close(keyfd);
+
+ /*
+ * For the encrypted case, we triple our buffer size to
+ * allow for the stream buffer and the ciphertext buffer.
+ */
+ inbuf = Zalloc(bufsz * 3);
+ key = keybuf;
+ Verify(key);
+
+ logprint(SC_SL_ERR | SC_IF_VERBOSE, "Decrypting and copying "
+ "%s to %s/%s\n", dumpfile, savedir, corefile);
+ } else {
+ inbuf = Zalloc(bufsz);
+
+ logprint(SC_SL_ERR | SC_IF_VERBOSE,
+ "Copying %s to %s/%s\n", dumpfile, savedir, corefile);
+ }
/*
- * This dump file is still compressed
+ * This dump file is still compressed -- but it will no longer be
+ * encrypted.
*/
corehdr.dump_flags |= DF_COMPRESSED | DF_VALID;
+ corehdr.dump_flags &= ~DF_ENCRYPTED;
/*
* Leave room for corehdr, it is updated and written last
@@ -595,7 +720,7 @@ copy_crashfile(const char *corefile)
coreoff = roundup(coreoff, pagesize);
corehdr.dump_ksyms = coreoff;
Copy(dumphdr.dump_ksyms, dumphdr.dump_ksyms_csize, &coreoff, corefd,
- inbuf, bufsz);
+ inbuf, bufsz, key);
/*
* Save the pfn table.
@@ -603,7 +728,7 @@ copy_crashfile(const char *corefile)
coreoff = roundup(coreoff, pagesize);
corehdr.dump_pfn = coreoff;
Copy(dumphdr.dump_pfn, dumphdr.dump_npages * sizeof (pfn_t), &coreoff,
- corefd, inbuf, bufsz);
+ corefd, inbuf, bufsz, key);
/*
* Save the dump map.
@@ -611,7 +736,7 @@ copy_crashfile(const char *corefile)
coreoff = roundup(coreoff, pagesize);
corehdr.dump_map = coreoff;
Copy(dumphdr.dump_map, dumphdr.dump_nvtop * sizeof (mem_vtop_t),
- &coreoff, corefd, inbuf, bufsz);
+ &coreoff, corefd, inbuf, bufsz, key);
/*
* Save the data pages.
@@ -620,7 +745,7 @@ copy_crashfile(const char *corefile)
corehdr.dump_data = coreoff;
if (datahdr.dump_data_csize != 0)
Copy(dumphdr.dump_data, datahdr.dump_data_csize, &coreoff,
- corefd, inbuf, bufsz);
+ corefd, inbuf, bufsz, key);
else
CopyPages(&coreoff, corefd, inbuf, bufsz);
@@ -1657,6 +1782,8 @@ main(int argc, char *argv[])
struct rlimit rl;
long filebounds = -1;
char namelist[30], corefile[30], boundstr[30];
+ char *keyfile = NULL;
+
dumpfile = NULL;
startts = gethrtime();
@@ -1672,7 +1799,7 @@ main(int argc, char *argv[])
if (savedir != NULL)
savedir = strdup(savedir);
- while ((c = getopt(argc, argv, "Lvcdmf:r")) != EOF) {
+ while ((c = getopt(argc, argv, "Lvcdmf:rk:")) != EOF) {
switch (c) {
case 'L':
livedump++;
@@ -1696,6 +1823,9 @@ main(int argc, char *argv[])
dumpfile = optarg;
filebounds = getbounds(dumpfile);
break;
+ case 'k':
+ keyfile = optarg;
+ break;
case '?':
usage();
}
@@ -1756,6 +1886,18 @@ main(int argc, char *argv[])
read_dumphdr();
+ if (dumphdr.dump_flags & DF_ENCRYPTED) {
+ if (filemode) {
+ logprint(SC_SL_NONE | SC_EXIT_ERR, "saved dump file is "
+ "erroneously encrypted");
+ }
+
+ if (!csave) {
+ logprint(SC_SL_NONE | SC_EXIT_ERR, "dump is encrypted; "
+ "cannot be saved uncompressed");
+ }
+ }
+
/*
* We want this message to go to the log file, but not the console.
* There's no good way to do that with the existing syslog facility.
@@ -1860,7 +2002,7 @@ main(int argc, char *argv[])
"Saving compressed system crash dump in %s/%s",
savedir, corefile);
- copy_crashfile(corefile);
+ copy_crashfile(corefile, keyfile);
/*
* Raise a fault management event that indicates the system
@@ -1876,7 +2018,7 @@ main(int argc, char *argv[])
char *metrics = Zalloc(metrics_size + 1);
Pread(dumpfd, metrics, metrics_size, endoff +
- sizeof (dumphdr) + sizeof (datahdr));
+ dumphdr_size + sizeof (datahdr));
if (sec < 1)
sec = 1;
diff --git a/usr/src/common/crypto/chacha/chacha.c b/usr/src/common/crypto/chacha/chacha.c
index 5f9ef3b411..0a0b09919e 100644
--- a/usr/src/common/crypto/chacha/chacha.c
+++ b/usr/src/common/crypto/chacha/chacha.c
@@ -1,13 +1,25 @@
/*
+ * This implementation of ChaCha20 comes from the initial Dan Bernstein
+ * implementation, including a 256-bit key, a 64-bit nonce and a 64-bit
+ * counter. This is in contrast to ChaCha20 as defined in RFC 7539, which
+ * defines a 256-bit key, a 96-bit nonce and a 32-bit counter. In particular,
+ * kernel crash dump encryption relies on the fact that our larger counter
+ * allows for the encryption of very large messages (many gigabytes in
+ * length); any change to this implementation that reduces the size of the
+ * counter should be mindful of this use case.
+ */
+
+/*
chacha-merged.c version 20080118
D. J. Bernstein
Public domain.
*/
-/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */
+/* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */
-#include <chacha.h>
-#include <stddef.h>
+#include "chacha.h"
+#include <sys/stddef.h>
+#include <sys/null.h>
typedef unsigned char u8;
typedef unsigned int u32;
@@ -76,10 +88,10 @@ chacha_keysetup(chacha_ctx_t *x,const u8 *k,u32 kbits,u32 ivbits)
}
void
-chacha_ivsetup(chacha_ctx_t *x,const u8 *iv)
+chacha_ivsetup(chacha_ctx_t *x,const u8 *iv, const u8 *counter)
{
- x->chacha_input[12] = 0;
- x->chacha_input[13] = 0;
+ x->chacha_input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
+ x->chacha_input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
x->chacha_input[14] = U8TO32_LITTLE(iv + 0);
x->chacha_input[15] = U8TO32_LITTLE(iv + 4);
}
diff --git a/usr/src/common/crypto/chacha/chacha.h b/usr/src/common/crypto/chacha/chacha.h
index ac9993a8a4..edadca4934 100644
--- a/usr/src/common/crypto/chacha/chacha.h
+++ b/usr/src/common/crypto/chacha/chacha.h
@@ -10,7 +10,7 @@
*/
/*
- * Copyright (c) 2015, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _CHACHA_H
@@ -27,7 +27,7 @@
* over the data and xoring it with the generated cipher.
*/
-#include <inttypes.h>
+#include <sys/inttypes.h>
#ifdef __cplusplus
extern "C" {
@@ -39,7 +39,7 @@ typedef struct chacha_ctx {
extern void chacha_keysetup(chacha_ctx_t *, const uint8_t *, uint32_t,
uint32_t);
-extern void chacha_ivsetup(chacha_ctx_t *, const uint8_t *);
+extern void chacha_ivsetup(chacha_ctx_t *, const uint8_t *, const uint8_t *);
extern void chacha_encrypt_bytes(chacha_ctx_t *, const uint8_t *, uint8_t *,
uint32_t);
diff --git a/usr/src/lib/libc/port/gen/arc4random.c b/usr/src/lib/libc/port/gen/arc4random.c
index d82f12bd2a..f60ed09afc 100644
--- a/usr/src/lib/libc/port/gen/arc4random.c
+++ b/usr/src/lib/libc/port/gen/arc4random.c
@@ -2,7 +2,7 @@
* Copyright (c) 1996, David Mazieres <dm@uun.org>
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
* Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
- * Copyright (c) 2015 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -60,7 +60,7 @@ arc4_init(uint8_t *buf, size_t n)
abort();
chacha_keysetup(&arc4->arc4_chacha, buf, ARC4_KEYSZ * 8, 0);
- chacha_ivsetup(&arc4->arc4_chacha, buf + ARC4_KEYSZ);
+ chacha_ivsetup(&arc4->arc4_chacha, buf + ARC4_KEYSZ, NULL);
}
static void
diff --git a/usr/src/man/man1m/dumpadm.1m b/usr/src/man/man1m/dumpadm.1m
index 8d38d8474d..86f7285487 100644
--- a/usr/src/man/man1m/dumpadm.1m
+++ b/usr/src/man/man1m/dumpadm.1m
@@ -2,17 +2,18 @@
.\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved
.\" Copyright 2015 Nexenta Systems, Inc. All Rights Reserved.
.\" Copyright (c) 2013 by Delphix. All rights reserved.
+.\" Copyright 2019 Joyent, Inc.
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH DUMPADM 1M "Apr 09, 2015"
+.TH DUMPADM 1M "Jun 15, 2019"
.SH NAME
dumpadm \- configure operating system crash dump
.SH SYNOPSIS
.LP
.nf
\fB/usr/sbin/dumpadm\fR [\fB-enuy\fR] [\fB-c\fR \fIcontent-type\fR] [\fB-d\fR \fIdump-device\fR]
- [\fB-m\fR \fImin\fRk | \fImin\fRm | \fImin\fR%] [\fB-s\fR \fIsavecore-dir\fR]
+ [\fB-k\fR \fIkey-file\fR] [\fB-m\fR \fImin\fRk | \fImin\fRm | \fImin\fR%] [\fB-s\fR \fIsavecore-dir\fR]
[\fB-r\fR \fIroot-dir\fR] [\fB-z\fR on | off]
.fi
@@ -41,8 +42,10 @@ write it to the file system. The directory in which the crash
dump is saved on reboot can also be configured using \fBdumpadm\fR.
.sp
.LP
-When the operating system takes a crash dump the default behavior is to
-compress the crash dump. This behavior is controlled by the \fB-z\fR option.
+A crash dump is always compressed on the dump device. The dump is decompressed
+by the \fBsavecore\fR(1M) utility, which can optionally store the dump in its
+compressed state, thereby deferring decompression to a subsequent invocation
+of \fBsavecore\fR. This behavior is controlled by the \fB-z\fR option.
When compression is turned on, the \fBsavecore\fR(1M) utility writes one file
to the file system named \fIvmdump.X\fR. If compression is disabled, it instead
writes two files named \fIunix.X\fR and \fIvmcore.X\fR. In the uncompressed
@@ -50,6 +53,21 @@ case, both data files form the \fIsaved crash dump\fR. In both cases X is an
integer identifying the dump.
.sp
.LP
+Crash dump encryption may be optionally enabled via the \fB-k\fR option, which
+specifies a file that contains an encryption key. When crash dump encryption
+is enabled, the contents of kernel memory as stored in the dump device will be
+encrypted. Decryption of a kernel crash dump must occur when the dump is
+extracted via \fBsavecore\fR (to which the encryption key must be separately
+provided). Decompression can only occur on a decrypted dump; when dump
+encryption is enabled, \fBsavecore\fR must store the dump in its compressed
+state. Note that \fBsavecore\fR cannot extract an encrypted dump without also
+decrypting it; when dump encryption is enabled, the operator should be sure
+to only operate \fBsavecore\fR on a directory that is separately encrypted
+or otherwise secured. Finally, note that \fBdumpadm\fR does not store the
+crash dump encryption key persistently: upon system reset, crash dump
+encryption is always disabled.
+.sp
+.LP
For systems with a UFS root file system, the default dump device is configured
to be an appropriate swap partition. Swap partitions are disk partitions
reserved as virtual memory backing store for the operating system. Thus, no
@@ -68,6 +86,7 @@ example# \fBdumpadm\fR
Savecore directory: /var/crash/saturn
Savecore enabled: yes
Save compressed: on
+ Dump encrypted: no
.fi
.in -2
.sp
@@ -199,6 +218,18 @@ Estimates the size of the dump for the current running system.
.sp
.ne 2
.na
+\fB\fB-k\fR \fIkey-file\fR\fR
+.ad
+.sp .6
+.RS 4n
+Specifies that the dump should be encrypted based on the key found in
+\fIkey-file\fR. Note that any invocations of \fBsavecore\fR will need to
+specify the same key to be able to correctly retrieve the dump.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fB-m\fR \fImin\fR\fBk\fR | \fImin\fR\fBm\fR | \fImin\fR\fB%\fR\fR
.ad
.sp .6
@@ -346,6 +377,7 @@ example# dumpadm -d /dev/dsk/c0t2d0s2
Savecore directory: /var/crash/saturn
Savecore enabled: yes
Save compressed: on
+ Dump encrypted: no
.fi
.in -2
.sp
diff --git a/usr/src/man/man1m/savecore.1m b/usr/src/man/man1m/savecore.1m
index 28eee7cbba..051c9f2a9e 100644
--- a/usr/src/man/man1m/savecore.1m
+++ b/usr/src/man/man1m/savecore.1m
@@ -3,13 +3,13 @@
.\" Copyright (c) 1983 Regents of the University of California. All rights reserved. The Berkeley software License Agreement specifies the terms and conditions for redistribution.
.\" Copyright 2013 Nexenta Systems, Inc. All Rights Reserved.
.\" Copyright 2019 Joyent, Inc.
-.TH SAVECORE 1M "February 22, 2019"
+.TH SAVECORE 1M "Jun 15, 2019"
.SH NAME
savecore \- save a crash dump of the operating system
.SH SYNOPSIS
.LP
.nf
-\fB/usr/bin/savecore\fR [\fB-L\fR | \fB-r\fR] [\fB-vd\fR] [\fB-f\fR \fIdumpfile\fR] [\fIdirectory\fR]
+\fB/usr/bin/savecore\fR [\fB-L\fR | \fB-r\fR] [\fB-vd\fR] [\fB-k\fR \fIkeyfile\fR] [\fB-f\fR \fIdumpfile\fR] [\fIdirectory\fR]
.fi
.SH DESCRIPTION
@@ -61,10 +61,21 @@ the dump has already been saved.
\fB\fB-f\fR \fIdumpfile\fR\fR
.ad
.RS 15n
-Attempt to save a crash dump from the specified file instead of from the
-system's current dump device. This option may be useful if the information
-stored on the dump device has been copied to an on-disk file by means of the
-\fBdd\fR(1M) command.
+Uncompress and save a crash dump and kernel namelist data from the specified
+compressed dump file.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-k\fR \fIkeyfile\fR\fR
+.ad
+.RS 15n
+Specifies that the dump should be decrypted based on the key found
+in \fIkeyfile\fR. Encrypted dumps are always decrypted before being stored
+in the file system, and must always be stored compressed. (That is,
+decompression can only occur on a decrypted dump.) The key must match the
+key specified when dump encryption is enabled via \fBdumpadm\fR.
.RE
.sp
@@ -73,7 +84,7 @@ stored on the dump device has been copied to an on-disk file by means of the
\fB\fB-L\fR\fR
.ad
.RS 15n
-Save a crash dump of the live running Solaris system, without actually
+Save a crash dump of the live running system, without actually
rebooting or altering the system in any way. This option forces \fBsavecore\fR
to save a live snapshot of the system to the dump device, and then immediately
to retrieve the data and to write it out to a new set of crash dump files in
@@ -177,7 +188,7 @@ default crash dump directory
.SH SEE ALSO
.LP
-\fBadb\fR(1), \fBmdb\fR(1), \fBsvcs\fR(1), \fBdd\fR(1M), \fBdumpadm\fR(1M),
+\fBadb\fR(1), \fBmdb\fR(1), \fBsvcs\fR(1), \fBdumpadm\fR(1M),
\fBsvcadm\fR(1M), \fBsyslog\fR(3C), \fBattributes\fR(5), \fBsmf\fR(5)
.SH NOTES
.LP
diff --git a/usr/src/test/libc-tests/tests/random/chacha_tv.c b/usr/src/test/libc-tests/tests/random/chacha_tv.c
index 636ee114c8..a02c2905ab 100644
--- a/usr/src/test/libc-tests/tests/random/chacha_tv.c
+++ b/usr/src/test/libc-tests/tests/random/chacha_tv.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright (c) 2015, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -285,7 +285,7 @@ chacha_test(uint8_t *key, uint8_t keylen, uint8_t *iv, uint8_t *bl0,
bzero(res0, sizeof (res0));
bzero(res1, sizeof (res1));
chacha_keysetup(&ctx, key, keylen * 8, 0);
- chacha_ivsetup(&ctx, iv);
+ chacha_ivsetup(&ctx, iv, NULL);
chacha_encrypt_bytes(&ctx, res0, res0, sizeof (res0));
chacha_encrypt_bytes(&ctx, res1, res1, sizeof (res1));
ret = bcmp(res0, bl0, sizeof (res0));
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 43919b6e3a..48e7efb278 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -120,6 +120,7 @@ GENUNIX_OBJS += \
bz2huffman.o \
callb.o \
callout.o \
+ chacha.o \
chdir.o \
chmod.o \
chown.o \
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index 593c21d976..7395a22e5f 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -1602,6 +1602,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/rpc/sec_gss/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(COMMONBASE)/crypto/chacha/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(COMMONBASE)/crypto/edonr/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
diff --git a/usr/src/uts/common/io/dump.c b/usr/src/uts/common/io/dump.c
index 4fd52e6448..f4d8c1cf2c 100644
--- a/usr/src/uts/common/io/dump.c
+++ b/usr/src/uts/common/io/dump.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Delphix (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
@@ -46,6 +47,7 @@
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
+#include <sys/random.h>
static dev_info_t *dump_devi;
@@ -141,16 +143,20 @@ dump_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp)
*rvalp = dump_conflags;
if (dumpvp && !(dumpvp->v_flag & VISSWAP))
*rvalp |= DUMP_EXCL;
+
mutex_exit(&dump_lock);
break;
case DIOCSETCONF:
mutex_enter(&dump_lock);
if (arg == DUMP_KERNEL || arg == DUMP_ALL ||
- arg == DUMP_CURPROC)
- dump_conflags = arg;
- else
+ arg == DUMP_CURPROC) {
+ dump_conflags = (dump_conflags & DUMP_STATE) |
+ (arg & DUMP_CONTENT);
+ } else {
error = EINVAL;
+ }
+
mutex_exit(&dump_lock);
break;
@@ -181,6 +187,24 @@ dump_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp)
VN_RELE(vp);
break;
+ case DIOCSCRYPTKEY: {
+ uint8_t key[DUMP_CRYPT_KEYLEN];
+ uint8_t nonce[DUMP_CRYPT_NONCELEN];
+
+ if ((error = copyin((uint8_t *)arg, key, sizeof (key))) != 0)
+ break;
+
+ (void) random_get_pseudo_bytes(nonce, sizeof (nonce));
+
+ mutex_enter(&dump_lock);
+ bcopy(key, dump_crypt_key, DUMP_CRYPT_KEYLEN);
+ bcopy(nonce, dump_crypt_nonce, DUMP_CRYPT_NONCELEN);
+ dump_conflags |= DUMP_ENCRYPT; /* a one-way trip */
+ mutex_exit(&dump_lock);
+
+ break;
+ }
+
case DIOCDUMP:
mutex_enter(&dump_lock);
if (dumpvp == NULL)
diff --git a/usr/src/uts/common/os/dumpsubr.c b/usr/src/uts/common/os/dumpsubr.c
index 484b2042e2..868ed9e5c4 100644
--- a/usr/src/uts/common/os/dumpsubr.c
+++ b/usr/src/uts/common/os/dumpsubr.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
* Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
@@ -75,6 +75,7 @@
#include <sys/cpu.h>
#include <bzip2/bzlib.h>
+#include <crypto/chacha/chacha.h>
#define ONE_GIG (1024 * 1024 * 1024UL)
@@ -112,6 +113,8 @@ int dump_timeout = 120; /* timeout for dumping pages */
int dump_timeleft; /* portion of dump_timeout remaining */
int dump_ioerr; /* dump i/o error */
int dump_check_used; /* enable check for used pages */
+uint8_t dump_crypt_key[DUMP_CRYPT_KEYLEN]; /* dump encryption key */
+uint8_t dump_crypt_nonce[DUMP_CRYPT_NONCELEN]; /* dump nonce */
char *dump_stack_scratch; /* scratch area for saving stack summary */
/*
@@ -357,6 +360,7 @@ typedef struct dumpsync {
hrtime_t iotime; /* time spent writing nwrite bytes */
hrtime_t iowait; /* time spent waiting for output */
hrtime_t iowaitts; /* iowait timestamp */
+ hrtime_t crypt; /* time spent encrypting */
perpage_t perpage; /* metrics */
perpage_t perpagets;
int dumpcpu; /* master cpu */
@@ -435,6 +439,7 @@ typedef struct dumpbuf {
char *cur; /* dump write pointer */
char *start; /* dump buffer address */
char *end; /* dump buffer end */
+ char *scratch; /* scratch buffer */
size_t size; /* size of dumpbuf in bytes */
size_t iosize; /* best transfer size for device */
} dumpbuf_t;
@@ -493,11 +498,16 @@ dumpbuf_resize(void)
if (new_size <= old_size)
return; /* no need to reallocate buffer */
- new_buf = kmem_alloc(new_size, KM_SLEEP);
+ /*
+ * Allocate thrice the size of buffer to allow for space for the stream
+ * and its ciphertext should encryption be enabled (or become so).
+ */
+ new_buf = kmem_alloc(new_size * 3, KM_SLEEP);
dumpbuf.size = new_size;
dumpbuf.start = new_buf;
dumpbuf.end = new_buf + new_size;
- kmem_free(old_buf, old_size);
+ dumpbuf.scratch = dumpbuf.end + new_size;
+ kmem_free(old_buf, old_size * 3);
}
/*
@@ -1125,9 +1135,16 @@ dumphdr_init(void)
dumphdr->dump_pagesize = PAGESIZE;
dumphdr->dump_utsname = utsname;
(void) strcpy(dumphdr->dump_platform, platform);
+
+ /*
+ * Allocate our buffer, assuring enough room for encryption
+ * should it become configured.
+ */
dumpbuf.size = dumpbuf_iosize(maxphys);
- dumpbuf.start = kmem_alloc(dumpbuf.size, KM_SLEEP);
+ dumpbuf.start = kmem_alloc(dumpbuf.size * 3, KM_SLEEP);
dumpbuf.end = dumpbuf.start + dumpbuf.size;
+ dumpbuf.scratch = dumpbuf.end + dumpbuf.size;
+
dumpcfg.pids = kmem_alloc(v.v_proc * sizeof (pid_t), KM_SLEEP);
dumpcfg.helpermap = kmem_zalloc(BT_SIZEOFMAP(NCPU), KM_SLEEP);
LOCK_INIT_HELD(&dumpcfg.helper_lock);
@@ -1317,6 +1334,41 @@ dumpfini(void)
dumppath = NULL;
}
+static void
+dumpvp_encrypt(size_t size)
+{
+ size_t nelems = size / sizeof (uint64_t), i;
+ uint64_t *start = (uint64_t *)dumpbuf.start;
+ uint64_t *stream = (uint64_t *)dumpbuf.end;
+ uint64_t *crypt = (uint64_t *)dumpbuf.scratch;
+ uint64_t ctr = dumpbuf.vp_off >> DUMP_CRYPT_BLOCKSHIFT;
+ hrtime_t ts = gethrtime();
+ offset_t dumpoff = dumpbuf.vp_off;
+ chacha_ctx_t ctx;
+
+ /*
+ * Our size should be 64-bit aligned and our offset must be aligned
+ * to our crypto blocksize.
+ */
+ ASSERT(!(size & (sizeof (uint64_t) - 1)));
+ ASSERT(!(dumpbuf.vp_off & ((1 << DUMP_CRYPT_BLOCKSHIFT) - 1)));
+
+ chacha_keysetup(&ctx, dump_crypt_key, DUMP_CRYPT_KEYLEN * 8, 0);
+ chacha_ivsetup(&ctx, dump_crypt_nonce, (uint8_t *)&ctr);
+
+ for (i = 0; i < nelems; i++) {
+ stream[i] = dumpoff;
+ dumpoff += sizeof (uint64_t);
+ }
+
+ chacha_encrypt_bytes(&ctx, (uint8_t *)stream, (uint8_t *)crypt, size);
+
+ for (i = 0; i < nelems; i++)
+ start[i] ^= crypt[i];
+
+ dumpsync.crypt += gethrtime() - ts;
+}
+
static offset_t
dumpvp_flush(void)
{
@@ -1328,6 +1380,17 @@ dumpvp_flush(void)
dump_ioerr = ENOSPC;
dumpbuf.vp_off = dumpbuf.vp_limit;
} else if (size != 0) {
+ /*
+ * If our dump is encrypted and this is neither the initial
+ * dump header nor the terminal dump header and metrics,
+ * encrypt the buffer before writing it.
+ */
+ if ((dump_conflags & DUMP_ENCRYPT) &&
+ dumpbuf.vp_off > dumphdr->dump_start &&
+ dumpbuf.vp_off < dumpbuf.vp_limit - DUMP_OFFSET) {
+ dumpvp_encrypt(size);
+ }
+
iotime = gethrtime();
dumpsync.iowait += iotime - dumpsync.iowaitts;
if (panicstr)
@@ -2618,6 +2681,7 @@ dumpsys_metrics(dumpsync_t *ds, char *buf, size_t size)
P("Dump I/O rate MBS,%d.%02d\n", iorate / 100, iorate % 100);
P("..total bytes,%lld\n", (u_longlong_t)ds->nwrite);
P("..total nsec,%lld\n", (u_longlong_t)ds->iotime);
+ P("..crypt nsec,%lld\n", (u_longlong_t)ds->crypt);
P("dumpbuf.iosize,%ld\n", dumpbuf.iosize);
P("dumpbuf.size,%ld\n", dumpbuf.size);
@@ -2658,6 +2722,29 @@ dumpsys_metrics(dumpsync_t *ds, char *buf, size_t size)
}
#endif /* COLLECT_METRICS */
+CTASSERT(DUMP_CRYPT_HMACLEN <= sizeof (struct utsname));
+
+/*
+ * Mark the dump as encrypted and calculate our (crude) HMAC based on the
+ * dump_utsname. (The purpose of the HMAC is to merely allow for incorrect
+ * keys to be quickly rejected.)
+ */
+void
+dumpsys_crypt(dumphdr_t *dumphdr, dump_crypt_t *dcrypt)
+{
+ chacha_ctx_t ctx;
+
+ dumphdr->dump_flags |= DF_ENCRYPTED;
+ bcopy(dump_crypt_nonce, dcrypt->dump_crypt_nonce, DUMP_CRYPT_NONCELEN);
+ dcrypt->dump_crypt_algo = DUMP_CRYPT_ALGO_CHACHA20;
+
+ chacha_keysetup(&ctx, dump_crypt_key, DUMP_CRYPT_KEYLEN * 8, 0);
+ chacha_ivsetup(&ctx, dump_crypt_nonce, NULL);
+
+ chacha_encrypt_bytes(&ctx, (uint8_t *)&dumphdr->dump_utsname,
+ (uint8_t *)&dcrypt->dump_crypt_hmac, DUMP_CRYPT_HMACLEN);
+}
+
/*
* Dump the system.
*/
@@ -2679,6 +2766,7 @@ dumpsys(void)
dumpmlw_t mlw;
dumpcsize_t datatag;
dumpdatahdr_t datahdr;
+ dump_crypt_t dcrypt;
if (dumpvp == NULL || dumphdr == NULL) {
uprintf("skipping system dump - no dump device configured\n");
@@ -2733,6 +2821,9 @@ dumpsys(void)
/* Make sure nodename is current */
bcopy(utsname.nodename, dumphdr->dump_utsname.nodename, SYS_NMLN);
+ if (dump_conflags & DUMP_ENCRYPT)
+ dumpsys_crypt(dumphdr, &dcrypt);
+
/*
* If this is a live dump, try to open a VCHR vnode for better
* performance. We must take care to flush the buffer cache
@@ -2999,11 +3090,19 @@ dumpsys(void)
*/
dumpbuf.vp_off = dumphdr->dump_start;
dumpvp_write(dumphdr, sizeof (dumphdr_t));
+
+ if (dump_conflags & DUMP_ENCRYPT)
+ dumpvp_write(&dcrypt, sizeof (dump_crypt_t));
+
(void) dumpvp_flush();
dumpbuf.vp_limit = dumpvp_size;
dumpbuf.vp_off = dumpbuf.vp_limit - DUMP_OFFSET;
dumpvp_write(dumphdr, sizeof (dumphdr_t));
+
+ if (dump_conflags & DUMP_ENCRYPT)
+ dumpvp_write(&dcrypt, sizeof (dump_crypt_t));
+
dumpvp_write(&datahdr, sizeof (dumpdatahdr_t));
dumpvp_write(dumpcfg.cbuf[0].buf, datahdr.dump_metrics);
diff --git a/usr/src/uts/common/sys/dumpadm.h b/usr/src/uts/common/sys/dumpadm.h
index 616828bb2b..8ca10ff3c5 100644
--- a/usr/src/uts/common/sys/dumpadm.h
+++ b/usr/src/uts/common/sys/dumpadm.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _SYS_DUMPADM_H
@@ -44,11 +45,13 @@ extern "C" {
#define DIOCSETUUID (DDIOC | 0x17)
#define DIOCGETUUID (DDIOC | 0x18)
#define DIOCRMDEV (DDIOC | 0x19)
+#define DIOCSCRYPTKEY (DDIOC | 0x1a)
/*
* Kernel-controlled dump state flags for dump_conflags
*/
#define DUMP_EXCL 0x00000001 /* dedicated dump device (not swap) */
+#define DUMP_ENCRYPT 0x00000002 /* encrypt dump */
#define DUMP_STATE 0x0000ffff /* the set of all kernel flags */
/*
diff --git a/usr/src/uts/common/sys/dumphdr.h b/usr/src/uts/common/sys/dumphdr.h
index f418913257..57a9a9c2dc 100644
--- a/usr/src/uts/common/sys/dumphdr.h
+++ b/usr/src/uts/common/sys/dumphdr.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _SYS_DUMPHDR_H
@@ -60,6 +61,22 @@ extern "C" {
sizeof (summary_dump_t) + 1024), \
DUMP_OFFSET)) /* summary save area */
+#define DUMP_CRYPT_KEYLEN 32 /* byte len for crypto key */
+#define DUMP_CRYPT_NONCELEN 8 /* byte len for nonce */
+#define DUMP_CRYPT_HMACLEN 64 /* byte len for HMAC */
+#define DUMP_CRYPT_BLOCKSHIFT 6 /* 64-byte blocks */
+
+#define DUMP_CRYPT_ALGO_NONE 0 /* dump not encrypted */
+#define DUMP_CRYPT_ALGO_CHACHA20 1 /* ChaCha20 */
+
+#if DUMP_OFFSET & ((1 << DUMP_CRYPT_BLOCKSHIFT) - 1)
+#error DUMP_OFFSET not DUMP_CRYPT_BLOCKSHIFT aligned
+#endif
+
+#if DUMP_LOGSIZE & ((1 << DUMP_CRYPT_BLOCKSHIFT) - 1)
+#error DUMP_LOGSIZE not DUMP_CRYPT_BLOCKSHIFT aligned
+#endif
+
typedef struct dumphdr {
uint32_t dump_magic; /* magic number */
uint32_t dump_version; /* version number */
@@ -86,12 +103,22 @@ typedef struct dumphdr {
} dumphdr_t;
/*
+ * If DF_ENCRYPTED is set, this header will be found after the dumphdr.
+ */
+typedef struct dump_crypt {
+ uint8_t dump_crypt_algo; /* encryption algorithm */
+ uint8_t dump_crypt_hmac[DUMP_CRYPT_HMACLEN]; /* HMAC for crypto key */
+ uint8_t dump_crypt_nonce[DUMP_CRYPT_NONCELEN]; /* encryption none */
+} dump_crypt_t;
+
+/*
* Values for dump_flags
*/
#define DF_VALID 0x00000001 /* Dump is valid (savecore clears) */
#define DF_COMPLETE 0x00000002 /* All pages present as configured */
#define DF_LIVE 0x00000004 /* Dump was taken on a live system */
#define DF_COMPRESSED 0x00000008 /* Dump is compressed */
+#define DF_ENCRYPTED 0x00000010 /* Dump is encrypted */
#define DF_KERNEL 0x00010000 /* Contains kernel pages only */
#define DF_ALL 0x00020000 /* Contains all pages */
#define DF_CURPROC 0x00040000 /* Contains kernel + cur proc pages */
@@ -175,6 +202,8 @@ extern u_offset_t dumpvp_size;
extern struct dumphdr *dumphdr;
extern int dump_conflags;
extern char *dumppath;
+extern uint8_t dump_crypt_key[DUMP_CRYPT_KEYLEN];
+extern uint8_t dump_crypt_nonce[DUMP_CRYPT_NONCELEN];
extern int dump_timeout;
extern int dump_timeleft;