Merge "Implement load at fixed address feature"
This commit is contained in:
commit
5238eb0984
|
@ -80,6 +80,24 @@ enum {
|
||||||
*/
|
*/
|
||||||
ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80,
|
ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80,
|
||||||
|
|
||||||
|
/* Instructs dlopen to load the library at the address specified by reserved_addr.
|
||||||
|
*
|
||||||
|
* The difference between ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS and ANDROID_DLEXT_RESERVED_ADDRESS
|
||||||
|
* is that for ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS the linker reserves memory at reserved_addr
|
||||||
|
* whereas for ANDROID_DLEXT_RESERVED_ADDRESS the linker relies on the caller to reserve the memory.
|
||||||
|
*
|
||||||
|
* This flag can be used with ANDROID_DLEXT_FORCE_FIXED_VADDR; when ANDROID_DLEXT_FORCE_FIXED_VADDR
|
||||||
|
* is set and load_bias is not 0 (load_bias is min(p_vaddr) of PT_LOAD segments) this flag is ignored.
|
||||||
|
* This is implemented this way because the linker has to pick one address over the other and this
|
||||||
|
* way is more convenient for art. Note that ANDROID_DLEXT_FORCE_FIXED_VADDR does not generate
|
||||||
|
* an error when min(p_vaddr) is 0.
|
||||||
|
*
|
||||||
|
* Cannot be used with ANDROID_DLEXT_RESERVED_ADDRESS or ANDROID_DLEXT_RESERVED_ADDRESS_HINT.
|
||||||
|
*
|
||||||
|
* This flag is for ART internal use only.
|
||||||
|
*/
|
||||||
|
ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS = 0x100,
|
||||||
|
|
||||||
/* Mask of valid bits */
|
/* Mask of valid bits */
|
||||||
ANDROID_DLEXT_VALID_FLAG_BITS = ANDROID_DLEXT_RESERVED_ADDRESS |
|
ANDROID_DLEXT_VALID_FLAG_BITS = ANDROID_DLEXT_RESERVED_ADDRESS |
|
||||||
ANDROID_DLEXT_RESERVED_ADDRESS_HINT |
|
ANDROID_DLEXT_RESERVED_ADDRESS_HINT |
|
||||||
|
@ -88,7 +106,8 @@ enum {
|
||||||
ANDROID_DLEXT_USE_LIBRARY_FD |
|
ANDROID_DLEXT_USE_LIBRARY_FD |
|
||||||
ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
|
ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
|
||||||
ANDROID_DLEXT_FORCE_LOAD |
|
ANDROID_DLEXT_FORCE_LOAD |
|
||||||
ANDROID_DLEXT_FORCE_FIXED_VADDR,
|
ANDROID_DLEXT_FORCE_FIXED_VADDR |
|
||||||
|
ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -1995,12 +1995,20 @@ soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
|
||||||
DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
|
DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
|
if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
|
||||||
(extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
|
(extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
|
||||||
DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
|
DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
|
||||||
"ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
|
"ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
|
||||||
|
(extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
|
||||||
|
DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
|
||||||
|
"compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtectedDataGuard guard;
|
ProtectedDataGuard guard;
|
||||||
|
|
|
@ -386,8 +386,9 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
|
||||||
void* start;
|
void* start;
|
||||||
size_t reserved_size = 0;
|
size_t reserved_size = 0;
|
||||||
bool reserved_hint = true;
|
bool reserved_hint = true;
|
||||||
|
bool strict_hint = false;
|
||||||
// Assume position independent executable by default.
|
// Assume position independent executable by default.
|
||||||
uint8_t* mmap_hint = nullptr;
|
void* mmap_hint = nullptr;
|
||||||
|
|
||||||
if (extinfo != nullptr) {
|
if (extinfo != nullptr) {
|
||||||
if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
|
if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
|
||||||
|
@ -397,8 +398,11 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
|
||||||
reserved_size = extinfo->reserved_size;
|
reserved_size = extinfo->reserved_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((extinfo->flags & ANDROID_DLEXT_FORCE_FIXED_VADDR) != 0) {
|
if (addr != nullptr && (extinfo->flags & ANDROID_DLEXT_FORCE_FIXED_VADDR) != 0) {
|
||||||
mmap_hint = addr;
|
mmap_hint = addr;
|
||||||
|
} else if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0) {
|
||||||
|
mmap_hint = extinfo->reserved_addr;
|
||||||
|
strict_hint = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,6 +418,12 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
|
||||||
DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_.c_str());
|
DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (strict_hint && (start != mmap_hint)) {
|
||||||
|
munmap(start, load_size_);
|
||||||
|
DL_ERR("couldn't reserve %zd bytes of address space at %p for \"%s\"",
|
||||||
|
load_size_, mmap_hint, name_.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
start = extinfo->reserved_addr;
|
start = extinfo->reserved_addr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -343,6 +343,43 @@ TEST_F(DlExtTest, ReservedHintTooSmall) {
|
||||||
EXPECT_EQ(4, f());
|
EXPECT_EQ(4, f());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DlExtTest, LoadAtFixedAddress) {
|
||||||
|
void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||||
|
-1, 0);
|
||||||
|
ASSERT_TRUE(start != MAP_FAILED);
|
||||||
|
munmap(start, LIBSIZE);
|
||||||
|
|
||||||
|
android_dlextinfo extinfo;
|
||||||
|
extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
|
||||||
|
extinfo.reserved_addr = start;
|
||||||
|
|
||||||
|
handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
|
||||||
|
ASSERT_DL_NOTNULL(handle_);
|
||||||
|
fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
|
||||||
|
ASSERT_DL_NOTNULL(f);
|
||||||
|
EXPECT_GE(reinterpret_cast<void*>(f), start);
|
||||||
|
EXPECT_LT(reinterpret_cast<void*>(f), reinterpret_cast<char*>(start) + LIBSIZE);
|
||||||
|
|
||||||
|
EXPECT_EQ(4, f());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DlExtTest, LoadAtFixedAddressTooSmall) {
|
||||||
|
void* start = mmap(nullptr, LIBSIZE + PAGE_SIZE, PROT_NONE,
|
||||||
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
ASSERT_TRUE(start != MAP_FAILED);
|
||||||
|
munmap(start, LIBSIZE + PAGE_SIZE);
|
||||||
|
void* new_addr = mmap(reinterpret_cast<uint8_t*>(start) + PAGE_SIZE, LIBSIZE, PROT_NONE,
|
||||||
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
ASSERT_TRUE(new_addr != MAP_FAILED);
|
||||||
|
|
||||||
|
android_dlextinfo extinfo;
|
||||||
|
extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
|
||||||
|
extinfo.reserved_addr = start;
|
||||||
|
|
||||||
|
handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
|
||||||
|
ASSERT_TRUE(handle_ == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
class DlExtRelroSharingTest : public DlExtTest {
|
class DlExtRelroSharingTest : public DlExtTest {
|
||||||
protected:
|
protected:
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
|
|
Loading…
Reference in New Issue