Skip to content

Commit 1756dde

Browse files
ardbiesheuvelkees
authored andcommitted
pstore: Remove worst-case compression size logic
The worst case compression size used by pstore gives an upper bound for how much the data might inadvertently *grow* due to encapsulation overhead if the input is not compressible at all. Given that pstore records have individual 'compressed' flags, we can simply store the uncompressed data if compressing it would end up using more space, making the worst case identical to the uncompressed case. This means we can just drop all the elaborate logic that reasons about upper bounds for each individual compression algorithm, and just store the uncompressed data directly if compression fails for any reason. Co-developed-by: Kees Cook <keescook@chromium.org> Tested-by: "Guilherme G. Piccoli" <gpiccoli@igalia.com> # Steam Deck Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Eric Biggers <ebiggers@google.com> Link: https://lore.kernel.org/r/20230712162332.2670437-2-ardb@kernel.org Signed-off-by: Kees Cook <keescook@chromium.org>
1 parent fdf0eaf commit 1756dde

File tree

1 file changed

+19
-187
lines changed

1 file changed

+19
-187
lines changed

fs/pstore/platform.c

Lines changed: 19 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,6 @@
1616
#include <linux/console.h>
1717
#include <linux/module.h>
1818
#include <linux/pstore.h>
19-
#if IS_ENABLED(CONFIG_PSTORE_LZO_COMPRESS)
20-
#include <linux/lzo.h>
21-
#endif
22-
#if IS_ENABLED(CONFIG_PSTORE_LZ4_COMPRESS) || IS_ENABLED(CONFIG_PSTORE_LZ4HC_COMPRESS)
23-
#include <linux/lz4.h>
24-
#endif
25-
#if IS_ENABLED(CONFIG_PSTORE_ZSTD_COMPRESS)
26-
#include <linux/zstd.h>
27-
#endif
2819
#include <linux/crypto.h>
2920
#include <linux/string.h>
3021
#include <linux/timer.h>
@@ -97,13 +88,7 @@ MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)");
9788
/* Compression parameters */
9889
static struct crypto_comp *tfm;
9990

100-
struct pstore_zbackend {
101-
int (*zbufsize)(size_t size);
102-
const char *name;
103-
};
104-
10591
static char *big_oops_buf;
106-
static size_t big_oops_buf_sz;
10792

10893
void pstore_set_kmsg_bytes(int bytes)
10994
{
@@ -168,105 +153,6 @@ static bool pstore_cannot_block_path(enum kmsg_dump_reason reason)
168153
}
169154
}
170155

