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. Reference: https://lkml.org/lkml/2010/12/9/222 http://seclists.org/oss-sec/2010/q4/307 Acknowledgements: Red Hat would like to thank Tavis Ormandy for reporting this issue.
Statement: The Linux kernel as shipped with Red Hat Enterprise Linux 4 is not vulnerable because it checks for mmap_min_addr even in special cases. The Linux kernel as shipped with Red Hat Enterprise Linux 5, 6, and Red Hat Enterprise MRG have mmap_min_addr sysctl tunable set to 4096, and therefore are not affected by this issue. However, as a preventive measure (for example, for administrators who have increased mmap_min_addr), we have addressed this in Red Hat Enterprise Linux 5, 6 and MRG via https://rhn.redhat.com/errata/RHSA-2011-0429.html, https://rhn.redhat.com/errata/RHSA-2011-0421.html, and https://rhn.redhat.com/errata/RHSA-2011-0330.html.
Created attachment 468055 [details] Patch proposed by Tavis Ormandi
Created attachment 468057 [details] RHEL5'ish patch proposed by Solar Designer
(In reply to comment #2) > The Linux kernel as shipped with Red Hat Enterprise Linux 5, 6, and Red Hat > Enterprise MRG have mmap_min_addr sysctl tunable set to 4096, and therefore are > not affected by this issue. I think this is a misunderstanding. Your setting of mmap_min_addr to 4096 is precisely what makes you vulnerable to the fullest extent: the attack demonstrated by Tavis allows to map a page at exactly one page below mmap_min_addr, and you only have exactly one page - so it should get mapped at 0 (NULL). Isn't this what happens when you try Tavis' PoC program on a clean RHEL 5 or 6 system? I must admit I have not tried. There might be something that prevents this from happening, but no one has mentioned such a thing so far (or have I missed it?)
(In reply to comment #6) > (In reply to comment #2) > > The Linux kernel as shipped with Red Hat Enterprise Linux 5, 6, and Red Hat > > Enterprise MRG have mmap_min_addr sysctl tunable set to 4096, and therefore are > > not affected by this issue. > > I think this is a misunderstanding. Your setting of mmap_min_addr to 4096 is > precisely what makes you vulnerable to the fullest extent: the attack > demonstrated by Tavis allows to map a page at exactly one page below > mmap_min_addr, and you only have exactly one page - so it should get mapped at > 0 (NULL). Isn't this what happens when you try Tavis' PoC program on a clean > RHEL 5 or 6 system? I must admit I have not tried. There might be something > that prevents this from happening, but no one has mentioned such a thing so far > (or have I missed it?) Update: The following seems to be true for RHEL6. On both systems vm.overcommit_memory=1 might be needed. On my testing RHEL5 system vdso keeps to be mapped to 0xffffe000 which looks like COMPAT_VDSO. Either way I was not able to use intstall_special_mapping() to map anything to address 0 on RHEL. -- This is what I was thinking first as well and tried to make the vdso getting mapped to address 0. I tested it on a a 2.6.35 upstream kernel, but on RHEL it's the same (32bit program on x86-64, on 32bit it's similar): cynique@gentoo64 ~ $ cat /proc/2588/maps 00001000-00002000 r-xp 00001000 03:03 230335 /home/cynique/nada 00002000-ffff2000 rwxp 00000000 00:00 0 [stack] ffff2000-ffff3000 r-xp 00000000 00:00 0 [vdso] cynique@gentoo64 ~ $ nasm -D__NR_pause=29 -DBSS_SIZE=0xffffc000 -f elf -o nada.o nada.s cynique@gentoo64 ~ $ ld -m elf_i386 -Ttext=0x1000 -Tbss=0x2000 -o nada nada.o cynique@gentoo64 ~ $ ./nada Killed cynique@gentoo64 ~ $ breakpoint 4, arch_get_unmapped_area_topdown (filp=0x0, addr0=0x0, len=0x1000, pgoff=0x0, flags=0x0) at arch/x86/kernel/sys_x86_64.c:192 192 } while (len < vma->vm_start); gdb> p len $23 = 0x1000 gdb> p vma->vm_start $24 = 0x1000 gdb> The problem AFAIK is in the while condition: the len is 0x1000 because we are looking for one page and the next vma->vm_start is 0x1000 as that is a vma with /home/cynique/nada. The condition (len < vma->vm_start) effectively skips the free page. After the "} while (len <= vma->vm_start);" patch cynique@gentoo64 ~ $ nasm -D__NR_pause=29 -DBSS_SIZE=0xffffc000 -f elf -o nada.o nada.s cynique@gentoo64 ~ $ ld -m elf_i386 -Ttext=0x1000 -Tbss=0x2000 -o nada nada.o cynique@gentoo64 ~ $ ./nada & [1] 2555 cynique@gentoo64 ~ $ cat /proc/2555/maps 00000000-00001000 r-xp 00000000 00:00 0 [vdso] 00001000-00002000 r-xp 00001000 03:03 230335 /home/cynique/nada 00002000-ffffe000 rwxp 00000000 00:00 0 [stack] cynique@gentoo64 ~ $ cat /proc/sys/vm/mmap_min_addr 4096 cynique@gentoo64 ~ $
Upstream commit 462e635e5b73ba9a4c03913b77138cd57ce4b050 http://git.kernel.org/linus/462e635e5b73ba9a4c03913b77138cd57ce4b050
This issue has been addressed in following products: MRG for RHEL-5 Via RHSA-2011:0330 https://rhn.redhat.com/errata/RHSA-2011-0330.html
This issue has been addressed in following products: Red Hat Enterprise Linux 6 Via RHSA-2011:0421 https://rhn.redhat.com/errata/RHSA-2011-0421.html
This issue has been addressed in following products: Red Hat Enterprise Linux 5 Via RHSA-2011:0429 https://rhn.redhat.com/errata/RHSA-2011-0429.html