diff options
author | Eric van Gyzen <vangyzen@FreeBSD.org> | 2021-08-06 15:38:51 +0000 |
---|---|---|
committer | Eric van Gyzen <vangyzen@FreeBSD.org> | 2021-08-11 15:54:56 +0000 |
commit | 13a58148de1730f851d37513913fae547e53a512 (patch) | |
tree | 75b9846cb17d90188c10b9eba01e796383d13e78 | |
parent | 96f9bd46547d6dfbaf219ab449efacacb0dacccc (diff) | |
download | src-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.c | 20 | ||||
-rw-r--r-- | sys/netinet/netdump/netdump_client.c | 42 | ||||
-rw-r--r-- | sys/sys/conf.h | 5 |
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 */ |