-
Notifications
You must be signed in to change notification settings - Fork 914
Protect patching with an open handle #1264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 18 commits
a210c87
295b14e
165cd18
4fc704a
547a727
4bda095
46d7a25
5fb3a15
9897f7e
08e8e05
1c5c9ae
0c74ccf
003224b
4a10fe5
5abfd2f
5c6a2c9
e6ce338
5653968
03d8f79
ef47cb2
b2b8b68
cc0b9d9
efae089
1feaf12
19a552c
dbb4d67
79d93a0
108598c
85d2ebb
964d025
aa02f9e
842e2da
92944da
a38d144
683825d
c2e56c8
3dd17e6
646cbf7
5378fcf
b479c11
2c69485
d837bc9
20f5f81
79da179
457d59a
fa529c8
15eeade
d58c662
cda6051
a6b3804
bc30666
bc19fc3
15da753
14a8a55
8de5e01
8f57df7
1edc7f6
4e5fb57
5cff23d
50ead5b
0eacfab
7cdfa80
b310dba
fa729eb
c17d592
94dd779
7d4cb93
45e9622
b5d4e19
5e10cdd
70c3800
4542d1d
2abe2aa
8974647
dcd97c7
1d049c5
7a1895a
7e575b4
6f3e498
42879e3
2e1c15b
a5c24b0
7e0a452
703950b
1e83770
ff43185
b220a20
a7103d0
4d5645f
873ce86
ffdeb52
01fc8eb
017ff0d
30364f0
9ae2c0f
7acb726
d93698b
00ac27e
41d89d1
9191dc2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,12 +29,14 @@ size_t NativeFunc::usedMemory(const char* name) { | |
|
||
|
||
CodeCache::CodeCache(const char* name, short lib_index, bool imports_patchable, | ||
const void* min_address, const void* max_address) { | ||
const void* min_address, const void* max_address, | ||
const char* image_base) { | ||
_name = NativeFunc::create(name, -1); | ||
_lib_index = lib_index; | ||
_min_address = min_address; | ||
_max_address = max_address; | ||
_text_base = NULL; | ||
_image_base = image_base; | ||
|
||
_plt_offset = 0; | ||
_plt_size = 0; | ||
|
@@ -311,3 +313,16 @@ size_t CodeCache::usedMemory() { | |
} | ||
return bytes; | ||
} | ||
|
||
bool CodeCache::isValidHandle(void* handle) const { | ||
#ifdef __linux__ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CodeCache is just a data structure, it's not good to have platform-dependent code here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
struct link_map* map; | ||
// validate that the current loaded library is the same library that was observed during the /proc/self/maps processing | ||
if (handle != NULL && dlinfo(handle, RTLD_DI_LINKMAP, &map) == 0) { | ||
return _image_base == (const char*)map->l_addr; | ||
} | ||
return false; | ||
#else | ||
return handle != NULL; | ||
#endif | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,11 @@ | |
#define _CODECACHE_H | ||
|
||
#include <jvmti.h> | ||
#include <dlfcn.h> | ||
fandreuz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#ifdef __linux__ | ||
#include <link.h> | ||
#endif | ||
|
||
|
||
#define NO_MIN_ADDRESS ((const void*)-1) | ||
|
@@ -107,6 +112,8 @@ class CodeCache { | |
const void* _min_address; | ||
const void* _max_address; | ||
const char* _text_base; | ||
// TODO: Cleanup usages of lib.image_base | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this leftover? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is something we should do, but could pollute this PR. Basically there are some cases where we pass both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
const char* _image_base; | ||
|
||
unsigned int _plt_offset; | ||
unsigned int _plt_size; | ||
|
@@ -131,7 +138,8 @@ class CodeCache { | |
short lib_index = -1, | ||
bool imports_patchable = false, | ||
const void* min_address = NO_MIN_ADDRESS, | ||
const void* max_address = NO_MAX_ADDRESS); | ||
const void* max_address = NO_MAX_ADDRESS, | ||
const char* image_base = NULL); | ||
|
||
~CodeCache(); | ||
|
||
|
@@ -147,6 +155,10 @@ class CodeCache { | |
return _max_address; | ||
} | ||
|
||
const char* imageBase() const { | ||
return _image_base; | ||
} | ||
|
||
bool contains(const void* address) const { | ||
return address >= _min_address && address < _max_address; | ||
} | ||
|
@@ -201,6 +213,8 @@ class CodeCache { | |
void setDwarfTable(FrameDesc* table, int length); | ||
FrameDesc* findFrameDesc(const void* pc); | ||
|
||
bool isValidHandle(void* handle) const; | ||
|
||
size_t usedMemory(); | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,13 +8,24 @@ | |
|
||
#include "codeCache.h" | ||
#include "mutex.h" | ||
#include <dlfcn.h> | ||
|
||
|
||
class Symbols { | ||
private: | ||
static Mutex _parse_lock; | ||
static bool _have_kernel_symbols; | ||
static bool _libs_limit_reported; | ||
static const void* _main_phdr; | ||
static const char* _ld_base; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those are Linux-specific and not part of Symbols public interface. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
static bool isMainExecutable(const char* image_base, const void* map_end) { | ||
return _main_phdr != NULL && _main_phdr >= image_base && _main_phdr < map_end; | ||
} | ||
|
||
static bool isLoader(const char* image_base) { | ||
return _ld_base != NULL && _ld_base == image_base; | ||
} | ||
|
||
public: | ||
static void parseKernelSymbols(CodeCache* cc); | ||
|
@@ -23,6 +34,32 @@ class Symbols { | |
static bool haveKernelSymbols() { | ||
return _have_kernel_symbols; | ||
} | ||
|
||
static bool isSafeToPatch(CodeCache* cc, void **handle_ptr) { | ||
fandreuz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*handle_ptr = NULL; | ||
|
||
if (isMainExecutable(cc->imageBase(), cc->maxAddress()) || isLoader(cc->imageBase())) { | ||
return true; | ||
} | ||
|
||
// Protect library from unloading while parsing in-memory ELF program headers. | ||
// Also, dlopen() ensures the library is fully loaded. | ||
*handle_ptr = dlopen(cc->name(), RTLD_LAZY | RTLD_NOLOAD); | ||
if (cc->isValidHandle(*handle_ptr)) { | ||
// Up to the user to dlclose the handle | ||
return true; | ||
} | ||
|
||
if (*handle_ptr != NULL) { | ||
dlclose(*handle_ptr); | ||
*handle_ptr = NULL; | ||
} | ||
return false; | ||
} | ||
|
||
Symbols(); | ||
fandreuz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
static Symbols symbols; | ||
fandreuz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#endif // _SYMBOLS_H |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is only called from the
UnloadProtection
I think it makes sense to move this function implementation into that class as a private method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this rather belongs to
CodeCache
, it's just a check against a private field ofCodeCache
. Also, it's called in theUnloadProtection
ctor, thus the object is not fully constructed when we need itThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could eliminate this inversion by introducing a factory method:
Then,
cc
is free to access its private fields before constructing theUnloadProtection
.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was exactly the previous implementation, before I got this comment.
See 5378fcf
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this assignment?
UnloadProtection handle(cc)
is simpler.I'd say that checking
dlopen
handle inCodeCache
looks unnatural. Keep in mind thatCodeCache
is an abstraction that is not necessarily related to a loaded library (e.g. CodeCache for JVM runtime stubs or CodeCache for kernel symbols).Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
20f5f81