Message ID | 1299680752-8768-1-git-send-email-sconklin@canonical.com |
---|---|
State | New |
Headers | show |
On 03/09/2011 03:25 PM, Steve Conklin wrote: > From: Tavis Ormandy <taviso@cmpxchg8b.com> > > BugLink: http://bugs.launchpad.net/bugs/731971 > > CVE-2010-4346 > > The install_special_mapping routine (used, for example, to setup the > vdso) skips the security check before insert_vm_struct, allowing a local > attacker to bypass the mmap_min_addr security restriction by limiting > the available pages for special mappings. > > bprm_mm_init() also skips the check, and although I don't think this can > be used to bypass any restrictions, I don't see any reason not to have > the security check. > > $ uname -m > x86_64 > $ cat /proc/sys/vm/mmap_min_addr > 65536 > $ cat install_special_mapping.s > section .bss > resb BSS_SIZE > section .text > global _start > _start: > mov eax, __NR_pause > int 0x80 > $ nasm -D__NR_pause=29 -DBSS_SIZE=0xfffed000 -f elf -o install_special_mapping.o install_special_mapping.s > $ ld -m elf_i386 -Ttext=0x10000 -Tbss=0x11000 -o install_special_mapping install_special_mapping.o > $ ./install_special_mapping & > [1] 14303 > $ cat /proc/14303/maps > 0000f000-00010000 r-xp 00000000 00:00 0 [vdso] > 00010000-00011000 r-xp 00001000 00:19 2453665 /home/taviso/install_special_mapping > 00011000-ffffe000 rwxp 00000000 00:00 0 [stack] > > It's worth noting that Red Hat are shipping with mmap_min_addr set to > 4096. > > Signed-off-by: Tavis Ormandy <taviso@google.com> > Acked-by: Kees Cook <kees@ubuntu.com> > Acked-by: Robert Swiecki <swiecki@google.com> > [ Changed to not drop the error code - akpm ] > Reviewed-by: James Morris <jmorris@namei.org> > Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> > backported from upstream commit 462e635e5b73ba9a4c03913b77138cd57ce4b050 > Signed-off-by: Steve Conklin <sconklin@canonical.com> Acked-by: Stefan Bader <stefan.bader@canonical.com> > --- > fs/exec.c | 7 +++++++ > mm/mmap.c | 16 ++++++++++++---- > 2 files changed, 19 insertions(+), 4 deletions(-) > > diff --git a/fs/exec.c b/fs/exec.c > index 1bedd94..a13f815 100644 > --- a/fs/exec.c > +++ b/fs/exec.c > @@ -247,6 +247,13 @@ static int __bprm_mm_init(struct linux_binprm *bprm) > vma->vm_start = vma->vm_end - PAGE_SIZE; > vma->vm_flags = VM_STACK_FLAGS; > vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); > + > + INIT_LIST_HEAD(&vma->anon_vma_chain); > + > + err = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); > + if (err) > + goto err; > + > err = insert_vm_struct(mm, vma); > if (err) > goto err; > diff --git a/mm/mmap.c b/mm/mmap.c > index ac9cceb..a53ad79 100644 > --- a/mm/mmap.c > +++ b/mm/mmap.c > @@ -2390,6 +2390,7 @@ int install_special_mapping(struct mm_struct *mm, > unsigned long addr, unsigned long len, > unsigned long vm_flags, struct page **pages) > { > + int ret; > struct vm_area_struct *vma; > > vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); > @@ -2406,16 +2407,23 @@ int install_special_mapping(struct mm_struct *mm, > vma->vm_ops = &special_mapping_vmops; > vma->vm_private_data = pages; > > - if (unlikely(insert_vm_struct(mm, vma))) { > - kmem_cache_free(vm_area_cachep, vma); > - return -ENOMEM; > - } > + ret = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); > + if (ret) > + goto out; > + > + ret = insert_vm_struct(mm, vma); > + if (ret) > + goto out; > > mm->total_vm += len >> PAGE_SHIFT; > > perf_counter_mmap(vma); > > return 0; > + > +out: > + kmem_cache_free(vm_area_cachep, vma); > + return ret; > } > > static DEFINE_MUTEX(mm_all_locks_mutex);
On 03/09/2011 02:25 PM, Steve Conklin wrote: > From: Tavis Ormandy<taviso@cmpxchg8b.com> > > BugLink: http://bugs.launchpad.net/bugs/731971 > > CVE-2010-4346 > > The install_special_mapping routine (used, for example, to setup the > vdso) skips the security check before insert_vm_struct, allowing a local > attacker to bypass the mmap_min_addr security restriction by limiting > the available pages for special mappings. > > bprm_mm_init() also skips the check, and although I don't think this can > be used to bypass any restrictions, I don't see any reason not to have > the security check. > > $ uname -m > x86_64 > $ cat /proc/sys/vm/mmap_min_addr > 65536 > $ cat install_special_mapping.s > section .bss > resb BSS_SIZE > section .text > global _start > _start: > mov eax, __NR_pause > int 0x80 > $ nasm -D__NR_pause=29 -DBSS_SIZE=0xfffed000 -f elf -o install_special_mapping.o install_special_mapping.s > $ ld -m elf_i386 -Ttext=0x10000 -Tbss=0x11000 -o install_special_mapping install_special_mapping.o > $ ./install_special_mapping& > [1] 14303 > $ cat /proc/14303/maps > 0000f000-00010000 r-xp 00000000 00:00 0 [vdso] > 00010000-00011000 r-xp 00001000 00:19 2453665 /home/taviso/install_special_mapping > 00011000-ffffe000 rwxp 00000000 00:00 0 [stack] > > It's worth noting that Red Hat are shipping with mmap_min_addr set to > 4096. > > Signed-off-by: Tavis Ormandy<taviso@google.com> > Acked-by: Kees Cook<kees@ubuntu.com> > Acked-by: Robert Swiecki<swiecki@google.com> > [ Changed to not drop the error code - akpm ] > Reviewed-by: James Morris<jmorris@namei.org> > Signed-off-by: Linus Torvalds<torvalds@linux-foundation.org> > backported from upstream commit 462e635e5b73ba9a4c03913b77138cd57ce4b050 > Signed-off-by: Steve Conklin<sconklin@canonical.com> > --- > fs/exec.c | 7 +++++++ > mm/mmap.c | 16 ++++++++++++---- > 2 files changed, 19 insertions(+), 4 deletions(-) > > diff --git a/fs/exec.c b/fs/exec.c > index 1bedd94..a13f815 100644 > --- a/fs/exec.c > +++ b/fs/exec.c > @@ -247,6 +247,13 @@ static int __bprm_mm_init(struct linux_binprm *bprm) > vma->vm_start = vma->vm_end - PAGE_SIZE; > vma->vm_flags = VM_STACK_FLAGS; > vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); > + > + INIT_LIST_HEAD(&vma->anon_vma_chain); > + > + err = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); > + if (err) > + goto err; > + > err = insert_vm_struct(mm, vma); > if (err) > goto err; > diff --git a/mm/mmap.c b/mm/mmap.c > index ac9cceb..a53ad79 100644 > --- a/mm/mmap.c > +++ b/mm/mmap.c > @@ -2390,6 +2390,7 @@ int install_special_mapping(struct mm_struct *mm, > unsigned long addr, unsigned long len, > unsigned long vm_flags, struct page **pages) > { > + int ret; > struct vm_area_struct *vma; > > vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); > @@ -2406,16 +2407,23 @@ int install_special_mapping(struct mm_struct *mm, > vma->vm_ops =&special_mapping_vmops; > vma->vm_private_data = pages; > > - if (unlikely(insert_vm_struct(mm, vma))) { > - kmem_cache_free(vm_area_cachep, vma); > - return -ENOMEM; > - } > + ret = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); > + if (ret) > + goto out; > + > + ret = insert_vm_struct(mm, vma); > + if (ret) > + goto out; > > mm->total_vm += len>> PAGE_SHIFT; > > perf_counter_mmap(vma); > > return 0; > + > +out: > + kmem_cache_free(vm_area_cachep, vma); > + return ret; > } > > static DEFINE_MUTEX(mm_all_locks_mutex); Acked-by: Brad Figg <brad.figg@canonical.com>
On 03/09/2011 03:25 PM, Steve Conklin wrote: > From: Tavis Ormandy <taviso@cmpxchg8b.com> > > BugLink: http://bugs.launchpad.net/bugs/731971 > > CVE-2010-4346 > > The install_special_mapping routine (used, for example, to setup the > vdso) skips the security check before insert_vm_struct, allowing a local > attacker to bypass the mmap_min_addr security restriction by limiting > the available pages for special mappings. > > bprm_mm_init() also skips the check, and although I don't think this can > be used to bypass any restrictions, I don't see any reason not to have > the security check. > > $ uname -m > x86_64 > $ cat /proc/sys/vm/mmap_min_addr > 65536 > $ cat install_special_mapping.s > section .bss > resb BSS_SIZE > section .text > global _start > _start: > mov eax, __NR_pause > int 0x80 > $ nasm -D__NR_pause=29 -DBSS_SIZE=0xfffed000 -f elf -o install_special_mapping.o install_special_mapping.s > $ ld -m elf_i386 -Ttext=0x10000 -Tbss=0x11000 -o install_special_mapping install_special_mapping.o > $ ./install_special_mapping & > [1] 14303 > $ cat /proc/14303/maps > 0000f000-00010000 r-xp 00000000 00:00 0 [vdso] > 00010000-00011000 r-xp 00001000 00:19 2453665 /home/taviso/install_special_mapping > 00011000-ffffe000 rwxp 00000000 00:00 0 [stack] > > It's worth noting that Red Hat are shipping with mmap_min_addr set to > 4096. > > Signed-off-by: Tavis Ormandy <taviso@google.com> > Acked-by: Kees Cook <kees@ubuntu.com> > Acked-by: Robert Swiecki <swiecki@google.com> > [ Changed to not drop the error code - akpm ] > Reviewed-by: James Morris <jmorris@namei.org> > Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> > backported from upstream commit 462e635e5b73ba9a4c03913b77138cd57ce4b050 > Signed-off-by: Steve Conklin <sconklin@canonical.com> > --- > fs/exec.c | 7 +++++++ > mm/mmap.c | 16 ++++++++++++---- > 2 files changed, 19 insertions(+), 4 deletions(-) > > diff --git a/fs/exec.c b/fs/exec.c > index 1bedd94..a13f815 100644 > --- a/fs/exec.c > +++ b/fs/exec.c > @@ -247,6 +247,13 @@ static int __bprm_mm_init(struct linux_binprm *bprm) > vma->vm_start = vma->vm_end - PAGE_SIZE; > vma->vm_flags = VM_STACK_FLAGS; > vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); > + > + INIT_LIST_HEAD(&vma->anon_vma_chain); I think thats actually wrong > + > + err = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); > + if (err) > + goto err; > + > err = insert_vm_struct(mm, vma); > if (err) > goto err; > diff --git a/mm/mmap.c b/mm/mmap.c > index ac9cceb..a53ad79 100644 > --- a/mm/mmap.c > +++ b/mm/mmap.c > @@ -2390,6 +2390,7 @@ int install_special_mapping(struct mm_struct *mm, > unsigned long addr, unsigned long len, > unsigned long vm_flags, struct page **pages) > { > + int ret; > struct vm_area_struct *vma; > > vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); > @@ -2406,16 +2407,23 @@ int install_special_mapping(struct mm_struct *mm, > vma->vm_ops = &special_mapping_vmops; > vma->vm_private_data = pages; > > - if (unlikely(insert_vm_struct(mm, vma))) { > - kmem_cache_free(vm_area_cachep, vma); > - return -ENOMEM; > - } > + ret = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); > + if (ret) > + goto out; > + > + ret = insert_vm_struct(mm, vma); > + if (ret) > + goto out; > > mm->total_vm += len >> PAGE_SHIFT; > > perf_counter_mmap(vma); > > return 0; > + > +out: > + kmem_cache_free(vm_area_cachep, vma); > + return ret; > } > > static DEFINE_MUTEX(mm_all_locks_mutex);
diff --git a/fs/exec.c b/fs/exec.c index 1bedd94..a13f815 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -247,6 +247,13 @@ static int __bprm_mm_init(struct linux_binprm *bprm) vma->vm_start = vma->vm_end - PAGE_SIZE; vma->vm_flags = VM_STACK_FLAGS; vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + + INIT_LIST_HEAD(&vma->anon_vma_chain); + + err = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); + if (err) + goto err; + err = insert_vm_struct(mm, vma); if (err) goto err; diff --git a/mm/mmap.c b/mm/mmap.c index ac9cceb..a53ad79 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2390,6 +2390,7 @@ int install_special_mapping(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long vm_flags, struct page **pages) { + int ret; struct vm_area_struct *vma; vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); @@ -2406,16 +2407,23 @@ int install_special_mapping(struct mm_struct *mm, vma->vm_ops = &special_mapping_vmops; vma->vm_private_data = pages; - if (unlikely(insert_vm_struct(mm, vma))) { - kmem_cache_free(vm_area_cachep, vma); - return -ENOMEM; - } + ret = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); + if (ret) + goto out; + + ret = insert_vm_struct(mm, vma); + if (ret) + goto out; mm->total_vm += len >> PAGE_SHIFT; perf_counter_mmap(vma); return 0; + +out: + kmem_cache_free(vm_area_cachep, vma); + return ret; } static DEFINE_MUTEX(mm_all_locks_mutex);