From: Siddhesh Poyarekar Date: Tue, 29 May 2012 22:06:22 +0000 (-0700) Subject: mm/fork: fix overflow in vma length when copying mmap on clone X-Git-Tag: v3.2.20~58 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=ff8445f52037e30411691d0d1ced9650c780c3c2;p=karo-tx-linux.git mm/fork: fix overflow in vma length when copying mmap on clone commit 7edc8b0ac16cbaed7cb4ea4c6b95ce98d2997e84 upstream. The vma length in dup_mmap is calculated and stored in a unsigned int, which is insufficient and hence overflows for very large maps (beyond 16TB). The following program demonstrates this: #include #include #include #define GIG 1024 * 1024 * 1024L #define EXTENT 16393 int main(void) { int i, r; void *m; char buf[1024]; for (i = 0; i < EXTENT; i++) { m = mmap(NULL, (size_t) 1 * 1024 * 1024 * 1024L, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (m == (void *)-1) printf("MMAP Failed: %d\n", m); else printf("%d : MMAP returned %p\n", i, m); r = fork(); if (r == 0) { printf("%d: successed\n", i); return 0; } else if (r < 0) printf("FORK Failed: %d\n", r); else if (r > 0) wait(NULL); } return 0; } Increase the storage size of the result to unsigned long, which is sufficient for storing the difference between addresses. Signed-off-by: Siddhesh Poyarekar Cc: Tejun Heo Cc: Oleg Nesterov Cc: Jens Axboe Cc: Peter Zijlstra Acked-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings --- diff --git a/kernel/fork.c b/kernel/fork.c index 26f1ab0b1c95..79ee71f8b5a0 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -352,7 +352,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) } charge = 0; if (mpnt->vm_flags & VM_ACCOUNT) { - unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + unsigned long len; + len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; if (security_vm_enough_memory(len)) goto fail_nomem; charge = len;