linux kernel 2.6.25.15 (intel e1000) untangle the do_mremap() mess

2010-02-17 / 2010-02-18
Credit: Al Viro
Risk: Low
Local: Yes
Remote: No
CWE: CWE-264


CVSS Base Score: 4.6/10
Impact Subscore: 6.4/10
Exploitability Subscore: 3.9/10
Exploit range: Local
Attack complexity: Low
Authentication: No required
Confidentiality impact: Partial
Integrity impact: Partial
Availability impact: Partial

[NOTE: the patch series below is not for merge until ACKed by arch maintainers] We have a bunch of interesting problems with mmap/mremap. 1) MREMAP_FIXED allows remap to any location, regardless of what the architecture has to say about it. The only check is TASK_SIZE. That's not enough - e.g. there are architectures where some ranges are simply absent (itanic, sparc), there are some that have cache coherency requirements on alignments of shared mapping (a lot - anything with VIPT cache, itanic where it's not a coherency but a performance issue). There are architectures where specific ranges are reserved for hugetlb and they either simply do not allow normal mappings in there or need to do something to make them possible (as ppc64 does). sparc tried to deal with that problem, but it hadn't been complete (alignment issues) and it had been actually wrong for non-MREMAP_FIXED calls of mremap(). 2) without MREMAP_FIXED we happily allowed extension into a hole in address space - the only check for being able to extend without move had been for TASK_SIZE (and for non-overlap with other vmas). Victims: sparc, itanic due to extending into holes, powerpc due to extending into hugetlb range. 3) in case of relocation without MREMAP_FIXED we ended up doing get_unmapped_area() with wrong pgoff if the starting address had been in the middle of a mapping. New vma gets the right pgoff, the checks are done for the wrong one. Cache coherency issues on all VIPT architectures. 4) mmap() with MAP_HUGETLB leaks struct file if it bails out anywhere past the allocation of struct file (by do_mmap_pgoff()) 5) brk() into a hugetlb range failed without trying to do anything; known thing, ppc folks had been unhappy about that. Series below should deal with those, mostly by switching to consistent use of get_unmapped_area() and sanitizing mmap/mremap code in general. There is one case where we still have a serious PITA and I'm not sure how to deal with that; it's expand_stack(). We can trigger that by creating a VM_GROWS{UP,DOWN} mapping and either hitting a pagefault on address {below,above} it or doing PTRACE_POKEDATA on such address. As it is, we only check that range we are expanding into is not a hugetlb-only one. The thing is, we *can't* just do the normal checks as-is there. For cases when we do expand_stack() for our own mm that would work just fine and do the right thing. Unfortunately, we have places that hit it from get_user_pages() for another process. And checks (starting with "what's the maximal address we allow") are process-dependent on biarch architectures. Worse yet, execve() does that when we have no other process - it creates new mm, puts an anonymous mapping as high as possible in it and copies argv/envp in there. And that's done with get_user_pages() on new mm. If we have a 32bit task on e.g. amd64, we'll have that mapping at addresses far above the TASK_SIZE of caller. Later, when ->load_binary() figures out what personality we'll get, it turns that mapping into a valid vma for stack, possibly relocating the entire thing to address suitable for resulting process. Breaking execve() from 32bit processes on biarch architectures would be a bad thing, so we can't just add the normal set of checks to expand_stack() (acct_stack_growth(), actually). The problem is quite real, though, since e.g. on itanic PTRACE_POKEDATA can be used to get a vma hanging down into a gap in address space quite easily. Results are not pretty... One way to deal with that would be to put enough information into mm_struct so that all these checks wouldn't have to look at the caller's personality. I'm not sure how much PITA would that be, though; I've been digging through the arch/* VM code for several weeks by now, but I certainly don't pretend to be able to spot e.g. performance implications of such change.

References:

http://www.kernel.org/pub/linux/kernel/v2.6/ChangeLog-2.6.32.4
https://bugzilla.redhat.com/show_bug.cgi?id=556703
http://marc.info/?l=oss-security&m=126406814304720&w=2
http://marc.info/?l=oss-security&m=126400443123998&w=2
http://marc.info/?l=oss-security&m=126399980216047&w=2
http://marc.info/?l=oss-security&m=126396609004884&w=2
http://marc.info/?l=oss-security&m=126396065732697&w=2
http://marc.info/?l=oss-security&m=126395874130875&w=2
http://marc.info/?l=oss-security&m=126393370931972&w=2
http://marc.info/?l=oss-security&m=126388181420690&w=2
http://marc.info/?l=linux-arch&m=126004438008670&w=2
http://groups.google.com/group/linux.kernel/msg/895f20870532241e
http://groups.google.co.jp/group/fa.linux.kernel/browse_thread/thread/8bf22336b1082090
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=f8b7256096a20436f6d0926747e3ac3d64c81d24
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=f106af4e90eadd76cfc0b5325f659619e08fb762
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=ecc1a8993751de4e82eb18640d631dae1f626bd6
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=e77414e0aad6a1b063ba5e5750c582c75327ea6a
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=c4caa778157dbbf04116f0ac2111e389b5cd7a29
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=bb52d6694002b9d632bb355f64daa045c6293a4e
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=aa65607373a4daf2010e8c3867b6317619f3c1a3
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=935874141df839c706cd6cdc438e85eb69d1525e
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=9206de95b1ea68357996ec02be5db0638a0de2c1
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=8c7b49b3ecd48923eb64ff57e07a1cdb74782970
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=570dcf2c15463842e384eb597a87c1e39bead99b
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=564b3bffc619dcbdd160de597b0547a7017ea010
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=54f5de709984bae0d31d823ff03de755f9dcac54
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=2ea1d13f64efdf49319e86c87d9ba38c30902782
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=2c6a10161d0b5fc047b5bd81b03693b9af99fab5
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=1a0ef85f84feb13f07b604fcf5b90ef7c2b5c82f
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=0ec62d290912bb4b989be7563851bc364ec73b56
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=097eed103862f9c6a97f2e415e21d1134017b135
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=05d72faa6d13c9d857478a5d35c85db9adada685
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=0067bd8a55862ac9dd212bd1c4f6f5bff1ca1301


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2024, cxsecurity.com

 

Back to Top