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
This commit is contained in:
Eric van Gyzen 2021-08-06 10:38:51 -05:00
parent 96f9bd4654
commit 13a58148de
3 changed files with 43 additions and 24 deletions

View File

@ -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 +

View File

@ -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();

View File

@ -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 */