Commit 8c8296223f3abb142be8fc31711b18a704c0e7d8

Authored by yonghua zheng
Committed by Linus Torvalds
1 parent 57a1a19763

fs/proc/task_mmu.c: fix buffer overflow in add_page_map()

Recently we met quite a lot of random kernel panic issues after enabling
CONFIG_PROC_PAGE_MONITOR.  After debuggind we found this has something
to do with following bug in pagemap:

In struct pagemapread:

  struct pagemapread {
      int pos, len;
      pagemap_entry_t *buffer;
      bool v2;
  };

pos is number of PM_ENTRY_BYTES in buffer, but len is the size of
buffer, it is a mistake to compare pos and len in add_page_map() for
checking buffer is full or not, and this can lead to buffer overflow and
random kernel panic issue.

Correct len to be total number of PM_ENTRY_BYTES in buffer.

[akpm@linux-foundation.org: document pagemapread.pos and .len units, fix PM_ENTRY_BYTES definition]
Signed-off-by: Yonghua Zheng <younghua.zheng@gmail.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

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

... ... @@ -868,7 +868,7 @@
868 868 } pagemap_entry_t;
869 869  
870 870 struct pagemapread {
871   - int pos, len;
  871 + int pos, len; /* units: PM_ENTRY_BYTES, not bytes */
872 872 pagemap_entry_t *buffer;
873 873 bool v2;
874 874 };
... ... @@ -876,7 +876,7 @@
876 876 #define PAGEMAP_WALK_SIZE (PMD_SIZE)
877 877 #define PAGEMAP_WALK_MASK (PMD_MASK)
878 878  
879   -#define PM_ENTRY_BYTES sizeof(u64)
  879 +#define PM_ENTRY_BYTES sizeof(pagemap_entry_t)
880 880 #define PM_STATUS_BITS 3
881 881 #define PM_STATUS_OFFSET (64 - PM_STATUS_BITS)
882 882 #define PM_STATUS_MASK (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET)
... ... @@ -1127,8 +1127,8 @@
1127 1127 goto out_task;
1128 1128  
1129 1129 pm.v2 = soft_dirty_cleared;
1130   - pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT);
1131   - pm.buffer = kmalloc(pm.len, GFP_TEMPORARY);
  1130 + pm.len = (PAGEMAP_WALK_SIZE >> PAGE_SHIFT);
  1131 + pm.buffer = kmalloc(pm.len * PM_ENTRY_BYTES, GFP_TEMPORARY);
1132 1132 ret = -ENOMEM;
1133 1133 if (!pm.buffer)
1134 1134 goto out_task;