171-
#if IS_ENABLED(CONFIG_PSTORE_DEFLATE_COMPRESS)
172-
static int zbufsize_deflate(size_t size)
173-
{
174-
size_t cmpr;
175-
176-
switch (size) {
177-
/* buffer range for efivars */
178-
case 1000 ... 2000:
179-
cmpr = 56;
180-
break;
181-
case 2001 ... 3000:
182-
cmpr = 54;
183-
break;
184-
case 3001 ... 3999:
185-
cmpr = 52;
186-
break;
187-
/* buffer range for nvram, erst */
188-
case 4000 ... 10000:
189-
cmpr = 45;
190-
break;
191-
default:
192-
cmpr = 60;
193-
break;
194-
}
195-
196-
return (size * 100) / cmpr;
197-
}
198-
#endif
199-
200-
#if IS_ENABLED(CONFIG_PSTORE_LZO_COMPRESS)
201-
static int zbufsize_lzo(size_t size)
202-
{
203-
return lzo1x_worst_compress(size);
204-
}
205-
#endif
206-
207-
#if IS_ENABLED(CONFIG_PSTORE_LZ4_COMPRESS) || IS_ENABLED(CONFIG_PSTORE_LZ4HC_COMPRESS)
208-
static int zbufsize_lz4(size_t size)
209-
{
210-
return LZ4_compressBound(size);
211-
}
212-
#endif
213-
214-
#if IS_ENABLED(CONFIG_PSTORE_842_COMPRESS)
215-
static int zbufsize_842(size_t size)
216-
{
217-
return size;
218-
}
219-
#endif
220-
221-
#if IS_ENABLED(CONFIG_PSTORE_ZSTD_COMPRESS)
222-
static int zbufsize_zstd(size_t size)
223-
{
224-
return zstd_compress_bound(size);
225-
}
226-
#endif
227-
228-
static const struct pstore_zbackend *zbackend __ro_after_init;
229-
230-
static const struct pstore_zbackend zbackends[] = {
231-
#if IS_ENABLED(CONFIG_PSTORE_DEFLATE_COMPRESS)
232-
{
233-
.zbufsize = zbufsize_deflate,
234-
.name = "deflate",
235-
},
236-
#endif
237-
#if IS_ENABLED(CONFIG_PSTORE_LZO_COMPRESS)
238-
{
239-
.zbufsize = zbufsize_lzo,
240-
.name = "lzo",
241-
},
242-
#endif
243-
#if IS_ENABLED(CONFIG_PSTORE_LZ4_COMPRESS)
244-
{
245-
.zbufsize = zbufsize_lz4,
246-
.name = "lz4",
247-
},
248-
#endif
249-
#if IS_ENABLED(CONFIG_PSTORE_LZ4HC_COMPRESS)
250-
{
251-
.zbufsize = zbufsize_lz4,
252-
.name = "lz4hc",
253-
},
254-
#endif
255-
#if IS_ENABLED(CONFIG_PSTORE_842_COMPRESS)
256-
{
257-
.zbufsize = zbufsize_842,
258-
.name = "842",
259-
},
260-
#endif
261-
#if IS_ENABLED(CONFIG_PSTORE_ZSTD_COMPRESS)
262-
{
263-
.zbufsize = zbufsize_zstd,
264-
.name = "zstd",
265-
},
266-
#endif
267-
{ }
268-
};
269-
270156
static int pstore_compress(const void *in, void *out,
271157
unsigned int inlen, unsigned int outlen)
272158
{
@@ -287,50 +173,46 @@ static int pstore_compress(const void *in, void *out,
287173
static void allocate_buf_for_compression(void)
288174
{
289175
struct crypto_comp *ctx;
290-
int size;
291176
char *buf;
292177

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

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

301-
if (!crypto_has_comp(zbackend->name, 0, 0)) {
302-
pr_err("Unknown compression: %s\n", zbackend->name);
303-
return;
304-
}
305-
306-
size = zbackend->zbufsize(psinfo->bufsize);
307-
if (size <= 0) {
308-
pr_err("Invalid compression size for %s: %d\n",
309-
zbackend->name, size);
186+
if (!crypto_has_comp(compress, 0, 0)) {
187+
pr_err("Unknown compression: %s\n", compress);
310188
return;
311189
}
312190

313-
buf = kmalloc(size, GFP_KERNEL);
191+
/*
192+
* The compression buffer only needs to be as large as the maximum
193+
* uncompressed record size, since any record that would be expanded by
194+
* compression is just stored uncompressed.
195+
*/
196+
buf = kmalloc(psinfo->bufsize, GFP_KERNEL);
314197
if (!buf) {
315-
pr_err("Failed %d byte compression buffer allocation for: %s\n",
316-
size, zbackend->name);
198+
pr_err("Failed %zu byte compression buffer allocation for: %s\n",
199+
psinfo->bufsize, compress);
317200
return;
318201
}
319202

320-
ctx = crypto_alloc_comp(zbackend->name, 0, 0);
203+
ctx = crypto_alloc_comp(compress, 0, 0);
321204
if (IS_ERR_OR_NULL(ctx)) {
322205
kfree(buf);
323-
pr_err("crypto_alloc_comp('%s') failed: %ld\n", zbackend->name,
206+
pr_err("crypto_alloc_comp('%s') failed: %ld\n", compress,
324207
PTR_ERR(ctx));
325208
return;
326209
}
327210

328211
/* A non-NULL big_oops_buf indicates compression is available. */
329212
tfm = ctx;
330-
big_oops_buf_sz = size;
331213
big_oops_buf = buf;
332214

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

336218
static void free_buf_for_compression(void)
@@ -341,33 +223,6 @@ static void free_buf_for_compression(void)
341223
}
342224
kfree(big_oops_buf);
343225
big_oops_buf = NULL;
344-
big_oops_buf_sz = 0;
345-
}
346-
347-
/*
348-
* Called when compression fails, since the printk buffer
349-
* would be fetched for compression calling it again when
350-
* compression fails would have moved the iterator of
351-
* printk buffer which results in fetching old contents.
352-
* Copy the recent messages from big_oops_buf to psinfo->buf
353-
*/
354-
static size_t copy_kmsg_to_buffer(int hsize, size_t len)
355-
{
356-
size_t total_len;
357-
size_t diff;
358-
359-
total_len = hsize + len;
360-
361-
if (total_len > psinfo->bufsize) {
362-
diff = total_len - psinfo->bufsize + hsize;
363-
memcpy(psinfo->buf, big_oops_buf, hsize);
364-
memcpy(psinfo->buf + hsize, big_oops_buf + diff,
365-
psinfo->bufsize - hsize);
366-
total_len = psinfo->bufsize;
367-
} else
368-
memcpy(psinfo->buf, big_oops_buf, total_len);
369-
370-
return total_len;
371226
}
372227

373228
void pstore_record_init(struct pstore_record *record,
@@ -426,13 +281,8 @@ static void pstore_dump(struct kmsg_dumper *dumper,
426281
record.part = part;
427282
record.buf = psinfo->buf;
428283

429-
if (big_oops_buf) {
430-
dst = big_oops_buf;
431-
dst_size = big_oops_buf_sz;
432-
} else {
433-
dst = psinfo->buf;
434-
dst_size = psinfo->bufsize;
435-
}
284+
dst = big_oops_buf ?: psinfo->buf;
285+
dst_size = psinfo->bufsize;
436286

437287
/* Write dump header. */
438288
header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why,
@@ -453,8 +303,8 @@ static void pstore_dump(struct kmsg_dumper *dumper,
453303
record.compressed = true;
454304
record.size = zipped_len;
455305
} else {
456-
record.size = copy_kmsg_to_buffer(header_size,
457-
dump_size);
306+
record.size = header_size + dump_size;
307+
memcpy(psinfo->buf, dst, record.size);
458308
}
459309
} else {
460310
record.size = header_size + dump_size;
@@ -703,8 +553,7 @@ static void decompress_record(struct pstore_record *record)
703553
}
704554

705555
/* Allocate enough space to hold max decompression and ECC. */
706-
unzipped_len = big_oops_buf_sz;
707-
workspace = kmalloc(unzipped_len + record->ecc_notice_size,
556+
workspace = kmalloc(psinfo->bufsize + record->ecc_notice_size,
708557
GFP_KERNEL);
709558
if (!workspace)
710559
return;
@@ -818,27 +667,10 @@ static void pstore_timefunc(struct timer_list *unused)
818667
pstore_timer_kick();
819668
}
820669

821-
static void __init pstore_choose_compression(void)
822-
{
823-
const struct pstore_zbackend *step;
824-
825-
if (!compress)
826-
return;
827-
828-
for (step = zbackends; step->name; step++) {
829-
if (!strcmp(compress, step->name)) {
830-
zbackend = step;
831-
return;
832-
}
833-
}
834-
}
835-
836670
static int __init pstore_init(void)
837671
{
838672
int ret;
839673

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

0 commit comments

Comments
 (0)