Commit 7e76f34fa103677a27d96a7cfef8ce61389a32de

Authored by Aruna Balakrishnaiah
Committed by Benjamin Herrenschmidt
1 parent 4e90a2a737

powerpc/pseries: Fix buffer overflow when reading from pstore

When reading from pstore there is a buffer overflow during decompression
due to the header added in unzip_oops. Remove unzip_oops and call
pstore_decompress directly in nvram_pstore_read. Allocate buffer of size
report_length of the oops header as header will not be deallocated in pstore.
Since we have 'openssl' command line tool to decompress the compressed data,
dump the compressed data in case decompression fails instead of not dumping
anything.

Signed-off-by: Aruna Balakrishnaiah <aruna@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Showing 1 changed file with 24 additions and 46 deletions Side-by-side Diff

arch/powerpc/platforms/pseries/nvram.c
... ... @@ -569,35 +569,6 @@
569 569 return ret;
570 570 }
571 571  
572   -static int unzip_oops(char *oops_buf, char *big_buf)
573   -{
574   - struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
575   - u64 timestamp = oops_hdr->timestamp;
576   - char *big_oops_data = NULL;
577   - char *oops_data_buf = NULL;
578   - size_t big_oops_data_sz;
579   - int unzipped_len;
580   -
581   - big_oops_data = big_buf + sizeof(struct oops_log_info);
582   - big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info);
583   - oops_data_buf = oops_buf + sizeof(struct oops_log_info);
584   -
585   - unzipped_len = nvram_decompress(oops_data_buf, big_oops_data,
586   - oops_hdr->report_length,
587   - big_oops_data_sz);
588   -
589   - if (unzipped_len < 0) {
590   - pr_err("nvram: decompression failed; returned %d\n",
591   - unzipped_len);
592   - return -1;
593   - }
594   - oops_hdr = (struct oops_log_info *)big_buf;
595   - oops_hdr->version = OOPS_HDR_VERSION;
596   - oops_hdr->report_length = (u16) unzipped_len;
597   - oops_hdr->timestamp = timestamp;
598   - return 0;
599   -}
600   -
601 572 static int nvram_pstore_open(struct pstore_info *psi)
602 573 {
603 574 /* Reset the iterator to start reading partitions again */
604 575  
... ... @@ -685,10 +656,9 @@
685 656 unsigned int err_type, id_no, size = 0;
686 657 struct nvram_os_partition *part = NULL;
687 658 char *buff = NULL, *big_buff = NULL;
688   - int rc, sig = 0;
  659 + int sig = 0;
689 660 loff_t p;
690 661  
691   -read_partition:
692 662 read_type++;
693 663  
694 664 switch (nvram_type_ids[read_type]) {
695 665  
696 666  
697 667  
698 668  
699 669  
700 670  
... ... @@ -749,30 +719,36 @@
749 719 *id = id_no;
750 720  
751 721 if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
  722 + int length, unzipped_len;
  723 +
752 724 oops_hdr = (struct oops_log_info *)buff;
753   - *buf = buff + sizeof(*oops_hdr);
  725 + length = oops_hdr->report_length;
  726 + *buf = kmalloc(length, GFP_KERNEL);
  727 + if (*buf == NULL)
  728 + return -ENOMEM;
  729 + memcpy(*buf, buff + sizeof(*oops_hdr), length);
  730 + time->tv_sec = oops_hdr->timestamp;
  731 + time->tv_nsec = 0;
  732 + kfree(buff);
754 733  
755 734 if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) {
756 735 big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL);
757 736 if (!big_buff)
758 737 return -ENOMEM;
759 738  
760   - rc = unzip_oops(buff, big_buff);
  739 + unzipped_len = nvram_decompress(*buf, big_buff,
  740 + length, big_oops_buf_sz);
761 741  
762   - if (rc != 0) {
763   - kfree(buff);
  742 + if (unzipped_len < 0) {
  743 + pr_err("nvram: decompression failed, returned "
  744 + "rc %d\n", unzipped_len);
764 745 kfree(big_buff);
765   - goto read_partition;
  746 + } else {
  747 + *buf = big_buff;
  748 + length = unzipped_len;
766 749 }
767   -
768   - oops_hdr = (struct oops_log_info *)big_buff;
769   - *buf = big_buff + sizeof(*oops_hdr);
770   - kfree(buff);
771 750 }
772   -
773   - time->tv_sec = oops_hdr->timestamp;
774   - time->tv_nsec = 0;
775   - return oops_hdr->report_length;
  751 + return length;
776 752 }
777 753  
778 754 *buf = buff;
... ... @@ -816,6 +792,7 @@
816 792 static void __init nvram_init_oops_partition(int rtas_partition_exists)
817 793 {
818 794 int rc;
  795 + size_t size;
819 796  
820 797 rc = pseries_nvram_init_os_partition(&oops_log_partition);
821 798 if (rc != 0) {
... ... @@ -844,8 +821,9 @@
844 821 big_oops_buf_sz = (oops_data_sz * 100) / 45;
845 822 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
846 823 if (big_oops_buf) {
847   - stream.workspace = kmalloc(zlib_deflate_workspacesize(
848   - WINDOW_BITS, MEM_LEVEL), GFP_KERNEL);
  824 + size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
  825 + zlib_inflate_workspacesize());
  826 + stream.workspace = kmalloc(size, GFP_KERNEL);
849 827 if (!stream.workspace) {
850 828 pr_err("nvram: No memory for compression workspace; "
851 829 "skipping compression of %s partition data\n",