Commit bdabc8e7 authored by Kees Cook's avatar Kees Cook

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: default avatarKees Cook <keescook@chromium.org>
parent 971f66d8
...@@ -258,20 +258,6 @@ static int pstore_compress(const void *in, void *out, ...@@ -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); ...@@ -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) ...@@ -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;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment