diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2016-09-08 07:48:05 -0400 |
---|---|---|
committer | Kees Cook <keescook@chromium.org> | 2016-09-08 17:58:00 -0400 |
commit | 4407de74df18ed405cc5998990004c813ccfdbde (patch) | |
tree | 757205808fa294bbf533099aa991ebaff20d06cb | |
parent | d71f058617564750261b673ea9b3352382b9cde4 (diff) |
pstore/ramoops: fixup driver removal
A basic rmmod ramoops segfaults. Let's see why.
Since commit 34f0ec82e0a9 ("pstore: Correct the max_dump_cnt clearing of
ramoops") sets ->max_dump_cnt to zero before looping over ->przs but we
didn't use it before that either.
And since commit ee1d267423a1 ("pstore: add pstore unregister") we free
that memory on rmmod.
But even then, we looped until a NULL pointer or ERR. I don't see where
it is ensured that the last member is NULL. Let's try this instead:
simply error recovery and free. Clean up in error case where resources
were allocated. And then, in the free path, rely on ->max_dump_cnt in
the free path.
Cc: Anton Vorontsov <anton@enomsg.org>
Cc: Colin Cross <ccross@android.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org # 4.4.x-
-rw-r--r-- | fs/pstore/ram.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 7a034d62cf8c..2340262a7e97 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c | |||
@@ -377,13 +377,14 @@ static void ramoops_free_przs(struct ramoops_context *cxt) | |||
377 | { | 377 | { |
378 | int i; | 378 | int i; |
379 | 379 | ||
380 | cxt->max_dump_cnt = 0; | ||
381 | if (!cxt->przs) | 380 | if (!cxt->przs) |
382 | return; | 381 | return; |
383 | 382 | ||
384 | for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++) | 383 | for (i = 0; i < cxt->max_dump_cnt; i++) |
385 | persistent_ram_free(cxt->przs[i]); | 384 | persistent_ram_free(cxt->przs[i]); |
385 | |||
386 | kfree(cxt->przs); | 386 | kfree(cxt->przs); |
387 | cxt->max_dump_cnt = 0; | ||
387 | } | 388 | } |
388 | 389 | ||
389 | static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, | 390 | static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, |
@@ -408,7 +409,7 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, | |||
408 | GFP_KERNEL); | 409 | GFP_KERNEL); |
409 | if (!cxt->przs) { | 410 | if (!cxt->przs) { |
410 | dev_err(dev, "failed to initialize a prz array for dumps\n"); | 411 | dev_err(dev, "failed to initialize a prz array for dumps\n"); |
411 | goto fail_prz; | 412 | goto fail_mem; |
412 | } | 413 | } |
413 | 414 | ||
414 | for (i = 0; i < cxt->max_dump_cnt; i++) { | 415 | for (i = 0; i < cxt->max_dump_cnt; i++) { |
@@ -419,6 +420,11 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, | |||
419 | err = PTR_ERR(cxt->przs[i]); | 420 | err = PTR_ERR(cxt->przs[i]); |
420 | dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", | 421 | dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", |
421 | cxt->record_size, (unsigned long long)*paddr, err); | 422 | cxt->record_size, (unsigned long long)*paddr, err); |
423 | |||
424 | while (i > 0) { | ||
425 | i--; | ||
426 | persistent_ram_free(cxt->przs[i]); | ||
427 | } | ||
422 | goto fail_prz; | 428 | goto fail_prz; |
423 | } | 429 | } |
424 | *paddr += cxt->record_size; | 430 | *paddr += cxt->record_size; |
@@ -426,7 +432,9 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, | |||
426 | 432 | ||
427 | return 0; | 433 | return 0; |
428 | fail_prz: | 434 | fail_prz: |
429 | ramoops_free_przs(cxt); | 435 | kfree(cxt->przs); |
436 | fail_mem: | ||
437 | cxt->max_dump_cnt = 0; | ||
430 | return err; | 438 | return err; |
431 | } | 439 | } |
432 | 440 | ||
@@ -659,7 +667,6 @@ static int ramoops_remove(struct platform_device *pdev) | |||
659 | struct ramoops_context *cxt = &oops_cxt; | 667 | struct ramoops_context *cxt = &oops_cxt; |
660 | 668 | ||
661 | pstore_unregister(&cxt->pstore); | 669 | pstore_unregister(&cxt->pstore); |
662 | cxt->max_dump_cnt = 0; | ||
663 | 670 | ||
664 | kfree(cxt->pstore.buf); | 671 | kfree(cxt->pstore.buf); |
665 | cxt->pstore.bufsize = 0; | 672 | cxt->pstore.bufsize = 0; |