pstore: Do not use crash buffer for decompression
The pre-allocated compression buffer used for crash dumping was also being used for decompression. This isn't technically safe, since it's possible the kernel may attempt a crashdump while pstore is populating the pstore filesystem (and performing decompression). Instead, just allocate a separate buffer for decompression. Correctness is preferred over performance here. Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
parent
971f66d8a7
commit
bdabc8e71c
@ -258,20 +258,6 @@ static int pstore_compress(const void *in, void *out,
|
|||||||
return outlen;
|
return outlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pstore_decompress(void *in, void *out,
|
|
||||||
unsigned int inlen, unsigned int outlen)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = crypto_comp_decompress(tfm, in, inlen, out, &outlen);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("crypto_comp_decompress failed, ret = %d!\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return outlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void allocate_buf_for_compression(void)
|
static void allocate_buf_for_compression(void)
|
||||||
{
|
{
|
||||||
struct crypto_comp *ctx;
|
struct crypto_comp *ctx;
|
||||||
@ -656,8 +642,9 @@ EXPORT_SYMBOL_GPL(pstore_unregister);
|
|||||||
|
|
||||||
static void decompress_record(struct pstore_record *record)
|
static void decompress_record(struct pstore_record *record)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
int unzipped_len;
|
int unzipped_len;
|
||||||
char *decompressed;
|
char *unzipped, *workspace;
|
||||||
|
|
||||||
if (!record->compressed)
|
if (!record->compressed)
|
||||||
return;
|
return;
|
||||||
@ -668,35 +655,42 @@ static void decompress_record(struct pstore_record *record)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No compression method has created the common buffer. */
|
/* Missing compression buffer means compression was not initialized. */
|
||||||
if (!big_oops_buf) {
|
if (!big_oops_buf) {
|
||||||
pr_warn("no decompression buffer allocated\n");
|
pr_warn("no decompression method initialized!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unzipped_len = pstore_decompress(record->buf, big_oops_buf,
|
/* Allocate enough space to hold max decompression and ECC. */
|
||||||
record->size, big_oops_buf_sz);
|
unzipped_len = big_oops_buf_sz;
|
||||||
if (unzipped_len <= 0) {
|
workspace = kmalloc(unzipped_len + record->ecc_notice_size,
|
||||||
pr_err("decompression failed: %d\n", unzipped_len);
|
GFP_KERNEL);
|
||||||
|
if (!workspace)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* Build new buffer for decompressed contents. */
|
/* After decompression "unzipped_len" is almost certainly smaller. */
|
||||||
decompressed = kmalloc(unzipped_len + record->ecc_notice_size,
|
ret = crypto_comp_decompress(tfm, record->buf, record->size,
|
||||||
GFP_KERNEL);
|
workspace, &unzipped_len);
|
||||||
if (!decompressed) {
|
if (ret) {
|
||||||
pr_err("decompression ran out of memory\n");
|
pr_err("crypto_comp_decompress failed, ret = %d!\n", ret);
|
||||||
|
kfree(workspace);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(decompressed, big_oops_buf, unzipped_len);
|
|
||||||
|
|
||||||
/* Append ECC notice to decompressed buffer. */
|
/* Append ECC notice to decompressed buffer. */
|
||||||
memcpy(decompressed + unzipped_len, record->buf + record->size,
|
memcpy(workspace + unzipped_len, record->buf + record->size,
|
||||||
record->ecc_notice_size);
|
record->ecc_notice_size);
|
||||||
|
|
||||||
/* Swap out compresed contents with decompressed contents. */
|
/* Copy decompressed contents into an minimum-sized allocation. */
|
||||||
|
unzipped = kmemdup(workspace, unzipped_len + record->ecc_notice_size,
|
||||||
|
GFP_KERNEL);
|
||||||
|
kfree(workspace);
|
||||||
|
if (!unzipped)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Swap out compressed contents with decompressed contents. */
|
||||||
kfree(record->buf);
|
kfree(record->buf);
|
||||||
record->buf = decompressed;
|
record->buf = unzipped;
|
||||||
record->size = unzipped_len;
|
record->size = unzipped_len;
|
||||||
record->compressed = false;
|
record->compressed = false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user