Commit 82c5561b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pstore-v6.6-rc1-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull pstore fix from Kees Cook:

 - Adjust sizes of buffers just avoid uncompress failures (Ard
   Biesheuvel)

* tag 'pstore-v6.6-rc1-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  pstore: Base compression input buffer size on estimated compressed size
parents fdde6187 94160062
...@@ -98,7 +98,14 @@ MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)"); ...@@ -98,7 +98,14 @@ MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)");
static void *compress_workspace; static void *compress_workspace;
/*
* Compression is only used for dmesg output, which consists of low-entropy
* ASCII text, and so we can assume worst-case 60%.
*/
#define DMESG_COMP_PERCENT 60
static char *big_oops_buf; static char *big_oops_buf;
static size_t max_compressed_size;
void pstore_set_kmsg_bytes(int bytes) void pstore_set_kmsg_bytes(int bytes)
{ {
...@@ -196,6 +203,7 @@ static int pstore_compress(const void *in, void *out, ...@@ -196,6 +203,7 @@ static int pstore_compress(const void *in, void *out,
static void allocate_buf_for_compression(void) static void allocate_buf_for_compression(void)
{ {
size_t compressed_size;
char *buf; char *buf;
/* Skip if not built-in or compression disabled. */ /* Skip if not built-in or compression disabled. */
...@@ -216,7 +224,8 @@ static void allocate_buf_for_compression(void) ...@@ -216,7 +224,8 @@ static void allocate_buf_for_compression(void)
* uncompressed record size, since any record that would be expanded by * uncompressed record size, since any record that would be expanded by
* compression is just stored uncompressed. * compression is just stored uncompressed.
*/ */
buf = kvzalloc(psinfo->bufsize, GFP_KERNEL); compressed_size = (psinfo->bufsize * 100) / DMESG_COMP_PERCENT;
buf = kvzalloc(compressed_size, GFP_KERNEL);
if (!buf) { if (!buf) {
pr_err("Failed %zu byte compression buffer allocation for: %s\n", pr_err("Failed %zu byte compression buffer allocation for: %s\n",
psinfo->bufsize, compress); psinfo->bufsize, compress);
...@@ -233,6 +242,7 @@ static void allocate_buf_for_compression(void) ...@@ -233,6 +242,7 @@ static void allocate_buf_for_compression(void)
/* A non-NULL big_oops_buf indicates compression is available. */ /* A non-NULL big_oops_buf indicates compression is available. */
big_oops_buf = buf; big_oops_buf = buf;
max_compressed_size = compressed_size;
pr_info("Using crash dump compression: %s\n", compress); pr_info("Using crash dump compression: %s\n", compress);
} }
...@@ -246,6 +256,7 @@ static void free_buf_for_compression(void) ...@@ -246,6 +256,7 @@ static void free_buf_for_compression(void)
kvfree(big_oops_buf); kvfree(big_oops_buf);
big_oops_buf = NULL; big_oops_buf = NULL;
max_compressed_size = 0;
} }
void pstore_record_init(struct pstore_record *record, void pstore_record_init(struct pstore_record *record,
...@@ -305,7 +316,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, ...@@ -305,7 +316,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
record.buf = psinfo->buf; record.buf = psinfo->buf;
dst = big_oops_buf ?: psinfo->buf; dst = big_oops_buf ?: psinfo->buf;
dst_size = psinfo->bufsize; dst_size = max_compressed_size ?: psinfo->bufsize;
/* Write dump header. */ /* Write dump header. */
header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why, header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why,
...@@ -326,8 +337,15 @@ static void pstore_dump(struct kmsg_dumper *dumper, ...@@ -326,8 +337,15 @@ static void pstore_dump(struct kmsg_dumper *dumper,
record.compressed = true; record.compressed = true;
record.size = zipped_len; record.size = zipped_len;
} else { } else {
record.size = header_size + dump_size; /*
memcpy(psinfo->buf, dst, record.size); * Compression failed, so the buffer is most
* likely filled with binary data that does not
* compress as well as ASCII text. Copy as much
* of the uncompressed data as possible into
* the pstore record, and discard the rest.
*/
record.size = psinfo->bufsize;
memcpy(psinfo->buf, dst, psinfo->bufsize);
} }
} else { } else {
record.size = header_size + dump_size; record.size = header_size + dump_size;
...@@ -560,6 +578,7 @@ static void decompress_record(struct pstore_record *record, ...@@ -560,6 +578,7 @@ static void decompress_record(struct pstore_record *record,
int ret; int ret;
int unzipped_len; int unzipped_len;
char *unzipped, *workspace; char *unzipped, *workspace;
size_t max_uncompressed_size;
if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !record->compressed) if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !record->compressed)
return; return;
...@@ -583,7 +602,8 @@ static void decompress_record(struct pstore_record *record, ...@@ -583,7 +602,8 @@ static void decompress_record(struct pstore_record *record,
} }
/* Allocate enough space to hold max decompression and ECC. */ /* Allocate enough space to hold max decompression and ECC. */
workspace = kvzalloc(psinfo->bufsize + record->ecc_notice_size, max_uncompressed_size = 3 * psinfo->bufsize;
workspace = kvzalloc(max_uncompressed_size + record->ecc_notice_size,
GFP_KERNEL); GFP_KERNEL);
if (!workspace) if (!workspace)
return; return;
...@@ -591,11 +611,11 @@ static void decompress_record(struct pstore_record *record, ...@@ -591,11 +611,11 @@ static void decompress_record(struct pstore_record *record,
zstream->next_in = record->buf; zstream->next_in = record->buf;
zstream->avail_in = record->size; zstream->avail_in = record->size;
zstream->next_out = workspace; zstream->next_out = workspace;
zstream->avail_out = psinfo->bufsize; zstream->avail_out = max_uncompressed_size;
ret = zlib_inflate(zstream, Z_FINISH); ret = zlib_inflate(zstream, Z_FINISH);
if (ret != Z_STREAM_END) { if (ret != Z_STREAM_END) {
pr_err("zlib_inflate() failed, ret = %d!\n", ret); pr_err_ratelimited("zlib_inflate() failed, ret = %d!\n", ret);
kvfree(workspace); kvfree(workspace);
return; return;
} }
......
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