Commit 82c5561b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+27 −7
Original line number Diff line number Diff line
@@ -98,7 +98,14 @@ MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)");

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 size_t max_compressed_size;

void pstore_set_kmsg_bytes(int bytes)
{
@@ -196,6 +203,7 @@ static int pstore_compress(const void *in, void *out,

static void allocate_buf_for_compression(void)
{
	size_t compressed_size;
	char *buf;

	/* Skip if not built-in or compression disabled. */
@@ -216,7 +224,8 @@ static void allocate_buf_for_compression(void)
	 * uncompressed record size, since any record that would be expanded by
	 * 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) {
		pr_err("Failed %zu byte compression buffer allocation for: %s\n",
		       psinfo->bufsize, compress);
@@ -233,6 +242,7 @@ static void allocate_buf_for_compression(void)

	/* A non-NULL big_oops_buf indicates compression is available. */
	big_oops_buf = buf;
	max_compressed_size = compressed_size;

	pr_info("Using crash dump compression: %s\n", compress);
}
@@ -246,6 +256,7 @@ static void free_buf_for_compression(void)

	kvfree(big_oops_buf);
	big_oops_buf = NULL;
	max_compressed_size = 0;
}

void pstore_record_init(struct pstore_record *record,
@@ -305,7 +316,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
		record.buf = psinfo->buf;

		dst = big_oops_buf ?: psinfo->buf;
		dst_size = psinfo->bufsize;
		dst_size = max_compressed_size ?: psinfo->bufsize;

		/* Write dump header. */
		header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why,
@@ -326,8 +337,15 @@ static void pstore_dump(struct kmsg_dumper *dumper,
				record.compressed = true;
				record.size = zipped_len;
			} 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 {
			record.size = header_size + dump_size;
@@ -560,6 +578,7 @@ static void decompress_record(struct pstore_record *record,
	int ret;
	int unzipped_len;
	char *unzipped, *workspace;
	size_t max_uncompressed_size;

	if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !record->compressed)
		return;
@@ -583,7 +602,8 @@ static void decompress_record(struct pstore_record *record,
	}

	/* 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);
	if (!workspace)
		return;
@@ -591,11 +611,11 @@ static void decompress_record(struct pstore_record *record,
	zstream->next_in	= record->buf;
	zstream->avail_in	= record->size;
	zstream->next_out	= workspace;
	zstream->avail_out	= psinfo->bufsize;
	zstream->avail_out	= max_uncompressed_size;

	ret = zlib_inflate(zstream, Z_FINISH);
	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);
		return;
	}