* [PATCH] mm: Ensure get_unmapped_area() returns higher address than mmap_min_addr @ 2013-10-23 2:46 Akira Takeuchi 2013-10-23 4:26 ` [PATCH] mm: Ensure get_unmapped_area() returns higher addressthan mmap_min_addr Naoya Horiguchi 0 siblings, 1 reply; 7+ messages in thread From: Akira Takeuchi @ 2013-10-23 2:46 UTC (permalink / raw) To: linux-mm; +Cc: linux-kernel This patch fixes the problem that get_unmapped_area() can return illegal address and result in failing mmap(2) etc. In case that the address higher than PAGE_SIZE is set to /proc/sys/vm/mmap_min_addr, the address lower than mmap_min_addr can be returned by get_unmapped_area(), even if you do not pass any virtual address hint (i.e. the second argument). This is because the current get_unmapped_area() code does not take into account mmap_min_addr. This leads to two actual problems as follows: 1. mmap(2) can fail with EPERM on the process without CAP_SYS_RAWIO, although any illegal parameter is not passed. 2. The bottom-up search path after the top-down search might not work in arch_get_unmapped_area_topdown(). [How to reproduce] --- test.c ------------------------------------------------- #include <stdio.h> #include <unistd.h> #include <sys/mman.h> #include <sys/errno.h> int main(int argc, char *argv[]) { void *ret = NULL, *last_map; size_t pagesize = sysconf(_SC_PAGESIZE); do { last_map = ret; ret = mmap(0, pagesize, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); // printf("ret=%p\n", ret); } while (ret != MAP_FAILED); if (errno != ENOMEM) { printf("ERR: unexpected errno: %d (last map=%p)\n", errno, last_map); } return 0; } --------------------------------------------------------------- $ gcc -m32 -o test test.c $ sudo sysctl -w vm.mmap_min_addr=65536 vm.mmap_min_addr = 65536 $ ./test (run as non-priviledge user) ERR: unexpected errno: 1 (last map=0x10000) Signed-off-by: Akira Takeuchi <takeuchi.akr@jp.panasonic.com> Signed-off-by: Kiyoshi Owada <owada.kiyoshi@jp.panasonic.com> --- mm/mmap.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mm/mmap.c b/mm/mmap.c index 9d54851..362e5f1 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1856,7 +1856,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, struct vm_area_struct *vma; struct vm_unmapped_area_info info; - if (len > TASK_SIZE) + if (len > TASK_SIZE - mmap_min_addr) return -ENOMEM; if (flags & MAP_FIXED) @@ -1865,7 +1865,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && (!vma || addr + len <= vma->vm_start)) return addr; } @@ -1895,7 +1895,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, struct vm_unmapped_area_info info; /* requested length too big for entire address space */ - if (len > TASK_SIZE) + if (len > TASK_SIZE - mmap_min_addr) return -ENOMEM; if (flags & MAP_FIXED) @@ -1905,14 +1905,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && (!vma || addr + len <= vma->vm_start)) return addr; } info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.length = len; - info.low_limit = PAGE_SIZE; + info.low_limit = max(PAGE_SIZE, mmap_min_addr); info.high_limit = mm->mmap_base; info.align_mask = 0; addr = vm_unmapped_area(&info); -- 1.7.0.4 -- Akira Takeuchi <takeuchi.akr@jp.panasonic.com> -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] mm: Ensure get_unmapped_area() returns higher addressthan mmap_min_addr 2013-10-23 2:46 [PATCH] mm: Ensure get_unmapped_area() returns higher address than mmap_min_addr Akira Takeuchi @ 2013-10-23 4:26 ` Naoya Horiguchi 2013-10-23 5:53 ` Akira Takeuchi 0 siblings, 1 reply; 7+ messages in thread From: Naoya Horiguchi @ 2013-10-23 4:26 UTC (permalink / raw) To: Akira Takeuchi; +Cc: linux-mm, linux-kernel Hi, On Wed, Oct 23, 2013 at 11:46:53AM +0900, Akira Takeuchi wrote: > This patch fixes the problem that get_unmapped_area() can return illegal > address and result in failing mmap(2) etc. > > In case that the address higher than PAGE_SIZE is set to > /proc/sys/vm/mmap_min_addr, the address lower than mmap_min_addr can be > returned by get_unmapped_area(), even if you do not pass any virtual > address hint (i.e. the second argument). > > This is because the current get_unmapped_area() code does not take into > account mmap_min_addr. > > This leads to two actual problems as follows: > > 1. mmap(2) can fail with EPERM on the process without CAP_SYS_RAWIO, > although any illegal parameter is not passed. > > 2. The bottom-up search path after the top-down search might not work in > arch_get_unmapped_area_topdown(). > > [How to reproduce] > > --- test.c ------------------------------------------------- > #include <stdio.h> > #include <unistd.h> > #include <sys/mman.h> > #include <sys/errno.h> > > int main(int argc, char *argv[]) > { > void *ret = NULL, *last_map; > size_t pagesize = sysconf(_SC_PAGESIZE); > > do { > last_map = ret; > ret = mmap(0, pagesize, PROT_NONE, > MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); > // printf("ret=%p\n", ret); > } while (ret != MAP_FAILED); > > if (errno != ENOMEM) { > printf("ERR: unexpected errno: %d (last map=%p)\n", > errno, last_map); > } > > return 0; > } > --------------------------------------------------------------- > > $ gcc -m32 -o test test.c > $ sudo sysctl -w vm.mmap_min_addr=65536 > vm.mmap_min_addr = 65536 > $ ./test (run as non-priviledge user) > ERR: unexpected errno: 1 (last map=0x10000) > > Signed-off-by: Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > Signed-off-by: Kiyoshi Owada <owada.kiyoshi@jp.panasonic.com> > --- > mm/mmap.c | 10 +++++----- > 1 files changed, 5 insertions(+), 5 deletions(-) > > diff --git a/mm/mmap.c b/mm/mmap.c > index 9d54851..362e5f1 100644 > --- a/mm/mmap.c > +++ b/mm/mmap.c > @@ -1856,7 +1856,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, > struct vm_area_struct *vma; > struct vm_unmapped_area_info info; > > - if (len > TASK_SIZE) > + if (len > TASK_SIZE - mmap_min_addr) > return -ENOMEM; > > if (flags & MAP_FIXED) I feel that it looks clearer to fix this in round_hint_to_min(), with doing mmap_min_addr check in hint == NULL case. Does it work for you? Thanks, Naoya Horiguchi > @@ -1865,7 +1865,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, > if (addr) { > addr = PAGE_ALIGN(addr); > vma = find_vma(mm, addr); > - if (TASK_SIZE - len >= addr && > + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && > (!vma || addr + len <= vma->vm_start)) > return addr; > } > @@ -1895,7 +1895,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, > struct vm_unmapped_area_info info; > > /* requested length too big for entire address space */ > - if (len > TASK_SIZE) > + if (len > TASK_SIZE - mmap_min_addr) > return -ENOMEM; > > if (flags & MAP_FIXED) > @@ -1905,14 +1905,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, > if (addr) { > addr = PAGE_ALIGN(addr); > vma = find_vma(mm, addr); > - if (TASK_SIZE - len >= addr && > + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && > (!vma || addr + len <= vma->vm_start)) > return addr; > } > > info.flags = VM_UNMAPPED_AREA_TOPDOWN; > info.length = len; > - info.low_limit = PAGE_SIZE; > + info.low_limit = max(PAGE_SIZE, mmap_min_addr); > info.high_limit = mm->mmap_base; > info.align_mask = 0; > addr = vm_unmapped_area(&info); > -- > 1.7.0.4 > > > -- > Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > > -- > To unsubscribe, send a message with 'unsubscribe linux-mm' in > the body to majordomo@kvack.org. For more info on Linux MM, > see: http://www.linux-mm.org/ . > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> > -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] mm: Ensure get_unmapped_area() returns higher addressthan mmap_min_addr 2013-10-23 4:26 ` [PATCH] mm: Ensure get_unmapped_area() returns higher addressthan mmap_min_addr Naoya Horiguchi @ 2013-10-23 5:53 ` Akira Takeuchi 2013-10-23 6:50 ` [PATCH] mm: Ensure get_unmapped_area() returns higheraddressthan mmap_min_addr Naoya Horiguchi 0 siblings, 1 reply; 7+ messages in thread From: Akira Takeuchi @ 2013-10-23 5:53 UTC (permalink / raw) To: Naoya Horiguchi; +Cc: linux-mm, linux-kernel Hi, On Wed, 23 Oct 2013 00:26:05 -0400 Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> wrote: > Hi, > > On Wed, Oct 23, 2013 at 11:46:53AM +0900, Akira Takeuchi wrote: > > This patch fixes the problem that get_unmapped_area() can return illegal > > address and result in failing mmap(2) etc. > > > > In case that the address higher than PAGE_SIZE is set to > > /proc/sys/vm/mmap_min_addr, the address lower than mmap_min_addr can be > > returned by get_unmapped_area(), even if you do not pass any virtual > > address hint (i.e. the second argument). > > > > This is because the current get_unmapped_area() code does not take into > > account mmap_min_addr. > > > > This leads to two actual problems as follows: > > > > 1. mmap(2) can fail with EPERM on the process without CAP_SYS_RAWIO, > > although any illegal parameter is not passed. > > > > 2. The bottom-up search path after the top-down search might not work in > > arch_get_unmapped_area_topdown(). > > > > [How to reproduce] > > > > --- test.c ------------------------------------------------- > > #include <stdio.h> > > #include <unistd.h> > > #include <sys/mman.h> > > #include <sys/errno.h> > > > > int main(int argc, char *argv[]) > > { > > void *ret = NULL, *last_map; > > size_t pagesize = sysconf(_SC_PAGESIZE); > > > > do { > > last_map = ret; > > ret = mmap(0, pagesize, PROT_NONE, > > MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); > > // printf("ret=%p\n", ret); > > } while (ret != MAP_FAILED); > > > > if (errno != ENOMEM) { > > printf("ERR: unexpected errno: %d (last map=%p)\n", > > errno, last_map); > > } > > > > return 0; > > } > > --------------------------------------------------------------- > > > > $ gcc -m32 -o test test.c > > $ sudo sysctl -w vm.mmap_min_addr=65536 > > vm.mmap_min_addr = 65536 > > $ ./test (run as non-priviledge user) > > ERR: unexpected errno: 1 (last map=0x10000) > > > > Signed-off-by: Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > > Signed-off-by: Kiyoshi Owada <owada.kiyoshi@jp.panasonic.com> > > --- > > mm/mmap.c | 10 +++++----- > > 1 files changed, 5 insertions(+), 5 deletions(-) > > > > diff --git a/mm/mmap.c b/mm/mmap.c > > index 9d54851..362e5f1 100644 > > --- a/mm/mmap.c > > +++ b/mm/mmap.c > > @@ -1856,7 +1856,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, > > struct vm_area_struct *vma; > > struct vm_unmapped_area_info info; > > > > - if (len > TASK_SIZE) > > + if (len > TASK_SIZE - mmap_min_addr) > > return -ENOMEM; > > > > if (flags & MAP_FIXED) > > I feel that it looks clearer to fix this in round_hint_to_min(), > with doing mmap_min_addr check in hint == NULL case. > Does it work for you? The current round_hint_to_min() code checks and adjusts just for the hint address, not for "len". Also, it returns no error. Do you mean adding "len" to the argument of round_hint_to_min() and making round_hint_to_min() return any error ? Regards, Akira Takeuchi > Thanks, > Naoya Horiguchi > > > @@ -1865,7 +1865,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, > > if (addr) { > > addr = PAGE_ALIGN(addr); > > vma = find_vma(mm, addr); > > - if (TASK_SIZE - len >= addr && > > + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && > > (!vma || addr + len <= vma->vm_start)) > > return addr; > > } > > @@ -1895,7 +1895,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, > > struct vm_unmapped_area_info info; > > > > /* requested length too big for entire address space */ > > - if (len > TASK_SIZE) > > + if (len > TASK_SIZE - mmap_min_addr) > > return -ENOMEM; > > > > if (flags & MAP_FIXED) > > @@ -1905,14 +1905,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, > > if (addr) { > > addr = PAGE_ALIGN(addr); > > vma = find_vma(mm, addr); > > - if (TASK_SIZE - len >= addr && > > + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && > > (!vma || addr + len <= vma->vm_start)) > > return addr; > > } > > > > info.flags = VM_UNMAPPED_AREA_TOPDOWN; > > info.length = len; > > - info.low_limit = PAGE_SIZE; > > + info.low_limit = max(PAGE_SIZE, mmap_min_addr); > > info.high_limit = mm->mmap_base; > > info.align_mask = 0; > > addr = vm_unmapped_area(&info); > > -- > > 1.7.0.4 > > > > > > -- > > Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > > > > -- > > To unsubscribe, send a message with 'unsubscribe linux-mm' in > > the body to majordomo@kvack.org. For more info on Linux MM, > > see: http://www.linux-mm.org/ . > > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> > > -- Akira Takeuchi <takeuchi.akr@jp.panasonic.com> -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] mm: Ensure get_unmapped_area() returns higheraddressthan mmap_min_addr 2013-10-23 5:53 ` Akira Takeuchi @ 2013-10-23 6:50 ` Naoya Horiguchi 2013-10-23 7:39 ` Akira Takeuchi 2013-10-23 7:44 ` [PATCH v2] mm: Ensure get_unmapped_area() returns higher address than mmap_min_addr Akira Takeuchi 0 siblings, 2 replies; 7+ messages in thread From: Naoya Horiguchi @ 2013-10-23 6:50 UTC (permalink / raw) To: Akira Takeuchi; +Cc: linux-mm, linux-kernel On Wed, Oct 23, 2013 at 02:53:03PM +0900, Akira Takeuchi wrote: > Hi, > > On Wed, 23 Oct 2013 00:26:05 -0400 > Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> wrote: > > > Hi, > > > > On Wed, Oct 23, 2013 at 11:46:53AM +0900, Akira Takeuchi wrote: > > > This patch fixes the problem that get_unmapped_area() can return illegal > > > address and result in failing mmap(2) etc. > > > > > > In case that the address higher than PAGE_SIZE is set to > > > /proc/sys/vm/mmap_min_addr, the address lower than mmap_min_addr can be > > > returned by get_unmapped_area(), even if you do not pass any virtual > > > address hint (i.e. the second argument). > > > > > > This is because the current get_unmapped_area() code does not take into > > > account mmap_min_addr. > > > > > > This leads to two actual problems as follows: > > > > > > 1. mmap(2) can fail with EPERM on the process without CAP_SYS_RAWIO, > > > although any illegal parameter is not passed. > > > > > > 2. The bottom-up search path after the top-down search might not work in > > > arch_get_unmapped_area_topdown(). > > > > > > [How to reproduce] > > > > > > --- test.c ------------------------------------------------- > > > #include <stdio.h> > > > #include <unistd.h> > > > #include <sys/mman.h> > > > #include <sys/errno.h> > > > > > > int main(int argc, char *argv[]) > > > { > > > void *ret = NULL, *last_map; > > > size_t pagesize = sysconf(_SC_PAGESIZE); > > > > > > do { > > > last_map = ret; > > > ret = mmap(0, pagesize, PROT_NONE, > > > MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); > > > // printf("ret=%p\n", ret); > > > } while (ret != MAP_FAILED); > > > > > > if (errno != ENOMEM) { > > > printf("ERR: unexpected errno: %d (last map=%p)\n", > > > errno, last_map); > > > } > > > > > > return 0; > > > } > > > --------------------------------------------------------------- > > > > > > $ gcc -m32 -o test test.c > > > $ sudo sysctl -w vm.mmap_min_addr=65536 > > > vm.mmap_min_addr = 65536 > > > $ ./test (run as non-priviledge user) > > > ERR: unexpected errno: 1 (last map=0x10000) > > > > > > Signed-off-by: Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > > > Signed-off-by: Kiyoshi Owada <owada.kiyoshi@jp.panasonic.com> > > > --- > > > mm/mmap.c | 10 +++++----- > > > 1 files changed, 5 insertions(+), 5 deletions(-) > > > > > > diff --git a/mm/mmap.c b/mm/mmap.c > > > index 9d54851..362e5f1 100644 > > > --- a/mm/mmap.c > > > +++ b/mm/mmap.c > > > @@ -1856,7 +1856,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, > > > struct vm_area_struct *vma; > > > struct vm_unmapped_area_info info; > > > > > > - if (len > TASK_SIZE) > > > + if (len > TASK_SIZE - mmap_min_addr) > > > return -ENOMEM; > > > > > > if (flags & MAP_FIXED) > > > > I feel that it looks clearer to fix this in round_hint_to_min(), > > with doing mmap_min_addr check in hint == NULL case. > > Does it work for you? > > The current round_hint_to_min() code checks and adjusts just for > the hint address, not for "len". Also, it returns no error. > > Do you mean adding "len" to the argument of round_hint_to_min() > and making round_hint_to_min() return any error ? I thought of just removing (hint != NULL) check in round_hint_to_min(), but in my rethinking I found that that affects other code and needs more changes, so your approach is simpler. I drop my suggestion. The above check is to detect too big request, and in your reproducer len is small (4096), so I'm a bit confused :) Although it doesn't fix your problem itself, it's correct, Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Thanks, Naoya Horiguchi > > Regards, > Akira Takeuchi > > > Thanks, > > Naoya Horiguchi > > > > > @@ -1865,7 +1865,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, > > > if (addr) { > > > addr = PAGE_ALIGN(addr); > > > vma = find_vma(mm, addr); > > > - if (TASK_SIZE - len >= addr && > > > + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && > > > (!vma || addr + len <= vma->vm_start)) > > > return addr; > > > } > > > @@ -1895,7 +1895,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, > > > struct vm_unmapped_area_info info; > > > > > > /* requested length too big for entire address space */ > > > - if (len > TASK_SIZE) > > > + if (len > TASK_SIZE - mmap_min_addr) > > > return -ENOMEM; > > > > > > if (flags & MAP_FIXED) > > > @@ -1905,14 +1905,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, > > > if (addr) { > > > addr = PAGE_ALIGN(addr); > > > vma = find_vma(mm, addr); > > > - if (TASK_SIZE - len >= addr && > > > + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && > > > (!vma || addr + len <= vma->vm_start)) > > > return addr; > > > } > > > > > > info.flags = VM_UNMAPPED_AREA_TOPDOWN; > > > info.length = len; > > > - info.low_limit = PAGE_SIZE; > > > + info.low_limit = max(PAGE_SIZE, mmap_min_addr); > > > info.high_limit = mm->mmap_base; > > > info.align_mask = 0; > > > addr = vm_unmapped_area(&info); > > > -- > > > 1.7.0.4 > > > > > > > > > -- > > > Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > > > > > > -- > > > To unsubscribe, send a message with 'unsubscribe linux-mm' in > > > the body to majordomo@kvack.org. For more info on Linux MM, > > > see: http://www.linux-mm.org/ . > > > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> > > > > > -- > Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > > -- > To unsubscribe, send a message with 'unsubscribe linux-mm' in > the body to majordomo@kvack.org. For more info on Linux MM, > see: http://www.linux-mm.org/ . > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> > -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] mm: Ensure get_unmapped_area() returns higheraddressthan mmap_min_addr 2013-10-23 6:50 ` [PATCH] mm: Ensure get_unmapped_area() returns higheraddressthan mmap_min_addr Naoya Horiguchi @ 2013-10-23 7:39 ` Akira Takeuchi 2013-10-23 7:44 ` [PATCH v2] mm: Ensure get_unmapped_area() returns higher address than mmap_min_addr Akira Takeuchi 1 sibling, 0 replies; 7+ messages in thread From: Akira Takeuchi @ 2013-10-23 7:39 UTC (permalink / raw) To: Naoya Horiguchi; +Cc: linux-mm, linux-kernel On Wed, 23 Oct 2013 02:50:49 -0400 Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> wrote: > On Wed, Oct 23, 2013 at 02:53:03PM +0900, Akira Takeuchi wrote: > > Hi, > > > > On Wed, 23 Oct 2013 00:26:05 -0400 > > Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> wrote: > > > > > Hi, > > > > > > On Wed, Oct 23, 2013 at 11:46:53AM +0900, Akira Takeuchi wrote: > > > > This patch fixes the problem that get_unmapped_area() can return illegal > > > > address and result in failing mmap(2) etc. > > > > > > > > In case that the address higher than PAGE_SIZE is set to > > > > /proc/sys/vm/mmap_min_addr, the address lower than mmap_min_addr can be > > > > returned by get_unmapped_area(), even if you do not pass any virtual > > > > address hint (i.e. the second argument). > > > > > > > > This is because the current get_unmapped_area() code does not take into > > > > account mmap_min_addr. > > > > > > > > This leads to two actual problems as follows: > > > > > > > > 1. mmap(2) can fail with EPERM on the process without CAP_SYS_RAWIO, > > > > although any illegal parameter is not passed. > > > > > > > > 2. The bottom-up search path after the top-down search might not work in > > > > arch_get_unmapped_area_topdown(). > > > > > > > > [How to reproduce] > > > > > > > > --- test.c ------------------------------------------------- > > > > #include <stdio.h> > > > > #include <unistd.h> > > > > #include <sys/mman.h> > > > > #include <sys/errno.h> > > > > > > > > int main(int argc, char *argv[]) > > > > { > > > > void *ret = NULL, *last_map; > > > > size_t pagesize = sysconf(_SC_PAGESIZE); > > > > > > > > do { > > > > last_map = ret; > > > > ret = mmap(0, pagesize, PROT_NONE, > > > > MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); > > > > // printf("ret=%p\n", ret); > > > > } while (ret != MAP_FAILED); > > > > > > > > if (errno != ENOMEM) { > > > > printf("ERR: unexpected errno: %d (last map=%p)\n", > > > > errno, last_map); > > > > } > > > > > > > > return 0; > > > > } > > > > --------------------------------------------------------------- > > > > > > > > $ gcc -m32 -o test test.c > > > > $ sudo sysctl -w vm.mmap_min_addr=65536 > > > > vm.mmap_min_addr = 65536 > > > > $ ./test (run as non-priviledge user) > > > > ERR: unexpected errno: 1 (last map=0x10000) > > > > > > > > Signed-off-by: Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > > > > Signed-off-by: Kiyoshi Owada <owada.kiyoshi@jp.panasonic.com> > > > > --- > > > > mm/mmap.c | 10 +++++----- > > > > 1 files changed, 5 insertions(+), 5 deletions(-) > > > > > > > > diff --git a/mm/mmap.c b/mm/mmap.c > > > > index 9d54851..362e5f1 100644 > > > > --- a/mm/mmap.c > > > > +++ b/mm/mmap.c > > > > @@ -1856,7 +1856,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, > > > > struct vm_area_struct *vma; > > > > struct vm_unmapped_area_info info; > > > > > > > > - if (len > TASK_SIZE) > > > > + if (len > TASK_SIZE - mmap_min_addr) > > > > return -ENOMEM; > > > > > > > > if (flags & MAP_FIXED) > > > > > > I feel that it looks clearer to fix this in round_hint_to_min(), > > > with doing mmap_min_addr check in hint == NULL case. > > > Does it work for you? > > > > The current round_hint_to_min() code checks and adjusts just for > > the hint address, not for "len". Also, it returns no error. > > > > Do you mean adding "len" to the argument of round_hint_to_min() > > and making round_hint_to_min() return any error ? > > I thought of just removing (hint != NULL) check in round_hint_to_min(), > but in my rethinking I found that that affects other code and needs > more changes, so your approach is simpler. I drop my suggestion. > > The above check is to detect too big request, and in your reproducer > len is small (4096), so I'm a bit confused :) > Although it doesn't fix your problem itself, it's correct, I'll add a description as a "Note" to my v2 patch to avoid such confusing. The difference between v1 and v2 patch is only adding the "Note". Thank you for reviewing ! Regadrs, Akira Takeuchi > Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> > > Thanks, > Naoya Horiguchi > > > > > Regards, > > Akira Takeuchi > > > > > Thanks, > > > Naoya Horiguchi > > > > > > > @@ -1865,7 +1865,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, > > > > if (addr) { > > > > addr = PAGE_ALIGN(addr); > > > > vma = find_vma(mm, addr); > > > > - if (TASK_SIZE - len >= addr && > > > > + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && > > > > (!vma || addr + len <= vma->vm_start)) > > > > return addr; > > > > } > > > > @@ -1895,7 +1895,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, > > > > struct vm_unmapped_area_info info; > > > > > > > > /* requested length too big for entire address space */ > > > > - if (len > TASK_SIZE) > > > > + if (len > TASK_SIZE - mmap_min_addr) > > > > return -ENOMEM; > > > > > > > > if (flags & MAP_FIXED) > > > > @@ -1905,14 +1905,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, > > > > if (addr) { > > > > addr = PAGE_ALIGN(addr); > > > > vma = find_vma(mm, addr); > > > > - if (TASK_SIZE - len >= addr && > > > > + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && > > > > (!vma || addr + len <= vma->vm_start)) > > > > return addr; > > > > } > > > > > > > > info.flags = VM_UNMAPPED_AREA_TOPDOWN; > > > > info.length = len; > > > > - info.low_limit = PAGE_SIZE; > > > > + info.low_limit = max(PAGE_SIZE, mmap_min_addr); > > > > info.high_limit = mm->mmap_base; > > > > info.align_mask = 0; > > > > addr = vm_unmapped_area(&info); > > > > -- > > > > 1.7.0.4 > > > > > > > > > > > > -- > > > > Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > > > > > > > > -- > > > > To unsubscribe, send a message with 'unsubscribe linux-mm' in > > > > the body to majordomo@kvack.org. For more info on Linux MM, > > > > see: http://www.linux-mm.org/ . > > > > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> > > > > > > > > -- > > Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > > > > -- > > To unsubscribe, send a message with 'unsubscribe linux-mm' in > > the body to majordomo@kvack.org. For more info on Linux MM, > > see: http://www.linux-mm.org/ . > > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> > > -- Akira Takeuchi <takeuchi.akr@jp.panasonic.com> -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2] mm: Ensure get_unmapped_area() returns higher address than mmap_min_addr 2013-10-23 6:50 ` [PATCH] mm: Ensure get_unmapped_area() returns higheraddressthan mmap_min_addr Naoya Horiguchi 2013-10-23 7:39 ` Akira Takeuchi @ 2013-10-23 7:44 ` Akira Takeuchi 2013-10-23 18:30 ` [PATCH v2] mm: Ensure get_unmapped_area() returns higher addressthan mmap_min_addr Naoya Horiguchi 1 sibling, 1 reply; 7+ messages in thread From: Akira Takeuchi @ 2013-10-23 7:44 UTC (permalink / raw) To: linux-mm; +Cc: linux-kernel This patch fixes the problem that get_unmapped_area() can return illegal address and result in failing mmap(2) etc. In case that the address higher than PAGE_SIZE is set to /proc/sys/vm/mmap_min_addr, the address lower than mmap_min_addr can be returned by get_unmapped_area(), even if you do not pass any virtual address hint (i.e. the second argument). This is because the current get_unmapped_area() code does not take into account mmap_min_addr. This leads to two actual problems as follows: 1. mmap(2) can fail with EPERM on the process without CAP_SYS_RAWIO, although any illegal parameter is not passed. 2. The bottom-up search path after the top-down search might not work in arch_get_unmapped_area_topdown(). Note: The first and third chunk of my patch, which changes "len" check, are for more precise check using mmap_min_addr, and not for solving the above problem. [How to reproduce] --- test.c ------------------------------------------------- #include <stdio.h> #include <unistd.h> #include <sys/mman.h> #include <sys/errno.h> int main(int argc, char *argv[]) { void *ret = NULL, *last_map; size_t pagesize = sysconf(_SC_PAGESIZE); do { last_map = ret; ret = mmap(0, pagesize, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); // printf("ret=%p\n", ret); } while (ret != MAP_FAILED); if (errno != ENOMEM) { printf("ERR: unexpected errno: %d (last map=%p)\n", errno, last_map); } return 0; } --------------------------------------------------------------- $ gcc -m32 -o test test.c $ sudo sysctl -w vm.mmap_min_addr=65536 vm.mmap_min_addr = 65536 $ ./test (run as non-priviledge user) ERR: unexpected errno: 1 (last map=0x10000) Signed-off-by: Akira Takeuchi <takeuchi.akr@jp.panasonic.com> Signed-off-by: Kiyoshi Owada <owada.kiyoshi@jp.panasonic.com> Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> --- mm/mmap.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mm/mmap.c b/mm/mmap.c index 9d54851..362e5f1 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1856,7 +1856,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, struct vm_area_struct *vma; struct vm_unmapped_area_info info; - if (len > TASK_SIZE) + if (len > TASK_SIZE - mmap_min_addr) return -ENOMEM; if (flags & MAP_FIXED) @@ -1865,7 +1865,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && (!vma || addr + len <= vma->vm_start)) return addr; } @@ -1895,7 +1895,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, struct vm_unmapped_area_info info; /* requested length too big for entire address space */ - if (len > TASK_SIZE) + if (len > TASK_SIZE - mmap_min_addr) return -ENOMEM; if (flags & MAP_FIXED) @@ -1905,14 +1905,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && (!vma || addr + len <= vma->vm_start)) return addr; } info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.length = len; - info.low_limit = PAGE_SIZE; + info.low_limit = max(PAGE_SIZE, mmap_min_addr); info.high_limit = mm->mmap_base; info.align_mask = 0; addr = vm_unmapped_area(&info); -- 1.7.0.4 -- Akira Takeuchi <takeuchi.akr@jp.panasonic.com> -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2] mm: Ensure get_unmapped_area() returns higher addressthan mmap_min_addr 2013-10-23 7:44 ` [PATCH v2] mm: Ensure get_unmapped_area() returns higher address than mmap_min_addr Akira Takeuchi @ 2013-10-23 18:30 ` Naoya Horiguchi 0 siblings, 0 replies; 7+ messages in thread From: Naoya Horiguchi @ 2013-10-23 18:30 UTC (permalink / raw) To: Akira Takeuchi; +Cc: linux-mm, linux-kernel, Andrew Morton Cc:ed Andrew, On Wed, Oct 23, 2013 at 04:44:47PM +0900, Akira Takeuchi wrote: > This patch fixes the problem that get_unmapped_area() can return illegal > address and result in failing mmap(2) etc. > > In case that the address higher than PAGE_SIZE is set to > /proc/sys/vm/mmap_min_addr, the address lower than mmap_min_addr can be > returned by get_unmapped_area(), even if you do not pass any virtual address > hint (i.e. the second argument). > > This is because the current get_unmapped_area() code does not take into > account mmap_min_addr. > > This leads to two actual problems as follows: > > 1. mmap(2) can fail with EPERM on the process without CAP_SYS_RAWIO, > although any illegal parameter is not passed. > > 2. The bottom-up search path after the top-down search might not work in > arch_get_unmapped_area_topdown(). > > Note: The first and third chunk of my patch, which changes "len" check, > are for more precise check using mmap_min_addr, and not for solving the > above problem. > > [How to reproduce] > > --- test.c ------------------------------------------------- > #include <stdio.h> > #include <unistd.h> > #include <sys/mman.h> > #include <sys/errno.h> > > int main(int argc, char *argv[]) > { > void *ret = NULL, *last_map; > size_t pagesize = sysconf(_SC_PAGESIZE); > > do { > last_map = ret; > ret = mmap(0, pagesize, PROT_NONE, > MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); > // printf("ret=%p\n", ret); > } while (ret != MAP_FAILED); > > if (errno != ENOMEM) { > printf("ERR: unexpected errno: %d (last map=%p)\n", > errno, last_map); > } > > return 0; > } > --------------------------------------------------------------- > > $ gcc -m32 -o test test.c > $ sudo sysctl -w vm.mmap_min_addr=65536 > vm.mmap_min_addr = 65536 > $ ./test (run as non-priviledge user) > ERR: unexpected errno: 1 (last map=0x10000) > > Signed-off-by: Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > Signed-off-by: Kiyoshi Owada <owada.kiyoshi@jp.panasonic.com> > Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> BTW, this bug seems to be very old, so I think this patch is worth going into all of currently living stable trees. Thanks, Naoya Horiguchi > --- > mm/mmap.c | 10 +++++----- > 1 files changed, 5 insertions(+), 5 deletions(-) > > diff --git a/mm/mmap.c b/mm/mmap.c > index 9d54851..362e5f1 100644 > --- a/mm/mmap.c > +++ b/mm/mmap.c > @@ -1856,7 +1856,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, > struct vm_area_struct *vma; > struct vm_unmapped_area_info info; > > - if (len > TASK_SIZE) > + if (len > TASK_SIZE - mmap_min_addr) > return -ENOMEM; > > if (flags & MAP_FIXED) > @@ -1865,7 +1865,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, > if (addr) { > addr = PAGE_ALIGN(addr); > vma = find_vma(mm, addr); > - if (TASK_SIZE - len >= addr && > + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && > (!vma || addr + len <= vma->vm_start)) > return addr; > } > @@ -1895,7 +1895,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, > struct vm_unmapped_area_info info; > > /* requested length too big for entire address space */ > - if (len > TASK_SIZE) > + if (len > TASK_SIZE - mmap_min_addr) > return -ENOMEM; > > if (flags & MAP_FIXED) > @@ -1905,14 +1905,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, > if (addr) { > addr = PAGE_ALIGN(addr); > vma = find_vma(mm, addr); > - if (TASK_SIZE - len >= addr && > + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && > (!vma || addr + len <= vma->vm_start)) > return addr; > } > > info.flags = VM_UNMAPPED_AREA_TOPDOWN; > info.length = len; > - info.low_limit = PAGE_SIZE; > + info.low_limit = max(PAGE_SIZE, mmap_min_addr); > info.high_limit = mm->mmap_base; > info.align_mask = 0; > addr = vm_unmapped_area(&info); > -- > 1.7.0.4 > > > -- > Akira Takeuchi <takeuchi.akr@jp.panasonic.com> > > -- > To unsubscribe, send a message with 'unsubscribe linux-mm' in > the body to majordomo@kvack.org. For more info on Linux MM, > see: http://www.linux-mm.org/ . > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> > -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2013-10-23 18:30 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2013-10-23 2:46 [PATCH] mm: Ensure get_unmapped_area() returns higher address than mmap_min_addr Akira Takeuchi 2013-10-23 4:26 ` [PATCH] mm: Ensure get_unmapped_area() returns higher addressthan mmap_min_addr Naoya Horiguchi 2013-10-23 5:53 ` Akira Takeuchi 2013-10-23 6:50 ` [PATCH] mm: Ensure get_unmapped_area() returns higheraddressthan mmap_min_addr Naoya Horiguchi 2013-10-23 7:39 ` Akira Takeuchi 2013-10-23 7:44 ` [PATCH v2] mm: Ensure get_unmapped_area() returns higher address than mmap_min_addr Akira Takeuchi 2013-10-23 18:30 ` [PATCH v2] mm: Ensure get_unmapped_area() returns higher addressthan mmap_min_addr Naoya Horiguchi
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).