Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F134788181
D4712.id11701.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
58 KB
Referenced Files
None
Subscribers
None
D4712.id11701.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D4712: Encrypted kernel crash dumps.
Attached
Detach File
Event Timeline
Log In to Comment