Skip to content

Commit 104fd0b

Browse files
zyxiaoookees
authored andcommitted
pstore: Support record sizes larger than kmalloc() limit
Currently pstore record buffers are allocated using kmalloc() which has a maximum size based on page size. If a large "pmsg-size" module parameter is specified, pmsg will fail to copy the contents since memdup_user() is limited to kmalloc() allocation sizes. Since we don't need physically contiguous memory for any of the pstore record buffers, use kvzalloc() to avoid such limitations in the core of pstore and in the ram backend, and explicitly read from userspace using vmemdup_user(). This also means that any other backends that want to (or do already) support larger record sizes will Just Work now. Signed-off-by: Yuxiao Zhang <yuxiaozhang@google.com> Link: https://lore.kernel.org/r/20230627202540.881909-2-yuxiaozhang@google.com Co-developed-by: Kees Cook <keescook@chromium.org> Signed-off-by: Kees Cook <keescook@chromium.org>
1 parent fe8c362 commit 104fd0b

File tree

4 files changed

+24
-21
lines changed

4 files changed

+24
-21
lines changed

fs/pstore/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ static void free_pstore_private(struct pstore_private *private)
5454
if (!private)
5555
return;
5656
if (private->record) {
57-
kfree(private->record->buf);
57+
kvfree(private->record->buf);
5858
kfree(private->record->priv);
5959
kfree(private->record);
6060
}

fs/pstore/platform.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/init.h>
1515
#include <linux/kmsg_dump.h>
1616
#include <linux/console.h>
17+
#include <linux/mm.h>
1718
#include <linux/module.h>
1819
#include <linux/pstore.h>
1920
#include <linux/string.h>
@@ -215,7 +216,7 @@ static void allocate_buf_for_compression(void)
215216
* uncompressed record size, since any record that would be expanded by
216217
* compression is just stored uncompressed.
217218
*/
218-
buf = kmalloc(psinfo->bufsize, GFP_KERNEL);
219+
buf = kvzalloc(psinfo->bufsize, GFP_KERNEL);
219220
if (!buf) {
220221
pr_err("Failed %zu byte compression buffer allocation for: %s\n",
221222
psinfo->bufsize, compress);
@@ -226,7 +227,7 @@ static void allocate_buf_for_compression(void)
226227
vmalloc(zlib_deflate_workspacesize(MAX_WBITS, DEF_MEM_LEVEL));
227228
if (!compress_workspace) {
228229
pr_err("Failed to allocate zlib deflate workspace\n");
229-
kfree(buf);
230+
kvfree(buf);
230231
return;
231232
}
232233

@@ -243,7 +244,7 @@ static void free_buf_for_compression(void)
243244
compress_workspace = NULL;
244245
}
245246

246-
kfree(big_oops_buf);
247+
kvfree(big_oops_buf);
247248
big_oops_buf = NULL;
248249
}
249250

