8183262: noexecstack check in os::dll_load on Linux is too expensive

Convert ElfFile::specifies_noexecstack() to static method which read file header and check executable stack flag.

Reviewed-by: iklam, stuefe
This commit is contained in:
Vladimir Kozlov 2017-07-05 11:03:19 -07:00
parent 907093af23
commit eb20e62194
4 changed files with 39 additions and 24 deletions

View file

@ -1639,8 +1639,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
//
// See Linux man page execstack(8) for more info.
if (os::uses_stack_guard_pages() && !os::Linux::_stack_is_executable) {
ElfFile ef(filename);
if (!ef.specifies_noexecstack()) {
if (!ElfFile::specifies_noexecstack(filename)) {
if (!is_init_completed()) {
os::Linux::_stack_is_executable = true;
// This is OK - No Java threads have been created yet, and hence no

View file

@ -29,6 +29,7 @@
#include "oops/method.hpp"
#include "prims/jvm.h"
#include "runtime/os.hpp"
#include "runtime/timerTrace.hpp"
GrowableArray<AOTCodeHeap*>* AOTLoader::_heaps = new(ResourceObj::C_HEAP, mtCode) GrowableArray<AOTCodeHeap*> (2, true);
GrowableArray<AOTLib*>* AOTLoader::_libraries = new(ResourceObj::C_HEAP, mtCode) GrowableArray<AOTLib*> (2, true);
@ -112,6 +113,8 @@ static const char* modules[] = {
};
void AOTLoader::initialize() {
TraceTime timer("AOT initialization", TRACETIME_LOG(Info, aot, startuptime));
if (FLAG_IS_DEFAULT(UseAOT) && AOTLibrary != NULL) {
// Don't need to set UseAOT on command line when AOTLibrary is specified
FLAG_SET_DEFAULT(UseAOT, true);

View file

@ -242,32 +242,45 @@ ElfStringTable* ElfFile::get_string_table(int index) {
}
#ifdef LINUX
bool ElfFile::specifies_noexecstack() {
Elf_Phdr phdr;
if (!m_file) return true;
bool ElfFile::specifies_noexecstack(const char* filepath) {
// Returns true if the elf file is marked NOT to require an executable stack,
// or if the file could not be opened.
// Returns false if the elf file requires an executable stack, the stack flag
// is not set at all, or if the file can not be read.
if (filepath == NULL) return true;
if (!fseek(m_file, m_elfHdr.e_phoff, SEEK_SET)) {
for (int index = 0; index < m_elfHdr.e_phnum; index ++) {
if (fread((void*)&phdr, sizeof(Elf_Phdr), 1, m_file) != 1) {
m_status = NullDecoder::file_invalid;
return false;
FILE* file = fopen(filepath, "r");
if (file == NULL) return true;
// AARCH64 defaults to noexecstack. All others default to execstack.
#ifdef AARCH64
bool result = true;
#else
bool result = false;
#endif
// Read file header
Elf_Ehdr head;
if (fread(&head, sizeof(Elf_Ehdr), 1, file) == 1 &&
is_elf_file(head) &&
fseek(file, head.e_phoff, SEEK_SET) == 0) {
// Read program header table
Elf_Phdr phdr;
for (int index = 0; index < head.e_phnum; index ++) {
if (fread((void*)&phdr, sizeof(Elf_Phdr), 1, file) != 1) {
result = false;
break;
}
if (phdr.p_type == PT_GNU_STACK) {
if (phdr.p_flags == (PF_R | PF_W)) {
return true;
} else {
return false;
}
result = (phdr.p_flags == (PF_R | PF_W));
break;
}
}
}
// AARCH64 defaults to noexecstack. All others default to execstack.
#ifdef AARCH64
return true;
#else
return false;
#endif
fclose(file);
return result;
}
#endif
#endif // LINUX
#endif // !_WINDOWS && !__APPLE__

View file

@ -108,7 +108,7 @@ class ElfFile: public CHeapObj<mtInternal> {
private:
// sanity check, if the file is a real elf file
bool is_elf_file(Elf_Ehdr&);
static bool is_elf_file(Elf_Ehdr&);
// load string tables from the elf file
bool load_tables();
@ -132,7 +132,7 @@ protected:
// Returns false if the elf file requires an executable stack, the stack flag
// is not set at all, or if the file can not be read.
// On systems other than linux it always returns false.
bool specifies_noexecstack() NOT_LINUX({ return false; });
static bool specifies_noexecstack(const char* filepath) NOT_LINUX({ return false; });
protected:
ElfFile* m_next;