aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric van Gyzen <vangyzen@FreeBSD.org>2021-08-06 15:38:51 +0000
committerEric van Gyzen <vangyzen@FreeBSD.org>2021-08-11 15:54:56 +0000
commit13a58148de1730f851d37513913fae547e53a512 (patch)
tree75b9846cb17d90188c10b9eba01e796383d13e78
parent96f9bd46547d6dfbaf219ab449efacacb0dacccc (diff)
downloadsrc-13a58148de1730f851d37513913fae547e53a512.tar.gz
src-13a58148de1730f851d37513913fae547e53a512.zip
netdump: send key before dump, in case dump fails
Previously, if an encrypted netdump failed, such as due to a timeout or network failure, the key was not saved, so a partial dump was completely useless. Send the key first, so the partial dump can be decrypted, because even a partial dump can be useful. Reviewed by: bdrewery, markj MFC after: 1 week Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D31453
-rw-r--r--sys/kern/kern_shutdown.c20
-rw-r--r--sys/netinet/netdump/netdump_client.c42
-rw-r--r--sys/sys/conf.h5
3 files changed, 43 insertions, 24 deletions
diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c
index fb2a69401801..3cc51fd31956 100644
--- a/sys/kern/kern_shutdown.c
+++ b/sys/kern/kern_shutdown.c
@@ -1488,7 +1488,7 @@ dump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
#ifdef EKCD
struct kerneldumpcrypto *kdc;
#endif
- void *buf, *key;
+ void *buf;
size_t hdrsz;
uint64_t extent;
uint32_t keysize;
@@ -1500,10 +1500,8 @@ dump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
#ifdef EKCD
kdc = di->kdcrypto;
- key = kdc->kdc_dumpkey;
keysize = kerneldumpcrypto_dumpkeysize(kdc);
#else
- key = NULL;
keysize = 0;
#endif
@@ -1512,7 +1510,7 @@ dump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
* of writing them out.
*/
if (di->dumper_hdr != NULL)
- return (di->dumper_hdr(di, kdh, key, keysize));
+ return (di->dumper_hdr(di, kdh));
if (hdrsz == di->blocksize)
buf = kdh;
@@ -1571,22 +1569,30 @@ dump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
int
dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh)
{
+#ifdef EKCD
+ struct kerneldumpcrypto *kdc;
+#endif
+ void *key;
uint64_t dumpextent, span;
uint32_t keysize;
int error;
#ifdef EKCD
- error = kerneldumpcrypto_init(di->kdcrypto);
+ /* Send the key before the dump so a partial dump is still usable. */
+ kdc = di->kdcrypto;
+ error = kerneldumpcrypto_init(kdc);
if (error != 0)
return (error);
- keysize = kerneldumpcrypto_dumpkeysize(di->kdcrypto);
+ keysize = kerneldumpcrypto_dumpkeysize(kdc);
+ key = keysize > 0 ? kdc->kdc_dumpkey : NULL;
#else
error = 0;
keysize = 0;
+ key = NULL;
#endif
if (di->dumper_start != NULL) {
- error = di->dumper_start(di);
+ error = di->dumper_start(di, key, keysize);
} else {
dumpextent = dtoh64(kdh->dumpextent);
span = SIZEOF_METADATA + dumpextent + 2 * di->blocksize +
diff --git a/sys/netinet/netdump/netdump_client.c b/sys/netinet/netdump/netdump_client.c
index 2669ec879d75..d6fd7db364b8 100644
--- a/sys/netinet/netdump/netdump_client.c
+++ b/sys/netinet/netdump/netdump_client.c
@@ -95,7 +95,8 @@ static int netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS);
static int netdump_ioctl(struct cdev *dev __unused, u_long cmd,
caddr_t addr, int flags __unused, struct thread *td);
static int netdump_modevent(module_t mod, int type, void *priv);
-static int netdump_start(struct dumperinfo *di);
+static int netdump_start(struct dumperinfo *di, void *key,
+ uint32_t keysize);
static void netdump_unconfigure(void);
/* Must be at least as big as the chunks dumpsys() gives us. */
@@ -285,7 +286,7 @@ netdump_dumper(void *priv __unused, void *virtual,
* Perform any initialization needed prior to transmitting the kernel core.
*/
static int
-netdump_start(struct dumperinfo *di)
+netdump_start(struct dumperinfo *di, void *key, uint32_t keysize)
{
struct debugnet_conn_params dcp;
struct debugnet_pcb *pcb;
@@ -336,12 +337,34 @@ netdump_start(struct dumperinfo *di)
printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf),
debugnet_get_gw_mac(pcb), ":");
nd_conf.nd_pcb = pcb;
- return (0);
+
+ /* Send the key before the dump so a partial dump is still usable. */
+ if (keysize > 0) {
+ if (keysize > sizeof(nd_buf)) {
+ printf("crypto key is too large (%u)\n", keysize);
+ error = EINVAL;
+ goto out;
+ }
+ memcpy(nd_buf, key, keysize);
+ error = debugnet_send(pcb, NETDUMP_EKCD_KEY, nd_buf, keysize,
+ NULL);
+ if (error != 0) {
+ printf("error %d sending crypto key\n", error);
+ goto out;
+ }
+ }
+
+out:
+ if (error != 0) {
+ /* As above, squash errors. */
+ error = EINVAL;
+ netdump_cleanup();
+ }
+ return (error);
}
static int
-netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh,
- void *key, uint32_t keysize)
+netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
{
int error;
@@ -351,15 +374,6 @@ netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh,
memcpy(nd_buf, kdh, sizeof(*kdh));
error = debugnet_send(nd_conf.nd_pcb, NETDUMP_KDH, nd_buf,
sizeof(*kdh), NULL);
- if (error == 0 && keysize > 0) {
- if (keysize > sizeof(nd_buf)) {
- error = EINVAL;
- goto out;
- }
- memcpy(nd_buf, key, keysize);
- error = debugnet_send(nd_conf.nd_pcb, NETDUMP_EKCD_KEY, nd_buf,
- keysize, NULL);
- }
out:
if (error != 0)
netdump_cleanup();
diff --git a/sys/sys/conf.h b/sys/sys/conf.h
index 123bf91cf952..053cf6ddb016 100644
--- a/sys/sys/conf.h
+++ b/sys/sys/conf.h
@@ -133,9 +133,8 @@ typedef int dumper_t(
vm_offset_t _physical, /* Physical address of virtual. */
off_t _offset, /* Byte-offset to write at. */
size_t _length); /* Number of bytes to dump. */
-typedef int dumper_start_t(struct dumperinfo *di);
-typedef int dumper_hdr_t(struct dumperinfo *di, struct kerneldumpheader *kdh,
- void *key, uint32_t keylen);
+typedef int dumper_start_t(struct dumperinfo *di, void *key, uint32_t keysize);
+typedef int dumper_hdr_t(struct dumperinfo *di, struct kerneldumpheader *kdh);
#endif /* _KERNEL */