diff --git a/headers/private/kernel/vm/vm.h b/headers/private/kernel/vm/vm.h index bd9fd16aa8..1962f418a2 100644 --- a/headers/private/kernel/vm/vm.h +++ b/headers/private/kernel/vm/vm.h @@ -121,6 +121,8 @@ status_t vm_delete_area(team_id teamID, area_id areaID, bool kernel); status_t vm_create_vnode_cache(struct vnode *vnode, struct VMCache **_cache); status_t vm_set_area_memory_type(area_id id, phys_addr_t physicalBase, uint32 type); +status_t vm_set_area_protection(team_id team, area_id areaID, + uint32 newProtection, bool kernel); status_t vm_get_page_mapping(team_id team, addr_t vaddr, phys_addr_t *paddr); bool vm_test_map_modification(struct vm_page *page); void vm_clear_map_flags(struct vm_page *page, uint32 flags); diff --git a/src/system/kernel/elf.cpp b/src/system/kernel/elf.cpp index d937d8aad7..4d18448ad6 100644 --- a/src/system/kernel/elf.cpp +++ b/src/system/kernel/elf.cpp @@ -1827,6 +1827,7 @@ elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry) int i; addr_t delta = 0; uint32 addressSpec = B_RANDOMIZED_BASE_ADDRESS; + area_id* mappedAreas = NULL; TRACE(("elf_load: entry path '%s', team %p\n", path, team)); @@ -1906,7 +1907,14 @@ elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry) strcpy(baseName, leaf); } - // map the program's segments into memory + // map the program's segments into memory, initially with rw access + // correct area protection will be set after relocation + + mappedAreas = (area_id*)malloc(sizeof(area_id) * elfHeader.e_phnum); + if (mappedAreas == NULL) { + status = B_NO_MEMORY; + goto error2; + } image_info imageInfo; memset(&imageInfo, 0, sizeof(image_info)); @@ -1917,6 +1925,8 @@ elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry) char *originalRegionAddress; area_id id; + mappedAreas[i] = -1; + if (programHeaders[i].p_type == PT_DYNAMIC) { image->dynamic_section = programHeaders[i].p_vaddr; continue; @@ -1950,6 +1960,7 @@ elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry) status = B_NOT_AN_EXECUTABLE; goto error2; } + mappedAreas[i] = id; imageInfo.data = regionAddress; imageInfo.data_size = memUpperBound; @@ -1998,14 +2009,16 @@ elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry) id = vm_map_file(team->id, regionName, (void **)®ionAddress, addressSpec, segmentSize, - B_READ_AREA | B_EXECUTE_AREA | B_WRITE_AREA, REGION_PRIVATE_MAP, - false, fd, ROUNDDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); + B_READ_AREA | B_WRITE_AREA, REGION_PRIVATE_MAP, false, fd, + ROUNDDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); if (id < B_OK) { dprintf("error mapping file text: %s!\n", strerror(id)); status = B_NOT_AN_EXECUTABLE; goto error2; } + mappedAreas[i] = id; + imageInfo.text = regionAddress; imageInfo.text_size = segmentSize; @@ -2033,6 +2046,26 @@ elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry) if (status != B_OK) goto error2; + // set correct area protection + for (i = 0; i < elfHeader.e_phnum; i++) { + if (mappedAreas[i] == -1) + continue; + + uint32 protection = 0; + + if (programHeaders[i].p_flags & PF_EXECUTE) + protection |= B_EXECUTE_AREA; + if (programHeaders[i].p_flags & PF_WRITE) + protection |= B_WRITE_AREA; + if (programHeaders[i].p_flags & PF_READ) + protection |= B_READ_AREA; + + status = vm_set_area_protection(team->id, mappedAreas[i], protection, + true); + if (status != B_OK) + goto error2; + } + // register the loaded image imageInfo.type = B_LIBRARY_IMAGE; imageInfo.device = st.st_dev; @@ -2056,6 +2089,8 @@ elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry) status = B_OK; error2: + free(mappedAreas); + image->elf_header = NULL; delete_elf_image(image); diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 175704f809..f5aa4e2184 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -274,6 +274,7 @@ static status_t map_backing_store(VMAddressSpace* addressSpace, int protection, int mapping, uint32 flags, const virtual_address_restrictions* addressRestrictions, bool kernel, VMArea** _area, void** _virtualAddress); +static void fix_protection(uint32* protection); // #pragma mark - @@ -2527,10 +2528,12 @@ vm_copy_area(team_id team, const char* name, void** _address, } -static status_t +status_t vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection, bool kernel) { + fix_protection(&newProtection); + TRACE(("vm_set_area_protection(team = %#" B_PRIx32 ", area = %#" B_PRIx32 ", protection = %#" B_PRIx32 ")\n", team, areaID, newProtection)); @@ -5808,8 +5811,6 @@ _get_next_area_info(team_id team, ssize_t* cookie, area_info* info, size_t size) status_t set_area_protection(area_id area, uint32 newProtection) { - fix_protection(&newProtection); - return vm_set_area_protection(VMAddressSpace::KernelID(), area, newProtection, true); } @@ -6037,8 +6038,6 @@ _user_set_area_protection(area_id area, uint32 newProtection) if ((newProtection & ~B_USER_PROTECTION) != 0) return B_BAD_VALUE; - fix_protection(&newProtection); - return vm_set_area_protection(VMAddressSpace::CurrentID(), area, newProtection, false); }