mirror of
https://review.haiku-os.org/haiku
synced 2025-01-18 12:38:51 +01:00
runtime_loader: Actually respect PF_EXECUTE program header.
If it's not set (and we aren't on pre-Haiku GCC2 ABI), then don't make the region executable. This mostly only makes a difference for Clang/LLD-linked binaries that have a readable, non-writable, non-executable program segment. GCC/LD-linked binaries just have all read-only data in the main read+execute section by default.
This commit is contained in:
parent
e0101fa39b
commit
e38be9392a
@ -120,6 +120,17 @@ parse_program_headers(image_t* image, char* buff, int phnum, int phentsize)
|
||||
/* NOP header */
|
||||
break;
|
||||
case PT_LOAD:
|
||||
{
|
||||
uint32 flags = 0;
|
||||
if (pheader->p_flags & PF_WRITE) {
|
||||
// this is a writable segment
|
||||
flags |= RFLAG_WRITABLE;
|
||||
}
|
||||
if (pheader->p_flags & PF_EXECUTE) {
|
||||
// this is an executable segment
|
||||
flags |= RFLAG_EXECUTABLE;
|
||||
}
|
||||
|
||||
if (pheader->p_memsz == pheader->p_filesz) {
|
||||
/*
|
||||
* everything in one area
|
||||
@ -134,11 +145,7 @@ parse_program_headers(image_t* image, char* buff, int phnum, int phentsize)
|
||||
image->regions[regcount].fdstart = pheader->p_offset;
|
||||
image->regions[regcount].fdsize = pheader->p_filesz;
|
||||
image->regions[regcount].delta = 0;
|
||||
image->regions[regcount].flags = 0;
|
||||
if (pheader->p_flags & PF_WRITE) {
|
||||
// this is a writable segment
|
||||
image->regions[regcount].flags |= RFLAG_RW;
|
||||
}
|
||||
image->regions[regcount].flags = flags;
|
||||
} else {
|
||||
/*
|
||||
* may require splitting
|
||||
@ -158,11 +165,7 @@ parse_program_headers(image_t* image, char* buff, int phnum, int phentsize)
|
||||
image->regions[regcount].fdstart = pheader->p_offset;
|
||||
image->regions[regcount].fdsize = pheader->p_filesz;
|
||||
image->regions[regcount].delta = 0;
|
||||
image->regions[regcount].flags = 0;
|
||||
if (pheader->p_flags & PF_WRITE) {
|
||||
// this is a writable segment
|
||||
image->regions[regcount].flags |= RFLAG_RW;
|
||||
}
|
||||
image->regions[regcount].flags = flags;
|
||||
|
||||
if (A != B) {
|
||||
/*
|
||||
@ -182,15 +185,12 @@ parse_program_headers(image_t* image, char* buff, int phnum, int phentsize)
|
||||
image->regions[regcount].fdstart = 0;
|
||||
image->regions[regcount].fdsize = 0;
|
||||
image->regions[regcount].delta = 0;
|
||||
image->regions[regcount].flags = RFLAG_ANON;
|
||||
if (pheader->p_flags & PF_WRITE) {
|
||||
// this is a writable segment
|
||||
image->regions[regcount].flags |= RFLAG_RW;
|
||||
}
|
||||
image->regions[regcount].flags = flags | RFLAG_ANON;
|
||||
}
|
||||
}
|
||||
regcount += 1;
|
||||
break;
|
||||
}
|
||||
case PT_DYNAMIC:
|
||||
image->dynamic_ptr = pheader->p_vaddr;
|
||||
break;
|
||||
|
@ -348,9 +348,10 @@ map_image(int fd, char const* path, image_t* image, bool fixed)
|
||||
|
||||
for (uint32 i = 0; i < image->num_regions; i++) {
|
||||
char regionName[B_OS_NAME_LENGTH];
|
||||
|
||||
snprintf(regionName, sizeof(regionName), "%s_seg%" B_PRIu32 "%s",
|
||||
baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
|
||||
baseName, i, (image->regions[i].flags & RFLAG_EXECUTABLE) ?
|
||||
((image->regions[i].flags & RFLAG_WRITABLE) ? "rwx" : "rx")
|
||||
: (image->regions[i].flags & RFLAG_WRITABLE) ? "rw" : "ro");
|
||||
|
||||
get_image_region_load_address(image, i,
|
||||
i > 0 ? image->regions[i - 1].delta : 0, fixed, loadAddress,
|
||||
@ -380,7 +381,7 @@ map_image(int fd, char const* path, image_t* image, bool fixed)
|
||||
// of memory to be committed for them temporarily, just because we
|
||||
// have to write map them.
|
||||
uint32 protection = B_READ_AREA | B_WRITE_AREA
|
||||
| ((image->regions[i].flags & RFLAG_RW) != 0
|
||||
| ((image->regions[i].flags & RFLAG_WRITABLE) != 0
|
||||
? 0 : B_OVERCOMMITTING_AREA);
|
||||
image->regions[i].id = _kern_map_file(regionName,
|
||||
(void**)&loadAddress, B_EXACT_ADDRESS,
|
||||
@ -394,10 +395,10 @@ map_image(int fd, char const* path, image_t* image, bool fixed)
|
||||
|
||||
TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
|
||||
(void *)loadAddress, image->regions[i].vmsize,
|
||||
image->regions[i].flags & RFLAG_RW ? "rw" : "read-only"));
|
||||
image->regions[i].flags & RFLAG_WRITABLE ? "rw" : "read-only"));
|
||||
|
||||
// handle trailer bits in data segment
|
||||
if (image->regions[i].flags & RFLAG_RW) {
|
||||
if (image->regions[i].flags & RFLAG_WRITABLE) {
|
||||
addr_t startClearing = loadAddress
|
||||
+ PAGE_OFFSET(image->regions[i].start)
|
||||
+ image->regions[i].size;
|
||||
@ -437,11 +438,11 @@ unmap_image(image_t* image)
|
||||
}
|
||||
|
||||
|
||||
/*! This function will change the protection of all read-only segments to really
|
||||
be read-only (and executable).
|
||||
/*! This function will change the protection of all segments to what they're
|
||||
supposed to be.
|
||||
|
||||
The areas have to be read/write first, so that they can be relocated.
|
||||
If at least one image is in compatibility mode then we allow execution of
|
||||
If at least one image is in compatibility mode then we allow write/execute of
|
||||
all areas.
|
||||
*/
|
||||
void
|
||||
@ -455,9 +456,15 @@ remap_images()
|
||||
if ((region.flags & RFLAG_REMAPPED) != 0)
|
||||
continue;
|
||||
|
||||
uint32 protection = B_READ_AREA | B_EXECUTE_AREA;
|
||||
if ((region.flags & RFLAG_RW) != 0 || image->abi < B_HAIKU_ABI_GCC_2_HAIKU)
|
||||
uint32 protection = B_READ_AREA;
|
||||
if (image->abi < B_HAIKU_ABI_GCC_2_HAIKU) {
|
||||
protection |= B_WRITE_AREA | B_EXECUTE_AREA;
|
||||
} else {
|
||||
if ((region.flags & RFLAG_WRITABLE) != 0)
|
||||
protection |= B_WRITE_AREA;
|
||||
if ((region.flags & RFLAG_EXECUTABLE) != 0)
|
||||
protection |= B_EXECUTE_AREA;
|
||||
}
|
||||
|
||||
status_t result = _kern_set_area_protection(region.id, protection);
|
||||
if (result == B_OK)
|
||||
@ -498,7 +505,7 @@ register_image(image_t* image, int fd, const char* path)
|
||||
for (uint32 i= 0; i < image->num_regions; i++) {
|
||||
addr_t base = image->regions[i].vmstart;
|
||||
addr_t end = base + image->regions[i].vmsize;
|
||||
if (image->regions[i].flags & RFLAG_RW) {
|
||||
if (image->regions[i].flags & RFLAG_WRITABLE) {
|
||||
// data
|
||||
if (dataBase == 0) {
|
||||
dataBase = base;
|
||||
|
@ -16,8 +16,9 @@
|
||||
enum {
|
||||
// the lower two bits are reserved for RTLD_NOW and RTLD_GLOBAL
|
||||
|
||||
RFLAG_RW = 0x0010,
|
||||
RFLAG_ANON = 0x0020,
|
||||
RFLAG_WRITABLE = 0x0010,
|
||||
RFLAG_EXECUTABLE = 0x0020,
|
||||
RFLAG_ANON = 0x0040,
|
||||
|
||||
RFLAG_TERMINATED = 0x0200,
|
||||
RFLAG_INITIALIZED = 0x0400,
|
||||
|
Loading…
Reference in New Issue
Block a user