[PATCH 1/5] pstore: Remove worse-case compression size logic

From: Kees Cook
Date: Mon Oct 17 2022 - 22:09:35 EST


The worst case compression size is always the size of the uncompressed
data itself so avoid perfectly optimizing the oops buffer size. Hugely
simplifies the code.

Cc: Tony Luck <tony.luck@xxxxxxxxx>
Cc: "Guilherme G. Piccoli" <gpiccoli@xxxxxxxxxx>
Cc: Nick Terrell <terrelln@xxxxxx>
Cc: linux-hardening@xxxxxxxxxxxxxxx
Signed-off-by: Kees Cook <keescook@xxxxxxxxxxxx>
---
fs/pstore/platform.c | 144 +++----------------------------------------
1 file changed, 9 insertions(+), 135 deletions(-)

diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index cbc0b468c1ab..ef0bc3ae161b 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -97,11 +97,6 @@ MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)");
/* Compression parameters */
static struct crypto_comp *tfm;

-struct pstore_zbackend {
- int (*zbufsize)(size_t size);
- const char *name;
-};
-
static char *big_oops_buf;
static size_t big_oops_buf_sz;

@@ -168,105 +163,6 @@ static bool pstore_cannot_block_path(enum kmsg_dump_reason reason)
}
}

-#if IS_ENABLED(CONFIG_PSTORE_DEFLATE_COMPRESS)
-static int zbufsize_deflate(size_t size)
-{
- size_t cmpr;
-
- switch (size) {
- /* buffer range for efivars */
- case 1000 ... 2000:
- cmpr = 56;
- break;
- case 2001 ... 3000:
- cmpr = 54;
- break;
- case 3001 ... 3999:
- cmpr = 52;
- break;
- /* buffer range for nvram, erst */
- case 4000 ... 10000:
- cmpr = 45;
- break;
- default:
- cmpr = 60;
- break;
- }
-
- return (size * 100) / cmpr;
-}
-#endif
-
-#if IS_ENABLED(CONFIG_PSTORE_LZO_COMPRESS)
-static int zbufsize_lzo(size_t size)
-{
- return lzo1x_worst_compress(size);
-}
-#endif
-
-#if IS_ENABLED(CONFIG_PSTORE_LZ4_COMPRESS) || IS_ENABLED(CONFIG_PSTORE_LZ4HC_COMPRESS)
-static int zbufsize_lz4(size_t size)
-{
- return LZ4_compressBound(size);
-}
-#endif
-
-#if IS_ENABLED(CONFIG_PSTORE_842_COMPRESS)
-static int zbufsize_842(size_t size)
-{
- return size;
-}
-#endif
-
-#if IS_ENABLED(CONFIG_PSTORE_ZSTD_COMPRESS)
-static int zbufsize_zstd(size_t size)
-{
- return zstd_compress_bound(size);
-}
-#endif
-
-static const struct pstore_zbackend *zbackend __ro_after_init;
-
-static const struct pstore_zbackend zbackends[] = {
-#if IS_ENABLED(CONFIG_PSTORE_DEFLATE_COMPRESS)
- {
- .zbufsize = zbufsize_deflate,
- .name = "deflate",
- },
-#endif
-#if IS_ENABLED(CONFIG_PSTORE_LZO_COMPRESS)
- {
- .zbufsize = zbufsize_lzo,
- .name = "lzo",
- },
-#endif
-#if IS_ENABLED(CONFIG_PSTORE_LZ4_COMPRESS)
- {
- .zbufsize = zbufsize_lz4,
- .name = "lz4",
- },
-#endif
-#if IS_ENABLED(CONFIG_PSTORE_LZ4HC_COMPRESS)
- {
- .zbufsize = zbufsize_lz4,
- .name = "lz4hc",
- },
-#endif
-#if IS_ENABLED(CONFIG_PSTORE_842_COMPRESS)
- {
- .zbufsize = zbufsize_842,
- .name = "842",
- },
-#endif
-#if IS_ENABLED(CONFIG_PSTORE_ZSTD_COMPRESS)
- {
- .zbufsize = zbufsize_zstd,
- .name = "zstd",
- },
-#endif
- { }
-};
-
static int pstore_compress(const void *in, void *out,
unsigned int inlen, unsigned int outlen)
{
@@ -291,36 +187,31 @@ static void allocate_buf_for_compression(void)
char *buf;

/* Skip if not built-in or compression backend not selected yet. */
- if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !zbackend)
+ if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !compress)
return;

/* Skip if no pstore backend yet or compression init already done. */
if (!psinfo || tfm)
return;

- if (!crypto_has_comp(zbackend->name, 0, 0)) {
- pr_err("Unknown compression: %s\n", zbackend->name);
- return;
- }
-
- size = zbackend->zbufsize(psinfo->bufsize);
- if (size <= 0) {
- pr_err("Invalid compression size for %s: %d\n",
- zbackend->name, size);
+ if (!crypto_has_comp(compress, 0, 0)) {
+ pr_err("Unknown compression: %s\n", compress);
return;
}

+ /* Worst-case compression should never be more than uncompressed. */
+ size = psinfo->bufsize;
buf = kmalloc(size, GFP_KERNEL);
if (!buf) {
pr_err("Failed %d byte compression buffer allocation for: %s\n",
- size, zbackend->name);
+ size, compress);
return;
}

- ctx = crypto_alloc_comp(zbackend->name, 0, 0);
+ ctx = crypto_alloc_comp(compress, 0, 0);
if (IS_ERR_OR_NULL(ctx)) {
kfree(buf);
- pr_err("crypto_alloc_comp('%s') failed: %ld\n", zbackend->name,
+ pr_err("crypto_alloc_comp('%s') failed: %ld\n", compress,
PTR_ERR(ctx));
return;
}
@@ -330,7 +221,7 @@ static void allocate_buf_for_compression(void)
big_oops_buf_sz = size;
big_oops_buf = buf;

- pr_info("Using crash dump compression: %s\n", zbackend->name);
+ pr_info("Using crash dump compression: %s\n", compress);
}

static void free_buf_for_compression(void)
@@ -818,27 +709,10 @@ static void pstore_timefunc(struct timer_list *unused)
pstore_timer_kick();
}

-static void __init pstore_choose_compression(void)
-{
- const struct pstore_zbackend *step;
-
- if (!compress)
- return;
-
- for (step = zbackends; step->name; step++) {
- if (!strcmp(compress, step->name)) {
- zbackend = step;
- return;
- }
- }
-}
-
static int __init pstore_init(void)
{
int ret;

- pstore_choose_compression();
-
/*
* Check if any pstore backends registered earlier but did not
* initialize compression because crypto was not ready. If so,
--
2.34.1