Changeset View
Standalone View
libexec/rtld-elf/map_object.c
Show First 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | goto error; | ||||
base_addr = (caddr_t) base_vaddr; | base_addr = (caddr_t) base_vaddr; | ||||
base_flags = __getosreldate() >= P_OSREL_MAP_GUARD ? MAP_GUARD : | base_flags = __getosreldate() >= P_OSREL_MAP_GUARD ? MAP_GUARD : | ||||
MAP_PRIVATE | MAP_ANON | MAP_NOCORE; | MAP_PRIVATE | MAP_ANON | MAP_NOCORE; | ||||
if (npagesizes > 1 && round_page(segs[0]->p_filesz) >= pagesizes[1]) | if (npagesizes > 1 && round_page(segs[0]->p_filesz) >= pagesizes[1]) | ||||
base_flags |= MAP_ALIGNED_SUPER; | base_flags |= MAP_ALIGNED_SUPER; | ||||
if (base_vaddr != 0) | if (base_vaddr != 0) | ||||
base_flags |= MAP_FIXED | MAP_EXCL; | base_flags |= MAP_FIXED | MAP_EXCL; | ||||
mapbase = mmap(base_addr, mapsize, PROT_NONE, base_flags, -1, 0); | mapbase = mmap(base_addr, mapsize, PROT_NONE | PROT_MAX(PROT_ALL), | ||||
kib: This is MAP_GUARD mapping, why do you need to specify PROT_MAX for it ? | |||||
kibUnsubmitted Not Done Inline ActionsSo why ? kib: So why ? | |||||
base_flags, -1, 0); | |||||
if (mapbase == (caddr_t) -1) { | if (mapbase == (caddr_t) -1) { | ||||
_rtld_error("%s: mmap of entire address space failed: %s", | _rtld_error("%s: mmap of entire address space failed: %s", | ||||
path, rtld_strerror(errno)); | path, rtld_strerror(errno)); | ||||
goto error; | goto error; | ||||
} | } | ||||
if (base_addr != NULL && mapbase != base_addr) { | if (base_addr != NULL && mapbase != base_addr) { | ||||
_rtld_error("%s: mmap returned wrong address: wanted %p, got %p", | _rtld_error("%s: mmap returned wrong address: wanted %p, got %p", | ||||
path, base_addr, mapbase); | path, base_addr, mapbase); | ||||
goto error1; | goto error1; | ||||
} | } | ||||
for (i = 0; i <= nsegs; i++) { | for (i = 0; i <= nsegs; i++) { | ||||
/* Overlay the segment onto the proper region. */ | /* Overlay the segment onto the proper region. */ | ||||
data_offset = trunc_page(segs[i]->p_offset); | data_offset = trunc_page(segs[i]->p_offset); | ||||
data_vaddr = trunc_page(segs[i]->p_vaddr); | data_vaddr = trunc_page(segs[i]->p_vaddr); | ||||
data_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_filesz); | data_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_filesz); | ||||
data_addr = mapbase + (data_vaddr - base_vaddr); | data_addr = mapbase + (data_vaddr - base_vaddr); | ||||
data_prot = convert_prot(segs[i]->p_flags); | data_prot = convert_prot(segs[i]->p_flags); | ||||
data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED; | data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED; | ||||
if (mmap(data_addr, data_vlimit - data_vaddr, data_prot, | if (mmap(data_addr, data_vlimit - data_vaddr, data_prot, | ||||
data_flags | MAP_PREFAULT_READ, fd, data_offset) == (caddr_t) -1) { | data_flags | MAP_PREFAULT_READ, fd, data_offset) == (caddr_t) -1) { | ||||
kibUnsubmitted Not Done Inline ActionsSo the executable segment mappings get maxprot PROT_READ | PROT_EXEC. Do breakpoint work with your change ? kib: So the executable segment mappings get maxprot PROT_READ | PROT_EXEC. Do breakpoint work with… | |||||
markjUnsubmitted Not Done Inline ActionsI can't see how it can work as-is. proc_rwmem() uses a copy-on-read fault to map a private copy of the page, and then modifies that page directly, but vm_map_lookup() requires maxprot VM_PROT_WRITE for this operation. markj: I can't see how it can work as-is. proc_rwmem() uses a copy-on-read fault to map a private copy… | |||||
markjUnsubmitted Not Done Inline ActionsSorry for the noise, I missed that the restriction applies only to shared mappings. markj: Sorry for the noise, I missed that the restriction applies only to shared mappings. | |||||
kibUnsubmitted Not Done Inline ActionsWhere do you see it ? If it is, I do not understand the reasoning. For 'attacker', the private rwx memory is as good as shared one. kib: Where do you see it ? If it is, I do not understand the reasoning. For 'attacker', the… | |||||
markjUnsubmitted Not Done Inline ActionsIn vm_map_lookup(): 4122 if ((fault_typea & VM_PROT_COPY) != 0 && 4123 (entry->max_protection & VM_PROT_WRITE) == 0 && 4124 (entry->eflags & MAP_ENTRY_COW) == 0) { 4125 vm_map_unlock_read(map); 4126 return (KERN_PROTECTION_FAILURE); 4127 } To make use of proc_rwmem(), an attacker would need to perform the modification from a separate process AFAIK. markj: In vm_map_lookup():
```
4122 if ((fault_typea & VM_PROT_COPY) != 0 &&… | |||||
kibUnsubmitted Not Done Inline ActionsNo, there is something mixed in the responses. My initial concern, still not refuted, is that breakpoints do not work with this patch, exactly due to the fragment in the vm_map_lookup(_entry) which you pointed out. I do not care about a way to subvert this feature, I only want to discuss breakpoints ATM. kib: No, there is something mixed in the responses. My initial concern, still not refuted, is that… | |||||
markjUnsubmitted Not Done Inline ActionsSegments mapped by rtld are private, so the corresponding map entries will have MAP_ENTRY_COW set, so the fragment I pointed out should have no effect. I tried the patch and was able to set breakpoints on libc symbols. markj: Segments mapped by rtld are private, so the corresponding map entries will have MAP_ENTRY_COW… | |||||
brooksAuthorUnsubmitted Done Inline ActionsWe're able to set breakpoints on mips64. I've not tested x86. brooks: We're able to set breakpoints on mips64. I've not tested x86. | |||||
_rtld_error("%s: mmap of data failed: %s", path, | _rtld_error("%s: mmap of data failed: %s", path, | ||||
rtld_strerror(errno)); | rtld_strerror(errno)); | ||||
goto error1; | goto error1; | ||||
} | } | ||||
/* Do BSS setup */ | /* Do BSS setup */ | ||||
if (segs[i]->p_filesz != segs[i]->p_memsz) { | if (segs[i]->p_filesz != segs[i]->p_memsz) { | ||||
▲ Show 20 Lines • Show All 244 Lines • Show Last 20 Lines |
This is MAP_GUARD mapping, why do you need to specify PROT_MAX for it ?