diff --git a/README.md b/README.md index dcfc798..65710ed 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ CPU/GPU Performance control library for benchmarking on Linux, x86, POWER, and N - [x] Flush addresses from cache (amd64, POWER) - [x] CUDA not required (GPU functions will not be compiled) - [x] Flush file system caches (linux) +- [x] Disable ASLR (linux) ## Contributors * [Carl Pearson](https://cwpearson.github.io) @@ -85,6 +86,20 @@ See [examples/gpu_monitor.cu](examples/gpu_monitor.cu) * `void Monitor::pause()`: pause the monitor thread * `void Monitor::resume()`: resume the monitor thread +### Disable ASLR + +`perfect` can disable ASLR + +See [tools/no_aslr.cpp](tools/no_aslr.cpp) + +```c++ +#include "perfect/aslr.hpp" +``` + +* `Result disable_aslr()`: disable ASLR +* `Result get_aslr(AslrState &state)`: save the current ASLR state +* `Result set_aslr(const AslrState &state)`: set a previously-saved ASLR state + ### Flush file system caches `perfect` can drop various filesystem caches @@ -192,7 +207,6 @@ See [examples/cpu_cache.cpp](examples/cpu_cache.cpp). - [ ] only monitor certain GPUs - [ ] hyperthreading interface -- [ ] ASLR interface - [ ] process priority interface - [ ] A wrapper utility - [ ] disable hyperthreading diff --git a/include/perfect/aslr.hpp b/include/perfect/aslr.hpp new file mode 100644 index 0000000..ced4201 --- /dev/null +++ b/include/perfect/aslr.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +#ifdef __linux__ +#include "detail/os/linux.hpp" +#endif +#include "init.hpp" +#include "result.hpp" + +namespace perfect { + +struct AslrState { +#ifdef __linux__ + unsigned long persona; +#else +#error "unsupported platform" +#endif +}; + +Result get_aslr(AslrState &state) { + int persona; + PERFECT_SUCCESS_OR_RETURN(detail::get_personality(persona)); + state.persona = persona; + return Result::SUCCESS; +} + +Result set_aslr(const AslrState &state) { + return detail::set_personality(state.persona); +} + +Result disable_aslr() { + int persona; + PERFECT_SUCCESS_OR_RETURN(detail::get_personality(persona)); + persona |= ADDR_NO_RANDOMIZE; + return detail::set_personality(persona); +} + +} // namespace perfect \ No newline at end of file diff --git a/include/perfect/detail/os/linux.hpp b/include/perfect/detail/os/linux.hpp index 63b66d3..2b6f0b4 100644 --- a/include/perfect/detail/os/linux.hpp +++ b/include/perfect/detail/os/linux.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "perfect/result.hpp" @@ -88,4 +89,24 @@ size_t cache_linesize() { #endif } +namespace detail { +Result get_personality(int &persona) { + int ret = personality(0xffffffff); + if (-1 == ret) { + return Result::UNKNOWN; + } else { + persona = ret; + } + return Result::SUCCESS; +} + +Result set_personality(const int persona) { + int ret = personality(persona); + if (-1 == ret) { + return Result::UNKNOWN; + } + return Result::SUCCESS; +} +} + } // namespace perfect \ No newline at end of file diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 86b5b3f..c2a4984 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -38,4 +38,7 @@ add_executable(enable-turbo enable_turbo.cpp) target_link_libraries(enable-turbo perfect) add_executable(sync-drop-caches sync_drop_caches.cpp) -target_link_libraries(sync-drop-caches perfect) \ No newline at end of file +target_link_libraries(sync-drop-caches perfect) + +add_executable(no-aslr no_aslr.cpp) +target_link_libraries(no-aslr perfect) \ No newline at end of file diff --git a/tools/no_aslr.cpp b/tools/no_aslr.cpp new file mode 100644 index 0000000..d7ce0b5 --- /dev/null +++ b/tools/no_aslr.cpp @@ -0,0 +1,77 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "perfect/aslr.hpp" + +using namespace perfect; + +int main(int argc, char **argv) { + + using namespace perfect; + + PERFECT(init()); + + pid_t pid; + int status; + pid = fork(); + if (pid == -1) { + // pid == -1 means error occured + std::cerr << "can't fork, error occured\n"; + exit(EXIT_FAILURE); + } else if (pid == 0) { + // in the child process + + // skip the first argument, which is this program + std::vector args; + for (int i = 1; i < argc; ++i) { + args.push_back(argv[i]); + } + assert(args.size() > 0); + args.push_back(nullptr); + + PERFECT(disable_aslr()); + + // the execv() only return if error occured. + // The return value is -1 + return execvp(args[0], args.data()); + } else { + // parent process + + if (waitpid(pid, &status, 0) > 0) { + + if (WIFEXITED(status) && !WEXITSTATUS(status)) { + // success + exit(status); + } + + else if (WIFEXITED(status) && WEXITSTATUS(status)) { + if (WEXITSTATUS(status) == 127) { + + // execv failed + std::cerr << "execv failed\n"; + exit(status); + } else { + std::cerr << "program terminated normally, but returned a non-zero status\n"; + exit(status); + } + } else { + printf("program didn't terminate normally\n"); + exit(status); + } + } else { + // waitpid() failed + printf("waitpid() failed\n"); + exit(EXIT_FAILURE); + } + exit(0); + } + return 0; +}