Page MenuHomeFreeBSD

D4712.id11701.diff
No OneTemporary

D4712.id11701.diff

Index: etc/defaults/rc.conf
===================================================================
--- etc/defaults/rc.conf
+++ etc/defaults/rc.conf
@@ -591,6 +591,7 @@
chkprintcap_flags="-d" # Create missing directories by default.
dumpdev="AUTO" # Device to crashdump to (device name, AUTO, or NO).
dumpdir="/var/crash" # Directory where crash dumps are to be stored
+dumppubkey="" # Public key for encrypted kernel crash dumps.
savecore_flags="-m 10" # Used if dumpdev is enabled above, and present.
# By default, only the 10 most recent kernel dumps
# are saved.
Index: etc/rc.d/dumpon
===================================================================
--- etc/rc.d/dumpon
+++ etc/rc.d/dumpon
@@ -16,7 +16,12 @@
dumpon_try()
{
- if /sbin/dumpon "${1}" ; then
+ if [ -n "${dumppubkey}" ]; then
+ /sbin/dumpon -k "${dumppubkey}" "${1}"
+ else
+ /sbin/dumpon "${1}"
+ fi
+ if [ $? -eq 0 ]; then
# Make a symlink in devfs for savecore
ln -fs "${1}" /dev/dumpdev
return 0
Index: sbin/Makefile
===================================================================
--- sbin/Makefile
+++ sbin/Makefile
@@ -12,6 +12,7 @@
comcontrol \
conscontrol \
ddb \
+ decryptcore \
devfs \
dhclient \
dmesg \
Index: sbin/decryptcore/Makefile
===================================================================
--- /dev/null
+++ sbin/decryptcore/Makefile
@@ -0,0 +1,14 @@
+PROG= decryptcore
+
+SRCS= ${PROG}.c
+
+LIBADD= crypto pjdlog
+
+MAN= decryptcore.8
+
+CFLAGS+=-I${.CURDIR}/../../sys
+CFLAGS+=-I${.CURDIR}/../../lib/libpjdlog
+
+WARNS?= 6
+
+.include <bsd.prog.mk>
Index: sbin/decryptcore/decryptcore.8
===================================================================
--- /dev/null
+++ sbin/decryptcore/decryptcore.8
@@ -0,0 +1,79 @@
+.\" Copyright (c) 2015 Konrad Witaszczyk <def@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd December 1, 2015
+.Dt DECRYPTCORE 8
+.Os
+.Sh NAME
+.Nm decryptcore
+.Nd "decrypt a core dump of the operating system"
+.Sh SYNOPSIS
+.Nm
+.Op Fl L
+.Op Fl v
+.Ar privatekey
+.Ar encryptedkey
+.Ar encryptedcore
+.Ar decryptedcore
+.Sh DESCRIPTION
+The
+.Nm
+first decrypts
+.Ar encryptedkey
+using
+.Ar privatekey
+and then uses the resulting key to decrypt
+.Ar encryptedcore
+saved by
+.Xr savecore 8 .
+Result is saved in
+.Ar decryptedcore .
+.Pp
+The
+.Nm
+utility can be started with the following command line arguments:
+.Bl -tag -width ".Fl L"
+.It Fl L
+Write log messages to
+.Xr syslogd 8 .
+.It Fl v
+Print or log verbose/debugging information.
+This option can be specified multiple times to raise the verbosity
+level.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr capsicum 4 ,
+.Xr dumpon 8 ,
+.Xr savecore 8 ,
+.Xr syslogd 8
+.Sh AUTHORS
+The
+.Nm
+was implemented by
+.An -nosplit
+.An Konrad Witaszczyk Aq Mt def@FreeBSD.org .
Index: sbin/decryptcore/decryptcore.c
===================================================================
--- /dev/null
+++ sbin/decryptcore/decryptcore.c
@@ -0,0 +1,354 @@
+/*-
+ * Copyright (c) 2015 Konrad Witaszczyk <def@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/capsicum.h>
+#include <sys/endian.h>
+#include <sys/kerneldump.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/engine.h>
+
+#include <fcntl.h>
+#include <pjdlog.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void
+usage(void)
+{
+
+ pjdlog_exitx(1, "usage: decryptcore [-Lv] privatekey encryptedkey encryptedcore decryptedcore");
+}
+
+static int
+wait_for_process(pid_t pid)
+{
+ int status;
+
+ if (waitpid(pid, &status, WUNTRACED | WEXITED) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to wait for a child process");
+ return (1);
+ }
+
+ if (WIFEXITED(status))
+ return (WEXITSTATUS(status));
+
+ return (1);
+}
+
+static struct kerneldumpkey *
+read_key(int kfd)
+{
+ uint8_t *buf, *p;
+ struct kerneldumpkey *kdk;
+ uint32_t encryptedkeysize;
+ ssize_t size;
+ size_t kdksize, bytes;
+
+ PJDLOG_ASSERT(kfd >= 0);
+
+ buf = NULL;
+ kdk = NULL;
+
+ kdksize = sizeof(*kdk);
+ kdk = calloc(1, kdksize);
+ if (kdk == NULL) {
+ pjdlog_errno(LOG_ERR, "Unable to allocate kernel dump key");
+ goto failed;
+ }
+
+ bytes = sizeof(kdk->kdk_encryption) + sizeof(kdk->kdk_iv) +
+ sizeof(kdk->kdk_encryptedkeysize);
+ buf = calloc(1, bytes);
+ if (buf == NULL) {
+ pjdlog_errno(LOG_ERR, "Unable to allocate buffer");
+ goto failed;
+ }
+
+ size = read(kfd, buf, bytes);
+ if (size == (ssize_t)bytes) {
+ p = buf;
+ kdk->kdk_encryption = *p;
+ p += sizeof(kdk->kdk_encryption);
+ bcopy(p, kdk->kdk_iv, sizeof(kdk->kdk_iv));
+ p += sizeof(kdk->kdk_iv);
+ bcopy(p, &encryptedkeysize, sizeof(encryptedkeysize));
+ kdk->kdk_encryptedkeysize = dtoh32(encryptedkeysize);
+ p += sizeof(encryptedkeysize);
+
+ kdksize += (size_t)kdk->kdk_encryptedkeysize;
+ kdk = realloc(kdk, kdksize);
+ if (kdk == NULL) {
+ pjdlog_errno(LOG_ERR, "Unable to reallocate kernel dump key");
+ goto failed;
+ }
+ bytes += (size_t)kdk->kdk_encryptedkeysize;
+ size += read(kfd, &kdk->kdk_encryptedkey,
+ kdk->kdk_encryptedkeysize);
+ }
+ if (size != (ssize_t)bytes) {
+ pjdlog_errno(LOG_ERR, "Unable to read key");
+ goto failed;
+ }
+
+ free(buf);
+ return (kdk);
+failed:
+ free(buf);
+ free(kdk);
+ return (NULL);
+}
+
+static bool
+decrypt(const char *privkeyfile, const char *keyfile, const char *input,
+ const char *output)
+{
+ uint8_t buf[2 * KERNELDUMP_BLOCK_SIZE], key[KERNELDUMP_KEY_MAX_SIZE];
+ EVP_CIPHER_CTX ctx;
+ const EVP_CIPHER *cipher;
+ FILE *fp;
+ struct kerneldumpkey *kdk;
+ RSA *privkey;
+ int ifd, kfd, ofd, olen, privkeysize;
+ ssize_t bytes;
+ pid_t pid;
+
+ PJDLOG_ASSERT(privkeyfile != NULL);
+ PJDLOG_ASSERT(keyfile != NULL);
+ PJDLOG_ASSERT(input != NULL);
+ PJDLOG_ASSERT(output != NULL);
+
+ privkey = NULL;
+
+ /*
+ * Decrypt a core dump in a child process so we can unlink a partially
+ * decrypted core if the child process fails.
+ */
+ pid = fork();
+ if (pid == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to create child process");
+ return (false);
+ }
+
+ if (pid > 0)
+ return (wait_for_process(pid) == 0);
+
+ kfd = open(keyfile, O_RDONLY);
+ if (kfd == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to open %s", keyfile);
+ goto failed;
+ }
+ ifd = open(input, O_RDONLY);
+ if (ifd == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to open %s", input);
+ goto failed;
+ }
+ ofd = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (ofd == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to open %s", output);
+ goto failed;
+ }
+ fp = fopen(privkeyfile, "r");
+ if (fp == NULL) {
+ pjdlog_errno(LOG_ERR, "Unable to open %s", privkeyfile);
+ goto failed;
+ }
+
+ if (cap_enter() == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to enter capability mode");
+ goto failed;
+ }
+
+ privkey = RSA_new();
+ if (privkey == NULL) {
+ pjdlog_error("Unable to allocate an RSA structure: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto failed;
+ }
+ EVP_CIPHER_CTX_init(&ctx);
+
+ kdk = read_key(kfd);
+ close(kfd);
+ if (kdk == NULL)
+ goto failed;
+
+ privkey = PEM_read_RSAPrivateKey(fp, &privkey, NULL, NULL);
+ fclose(fp);
+ if (privkey == NULL) {
+ pjdlog_error("Unable to read data from %s.", privkeyfile);
+ goto failed;
+ }
+
+ privkeysize = RSA_size(privkey);
+ if (privkeysize != (int)kdk->kdk_encryptedkeysize) {
+ pjdlog_error("RSA modulus size mismatch: equals %db and should be %ub.",
+ 8 * privkeysize, 8 * kdk->kdk_encryptedkeysize);
+ goto failed;
+ }
+
+ switch (kdk->kdk_encryption) {
+ case KERNELDUMP_ENC_AES_256_CBC:
+ cipher = EVP_aes_256_cbc();
+ break;
+ default:
+ pjdlog_error("Invalid encryption algorithm.");
+ goto failed;
+ }
+
+ if (RSA_private_decrypt(kdk->kdk_encryptedkeysize,
+ kdk->kdk_encryptedkey, key, privkey,
+ RSA_PKCS1_PADDING) != sizeof(key)) {
+ pjdlog_error("Unable to decrypt key: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto failed;
+ }
+ RSA_free(privkey);
+ privkey = NULL;
+
+ EVP_DecryptInit_ex(&ctx, cipher, NULL, key, kdk->kdk_iv);
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ bzero(key, sizeof(key));
+
+ do {
+ bytes = read(ifd, buf, sizeof(buf));
+ if (bytes < 0) {
+ pjdlog_errno(LOG_ERR, "Unable to read data from %s",
+ input);
+ goto failed;
+ } else if (bytes == 0) {
+ break;
+ }
+
+ if (bytes > 0) {
+ if (EVP_DecryptUpdate(&ctx, buf, &olen, buf,
+ bytes) == 0) {
+ pjdlog_error("Unable to decrypt core.");
+ goto failed;
+ }
+ } else {
+ if (EVP_DecryptFinal_ex(&ctx, buf, &olen) == 0) {
+ pjdlog_error("Unable to decrypt core.");
+ goto failed;
+ }
+ }
+
+ if (olen == 0)
+ continue;
+
+ if (write(ofd, buf, olen) != olen) {
+ pjdlog_errno(LOG_ERR, "Unable to write data to %s",
+ output);
+ goto failed;
+ }
+ } while (bytes > 0);
+
+ bzero(buf, sizeof(buf));
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ exit(0);
+failed:
+ bzero(key, sizeof(key));
+ bzero(buf, sizeof(buf));
+ RSA_free(privkey);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct stat sb;
+ const char *input, *keyfile, *output, *rsakeyfile;
+ int ch, debug;
+ bool usesyslog;
+
+ pjdlog_init(PJDLOG_MODE_STD);
+ pjdlog_prefix_set("(decryptcore) ");
+
+ debug = 0;
+ rsakeyfile = NULL;
+ usesyslog = false;
+ while ((ch = getopt(argc, argv, "Lv")) != -1) {
+ switch (ch) {
+ case 'L':
+ usesyslog = true;
+ break;
+ case 'v':
+ debug++;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ rsakeyfile = *argv;
+ argc--;
+ argv++;
+ if (rsakeyfile == NULL)
+ usage();
+ keyfile = *argv;
+ argc--;
+ argv++;
+ if (keyfile == NULL)
+ usage();
+ input = *argv;
+ argc--;
+ argv++;
+ if (input == NULL)
+ usage();
+ output = *argv;
+ argc--;
+ argv++;
+ if (output == NULL)
+ usage();
+
+ if (argc != 0)
+ usage();
+
+ if (usesyslog)
+ pjdlog_mode_set(PJDLOG_MODE_SYSLOG);
+ pjdlog_debug_set(debug);
+
+ if (!decrypt(rsakeyfile, keyfile, input, output)) {
+ if (stat(output, &sb) == 0 && unlink(output) != 0)
+ pjdlog_exit(1, "Unable to remove output");
+ exit(1);
+ }
+
+ pjdlog_fini();
+
+ exit(0);
+}
Index: sbin/dumpon/Makefile
===================================================================
--- sbin/dumpon/Makefile
+++ sbin/dumpon/Makefile
@@ -1,6 +1,9 @@
# $FreeBSD$
PROG= dumpon
+
+LIBADD= crypto
+
MAN= dumpon.8
.include <bsd.prog.mk>
Index: sbin/dumpon/dumpon.8
===================================================================
--- sbin/dumpon/dumpon.8
+++ sbin/dumpon/dumpon.8
@@ -37,6 +37,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl v
+.Op Fl k Ar public_key
.Ar special_file
.Nm
.Op Fl v
@@ -56,7 +57,9 @@
.Pa /etc/rc ,
controlled by the
.Dq dumpdev
-variable in the boot time configuration file
+and
+.Dq dumppubkey
+variables in the boot time configuration file
.Pa /etc/rc.conf .
.Pp
The default type of kernel crash dump is the mini crash dump.
@@ -82,6 +85,30 @@
variable.
.Pp
The
+.Op Fl k Ar public_key
+flag causes
+.Nm
+to generate an one-time key for kernel crash dump encryption.
+The key is encrypted using
+.Ar public_key .
+This process is sandboxed using
+.Xr capsicum 4 .
+Both plain and encrypted keys are send to kernel using
+.Dv DIOCSKERNELDUMP
+.Xr ioctl 2 .
+User can specify
+.Ar public_key
+in
+.Dq dumppubkey
+variable defined in
+.Pa /etc/rc.conf
+for use with
+.Pa /etc/rc.d/dumpon
+.Xr rc 8
+script.
+This option requires to compile EKCD into the kernel.
+.Pp
+The
.Fl l
flag causes
.Nm
@@ -140,13 +167,86 @@
.It Pa /etc/rc.conf
boot-time system configuration
.El
+.Sh EXAMPLES
+In order to generate an RSA private key user can use the
+.Xr genrsa 1
+tool:
+.Pp
+.Dl # openssl genrsa -out private.pem 4096
+.Pp
+A public key can be extracted from the private key using the
+.Xr rsa 1
+tool:
+.Pp
+.Dl # openssl rsa -in private.pem -out public.pem -pubout
+.Pp
+Once the RSA keys are created the private key should be moved to a safe place.
+Now
+.Pa public.pem
+can be used by
+.Nm
+to configure encrypted kernel crash dumps:
+.Pp
+.Dl # dumpon -k public.pem /dev/ada0s1b
+.Pp
+It is recommended to test if the kernel saves encrypted crash dumps using the
+current configuration.
+The easiest way to do that is to run the
+.Xr ddb 4
+debugger:
+.Pp
+.Dl # sysctl debug.kdb.enter=1
+.Pp
+In the debugger the following commands should be typed to write a core dump and
+exit:
+.Pp
+.Dl db> call doadump(0)
+.Dl db> continue
+.Pp
+.Xr savecore 8
+should be able to save the core dump in the core directory which is
+.Pa /var/crash
+by default:
+.Pp
+.Dl # savecore /var/crash /dev/ada0s1b
+.Pp
+Three files should be created in the core directory:
+.Pa info.# ,
+.Pa key.#
+and
+.Pa vmcore.#
+where
+.Dq #
+is the number of the last core dump saved by
+.Xr savecore 8 .
+The
+.Pa vmcore.#
+can be decrypted using the
+.Xr decryptcore 8
+utility:
+.Pp
+.Dl # decryptcore private.pem key.# vmcore.# vmcore-decrypted.#
+.Pp
+The
+.Pa vmcore-decrypted.#
+can be now examined using
+.Xr kgdb 1 :
+.Pp
+.Dl # kgdb /usr/obj/sys/GENERIC/kernel.debug vmcore-decrypted.#
+.Pp
+The core was decrypted properly if
+.Xr kgdb 1
+does not print any errors.
.Sh SEE ALSO
+.Xr kgdb 1 ,
+.Xr ddb 4 ,
.Xr fstab 5 ,
.Xr rc.conf 5 ,
.Xr config 8 ,
.Xr init 8 ,
.Xr loader 8 ,
.Xr rc 8 ,
+.Xr decryptcore 8 ,
.Xr savecore 8 ,
.Xr swapon 8 ,
.Xr panic 9
Index: sbin/dumpon/dumpon.c
===================================================================
--- sbin/dumpon/dumpon.c
+++ sbin/dumpon/dumpon.c
@@ -42,9 +42,15 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/capsicum.h>
#include <sys/disk.h>
#include <sys/sysctl.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+
+#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@@ -62,7 +68,7 @@
usage(void)
{
fprintf(stderr, "%s\n%s\n%s\n",
- "usage: dumpon [-v] special_file",
+ "usage: dumpon [-v] [-k public_key] special_file",
" dumpon [-v] off",
" dumpon [-v] -l");
exit(EX_USAGE);
@@ -95,6 +101,57 @@
}
static void
+genkey(const char *pubkeyfile, struct diocskerneldump_arg *kda)
+{
+ FILE *fp;
+ RSA *pubkey;
+
+ assert(pubkeyfile != NULL);
+ assert(kda != NULL);
+
+ fp = NULL;
+ pubkey = NULL;
+
+ fp = fopen(pubkeyfile, "r");
+ if (fp == NULL)
+ err(1, "Unable to open %s", pubkeyfile);
+
+ if (cap_enter() == -1)
+ err(1, "Unable to enter capability mode");
+
+ pubkey = RSA_new();
+ if (pubkey == NULL) {
+ errx(1, "Unable to allocate an RSA structure: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
+
+ pubkey = PEM_read_RSA_PUBKEY(fp, &pubkey, NULL, NULL);
+ fclose(fp);
+ fp = NULL;
+ if (pubkey == NULL)
+ errx(1, "Unable to read data from %s.", pubkeyfile);
+
+ kda->kda_encryptedkeysize = RSA_size(pubkey);
+ if (kda->kda_encryptedkeysize > KERNELDUMP_ENCKEY_MAX_SIZE) {
+ errx(1, "Public key has to be at most %db long.",
+ 8 * KERNELDUMP_ENCKEY_MAX_SIZE);
+ }
+
+ kda->kda_encryptedkey = calloc(1, kda->kda_encryptedkeysize);
+ if (kda->kda_encryptedkey == NULL)
+ err(1, "Unable to allocate encrypted key");
+
+ kda->kda_encryption = KERNELDUMP_ENC_AES_256_CBC;
+ arc4random_buf(kda->kda_key, sizeof(kda->kda_key));
+ if (RSA_public_encrypt(sizeof(kda->kda_key), kda->kda_key,
+ kda->kda_encryptedkey, pubkey,
+ RSA_PKCS1_PADDING) != (int)kda->kda_encryptedkeysize) {
+ errx(1, "Unable to encrypt the one-time key.");
+ }
+ RSA_free(pubkey);
+}
+
+static void
listdumpdev(void)
{
char dumpdev[PATH_MAX];
@@ -123,13 +180,19 @@
int
main(int argc, char *argv[])
{
+ struct diocskerneldump_arg kda;
+ const char *pubkeyfile;
int ch;
int i, fd;
- u_int u;
int do_listdumpdev = 0;
- while ((ch = getopt(argc, argv, "lv")) != -1)
+ pubkeyfile = NULL;
+
+ while ((ch = getopt(argc, argv, "k:lv")) != -1)
switch((char)ch) {
+ case 'k':
+ pubkeyfile = optarg;
+ break;
case 'l':
do_listdumpdev = 1;
break;
@@ -171,18 +234,29 @@
if (fd < 0)
err(EX_OSFILE, "%s", dumpdev);
check_size(fd, dumpdev);
- u = 0;
- i = ioctl(fd, DIOCSKERNELDUMP, &u);
- u = 1;
- i = ioctl(fd, DIOCSKERNELDUMP, &u);
+ bzero(&kda, sizeof(kda));
+
+ kda.kda_enable = 0;
+ i = ioctl(fd, DIOCSKERNELDUMP, &kda);
+ bzero(&kda, sizeof(kda));
+
+ if (pubkeyfile != NULL)
+ genkey(pubkeyfile, &kda);
+ kda.kda_enable = 1;
+ i = ioctl(fd, DIOCSKERNELDUMP, &kda);
+ bzero(kda.kda_encryptedkey, kda.kda_encryptedkeysize);
+ free(kda.kda_encryptedkey);
+ bzero(&kda, sizeof(kda));
if (i == 0 && verbose)
printf("kernel dumps on %s\n", dumpdev);
} else {
fd = open(_PATH_DEVNULL, O_RDONLY);
if (fd < 0)
err(EX_OSFILE, "%s", _PATH_DEVNULL);
- u = 0;
- i = ioctl(fd, DIOCSKERNELDUMP, &u);
+
+ kda.kda_enable = 0;
+ i = ioctl(fd, DIOCSKERNELDUMP, &kda);
+ bzero(&kda, sizeof(kda));
if (i == 0 && verbose)
printf("kernel dumps disabled\n");
}
Index: sbin/savecore/savecore.8
===================================================================
--- sbin/savecore/savecore.8
+++ sbin/savecore/savecore.8
@@ -119,6 +119,10 @@
.Ar directory Ns Pa /vmcore.#
and information about the core in
.Ar directory Ns Pa /info.# .
+If the core is encrypted, it saves the dump key in
+.Ar directory Ns Pa /key.# .
+The core can be later decrypted using
+.Xr decryptcore 8 .
For kernel textdumps generated with the
.Xr textdump 4
facility, output will be stored in the
@@ -166,6 +170,7 @@
.Xr xo_parse_args 3 ,
.Xr textdump 4 ,
.Xr tar 5 ,
+.Xr decryptcore 8 ,
.Xr dumpon 8 ,
.Xr syslogd 8
.Sh HISTORY
Index: sbin/savecore/savecore.c
===================================================================
--- sbin/savecore/savecore.c
+++ sbin/savecore/savecore.c
@@ -74,6 +74,7 @@
#include <paths.h>
#include <signal.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -183,6 +184,28 @@
fclose(fp);
}
+static bool
+writekey(const char *keyname, uint8_t *dumpkey, uint32_t dumpkeysize)
+{
+ int fd;
+
+ fd = open(keyname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd == -1) {
+ syslog(LOG_ERR, "Unable to open %s to write the key: %m.",
+ keyname);
+ return (false);
+ }
+
+ if (write(fd, dumpkey, dumpkeysize) != (ssize_t)dumpkeysize) {
+ syslog(LOG_ERR, "Unable to write the key to %s: %m.", keyname);
+ close(fd);
+ return (false);
+ }
+
+ close(fd);
+ return (true);
+}
+
static off_t
file_size(const char *path)
{
@@ -292,8 +315,8 @@
#define BLOCKMASK (~(BLOCKSIZE-1))
static int
-DoRegularFile(int fd, off_t dumpsize, char *buf, const char *device,
- const char *filename, FILE *fp)
+DoRegularFile(int fd, bool isencrypted, off_t dumpsize, char *buf,
+ const char *device, const char *filename, FILE *fp)
{
int he, hs, nr, nw, wl;
off_t dmpcnt, origsize;
@@ -315,7 +338,7 @@
nerr++;
return (-1);
}
- if (compress) {
+ if (compress || isencrypted) {
nw = fwrite(buf, 1, wl, fp);
} else {
for (nw = 0; nw < nr; nw = he) {
@@ -436,8 +459,10 @@
{
xo_handle_t *xostdout, *xoinfo;
static char infoname[PATH_MAX], corename[PATH_MAX], linkname[PATH_MAX];
+ static char keyname[PATH_MAX];
static char *buf = NULL;
struct kerneldumpheader kdhf, kdhl;
+ uint8_t *dumpkey;
off_t mediasize, dumpsize, firsthd, lasthd;
FILE *info, *fp;
mode_t oumask;
@@ -445,6 +470,8 @@
int bounds, status;
u_int sectorsize, xostyle;
int istextdump;
+ uint32_t dumpkeysize;
+ bool isencrypted;
bounds = getbounds();
mediasize = 0;
@@ -567,7 +594,8 @@
goto closefd;
}
dumpsize = dtoh64(kdhl.dumplength);
- firsthd = lasthd - dumpsize - sizeof kdhf;
+ dumpkeysize = dtoh32(kdhl.dumpkeysize);
+ firsthd = lasthd - dumpsize - sizeof kdhf - dumpkeysize;
if (lseek(fd, firsthd, SEEK_SET) != firsthd ||
read(fd, &kdhf, sizeof(kdhf)) != sizeof(kdhf)) {
syslog(LOG_ERR,
@@ -677,17 +705,43 @@
xo_finish_h(xoinfo);
fclose(info);
- syslog(LOG_NOTICE, "writing %score to %s/%s",
- compress ? "compressed " : "", savedir, corename);
+ if (dumpkeysize == 0) {
+ isencrypted = false;
+ } else {
+ isencrypted = true;
+ dumpkey = calloc(1, dumpkeysize);
+ if (dumpkey == NULL) {
+ syslog(LOG_ERR, "Unable to allocate kernel dump key.");
+ nerr++;
+ goto closeall;
+ }
+
+ if (read(fd, dumpkey, dumpkeysize) != (ssize_t)dumpkeysize) {
+ syslog(LOG_ERR, "Unable to read kernel dump key: %m.");
+ nerr++;
+ goto closeall;
+ }
+
+ snprintf(keyname, sizeof(keyname), "key.%d", bounds);
+ if (!writekey(keyname, dumpkey, dumpkeysize)) {
+ nerr++;
+ goto closeall;
+ }
+ }
+
+ syslog(LOG_NOTICE, "writing %s%score to %s/%s",
+ isencrypted ? "encrypted " : "", compress ? "compressed " : "",
+ savedir, corename);
if (istextdump) {
if (DoTextdumpFile(fd, dumpsize, lasthd, buf, device,
corename, fp) < 0)
goto closeall;
} else {
- if (DoRegularFile(fd, dumpsize, buf, device, corename, fp)
- < 0)
+ if (DoRegularFile(fd, isencrypted, dumpsize, buf, device,
+ corename, fp) < 0) {
goto closeall;
+ }
}
if (verbose)
printf("\n");
Index: share/man/man5/rc.conf.5
===================================================================
--- share/man/man5/rc.conf.5
+++ share/man/man5/rc.conf.5
@@ -3511,6 +3511,15 @@
at boot time when
.Va dumpdir
is set.
+.It Va dumppubkey
+.Pq Vt str
+Path to a public key.
+It is used by
+.Xr dumpon 8
+to encrypt an one-time key for a crash dump.
+The public key has to match a private key used by
+.Xr decryptcore 8
+to decrypt a crash dump after reboot.
.It Va savecore_flags
.Pq Vt str
If crash dumps are enabled, these are the flags to pass to the
Index: sys/amd64/amd64/minidump_machdep.c
===================================================================
--- sys/amd64/amd64/minidump_machdep.c
+++ sys/amd64/amd64/minidump_machdep.c
@@ -320,14 +320,21 @@
dumpsize += PAGE_SIZE;
/* Determine dump offset on device. */
- if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) {
+ if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2 +
+ kerneldumpcrypto_dumpkeysize(di->kdc)) {
error = E2BIG;
goto fail;
}
dumplo = di->mediaoffset + di->mediasize - dumpsize;
dumplo -= sizeof(kdh) * 2;
+ dumplo -= kerneldumpcrypto_dumpkeysize(di->kdc);
progress = dumpsize;
+ /* Initialize kernel dump crypto. */
+ error = kerneldumpcrypto_init(di->kdc);
+ if (error)
+ goto fail;
+
/* Initialize mdhdr */
bzero(&mdhdr, sizeof(mdhdr));
strcpy(mdhdr.magic, MINIDUMP_MAGIC);
@@ -339,17 +346,24 @@
mdhdr.dmapbase = DMAP_MIN_ADDRESS;
mdhdr.dmapend = DMAP_MAX_ADDRESS;
- mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_AMD64_VERSION, dumpsize, di->blocksize);
+ mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_AMD64_VERSION, dumpsize,
+ kerneldumpcrypto_dumpkeysize(di->kdc), di->blocksize);
printf("Dumping %llu out of %ju MB:", (long long)dumpsize >> 20,
ptoa((uintmax_t)physmem) / 1048576);
/* Dump leader */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
+ /* Dump key */
+ error = dump_write_key(di, 0, dumplo);
+ if (error)
+ goto fail;
+ dumplo += kerneldumpcrypto_dumpkeysize(di->kdc);
+
/* Dump my header */
bzero(&fakepd, sizeof(fakepd));
bcopy(&mdhdr, &fakepd, sizeof(mdhdr));
@@ -433,7 +447,7 @@
goto fail;
/* Dump trailer */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
Index: sys/arm/arm/minidump_machdep.c
===================================================================
--- sys/arm/arm/minidump_machdep.c
+++ sys/arm/arm/minidump_machdep.c
@@ -295,15 +295,22 @@
dumpsize += PAGE_SIZE;
/* Determine dump offset on device. */
- if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) {
+ if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2 +
+ kerneldumpcrypto_dumpkeysize(di->kdc)) {
error = ENOSPC;
goto fail;
}
dumplo = di->mediaoffset + di->mediasize - dumpsize;
dumplo -= sizeof(kdh) * 2;
+ dumplo -= kerneldumpcrypto_dumpkeysize(di->kdc);
progress = dumpsize;
+ /* Initialize kernel dump crypto. */
+ error = kerneldumpcrypto_init(di->kdc);
+ if (error)
+ goto fail;
+
/* Initialize mdhdr */
bzero(&mdhdr, sizeof(mdhdr));
strcpy(mdhdr.magic, MINIDUMP_MAGIC);
@@ -314,17 +321,23 @@
mdhdr.kernbase = KERNBASE;
mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARM_VERSION, dumpsize,
- di->blocksize);
+ kerneldumpcrypto_dumpkeysize(di->kdc), di->blocksize);
printf("Physical memory: %u MB\n", ptoa((uintmax_t)physmem) / 1048576);
printf("Dumping %llu MB:", (long long)dumpsize >> 20);
/* Dump leader */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
+ /* Dump key */
+ error = dump_write_key(di, 0, dumplo);
+ if (error)
+ goto fail;
+ dumplo += kerneldumpcrypto_dumpkeysize(di->kdc);
+
/* Dump my header */
bzero(&fakept, sizeof(fakept));
bcopy(&mdhdr, &fakept, sizeof(mdhdr));
@@ -455,7 +468,7 @@
}
/* Dump trailer */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
Index: sys/arm64/arm64/minidump_machdep.c
===================================================================
--- sys/arm64/arm64/minidump_machdep.c
+++ sys/arm64/arm64/minidump_machdep.c
@@ -283,14 +283,21 @@
dumpsize += PAGE_SIZE;
/* Determine dump offset on device. */
- if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) {
+ if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2 +
+ kerneldumpcrypto_dumpkeysize(di->kdc)) {
error = E2BIG;
goto fail;
}
dumplo = di->mediaoffset + di->mediasize - dumpsize;
dumplo -= sizeof(kdh) * 2;
+ dumplo -= kerneldumpcrypto_dumpkeysize(di->kdc);
progress = dumpsize;
+ /* Initialize kernel dump crypto. */
+ error = kerneldumpcrypto_init(di->kdc);
+ if (error)
+ goto fail;
+
/* Initialize mdhdr */
bzero(&mdhdr, sizeof(mdhdr));
strcpy(mdhdr.magic, MINIDUMP_MAGIC);
@@ -304,17 +311,23 @@
mdhdr.dmapend = DMAP_MAX_ADDRESS;
mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_AARCH64_VERSION,
- dumpsize, di->blocksize);
+ dumpsize, kerneldumpcrypto_dumpkeysize(di->kdc), di->blocksize);
printf("Dumping %llu out of %ju MB:", (long long)dumpsize >> 20,
ptoa((uintmax_t)physmem) / 1048576);
/* Dump leader */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
+ /* Dump key */
+ error = dump_write_key(di, 0, dumplo);
+ if (error)
+ goto fail;
+ dumplo += kerneldumpcrypto_dumpkeysize(di->kdc);
+
/* Dump my header */
bzero(&tmpbuffer, sizeof(tmpbuffer));
bcopy(&mdhdr, &tmpbuffer, sizeof(mdhdr));
@@ -412,7 +425,7 @@
goto fail;
/* Dump trailer */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
Index: sys/conf/NOTES
===================================================================
--- sys/conf/NOTES
+++ sys/conf/NOTES
@@ -3012,3 +3012,6 @@
# zlib I/O stream support
# This enables support for compressed core dumps.
options GZIO
+
+# Unattended encrypted kernel crash dumps.
+options EKCD
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -551,15 +551,15 @@
crypto/des/des_ecb.c optional crypto | ipsec | netsmb
crypto/des/des_setkey.c optional crypto | ipsec | netsmb
crypto/rc4/rc4.c optional netgraph_mppc_encryption | kgssapi
-crypto/rijndael/rijndael-alg-fst.c optional crypto | geom_bde | \
+crypto/rijndael/rijndael-alg-fst.c optional crypto | ekcd | geom_bde | \
ipsec | random !random_loadable | wlan_ccmp
-crypto/rijndael/rijndael-api-fst.c optional geom_bde | random !random_loadable
+crypto/rijndael/rijndael-api-fst.c optional ekcd | geom_bde | random !random_loadable
crypto/rijndael/rijndael-api.c optional crypto | ipsec | wlan_ccmp
crypto/sha1.c optional carp | crypto | ipsec | \
netgraph_mppc_encryption | sctp
crypto/sha2/sha2.c optional crypto | geom_bde | ipsec | random !random_loadable | \
sctp | zfs
-crypto/sha2/sha256c.c optional crypto | geom_bde | ipsec | random !random_loadable | \
+crypto/sha2/sha256c.c optional crypto | ekcd | geom_bde | ipsec | random !random_loadable | \
sctp | zfs
crypto/siphash/siphash.c optional inet | inet6
crypto/siphash/siphash_test.c optional inet | inet6
Index: sys/conf/options
===================================================================
--- sys/conf/options
+++ sys/conf/options
@@ -963,3 +963,6 @@
# Intel em(4) driver
EM_MULTIQUEUE opt_em.h
+
+# Unattended encrypted kernel crash dumps
+EKCD opt_ekcd.h
Index: sys/ddb/db_textdump.c
===================================================================
--- sys/ddb/db_textdump.c
+++ sys/ddb/db_textdump.c
@@ -427,6 +427,7 @@
void
textdump_dumpsys(struct dumperinfo *di)
{
+ struct kerneldumpcrypto *kdc;
off_t dumplen, trailer_offset;
if (di->blocksize != TEXTDUMP_BLOCKSIZE) {
@@ -449,6 +450,12 @@
textdump_error = 0;
/*
+ * Disable EKCD because we don't provide encrypted textdumps.
+ */
+ kdc = di->kdc;
+ di->kdc = NULL;
+
+ /*
* Position the start of the dump so that we'll write the kernel dump
* trailer immediately before the end of the partition, and then work
* our way back. We will rewrite this header later to reflect the
@@ -456,7 +463,8 @@
*/
textdump_offset = di->mediasize - sizeof(kdh);
textdump_saveoff(&trailer_offset);
- mkdumpheader(&kdh, TEXTDUMPMAGIC, KERNELDUMP_TEXT_VERSION, 0, TEXTDUMP_BLOCKSIZE);
+ mkdumpheader(&kdh, TEXTDUMPMAGIC, KERNELDUMP_TEXT_VERSION, 0, 0,
+ TEXTDUMP_BLOCKSIZE);
(void)textdump_writenextblock(di, (char *)&kdh);
/*
@@ -481,7 +489,7 @@
* size.
*/
dumplen = trailer_offset - (textdump_offset + TEXTDUMP_BLOCKSIZE);
- mkdumpheader(&kdh, TEXTDUMPMAGIC, KERNELDUMP_TEXT_VERSION, dumplen,
+ mkdumpheader(&kdh, TEXTDUMPMAGIC, KERNELDUMP_TEXT_VERSION, dumplen, 0,
TEXTDUMP_BLOCKSIZE);
(void)textdump_writenextblock(di, (char *)&kdh);
textdump_restoreoff(trailer_offset);
@@ -499,6 +507,11 @@
else
printf("Textdump complete.\n");
textdump_pending = 0;
+
+ /*
+ * Restore EKCD status.
+ */
+ di->kdc = kdc;
}
/*-
Index: sys/dev/null/null.c
===================================================================
--- sys/dev/null/null.c
+++ sys/dev/null/null.c
@@ -30,6 +30,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_compat.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
@@ -108,8 +110,13 @@
error = 0;
switch (cmd) {
+#ifdef COMPAT_FREEBSD10
+ case DIOCSKERNELDUMPOLD:
+ error = set_dumper(NULL, NULL, td, 0, NULL, 0, NULL);
+ break;
+#endif
case DIOCSKERNELDUMP:
- error = set_dumper(NULL, NULL, td);
+ error = set_dumper(NULL, NULL, td, 0, NULL, 0, NULL);
break;
case FIONBIO:
break;
Index: sys/geom/geom_dev.c
===================================================================
--- sys/geom/geom_dev.c
+++ sys/geom/geom_dev.c
@@ -36,6 +36,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_compat.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -128,36 +130,44 @@
}
static int
-g_dev_setdumpdev(struct cdev *dev, struct thread *td)
+g_dev_setdumpdev(struct cdev *dev, struct diocskerneldump_arg *kda,
+ struct thread *td)
{
struct g_kerneldump kd;
struct g_consumer *cp;
int error, len;
- if (dev == NULL)
- return (set_dumper(NULL, NULL, td));
+ if (dev == NULL || kda == NULL)
+ return (set_dumper(NULL, NULL, td, 0, NULL, 0, NULL));
cp = dev->si_drv2;
len = sizeof(kd);
kd.offset = 0;
kd.length = OFF_MAX;
error = g_io_getattr("GEOM::kerneldump", cp, &len, &kd);
- if (error == 0) {
- error = set_dumper(&kd.di, devtoname(dev), td);
- if (error == 0)
- dev->si_flags |= SI_DUMPDEV;
- }
+ if (error != 0)
+ return (error);
+
+ error = set_dumper(&kd.di, devtoname(dev), td, kda->kda_encryption,
+ kda->kda_key, kda->kda_encryptedkeysize, kda->kda_encryptedkey);
+ if (error == 0)
+ dev->si_flags |= SI_DUMPDEV;
+
return (error);
}
static int
init_dumpdev(struct cdev *dev)
{
+ struct diocskerneldump_arg kda;
struct g_consumer *cp;
const char *devprefix = "/dev/", *devname;
int error;
size_t len;
+ bzero(&kda, sizeof(kda));
+ kda.kda_enable = 1;
+
if (dumpdev == NULL)
return (0);
@@ -173,7 +183,7 @@
if (error != 0)
return (error);
- error = g_dev_setdumpdev(dev, curthread);
+ error = g_dev_setdumpdev(dev, &kda, curthread);
if (error == 0) {
freeenv(dumpdev);
dumpdev = NULL;
@@ -480,12 +490,56 @@
case DIOCGFRONTSTUFF:
error = g_io_getattr("GEOM::frontstuff", cp, &i, data);
break;
- case DIOCSKERNELDUMP:
- if (*(u_int *)data == 0)
- error = g_dev_setdumpdev(NULL, td);
+#ifdef COMPAT_FREEBSD10
+ case DIOCSKERNELDUMPOLD:
+ {
+ struct diocskerneldump_arg kda;
+
+ bzero(&kda, sizeof(kda));
+ kda.kda_encryption = KERNELDUMP_ENC_NONE;
+ kda.kda_enable = (uint8_t)*(u_int *)data;
+ if (kda.kda_enable == 0)
+ error = g_dev_setdumpdev(NULL, NULL, td);
else
- error = g_dev_setdumpdev(dev, td);
+ error = g_dev_setdumpdev(dev, &kda, td);
break;
+ }
+#endif
+ case DIOCSKERNELDUMP:
+ {
+ struct diocskerneldump_arg *kda;
+ uint8_t *encryptedkey;
+
+ kda = (struct diocskerneldump_arg *)data;
+ if (kda->kda_enable == 0) {
+ error = g_dev_setdumpdev(NULL, NULL, td);
+ break;
+ }
+
+ if (kda->kda_encryption != KERNELDUMP_ENC_NONE) {
+ if (kda->kda_encryptedkeysize <= 0 ||
+ kda->kda_encryptedkeysize >
+ KERNELDUMP_ENCKEY_MAX_SIZE) {
+ return (EINVAL);
+ }
+ encryptedkey = malloc(kda->kda_encryptedkeysize, M_TEMP,
+ M_WAITOK);
+ error = copyin(kda->kda_encryptedkey, encryptedkey,
+ kda->kda_encryptedkeysize);
+ } else {
+ encryptedkey = NULL;
+ }
+ if (error == 0) {
+ kda->kda_encryptedkey = encryptedkey;
+ error = g_dev_setdumpdev(dev, kda, td);
+ }
+ if (encryptedkey != NULL) {
+ bzero(encryptedkey, kda->kda_encryptedkeysize);
+ free(encryptedkey, M_TEMP);
+ }
+ bzero(kda, sizeof(*kda));
+ break;
+ }
case DIOCGFLUSH:
error = g_io_flush(cp);
break;
@@ -702,7 +756,7 @@
/* Reset any dump-area set on this device */
if (dev->si_flags & SI_DUMPDEV)
- (void)set_dumper(NULL, NULL, curthread);
+ (void)set_dumper(NULL, NULL, curthread, 0, NULL, 0, NULL);
/* Destroy the struct cdev *so we get no more requests */
destroy_dev_sched_cb(dev, g_dev_callback, cp);
Index: sys/i386/i386/minidump_machdep.c
===================================================================
--- sys/i386/i386/minidump_machdep.c
+++ sys/i386/i386/minidump_machdep.c
@@ -245,14 +245,21 @@
dumpsize += PAGE_SIZE;
/* Determine dump offset on device. */
- if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) {
+ if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2 +
+ kerneldumpcrypto_dumpkeysize(di->kdc)) {
error = ENOSPC;
goto fail;
}
dumplo = di->mediaoffset + di->mediasize - dumpsize;
dumplo -= sizeof(kdh) * 2;
+ dumplo -= kerneldumpcrypto_dumpkeysize(di->kdc);
progress = dumpsize;
+ /* Initialize kernel dump crypto. */
+ error = kerneldumpcrypto_init(di->kdc);
+ if (error)
+ goto fail;
+
/* Initialize mdhdr */
bzero(&mdhdr, sizeof(mdhdr));
strcpy(mdhdr.magic, MINIDUMP_MAGIC);
@@ -265,17 +272,24 @@
mdhdr.paemode = 1;
#endif
- mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_I386_VERSION, dumpsize, di->blocksize);
+ mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_I386_VERSION, dumpsize,
+ kerneldumpcrypto_dumpkeysize(di->kdc), di->blocksize);
printf("Physical memory: %ju MB\n", ptoa((uintmax_t)physmem) / 1048576);
printf("Dumping %llu MB:", (long long)dumpsize >> 20);
/* Dump leader */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
+ /* Dump key */
+ error = dump_write_key(di, 0, dumplo);
+ if (error)
+ goto fail;
+ dumplo += kerneldumpcrypto_dumpkeysize(di->kdc);
+
/* Dump my header */
bzero(&fakept, sizeof(fakept));
bcopy(&mdhdr, &fakept, sizeof(mdhdr));
@@ -349,7 +363,7 @@
goto fail;
/* Dump trailer */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
Index: sys/kern/kern_dump.c
===================================================================
--- sys/kern/kern_dump.c
+++ sys/kern/kern_dump.c
@@ -119,6 +119,32 @@
#endif
int
+dumpsys_buf_seek(struct dumperinfo *di, size_t sz)
+{
+ uint8_t buf[DEV_BSIZE];
+ size_t nbytes;
+ int error;
+
+ bzero(buf, sizeof(buf));
+
+ while (sz > 0) {
+ if (sz >= sizeof(buf))
+ nbytes = sizeof(buf);
+ else
+ nbytes = sz;
+
+ error = dump_write(di, buf, 0, dumplo, nbytes);
+ if (error)
+ return (error);
+ dumplo += nbytes;
+
+ sz -= nbytes;
+ }
+
+ return (0);
+}
+
+int
dumpsys_buf_write(struct dumperinfo *di, char *ptr, size_t sz)
{
size_t len;
@@ -327,25 +353,38 @@
hdrgap = fileofs - DEV_ALIGN(hdrsz);
/* Determine dump offset on device. */
- if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) {
+ if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2 +
+ kerneldumpcrypto_dumpkeysize(di->kdc)) {
error = ENOSPC;
goto fail;
}
dumplo = di->mediaoffset + di->mediasize - dumpsize;
dumplo -= sizeof(kdh) * 2;
+ dumplo -= kerneldumpcrypto_dumpkeysize(di->kdc);
+
+ /* Initialize kernel dump crypto. */
+ error = kerneldumpcrypto_init(di->kdc);
+ if (error)
+ goto fail;
mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARCH_VERSION, dumpsize,
- di->blocksize);
+ kerneldumpcrypto_dumpkeysize(di->kdc), di->blocksize);
printf("Dumping %ju MB (%d chunks)\n", (uintmax_t)dumpsize >> 20,
ehdr.e_phnum - DUMPSYS_NUM_AUX_HDRS);
/* Dump leader */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
+ /* Dump key */
+ error = dump_write_key(di, 0, dumplo);
+ if (error)
+ goto fail;
+ dumplo += kerneldumpcrypto_dumpkeysize(di->kdc);
+
/* Dump ELF header */
error = dumpsys_buf_write(di, (char*)&ehdr, sizeof(ehdr));
if (error)
@@ -367,7 +406,9 @@
* boundary. We cannot use MD_ALIGN on dumplo, because we don't
* care and may very well be unaligned within the dump device.
*/
- dumplo += hdrgap;
+ error = dumpsys_buf_seek(di, (size_t)hdrgap);
+ if (error)
+ goto fail;
/* Dump memory chunks (updates dumplo) */
error = dumpsys_foreach_chunk(dumpsys_cb_dumpdata, di);
@@ -375,9 +416,10 @@
goto fail;
/* Dump trailer */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
+ dumplo += sizeof(kdh);
/* Signal completion, signoff and exit stage left. */
dump_write(di, NULL, 0, 0, 0);
Index: sys/kern/kern_shutdown.c
===================================================================
--- sys/kern/kern_shutdown.c
+++ sys/kern/kern_shutdown.c
@@ -38,6 +38,7 @@
__FBSDID("$FreeBSD$");
#include "opt_ddb.h"
+#include "opt_ekcd.h"
#include "opt_kdb.h"
#include "opt_panic.h"
#include "opt_sched.h"
@@ -71,6 +72,9 @@
#include <sys/vnode.h>
#include <sys/watchdog.h>
+#include <crypto/rijndael/rijndael-api-fst.h>
+#include <crypto/sha2/sha2.h>
+
#include <ddb/ddb.h>
#include <machine/cpu.h>
@@ -141,6 +145,23 @@
SYSCTL_INT(_kern, OID_AUTO, suspend_blocked, CTLFLAG_RW,
&suspend_blocked, 0, "Block suspend due to a pending shutdown");
+#ifdef EKCD
+FEATURE(ekcd, "Encrypted kernel crash dumps support");
+
+MALLOC_DEFINE(M_EKCD, "ekcd", "Encrypted kernel crash dumps data");
+
+struct kerneldumpcrypto {
+ uint8_t kdc_encryption;
+ uint8_t kdc_iv[KERNELDUMP_IV_MAX_SIZE];
+ keyInstance kdc_ki;
+ cipherInstance kdc_ci;
+ off_t kdc_nextoffset;
+ uint32_t kdc_dumpkeysize;
+ uint32_t kdc_encryptedkeysize;
+ uint8_t kdc_encryptedkey[];
+};
+#endif
+
/*
* Variable panicstr contains argument to first call to panic; used as flag
* to indicate that the kernel has already called panic.
@@ -836,9 +857,106 @@
SYSCTL_STRING(_kern_shutdown, OID_AUTO, dumpdevname, CTLFLAG_RD,
dumpdevname, 0, "Device for kernel dumps");
+#ifdef EKCD
+static struct kerneldumpcrypto *
+kerneldumpcrypto_create(uint8_t encryption, const uint8_t *key,
+ uint32_t encryptedkeysize, const uint8_t *encryptedkey)
+{
+ struct kerneldumpcrypto *kdc;
+
+ kdc = malloc(sizeof(*kdc) + encryptedkeysize, M_EKCD,
+ M_WAITOK | M_ZERO);
+
+ arc4rand(kdc->kdc_iv, sizeof(kdc->kdc_iv), 0);
+
+ kdc->kdc_encryption = encryption;
+ switch (kdc->kdc_encryption) {
+ case KERNELDUMP_ENC_AES_256_CBC:
+ if (rijndael_makeKey(&kdc->kdc_ki, DIR_ENCRYPT, 256, key) <= 0)
+ goto failed;
+ break;
+ default:
+ goto failed;
+ }
+
+ kdc->kdc_encryptedkeysize = encryptedkeysize;
+ bcopy(encryptedkey, kdc->kdc_encryptedkey, kdc->kdc_encryptedkeysize);
+
+ kdc->kdc_dumpkeysize = (sizeof(kdc->kdc_encryption) +
+ sizeof(kdc->kdc_iv) + sizeof(kdc->kdc_encryptedkeysize) +
+ kdc->kdc_encryptedkeysize + KERNELDUMP_BLOCK_SIZE - 1) /
+ KERNELDUMP_BLOCK_SIZE * KERNELDUMP_BLOCK_SIZE;
+
+ return (kdc);
+failed:
+ bzero(kdc, sizeof(*kdc) + encryptedkeysize);
+ free(kdc, M_EKCD);
+ return (NULL);
+}
+#endif /* EKCD */
+
+int
+kerneldumpcrypto_init(struct kerneldumpcrypto *kdc)
+{
+#ifndef EKCD
+ return (0);
+#else
+ uint8_t hash[SHA256_DIGEST_LENGTH];
+ SHA256_CTX ctx;
+ int error;
+
+ error = 0;
+
+ if (kdc == NULL)
+ return (0);
+
+ /*
+ * When a user enters ddb it can write a crash dump multiple times.
+ * Each time it should be encrypted using a different IV.
+ */
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, kdc->kdc_iv, sizeof(kdc->kdc_iv));
+ SHA256_Final(hash, &ctx);
+ bcopy(hash, kdc->kdc_iv, sizeof(kdc->kdc_iv));
+
+ switch (kdc->kdc_encryption) {
+ case KERNELDUMP_ENC_AES_256_CBC:
+ if (rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC,
+ kdc->kdc_iv) <= 0) {
+ error = EINVAL;
+ goto failed;
+ }
+ break;
+ default:
+ error = EINVAL;
+ goto failed;
+ }
+
+ kdc->kdc_nextoffset = 0;
+failed:
+ bzero(hash, sizeof(hash));
+ return (error);
+#endif
+}
+
+uint32_t
+kerneldumpcrypto_dumpkeysize(const struct kerneldumpcrypto *kdc)
+{
+
+#ifdef EKCD
+ if (kdc == NULL)
+ return (0);
+ return (kdc->kdc_dumpkeysize);
+#else
+ return (0);
+#endif
+}
+
/* Registration of dumpers */
int
-set_dumper(struct dumperinfo *di, const char *devname, struct thread *td)
+set_dumper(struct dumperinfo *di, const char *devname, struct thread *td,
+ uint8_t encryption, const uint8_t *key, uint32_t encryptedkeysize,
+ const uint8_t *encryptedkey)
{
size_t wantcopy;
int error;
@@ -848,25 +966,50 @@
return (error);
if (di == NULL) {
- bzero(&dumper, sizeof dumper);
- dumpdevname[0] = '\0';
- return (0);
+ error = 0;
+ goto cleanup;
}
if (dumper.dumper != NULL)
return (EBUSY);
dumper = *di;
+ dumper.kdc = NULL;
+
+ if (encryption != KERNELDUMP_ENC_NONE) {
+#ifdef EKCD
+ dumper.kdc = kerneldumpcrypto_create(encryption, key,
+ encryptedkeysize, encryptedkey);
+ if (dumper.kdc == NULL) {
+ error = EINVAL;
+ goto cleanup;
+ }
+#else
+ error = EOPNOTSUPP;
+ goto cleanup;
+#endif
+ }
+
wantcopy = strlcpy(dumpdevname, devname, sizeof(dumpdevname));
if (wantcopy >= sizeof(dumpdevname)) {
printf("set_dumper: device name truncated from '%s' -> '%s'\n",
devname, dumpdevname);
}
+
return (0);
+cleanup:
+#ifdef EKCD
+ if (dumper.kdc != NULL) {
+ bzero(dumper.kdc, sizeof(*dumper.kdc) +
+ dumper.kdc->kdc_encryptedkeysize);
+ free(dumper.kdc, M_EKCD);
+ }
+#endif
+ bzero(&dumper, sizeof(dumper));
+ dumpdevname[0] = '\0';
+ return (error);
}
-/* Call dumper with bounds checking. */
-int
-dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
- off_t offset, size_t length)
+static int
+dump_check_bounds(struct dumperinfo *di, off_t offset, size_t length)
{
if (length != 0 && (offset < di->mediaoffset ||
@@ -877,12 +1020,170 @@
(uintmax_t)length, (intmax_t)di->mediasize);
return (ENOSPC);
}
+
+ return (0);
+}
+
+#ifdef EKCD
+static int
+dump_encrypt(struct kerneldumpcrypto *kdc, const uint8_t *src, uint8_t *dst,
+ size_t size)
+{
+
+ switch (kdc->kdc_encryption) {
+ case KERNELDUMP_ENC_AES_256_CBC:
+ if (rijndael_blockEncrypt(&kdc->kdc_ci, &kdc->kdc_ki, src,
+ 8 * size, dst) <= 0) {
+ return (EIO);
+ }
+ if (rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC,
+ dst + size - 16 /* IV size for AES-256-CBC */) <= 0) {
+ return (EIO);
+ }
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+/* Encrypt data and call dumper. */
+static int
+dump_encrypted_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
+ off_t offset, size_t length)
+{
+ uint8_t buf[2 * KERNELDUMP_BLOCK_SIZE];
+ struct kerneldumpcrypto *kdc;
+ int error;
+ size_t nbytes;
+ off_t nextoffset;
+
+ kdc = di->kdc;
+
+ error = dump_check_bounds(di, offset, length);
+ if (error != 0)
+ return (error);
+
+ /* Signal completion. */
+ if (virtual == NULL && physical == 0 && offset == 0 && length == 0) {
+ return (di->dumper(di->priv, virtual, physical, offset,
+ length));
+ }
+
+ /* Data have to be aligned to block size. */
+ if ((length % KERNELDUMP_BLOCK_SIZE) != 0)
+ return (EINVAL);
+
+ /*
+ * Data have to be written continuously becase we're encrypting using
+ * CBC mode which has this assumption.
+ */
+ if (kdc->kdc_nextoffset != 0 && kdc->kdc_nextoffset != offset)
+ return (EINVAL);
+
+ nextoffset = offset + (off_t)length;
+
+ while (length > 0) {
+ if (length >= sizeof(buf))
+ nbytes = sizeof(buf);
+ else
+ nbytes = length;
+ bcopy(virtual, buf, nbytes);
+
+ if (dump_encrypt(kdc, buf, buf, nbytes) != 0)
+ return (EIO);
+
+ error = di->dumper(di->priv, buf, physical, offset, nbytes);
+ if (error != 0)
+ return (error);
+
+ offset += nbytes;
+ virtual = (void *)((uint8_t *)virtual + nbytes);
+ length -= nbytes;
+ }
+
+ kdc->kdc_nextoffset = nextoffset;
+
+ return (0);
+}
+#endif /* EKCD */
+
+/* Call dumper with bounds checking. */
+static int
+dump_raw_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
+ off_t offset, size_t length)
+{
+ int error;
+
+ error = dump_check_bounds(di, offset, length);
+ if (error != 0)
+ return (error);
+
return (di->dumper(di->priv, virtual, physical, offset, length));
}
+int
+dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
+ off_t offset, size_t length)
+{
+
+#ifdef EKCD
+ if (di->kdc != NULL) {
+ return (dump_encrypted_write(di, virtual, physical, offset,
+ length));
+ }
+#endif
+
+ return (dump_raw_write(di, virtual, physical, offset, length));
+}
+
+int
+dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh,
+ vm_offset_t physical, off_t offset)
+{
+
+ return (dump_raw_write(di, kdh, physical, offset, sizeof(*kdh)));
+}
+
+int
+dump_write_key(struct dumperinfo *di, vm_offset_t physical, off_t offset)
+{
+#ifndef EKCD
+ return (0);
+#else /* EKCD */
+ uint8_t *buf, *p;
+ struct kerneldumpcrypto *kdc;
+ uint32_t encryptedkeysize;
+ int ret;
+
+ kdc = di->kdc;
+ if (kdc == NULL)
+ return (0);
+
+ buf = malloc(kdc->kdc_dumpkeysize, M_EKCD, M_WAITOK | M_ZERO);
+
+ p = buf;
+ *p = kdc->kdc_encryption;
+ p += sizeof(kdc->kdc_encryption);
+ bcopy(kdc->kdc_iv, p, sizeof(kdc->kdc_iv));
+ p += sizeof(kdc->kdc_iv);
+ encryptedkeysize = htod32(kdc->kdc_encryptedkeysize);
+ bcopy(&encryptedkeysize, p, sizeof(encryptedkeysize));
+ p += sizeof(encryptedkeysize);
+ bcopy(kdc->kdc_encryptedkey, p, kdc->kdc_encryptedkeysize);
+ p += kdc->kdc_encryptedkeysize;
+
+ ret = dump_raw_write(di, buf, physical, offset, kdc->kdc_dumpkeysize);
+ bzero(buf, kdc->kdc_dumpkeysize);
+ free(buf, M_EKCD);
+ return (ret);
+#endif /* !EKCD */
+}
+
void
mkdumpheader(struct kerneldumpheader *kdh, char *magic, uint32_t archver,
- uint64_t dumplen, uint32_t blksz)
+ uint64_t dumplen, uint32_t dumpkeysize, uint32_t blksz)
{
bzero(kdh, sizeof(*kdh));
@@ -892,6 +1193,7 @@
kdh->architectureversion = htod32(archver);
kdh->dumplength = htod64(dumplen);
kdh->dumptime = htod64(time_second);
+ kdh->dumpkeysize = htod32(dumpkeysize);
kdh->blocksize = htod32(blksz);
strlcpy(kdh->hostname, prison0.pr_hostname, sizeof(kdh->hostname));
strlcpy(kdh->versionstring, version, sizeof(kdh->versionstring));
Index: sys/mips/mips/minidump_machdep.c
===================================================================
--- sys/mips/mips/minidump_machdep.c
+++ sys/mips/mips/minidump_machdep.c
@@ -220,15 +220,22 @@
dumpsize += PAGE_SIZE;
/* Determine dump offset on device. */
- if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) {
+ if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2 +
+ kerneldumpcrypto_dumpkeysize(di->kdc)) {
error = ENOSPC;
goto fail;
}
origdumplo = dumplo = di->mediaoffset + di->mediasize - dumpsize;
dumplo -= sizeof(kdh) * 2;
+ dumplo -= kerneldumpcrypto_dumpkeysize(di->kdc);
progress = dumpsize;
+ /* Initialize kernel dump crypto. */
+ error = kerneldumpcrypto_init(di->kdc);
+ if (error)
+ goto fail;
+
/* Initialize mdhdr */
bzero(&mdhdr, sizeof(mdhdr));
strcpy(mdhdr.magic, MINIDUMP_MAGIC);
@@ -239,18 +246,24 @@
mdhdr.kernbase = VM_MIN_KERNEL_ADDRESS;
mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_MIPS_VERSION, dumpsize,
- di->blocksize);
+ kerneldumpcrypto_dumpkeysize(di->kdc), di->blocksize);
printf("Physical memory: %ju MB\n",
(uintmax_t)ptoa((uintmax_t)physmem) / 1048576);
printf("Dumping %llu MB:", (long long)dumpsize >> 20);
/* Dump leader */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
+ /* Dump key */
+ error = dump_write_key(di, 0, dumplo);
+ if (error)
+ goto fail;
+ dumplo += kerneldumpcrypto_dumpkeysize(di->kdc);
+
/* Dump my header */
bzero(tmpbuffer, sizeof(tmpbuffer));
bcopy(&mdhdr, tmpbuffer, sizeof(mdhdr));
@@ -317,7 +330,7 @@
}
/* Dump trailer */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
Index: sys/sparc64/sparc64/dump_machdep.c
===================================================================
--- sys/sparc64/sparc64/dump_machdep.c
+++ sys/sparc64/sparc64/dump_machdep.c
@@ -94,7 +94,8 @@
DEV_BSIZE);
size += hdrsize;
- totsize = size + 2 * sizeof(kdh);
+ totsize = size + 2 * sizeof(kdh) +
+ kerneldumpcrypto_dumpkeysize(di->kdc);
if (totsize > di->mediasize) {
printf("Insufficient space on device (need %ld, have %ld), "
"refusing to dump.\n", (long)totsize,
@@ -106,17 +107,28 @@
/* Determine dump offset on device. */
dumplo = di->mediaoffset + di->mediasize - totsize;
+ /* Initialize kernel dump crypto. */
+ error = kerneldumpcrypto_init(di->kdc);
+ if (error)
+ goto fail;
+
mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_SPARC64_VERSION, size,
- di->blocksize);
+ kerneldumpcrypto_dumpkeysize(di->kdc), di->blocksize);
printf("Dumping %lu MB (%d chunks)\n", (u_long)(size >> 20), nreg);
/* Dump leader */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
dumplo += sizeof(kdh);
+ /* Dump key */
+ error = dump_write_key(di, 0, dumplo);
+ if (error)
+ goto fail;
+ dumplo += kerneldumpcrypto_dumpkeysize(di->kdc);
+
/* Dump the private header. */
hdr.dh_hdr_size = hdrsize;
hdr.dh_tsb_pa = tsb_kernel_phys;
@@ -143,9 +155,10 @@
goto fail;
/* Dump trailer */
- error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+ error = dump_write_header(di, &kdh, 0, dumplo);
if (error)
goto fail;
+ dumplo += sizeof(kdh);
/* Signal completion, signoff and exit stage left. */
dump_write(di, NULL, 0, 0, 0);
Index: sys/sys/conf.h
===================================================================
--- sys/sys/conf.h
+++ sys/sys/conf.h
@@ -308,6 +308,8 @@
EVENTHANDLER_DECLARE(dev_clone, dev_clone_fn);
/* Stuff relating to kernel-dump */
+struct kerneldumpcrypto;
+struct kerneldumpheader;
struct dumperinfo {
dumper_t *dumper; /* Dumping function. */
@@ -316,10 +318,16 @@
u_int maxiosize; /* Max size allowed for an individual I/O */
off_t mediaoffset; /* Initial offset in bytes. */
off_t mediasize; /* Space available in bytes. */
+ struct kerneldumpcrypto *kdc; /* Kernel dump crypto. */
};
-int set_dumper(struct dumperinfo *, const char *_devname, struct thread *td);
+int set_dumper(struct dumperinfo *di, const char *devname, struct thread *td,
+ uint8_t encrypt, const uint8_t *key, uint32_t encryptedkeysize,
+ const uint8_t *encryptedkey);
int dump_write(struct dumperinfo *, void *, vm_offset_t, off_t, size_t);
+int dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh,
+ vm_offset_t physical, off_t offset);
+int dump_write_key(struct dumperinfo *di, vm_offset_t physical, off_t offset);
int doadump(boolean_t);
extern int dumping; /* system is dumping */
Index: sys/sys/disk.h
===================================================================
--- sys/sys/disk.h
+++ sys/sys/disk.h
@@ -14,6 +14,7 @@
#define _SYS_DISK_H_
#include <sys/ioccom.h>
+#include <sys/kerneldump.h>
#include <sys/types.h>
#ifdef _KERNEL
@@ -53,7 +54,7 @@
* disk label formats. Don't use it unless you have to.
*/
-#define DIOCSKERNELDUMP _IOW('d', 133, u_int) /* Set/Clear kernel dumps */
+#define DIOCSKERNELDUMPOLD _IOW('d', 133, u_int) /* Set/Clear kernel dumps */
/*
* Enable/Disable (the argument is boolean) the device for kernel
* core dumps.
@@ -136,4 +137,16 @@
};
#define DIOCGATTR _IOWR('d', 142, struct diocgattr_arg)
+struct diocskerneldump_arg {
+ uint8_t kda_enable;
+ uint8_t kda_encryption;
+ uint8_t kda_key[KERNELDUMP_KEY_MAX_SIZE];
+ uint32_t kda_encryptedkeysize;
+ uint8_t *kda_encryptedkey;
+};
+#define DIOCSKERNELDUMP _IOW('d', 143, struct diocskerneldump_arg)
+ /*
+ * Enable/Disable the device for kernel core dumps.
+ */
+
#endif /* _SYS_DISK_H_ */
Index: sys/sys/kerneldump.h
===================================================================
--- sys/sys/kerneldump.h
+++ sys/sys/kerneldump.h
@@ -38,6 +38,9 @@
#ifndef _SYS_KERNELDUMP_H
#define _SYS_KERNELDUMP_H
+#include <sys/param.h>
+#include <sys/conf.h>
+
#include <machine/endian.h>
#if BYTE_ORDER == LITTLE_ENDIAN
@@ -52,6 +55,14 @@
#define htod64(x) (x)
#endif
+#define KERNELDUMP_ENC_NONE 0
+#define KERNELDUMP_ENC_AES_256_CBC 1
+
+#define KERNELDUMP_BLOCK_SIZE 512
+#define KERNELDUMP_IV_MAX_SIZE 32
+#define KERNELDUMP_KEY_MAX_SIZE 64
+#define KERNELDUMP_ENCKEY_MAX_SIZE (16384 / 8)
+
/*
* All uintX_t fields are in dump byte order, which is the same as
* network byte order. Use the macros defined above to read or
@@ -76,13 +87,21 @@
#define KERNELDUMP_TEXT_VERSION 1
uint64_t dumplength; /* excl headers */
uint64_t dumptime;
+ uint32_t dumpkeysize;
uint32_t blocksize;
char hostname[64];
char versionstring[192];
- char panicstring[192];
+ char panicstring[188];
uint32_t parity;
};
+struct kerneldumpkey {
+ uint8_t kdk_encryption;
+ uint8_t kdk_iv[KERNELDUMP_IV_MAX_SIZE];
+ uint32_t kdk_encryptedkeysize;
+ uint8_t kdk_encryptedkey[];
+};
+
/*
* Parity calculation is endian insensitive.
*/
@@ -105,8 +124,11 @@
vm_paddr_t pa_size;
};
+int kerneldumpcrypto_init(struct kerneldumpcrypto *kdc);
+uint32_t kerneldumpcrypto_dumpkeysize(const struct kerneldumpcrypto *kdc);
+
void mkdumpheader(struct kerneldumpheader *kdh, char *magic, uint32_t archver,
- uint64_t dumplen, uint32_t blksz);
+ uint64_t dumplen, uint32_t dumpkeysize, uint32_t blksz);
int dumpsys_generic(struct dumperinfo *);
@@ -114,6 +136,7 @@
typedef int dumpsys_callback_t(struct dump_pa *, int, void *);
int dumpsys_foreach_chunk(dumpsys_callback_t, void *);
int dumpsys_cb_dumpdata(struct dump_pa *, int, void *);
+int dumpsys_buf_seek(struct dumperinfo *, size_t);
int dumpsys_buf_write(struct dumperinfo *, char *, size_t);
int dumpsys_buf_flush(struct dumperinfo *);

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 5, 3:25 PM (12 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24846525
Default Alt Text
D4712.id11701.diff (58 KB)

Event Timeline