Changeset View
Standalone View
sys/kern/kern_shutdown.c
Show First 20 Lines • Show All 891 Lines • ▼ Show 20 Lines | kerneldumpcrypto_create(size_t blocksize, uint8_t encryption, | ||||
return (kdc); | return (kdc); | ||||
failed: | failed: | ||||
explicit_bzero(kdc, sizeof(*kdc) + dumpkeysize); | explicit_bzero(kdc, sizeof(*kdc) + dumpkeysize); | ||||
free(kdc, M_EKCD); | free(kdc, M_EKCD); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
#endif /* EKCD */ | #endif /* EKCD */ | ||||
int | static int | ||||
kerneldumpcrypto_init(struct kerneldumpcrypto *kdc) | kerneldumpcrypto_init(struct kerneldumpcrypto *kdc) | ||||
{ | { | ||||
#ifndef EKCD | #ifndef EKCD | ||||
return (0); | return (0); | ||||
#else | #else | ||||
uint8_t hash[SHA256_DIGEST_LENGTH]; | uint8_t hash[SHA256_DIGEST_LENGTH]; | ||||
SHA256_CTX ctx; | SHA256_CTX ctx; | ||||
struct kerneldumpkey *kdk; | struct kerneldumpkey *kdk; | ||||
▲ Show 20 Lines • Show All 266 Lines • ▼ Show 20 Lines | dump_raw_write_pad(struct dumperinfo *di, void *virtual, vm_offset_t physical, | ||||
error = dump_pad(di, virtual, length, &buf, size); | error = dump_pad(di, virtual, length, &buf, size); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
return (dump_raw_write(di, buf, physical, offset, *size)); | return (dump_raw_write(di, buf, physical, offset, *size)); | ||||
} | } | ||||
int | static int | ||||
dump_write_pad(struct dumperinfo *di, void *virtual, vm_offset_t physical, | |||||
off_t offset, size_t length, size_t *size) | |||||
{ | |||||
void *buf; | |||||
int error; | |||||
error = dump_pad(di, virtual, length, &buf, size); | |||||
if (error != 0) | |||||
return (error); | |||||
return (dump_write(di, buf, physical, offset, *size)); | |||||
} | |||||
int | |||||
dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh, | dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh, | ||||
vm_offset_t physical, off_t offset) | vm_offset_t physical, off_t offset) | ||||
{ | { | ||||
size_t size; | size_t size; | ||||
int ret; | int ret; | ||||
ret = dump_raw_write_pad(di, kdh, physical, offset, sizeof(*kdh), | ret = dump_raw_write_pad(di, kdh, physical, offset, sizeof(*kdh), | ||||
&size); | &size); | ||||
if (ret == 0 && size != di->blocksize) | if (ret == 0 && size != di->blocksize) | ||||
ret = EINVAL; | ret = EINVAL; | ||||
return (ret); | return (ret); | ||||
} | } | ||||
int | static int | ||||
dump_write_key(struct dumperinfo *di, vm_offset_t physical, off_t offset) | dump_write_key(struct dumperinfo *di, vm_offset_t physical, off_t offset) | ||||
{ | { | ||||
#ifndef EKCD | #ifndef EKCD | ||||
return (0); | return (0); | ||||
#else /* EKCD */ | #else /* EKCD */ | ||||
struct kerneldumpcrypto *kdc; | struct kerneldumpcrypto *kdc; | ||||
kdc = di->kdc; | kdc = di->kdc; | ||||
if (kdc == NULL) | if (kdc == NULL) | ||||
return (0); | return (0); | ||||
return (dump_raw_write(di, kdc->kdc_dumpkey, physical, offset, | return (dump_raw_write(di, kdc->kdc_dumpkey, physical, offset, | ||||
kdc->kdc_dumpkeysize)); | kdc->kdc_dumpkeysize)); | ||||
#endif /* !EKCD */ | #endif /* !EKCD */ | ||||
} | |||||
/* | |||||
* Do some preliminary setup for a kernel dump: verify that we have enough space | |||||
* on the dump device, write the leading header, and optionally write the crypto | |||||
* key. | |||||
*/ | |||||
def: Can we move it to sys/sys/kerneldump.h and rename to KERNELDUMP_METADATA_SIZE so we can use it… | |||||
int | |||||
dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh, off_t *dumplop) | |||||
{ | |||||
uint64_t dumpsize; | |||||
off_t dumplo; | |||||
int error; | |||||
error = kerneldumpcrypto_init(di->kdc); | |||||
if (error != 0) | |||||
return (error); | |||||
dumpsize = dtoh64(kdh->dumplength) + 2 * di->blocksize + | |||||
kerneldumpcrypto_dumpkeysize(di->kdc); | |||||
if (di->mediasize < KERNELDUMP_METADATA_SIZE + dumpsize) | |||||
return (E2BIG); | |||||
dumplo = di->mediaoffset + di->mediasize - dumpsize; | |||||
error = dump_write_header(di, kdh, 0, dumplo); | |||||
if (error != 0) | |||||
Not Done Inline Actionsdump_start() returns ENOSPC now while in the past we set error to E2BIG in case of a lack of space on amd64 and arm64. On these architectures in the ENOSPC case we try to create a minidump again. We should remove E2BIG cases as it's dead code and check in case of ENOSPC if the first kernel dump header was successfully written. I think it doesn't make sense to try to write a crash dump again if we fail at the beginning. def: dump_start() returns ENOSPC now while in the past we set error to E2BIG in case of a lack of… | |||||
Not Done Inline ActionsOops, thanks for catching that. Note that dump_check_bounds() returns ENOSPC. I think it would be simpler to change this to return E2BIG instead? markj: Oops, thanks for catching that.
Note that dump_check_bounds() returns ENOSPC. I think it would… | |||||
Done Inline ActionsDo you mean to change dump_start() to return E2BIG if this check fails? This would be a good idea. Note that this also requires changes in MD code. def: Do you mean to change dump_start() to return E2BIG if this check fails? This would be a good… | |||||
Not Done Inline ActionsIndeed. markj: Indeed. | |||||
return (error); | |||||
dumplo += di->blocksize; | |||||
Done Inline ActionsCurrently dump_start() modifies dumplop even if it fails. I would introduce a temporary dumplo variable to update *dumplop if dump_start() is successful. It would be less bug prone if we'll want to reuse *dumplop in case of a failure in the future. It would be also consistent with dumplo being updated after each dump_write() call in MD code. def: Currently dump_start() modifies dumplop even if it fails. I would introduce a temporary dumplo… | |||||
error = dump_write_key(di, 0, dumplo); | |||||
if (error != 0) | |||||
return (error); | |||||
dumplo += kerneldumpcrypto_dumpkeysize(di->kdc); | |||||
*dumplop = dumplo; | |||||
return (0); | |||||
} | |||||
/* | |||||
* Write the trailing kernel dump header and signal to the lower layers that the | |||||
* dump has completed. | |||||
*/ | |||||
int | |||||
dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh, off_t dumplo) | |||||
{ | |||||
int error; | |||||
Not Done Inline ActionsFor consistency with dump_start() I would pass a pointer to dumplo to dump_finish() and update it after a kernel dump header is successfully written. def: For consistency with dump_start() I would pass a pointer to dumplo to dump_finish() and update… | |||||
Not Done Inline ActionsI'm not sure why it's important to be consistent in this way. A dumplop argument would point into a stack frame that's about to be freed anyway. Further, I'll note that the dumplo/dumplo arguments are removed in a later revision. markj: I'm not sure why it's important to be consistent in this way. A dumplop argument would point… | |||||
Not Done Inline ActionsOK. def: OK. | |||||
error = dump_write_header(di, kdh, 0, dumplo); | |||||
if (error != 0) | |||||
return (error); | |||||
(void)dump_write(di, NULL, 0, 0, 0); | |||||
return (0); | |||||
} | } | ||||
void | void | ||||
mkdumpheader(struct kerneldumpheader *kdh, char *magic, uint32_t archver, | mkdumpheader(struct kerneldumpheader *kdh, char *magic, uint32_t archver, | ||||
uint64_t dumplen, uint32_t dumpkeysize, uint32_t blksz) | uint64_t dumplen, uint32_t dumpkeysize, uint32_t blksz) | ||||
{ | { | ||||
bzero(kdh, sizeof(*kdh)); | bzero(kdh, sizeof(*kdh)); | ||||
Show All 25 Lines |
Can we move it to sys/sys/kerneldump.h and rename to KERNELDUMP_METADATA_SIZE so we can use it also in sys/ddb/ddb/db_textdump.c?