@@ -421,15 +422,15 @@ static int pstore_write_user_compat(struct pstore_record *record,
421422
if (record->buf)
422423
return -EINVAL;
423424

424-
record->buf = memdup_user(buf, record->size);
425+
record->buf = vmemdup_user(buf, record->size);
425426
if (IS_ERR(record->buf)) {
426427
ret = PTR_ERR(record->buf);
427428
goto out;
428429
}
429430

430431
ret = record->psi->write(record);
431432

432-
kfree(record->buf);
433+
kvfree(record->buf);
433434
out:
434435
record->buf = NULL;
435436

@@ -582,8 +583,8 @@ static void decompress_record(struct pstore_record *record,
582583
}
583584

584585
/* Allocate enough space to hold max decompression and ECC. */
585-
workspace = kmalloc(psinfo->bufsize + record->ecc_notice_size,
586-
GFP_KERNEL);
586+
workspace = kvzalloc(psinfo->bufsize + record->ecc_notice_size,
587+
GFP_KERNEL);
587588
if (!workspace)
588589
return;
589590

@@ -595,7 +596,7 @@ static void decompress_record(struct pstore_record *record,
595596
ret = zlib_inflate(zstream, Z_FINISH);
596597
if (ret != Z_STREAM_END) {
597598
pr_err("zlib_inflate() failed, ret = %d!\n", ret);
598-
kfree(workspace);
599+
kvfree(workspace);
599600
return;
600601
}
601602

@@ -606,14 +607,14 @@ static void decompress_record(struct pstore_record *record,
606607
record->ecc_notice_size);
607608

608609
/* Copy decompressed contents into an minimum-sized allocation. */
609-
unzipped = kmemdup(workspace, unzipped_len + record->ecc_notice_size,
610-
GFP_KERNEL);
611-
kfree(workspace);
610+
unzipped = kvmemdup(workspace, unzipped_len + record->ecc_notice_size,
611+
GFP_KERNEL);
612+
kvfree(workspace);
612613
if (!unzipped)
613614
return;
614615

615616
/* Swap out compressed contents with decompressed contents. */
616-
kfree(record->buf);
617+
kvfree(record->buf);
617618
record->buf = unzipped;
618619
record->size = unzipped_len;
619620
record->compressed = false;
@@ -673,7 +674,7 @@ void pstore_get_backend_records(struct pstore_info *psi,
673674
rc = pstore_mkfile(root, record);
674675
if (rc) {
675676
/* pstore_mkfile() did not take record, so free it. */
676-
kfree(record->buf);
677+
kvfree(record->buf);
677678
kfree(record->priv);
678679
kfree(record);
679680
if (rc != -EEXIST || !quiet)

fs/pstore/ram.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/compiler.h>
2121
#include <linux/of.h>
2222
#include <linux/of_address.h>
23+
#include <linux/mm.h>
2324

2425
#include "internal.h"
2526
#include "ram_internal.h"
@@ -268,7 +269,7 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
268269
/* ECC correction notice */
269270
record->ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);
270271

271-
record->buf = kmalloc(size + record->ecc_notice_size + 1, GFP_KERNEL);
272+
record->buf = kvzalloc(size + record->ecc_notice_size + 1, GFP_KERNEL);
272273
if (record->buf == NULL) {
273274
size = -ENOMEM;
274275
goto out;
@@ -282,7 +283,7 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record)
282283

283284
out:
284285
if (free_prz) {
285-
kfree(prz->old_log);
286+
kvfree(prz->old_log);
286287
kfree(prz);
287288
}
288289

@@ -833,7 +834,7 @@ static int ramoops_probe(struct platform_device *pdev)
833834
*/
834835
if (cxt->pstore.flags & PSTORE_FLAGS_DMESG) {
835836
cxt->pstore.bufsize = cxt->dprzs[0]->buffer_size;
836-
cxt->pstore.buf = kzalloc(cxt->pstore.bufsize, GFP_KERNEL);
837+
cxt->pstore.buf = kvzalloc(cxt->pstore.bufsize, GFP_KERNEL);
837838
if (!cxt->pstore.buf) {
838839
pr_err("cannot allocate pstore crash dump buffer\n");
839840
err = -ENOMEM;
@@ -866,7 +867,7 @@ static int ramoops_probe(struct platform_device *pdev)
866867
return 0;
867868

868869
fail_buf:
869-
kfree(cxt->pstore.buf);
870+
kvfree(cxt->pstore.buf);
870871
fail_clear:
871872
cxt->pstore.bufsize = 0;
872873
fail_init:
@@ -881,7 +882,7 @@ static void ramoops_remove(struct platform_device *pdev)
881882

882883
pstore_unregister(&cxt->pstore);
883884

884-
kfree(cxt->pstore.buf);
885+
kvfree(cxt->pstore.buf);
885886
cxt->pstore.bufsize = 0;
886887

887888
ramoops_free_przs(cxt);

fs/pstore/ram_core.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/slab.h>
1818
#include <linux/uaccess.h>
1919
#include <linux/vmalloc.h>
20+
#include <linux/mm.h>
2021
#include <asm/page.h>
2122

2223
#include "ram_internal.h"
@@ -301,7 +302,7 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz)
301302

302303
if (!prz->old_log) {
303304
persistent_ram_ecc_old(prz);
304-
prz->old_log = kmalloc(size, GFP_KERNEL);
305+
prz->old_log = kvzalloc(size, GFP_KERNEL);
305306
}
306307
if (!prz->old_log) {
307308
pr_err("failed to allocate buffer\n");
@@ -385,7 +386,7 @@ void *persistent_ram_old(struct persistent_ram_zone *prz)
385386

386387
void persistent_ram_free_old(struct persistent_ram_zone *prz)
387388
{
388-
kfree(prz->old_log);
389+
kvfree(prz->old_log);
389390
prz->old_log = NULL;
390391
prz->old_log_size = 0;
391392
}

0 commit comments

Comments
 (0)