From owner-svn-soc-all@FreeBSD.ORG Sun Jun 7 11:50:04 2015 Return-Path: Delivered-To: svn-soc-all@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 06608DAC for ; Sun, 7 Jun 2015 11:50:04 +0000 (UTC) (envelope-from def@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id E625D1184 for ; Sun, 7 Jun 2015 11:50:03 +0000 (UTC) (envelope-from def@FreeBSD.org) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.14.9/8.14.9) with ESMTP id t57Bo3IJ042561 for ; Sun, 7 Jun 2015 11:50:03 GMT (envelope-from def@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.14.9/8.14.9/Submit) id t57Bo0CT042516 for svn-soc-all@FreeBSD.org; Sun, 7 Jun 2015 11:50:00 GMT (envelope-from def@FreeBSD.org) Date: Sun, 7 Jun 2015 11:50:00 GMT Message-Id: <201506071150.t57Bo0CT042516@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to def@FreeBSD.org using -f From: def@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r286773 - in soc2013/def/crashdump-head: sbin/cryptcore sbin/savecore sys/amd64/amd64 sys/ddb sys/kern sys/sys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 07 Jun 2015 11:50:04 -0000 Author: def Date: Sun Jun 7 11:49:59 2015 New Revision: 286773 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=286773 Log: Dump an encrypted key of arbitrary size separately from a header. Modified: soc2013/def/crashdump-head/sbin/cryptcore/cryptcore.c soc2013/def/crashdump-head/sbin/savecore/savecore.c soc2013/def/crashdump-head/sys/amd64/amd64/minidump_machdep.c soc2013/def/crashdump-head/sys/ddb/db_textdump.c soc2013/def/crashdump-head/sys/kern/kern_dump.c soc2013/def/crashdump-head/sys/kern/kern_shutdown.c soc2013/def/crashdump-head/sys/sys/conf.h soc2013/def/crashdump-head/sys/sys/kerneldump.h Modified: soc2013/def/crashdump-head/sbin/cryptcore/cryptcore.c ============================================================================== --- soc2013/def/crashdump-head/sbin/cryptcore/cryptcore.c Sun Jun 7 10:57:02 2015 (r286772) +++ soc2013/def/crashdump-head/sbin/cryptcore/cryptcore.c Sun Jun 7 11:49:59 2015 (r286773) @@ -30,8 +30,8 @@ static void cryptcore_genkey(const char *pubkeyfile) { - uint8_t buf[KERNELDUMP_KEY_SIZE + KERNELDUMP_IV_SIZE]; - uint8_t ciphertext[KERNELDUMP_CIPHERTEXT_SIZE]; + uint8_t key[KERNELDUMP_KEY_SIZE]; + uint8_t *encryptedkey; FILE *fp; RSA *pubkey; int pubkeysize; @@ -49,43 +49,41 @@ fclose(fp); if (pubkey == NULL) pjdlog_exitx(1, "Unable to read data from %s.", pubkeyfile); + pubkeysize = RSA_size(pubkey); - if (pubkeysize > (int)sizeof(ciphertext)) { - pjdlog_exitx(1, "The maximum RSA modulus size is %lub.", - 8 * sizeof(ciphertext)); - } + encryptedkey = (uint8_t *)calloc(1, pubkeysize); + if (encryptedkey == NULL) + pjdlog_exitx(1, "Unable to allocate encrypted key"); - arc4random_buf(buf, sizeof(buf)); - if (RSA_public_encrypt(sizeof(buf), buf, ciphertext, pubkey, + arc4random_buf(key, sizeof(key)); + if (RSA_public_encrypt(sizeof(key), key, encryptedkey, pubkey, RSA_PKCS1_PADDING) != pubkeysize) { - pjdlog_exitx(1, "Unable to encrypt the one-time key."); + pjdlog_errno(LOG_ERR, "Unable to encrypt the one-time key"); + goto failed; } /* * From this moment on keys have to be erased before exit. */ - if (sysctlbyname("security.ekcd.keymaterial", NULL, NULL, buf, + if (sysctlbyname("security.ekcd.keymaterial", NULL, NULL, key, KERNELDUMP_KEY_SIZE) != 0) { pjdlog_errno(LOG_ERR, "Unable to set key material"); goto failed; } - if (sysctlbyname("security.ekcd.iv", NULL, NULL, - buf + KERNELDUMP_KEY_SIZE, KERNELDUMP_IV_SIZE) != 0) { - pjdlog_errno(LOG_ERR, "Unable to set IV"); - goto failed; - } - if (sysctlbyname("security.ekcd.ciphertext", NULL, NULL, ciphertext, - pubkeysize) != 0) { - pjdlog_errno(LOG_ERR, "Unable to set ciphertext"); + if (sysctlbyname("security.ekcd.encryptedkey", NULL, NULL, + encryptedkey, pubkeysize) != 0) { + pjdlog_errno(LOG_ERR, "Unable to set encrypted key"); goto failed; } - bzero(buf, sizeof(buf)); + bzero(key, sizeof(key)); + free(encryptedkey); RSA_free(pubkey); return; failed: - bzero(buf, sizeof(buf)); + bzero(key, sizeof(key)); + free(encryptedkey); RSA_free(pubkey); exit(1); } @@ -94,10 +92,10 @@ cryptcore_decrypt(const char *privkeyfile, const char *keyfile, const char *input, const char *output) { - uint8_t buf[KERNELDUMP_BUFFER_SIZE]; - uint8_t ciphertext[KERNELDUMP_CIPHERTEXT_SIZE]; + uint8_t buf[KERNELDUMP_BUFFER_SIZE], key[KERNELDUMP_KEY_SIZE]; EVP_CIPHER_CTX ctx; FILE *fp; + struct kerneldumpkey *kdk; RSA *privkey; int err, fd, ofd, privkeysize, size; size_t bufused, bytes; @@ -109,19 +107,29 @@ ofd = -1; fd = -1; + privkey = RSA_new(); if (privkey == NULL) pjdlog_exitx(1, "Unable to allocate an RSA structure."); EVP_CIPHER_CTX_init(&ctx); + kdk = (struct kerneldumpkey *)calloc(1, sizeof(struct kerneldumpkey)); + if (kdk == NULL) + pjdlog_exit(1, "Unable to allocate kernel dump key"); + fd = open(keyfile, O_RDONLY); if (fd == -1) pjdlog_exit(1, "Unable to open %s", keyfile); - size = (int)read(fd, ciphertext, sizeof(ciphertext)); + size = (int)read(fd, kdk, sizeof(struct kerneldumpkey)); + if (size == sizeof(struct kerneldumpkey)) { + kdk = (struct kerneldumpkey *)realloc(kdk, kdk->kdk_size); + size += read(fd, &kdk->kdk_encryptedkey, + kdk->kdk_size - sizeof(struct kerneldumpkey)); + } err = errno; close(fd); fd = -1; - if (size != sizeof(ciphertext)) { + if (size != (int)kdk->kdk_size) { errno = err; pjdlog_exit(1, "Unable to read data from %s", keyfile); } @@ -133,19 +141,19 @@ fclose(fp); if (privkey == NULL) pjdlog_exitx(1, "Unable to read data from %s.", privkeyfile); + /* * From this moment on keys have to be erased before exit. */ privkeysize = RSA_size(privkey); - if (privkeysize > (int)sizeof(ciphertext)) { - pjdlog_error("The maximum RSA modulus size is %lub.", - 8 * sizeof(ciphertext)); + if (privkeysize != kdk->kdk_encryptedkeylen) { + pjdlog_error("RSA modulus size mismatch: equals %db and should be %db.", + 8 * privkeysize, 8 * kdk->kdk_encryptedkeylen); goto failed; } - - if (RSA_private_decrypt(sizeof(ciphertext), ciphertext, buf, privkey, - RSA_PKCS1_PADDING) != KERNELDUMP_KEY_SIZE + KERNELDUMP_IV_SIZE) { - pjdlog_error("Unable to decrypt key and IV."); + if (RSA_private_decrypt(kdk->kdk_encryptedkeylen, kdk->kdk_encryptedkey, + key, privkey, RSA_PKCS1_PADDING) != sizeof(key)) { + pjdlog_error("Unable to decrypt key."); goto failed; } @@ -160,9 +168,8 @@ goto failed; } - EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, buf, - buf + KERNELDUMP_KEY_SIZE); - EVP_CIPHER_CTX_set_key_length(&ctx, KERNELDUMP_KEY_SIZE); + EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, kdk->kdk_iv); + EVP_CIPHER_CTX_set_key_length(&ctx, sizeof(key)); EVP_CIPHER_CTX_set_padding(&ctx, 0); bufused = 0; @@ -186,6 +193,7 @@ bufused = 0; } + bzero(key, sizeof(key)); bzero(buf, sizeof(buf)); EVP_CIPHER_CTX_cleanup(&ctx); RSA_free(privkey); @@ -199,6 +207,7 @@ close(ofd); if (fd >= 0) close(fd); + bzero(key, sizeof(key)); bzero(buf, sizeof(buf)); EVP_CIPHER_CTX_cleanup(&ctx); RSA_free(privkey); Modified: soc2013/def/crashdump-head/sbin/savecore/savecore.c ============================================================================== --- soc2013/def/crashdump-head/sbin/savecore/savecore.c Sun Jun 7 10:57:02 2015 (r286772) +++ soc2013/def/crashdump-head/sbin/savecore/savecore.c Sun Jun 7 11:49:59 2015 (r286773) @@ -74,6 +74,7 @@ #include #include #include +#include #include #include #include @@ -183,22 +184,26 @@ fclose(fp); } -static void -writekey(const char *keyname, struct kerneldumpheader *kdh) +static bool +writekey(const char *keyname, struct kerneldumpkey *kdk) { 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.", keyname); - exit(1); + return (false); } - if (write(fd, kdh->ciphertext, KERNELDUMP_CIPHERTEXT_SIZE) != - KERNELDUMP_CIPHERTEXT_SIZE) { + + if (write(fd, kdk, kerneldumpkey_size(kdk)) != + (ssize_t)kerneldumpkey_size(kdk)) { syslog(LOG_ERR, "Unable to write the key to %s.", keyname); - exit(1); + close(fd); + return (false); } + close(fd); + return (true); } static off_t @@ -452,6 +457,7 @@ static void DoFile(const char *savedir, const char *device) { + struct kerneldumpkey *kdk; xo_handle_t *xostdout, *xoinfo; static char infoname[PATH_MAX], corename[PATH_MAX], linkname[PATH_MAX]; static char keyname[PATH_MAX]; @@ -464,6 +470,7 @@ int bounds, status; u_int sectorsize, xostyle; int istextdump; + uint32_t dumpkeysize; bounds = getbounds(); mediasize = 0; @@ -587,7 +594,8 @@ goto closefd; } dumpsize = dtoh64(kdhl.dumplength); - firsthd = lasthd - dumpsize - sizeof kdhf; + dumpkeysize = dtoh32(kdhl.dumpkeysize); + firsthd = lasthd - dumpsize - sizeof kdhf - dumpkeysize; lseek(fd, firsthd, SEEK_SET); error = read(fd, &kdhf, sizeof kdhf); if (error != sizeof kdhf) { @@ -654,10 +662,6 @@ } oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ - if (encrypted) { - snprintf(keyname, sizeof(keyname), "key.%d", bounds); - writekey(keyname, &kdhl); - } if (compress) { snprintf(corename, sizeof(corename), "%s.%d.gz", istextdump ? "textdump.tar" : "vmcore", bounds); @@ -701,6 +705,28 @@ xo_finish_h(xoinfo); fclose(info); + if (encrypted) { + kdk = (struct kerneldumpkey *)calloc(1, dumpkeysize); + if (kdk == NULL) { + syslog(LOG_ERR, "Unable to allocate kernel dump key."); + nerr++; + goto closefd; + } + + error = read(fd, kdk, dumpkeysize); + if (error != (int)dumpkeysize) { + syslog(LOG_ERR, "Unable to read kernel dump key."); + nerr++; + goto closefd; + } + + snprintf(keyname, sizeof(keyname), "key.%d", bounds); + if (!writekey(keyname, kdk)) { + nerr++; + goto closefd; + } + } + syslog(LOG_NOTICE, "writing %s%score to %s/%s", encrypted ? "encrypted " : "", compress ? "compressed " : "", savedir, corename); Modified: soc2013/def/crashdump-head/sys/amd64/amd64/minidump_machdep.c ============================================================================== --- soc2013/def/crashdump-head/sys/amd64/amd64/minidump_machdep.c Sun Jun 7 10:57:02 2015 (r286772) +++ soc2013/def/crashdump-head/sys/amd64/amd64/minidump_machdep.c Sun Jun 7 11:49:59 2015 (r286773) @@ -320,12 +320,14 @@ 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 + + kerneldumpkey_size(di->kdk)) { error = E2BIG; goto fail; } dumplo = di->mediaoffset + di->mediasize - dumpsize; dumplo -= sizeof(kdh) * 2; + dumplo -= kerneldumpkey_size(di->kdk); progress = dumpsize; /* Initialize mdhdr */ @@ -339,17 +341,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, + kerneldumpkey_size(di->kdk), 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, di->kdk, 0, dumplo); + if (error) + goto fail; + dumplo += kerneldumpkey_size(di->kdk); + /* Dump my header */ bzero(&fakepd, sizeof(fakepd)); bcopy(&mdhdr, &fakepd, sizeof(mdhdr)); @@ -433,7 +442,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); Modified: soc2013/def/crashdump-head/sys/ddb/db_textdump.c ============================================================================== --- soc2013/def/crashdump-head/sys/ddb/db_textdump.c Sun Jun 7 10:57:02 2015 (r286772) +++ soc2013/def/crashdump-head/sys/ddb/db_textdump.c Sun Jun 7 11:49:59 2015 (r286773) @@ -456,7 +456,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, + kerneldumpkey_size(di->kdk), TEXTDUMP_BLOCKSIZE); (void)textdump_writenextblock(di, (char *)&kdh); /* @@ -482,7 +483,7 @@ */ dumplen = trailer_offset - (textdump_offset + TEXTDUMP_BLOCKSIZE); mkdumpheader(&kdh, TEXTDUMPMAGIC, KERNELDUMP_TEXT_VERSION, dumplen, - TEXTDUMP_BLOCKSIZE); + kerneldumpkey_size(di->kdk), TEXTDUMP_BLOCKSIZE); (void)textdump_writenextblock(di, (char *)&kdh); textdump_restoreoff(trailer_offset); (void)textdump_writenextblock(di, (char *)&kdh); Modified: soc2013/def/crashdump-head/sys/kern/kern_dump.c ============================================================================== --- soc2013/def/crashdump-head/sys/kern/kern_dump.c Sun Jun 7 10:57:02 2015 (r286772) +++ soc2013/def/crashdump-head/sys/kern/kern_dump.c Sun Jun 7 11:49:59 2015 (r286773) @@ -330,7 +330,7 @@ dumplo -= sizeof(kdh) * 2; mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARCH_VERSION, dumpsize, - di->blocksize); + kerneldumpkey_size(di->kdk), di->blocksize); printf("Dumping %ju MB (%d chunks)\n", (uintmax_t)dumpsize >> 20, ehdr.e_phnum - DUMPSYS_NUM_AUX_HDRS); Modified: soc2013/def/crashdump-head/sys/kern/kern_shutdown.c ============================================================================== --- soc2013/def/crashdump-head/sys/kern/kern_shutdown.c Sun Jun 7 10:57:02 2015 (r286772) +++ soc2013/def/crashdump-head/sys/kern/kern_shutdown.c Sun Jun 7 11:49:59 2015 (r286773) @@ -138,28 +138,35 @@ &show_busybufs, 0, ""); #ifdef EKCD -static struct kerneldumpkey dumperkey; -static struct kerneldumpbuffer dumperbuffer; +MALLOC_DEFINE(M_KDK, "kerneldumpkey", "Kernel dump key structure"); + +static struct kerneldumpcrypto { + int kdc_enable; + uint8_t kdc_key[KERNELDUMP_KEY_SIZE]; + uint8_t kdc_iv[KERNELDUMP_IV_SIZE]; + keyInstance kdc_ki; + cipherInstance kdc_ci; + off_t kdc_offset; + uint8_t kdc_buf[KERNELDUMP_BUFFER_SIZE]; + size_t kdc_bufused; +} dumpcrypto; + +static struct kerneldumpkey *dumpkey; static int kerneldump_sysctl_keymaterial(SYSCTL_HANDLER_ARGS); -static int kerneldump_sysctl_iv(SYSCTL_HANDLER_ARGS); +static int kerneldump_sysctl_encryptedkey(SYSCTL_HANDLER_ARGS); SYSCTL_NODE(_security, OID_AUTO, ekcd, CTLFLAG_RW, 0, "Encrypted kernel crash dumps"); -SYSCTL_INT(_security_ekcd, OID_AUTO, enable, CTLFLAG_RW, &dumperkey.kdk_enable, +SYSCTL_INT(_security_ekcd, OID_AUTO, enable, CTLFLAG_RW, &dumpcrypto.kdc_enable, 0, "Enable encrypted kernel crash dumps"); SYSCTL_PROC(_security_ekcd, OID_AUTO, keymaterial, CTLTYPE_OPAQUE | CTLFLAG_WR, - NULL, 0, kerneldump_sysctl_keymaterial, "", - "Key material used to encrypt a crash dump"); - -SYSCTL_PROC(_security_ekcd, OID_AUTO, iv, CTLTYPE_OPAQUE | CTLFLAG_WR, NULL, 0, - kerneldump_sysctl_iv, "", "IV used to encrypt a crash dump"); + NULL, 0, kerneldump_sysctl_keymaterial, "", "Key material"); -SYSCTL_OPAQUE(_security_ekcd, OID_AUTO, ciphertext, CTLFLAG_WR, - &dumperkey.kdk_ciphertext, KERNELDUMP_CIPHERTEXT_SIZE, "", - "Encrypted key material and IV"); +SYSCTL_PROC(_security_ekcd, OID_AUTO, encryptedkey, CTLTYPE_OPAQUE | CTLFLAG_WR, + NULL, 0, kerneldump_sysctl_encryptedkey, "", "Encrypted key material"); #endif /* EKCD */ /* @@ -849,56 +856,87 @@ #ifdef EKCD static int -kerneldump_sysctl_keymaterial(SYSCTL_HANDLER_ARGS) +kerneldump_crypto_init(struct dumperinfo *di, struct kerneldumpcrypto *kdc, + struct kerneldumpkey *kdk) { int error; - error = sysctl_handle_opaque(oidp, &dumperkey.kdk_keymaterial, - KERNELDUMP_KEY_SIZE, req); - if (error != 0) - return (error); - - if (req->newptr != NULL) { - rijndael_makeKey(&dumperkey.kdk_ki, DIR_ENCRYPT, - 8 * KERNELDUMP_KEY_SIZE, dumperkey.kdk_keymaterial); + if (kdc == NULL) { + printf("Attempt to use an invalid kernel dump crypto."); + return (EINVAL); } + error = rijndael_makeKey(&kdc->kdc_ki, DIR_ENCRYPT, + 8 * KERNELDUMP_KEY_SIZE, kdc->kdc_key); + if (error <= 0) + return (EINVAL); + + error = rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC, kdc->kdc_iv); + if (error <= 0) + return (EINVAL); + + kdc->kdc_offset = 0; + kdc->kdc_bufused = 0; + + di->kdc = kdc; + di->kdk = kdk; + return (0); } static int -kerneldump_sysctl_iv(SYSCTL_HANDLER_ARGS) +kerneldump_sysctl_keymaterial(SYSCTL_HANDLER_ARGS) { int error; - error = sysctl_handle_opaque(oidp, &dumperkey.kdk_iv, - KERNELDUMP_IV_SIZE, req); - if (error != 0) + error = sysctl_handle_opaque(oidp, dumpcrypto.kdc_key, + sizeof(dumpcrypto.kdc_key), req); + if (req->newptr == NULL || error != 0) return (error); - if (req->newptr != NULL) { - rijndael_cipherInit(&dumperkey.kdk_ci, MODE_CBC, - dumperkey.kdk_iv); - } + arc4rand(dumpcrypto.kdc_iv, sizeof(dumpcrypto.kdc_iv), 0); - return (0); + return (kerneldump_crypto_init(&dumper, &dumpcrypto, dumpkey)); } -static void -kerneldump_crypto_init(struct dumperinfo *di, struct kerneldumpkey *kdk, - struct kerneldumpbuffer *kdb) +static int +kerneldump_sysctl_encryptedkey(SYSCTL_HANDLER_ARGS) { + struct kerneldumpkey *kdk; + size_t kdksize; + int error; - if (kdk == NULL || kdb == NULL) { - printf("Attempt to use an invalid kernel dump key or buffer."); - return; + if (req->newptr == NULL) { + if (dumpkey == NULL) + return (0); + + return (sysctl_handle_opaque(oidp, dumpkey->kdk_encryptedkey, + dumpkey->kdk_encryptedkeylen, req)); } - bzero(kdk, sizeof(struct kerneldumpkey)); - bzero(kdb, sizeof(struct kerneldumpbuffer)); + kdksize = ((sizeof(*kdk) + req->newlen + KERNELDUMP_BLOCK_SIZE - 1) / + KERNELDUMP_BLOCK_SIZE) * KERNELDUMP_BLOCK_SIZE; - di->kdk = kdk; - di->kdb = kdb; + kdk = (struct kerneldumpkey *)malloc(kdksize, M_KDK, M_WAITOK); + if (kdk == NULL) + return (ENOMEM); + + kdk->kdk_size = kdksize; + bcopy(dumpcrypto.kdc_iv, kdk->kdk_iv, sizeof(kdk->kdk_iv)); + kdk->kdk_encryptedkeylen = req->newlen; + + error = sysctl_handle_opaque(oidp, kdk->kdk_encryptedkey, + kdk->kdk_encryptedkeylen, req); + if (error != 0) { + free(kdk, M_KDK); + return (error); + } + + free(dumpkey, M_KDK); + dumpkey = kdk; + dumper.kdk = dumpkey; + + return (0); } #endif /* EKCD */ @@ -927,7 +965,9 @@ dumper = *di; #ifdef EKCD - kerneldump_crypto_init(&dumper, &dumperkey, &dumperbuffer); + error = kerneldump_crypto_init(&dumper, &dumpcrypto, dumpkey); + if (error != 0) + return (error); #endif wantcopy = strlcpy(dumpdevname, devname, sizeof(dumpdevname)); @@ -943,64 +983,54 @@ dump_encrypted_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, off_t offset, size_t length) { + struct kerneldumpcrypto *kdc; struct kerneldumpkey *kdk; - struct kerneldumpbuffer *kdb; int error; size_t len; + kdc = di->kdc; kdk = di->kdk; - kdb = di->kdb; /* Data have to be written continuously. */ - if (kdb->kdb_offset != 0 && kdb->kdb_offset != offset && - kdb->kdb_offset + kdb->kdb_used != offset) { + if (kdc->kdc_offset != 0 && kdc->kdc_offset != offset && + kdc->kdc_offset + kdc->kdc_bufused != offset) { return (EINVAL); } - /* Write kernel dump headers. */ - if (kdb->kdb_offset == 0 || kdb->kdb_offset == di->mediaoffset + - di->mediasize - sizeof(struct kerneldumpheader)) { - kdb->kdb_offset = offset + length; - return (di->dumper(di->priv, virtual, physical, offset, - length)); - } - - while (kdb->kdb_used + length >= KERNELDUMP_BUFFER_SIZE) { - len = KERNELDUMP_BUFFER_SIZE - kdb->kdb_used; - memcpy(kdb->kdb_buf + kdb->kdb_used, virtual, len); - kdb->kdb_used += len; + while (kdc->kdc_bufused + length >= KERNELDUMP_BUFFER_SIZE) { + len = KERNELDUMP_BUFFER_SIZE - kdc->kdc_bufused; + memcpy(kdc->kdc_buf + kdc->kdc_bufused, virtual, len); + kdc->kdc_bufused += len; - error = rijndael_blockEncrypt(&kdk->kdk_ci, &kdk->kdk_ki, - kdb->kdb_buf, 8 * KERNELDUMP_BUFFER_SIZE, kdb->kdb_buf); + error = rijndael_blockEncrypt(&kdc->kdc_ci, &kdc->kdc_ki, + kdc->kdc_buf, 8 * KERNELDUMP_BUFFER_SIZE, kdc->kdc_buf); if (error <= 0) return (EIO); - error = rijndael_cipherInit(&kdk->kdk_ci, MODE_CBC, - kdb->kdb_buf + KERNELDUMP_BUFFER_SIZE - KERNELDUMP_IV_SIZE); + error = rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC, + kdc->kdc_buf + KERNELDUMP_BUFFER_SIZE - KERNELDUMP_IV_SIZE); if (error <= 0) return (EIO); - error = di->dumper(di->priv, kdb->kdb_buf, physical, - kdb->kdb_offset, KERNELDUMP_BUFFER_SIZE); + error = di->dumper(di->priv, kdc->kdc_buf, physical, + kdc->kdc_offset, KERNELDUMP_BUFFER_SIZE); if (error != 0) return (error); - kdb->kdb_used = 0; - kdb->kdb_offset += KERNELDUMP_BUFFER_SIZE; + kdc->kdc_bufused = 0; + kdc->kdc_offset += KERNELDUMP_BUFFER_SIZE; virtual = (void *)((char *)virtual + len); length -= len; } if (length > 0) { - memcpy(kdb->kdb_buf + kdb->kdb_used, virtual, length); - kdb->kdb_used += length; + memcpy(kdc->kdc_buf + kdc->kdc_bufused, virtual, length); + kdc->kdc_bufused += length; } return (0); } -/* 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 || @@ -1011,8 +1041,23 @@ (uintmax_t)length, (intmax_t)di->mediasize); return (ENOSPC); } + + return (0); +} + +/* Call dumper with bounds checking. */ +int +dump_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); + #ifdef EKCD - if (di->kdk->kdk_enable == 1) { + if (di->kdc->kdc_enable == 1) { return (dump_encrypted_write(di, virtual, physical, offset, length)); } @@ -1020,9 +1065,50 @@ return (di->dumper(di->priv, virtual, physical, offset, length)); } +int +dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh, + vm_offset_t physical, off_t offset) +{ + int error; + + error = dump_check_bounds(di, offset, sizeof(*kdh)); + if (error != 0) + return (error); + + error = di->dumper(di->priv, kdh, physical, offset, sizeof(*kdh)); + if (error != 0) + return (error); + + if (di->kdc->kdc_enable == 1) + di->kdc->kdc_offset = offset + sizeof(*kdh); + + return (0); +} + +int +dump_write_key(struct dumperinfo *di, struct kerneldumpkey *kdk, + vm_offset_t physical, off_t offset) +{ + int error; + + error = dump_check_bounds(di, offset, kerneldumpkey_size(kdk)); + if (error != 0) + return (error); + + error = di->dumper(di->priv, kdk, physical, offset, + kerneldumpkey_size(kdk)); + if (error != 0) + return (error); + + if (di->kdc->kdc_enable == 1) + di->kdc->kdc_offset = offset + kerneldumpkey_size(kdk); + + return (0); +} + 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)); @@ -1032,14 +1118,11 @@ kdh->architectureversion = htod32(archver); kdh->dumplength = htod64(dumplen); kdh->dumptime = htod64(time_second); + kdh->dumpkeysize = htod32(dumpkeysize); kdh->blocksize = htod32(blksz); strncpy(kdh->hostname, prison0.pr_hostname, sizeof(kdh->hostname)); strncpy(kdh->versionstring, version, sizeof(kdh->versionstring)); if (panicstr != NULL) strncpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring)); -#ifdef EKCD - memcpy(kdh->ciphertext, dumperkey.kdk_ciphertext, - KERNELDUMP_CIPHERTEXT_SIZE); -#endif kdh->parity = kerneldump_parity(kdh); } Modified: soc2013/def/crashdump-head/sys/sys/conf.h ============================================================================== --- soc2013/def/crashdump-head/sys/sys/conf.h Sun Jun 7 10:57:02 2015 (r286772) +++ soc2013/def/crashdump-head/sys/sys/conf.h Sun Jun 7 11:49:59 2015 (r286773) @@ -309,8 +309,9 @@ EVENTHANDLER_DECLARE(dev_clone, dev_clone_fn); /* EKCD structures. */ +struct kerneldumpheader; +struct kerneldumpcrypto; struct kerneldumpkey; -struct kerneldumpbuffer; struct dumperinfo { dumper_t *dumper; /* Dumping function. */ @@ -319,12 +320,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 kerneldumpkey *kdk; /* Kernel dump key. */ - struct kerneldumpbuffer *kdb; /* Kernel dump buffer. */ + struct kerneldumpcrypto *kdc; /* Kernel dump crypto. */ + struct kerneldumpkey *kdk; /* Kernel dump key. */ }; int set_dumper(struct dumperinfo *, const char *_devname, struct thread *td); 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, struct kerneldumpkey *kdk, + vm_offset_t physical, off_t offset); int doadump(boolean_t); extern int dumping; /* system is dumping */ Modified: soc2013/def/crashdump-head/sys/sys/kerneldump.h ============================================================================== --- soc2013/def/crashdump-head/sys/sys/kerneldump.h Sun Jun 7 10:57:02 2015 (r286772) +++ soc2013/def/crashdump-head/sys/sys/kerneldump.h Sun Jun 7 11:49:59 2015 (r286773) @@ -56,8 +56,8 @@ #define htod64(x) (x) #endif +#define KERNELDUMP_BLOCK_SIZE 512 #define KERNELDUMP_BUFFER_SIZE 1024 -#define KERNELDUMP_CIPHERTEXT_SIZE 512 #define KERNELDUMP_IV_SIZE 16 #define KERNELDUMP_KEY_SIZE 32 @@ -85,14 +85,29 @@ #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 ciphertext[KERNELDUMP_CIPHERTEXT_SIZE]; uint32_t parity; + char pad[508]; }; +struct kerneldumpkey { + uint32_t kdk_size; + uint8_t kdk_iv[KERNELDUMP_IV_SIZE]; + int kdk_encryptedkeylen; + uint8_t kdk_encryptedkey[]; +}; + +static __inline size_t +kerneldumpkey_size(struct kerneldumpkey *kdk) +{ + + return (kdk->kdk_size); +} + /* * Parity calculation is endian insensitive. */ @@ -110,28 +125,13 @@ } #ifdef _KERNEL -struct kerneldumpkey { - int kdk_enable; - uint8_t kdk_keymaterial[KERNELDUMP_KEY_SIZE]; - uint8_t kdk_iv[KERNELDUMP_IV_SIZE]; - uint8_t kdk_ciphertext[KERNELDUMP_CIPHERTEXT_SIZE]; - keyInstance kdk_ki; - cipherInstance kdk_ci; -}; - -struct kerneldumpbuffer { - uint8_t kdb_buf[KERNELDUMP_BUFFER_SIZE]; - size_t kdb_used; - off_t kdb_offset; -}; - struct dump_pa { vm_paddr_t pa_start; vm_paddr_t pa_size; }; 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 *);