diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 01e78409c8bec4c76386e39cfd9f760fde52ef03..37e6a4f67b2d4a4f7b95f8fc536f2dbb4b491e87 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,9 +56,17 @@ unit-test-job: # This job runs in the test stage. image: gekkofs/deps:0.9.4-dev needs: ['build-job'] script: - - ls -ltrh ${INSTALL_PATH} + - ${BUILD_PATH}/opendevnull --syscall open --reps 1 --verbose + - LD_PRELOAD=${BUILD_PATH}/libeval_intercept.so ${BUILD_PATH}/opendevnull --syscall open --reps 1 --verbose - ${BUILD_PATH}/opendevnull --syscall getpid --reps 1 --verbose - LD_PRELOAD=${BUILD_PATH}/libeval_intercept.so ${BUILD_PATH}/opendevnull --syscall getpid --reps 1 --verbose + - LD_PRELOAD=${BUILD_PATH}/libeval_intercept.so ${BUILD_PATH}/opendevnull --syscall getpid --reps 1 --verbose --always_syscall + - ${BUILD_PATH}/opendevnull --syscall kill --reps 1 --verbose + - LD_PRELOAD=${BUILD_PATH}/libeval_intercept.so ${BUILD_PATH}/opendevnull --syscall kill --reps 1 --verbose + - LD_PRELOAD=${BUILD_PATH}/libeval_intercept.so ${BUILD_PATH}/opendevnull --syscall kill --reps 1 --verbose --always_syscall + - ${BUILD_PATH}/opendevnull --syscall getpriority --reps 1 --verbose + - LD_PRELOAD=${BUILD_PATH}/libeval_intercept.so ${BUILD_PATH}/opendevnull --syscall getpriority --reps 1 --verbose + - LD_PRELOAD=${BUILD_PATH}/libeval_intercept.so ${BUILD_PATH}/opendevnull --syscall getpriority --reps 1 --verbose --always_syscall artifacts: expire_in: 1 week when: always diff --git a/CMakeLists.txt b/CMakeLists.txt index db1b3c4f00151b07e7ed38f4b5a0e5cf3efe77b3..d6f9914d0e29433760c077416555d78cd1b29ccd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,8 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH}) message(STATUS "[${PROJECT_NAME}] Checking for syscall_intercept") find_package(Syscall_intercept REQUIRED) +# Print the include directory for debugging +message(STATUS "Syscall_intercept include dir: ${Syscall_intercept_INCLUDE_DIR}") set(INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include") @@ -33,23 +35,20 @@ include_directories( ${INCLUDE_DIR} ${CMAKE_BINARY_DIR}/include /usr/include + ${Syscall_intercept_INCLUDE_DIR} ) +add_library(eval_intercept SHARED src/eval.cpp) +add_executable(opendevnull src/opendevnull.cpp) -add_library(eval_intercept SHARED) -add_executable(opendevnull) -target_sources(eval_intercept - PRIVATE - src/eval.cpp -) -target_sources(opendevnull +# Include path from Syscall_intercept into opendevnull +target_include_directories(opendevnull PRIVATE - src/opendevnull.cpp + ${Syscall_intercept_INCLUDE_DIR} ) -# Include path from Syscall_intercept into opendevnull -target_include_directories(opendevnull +target_include_directories(eval_intercept PRIVATE ${Syscall_intercept_INCLUDE_DIR} ) @@ -75,6 +74,6 @@ install( install( TARGETS opendevnull - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) diff --git a/Readme.md b/Readme.md index 7900f10b6232175023a1cbfae1fec36abeb7efdf..63916e7b7e4a3c0cb953dfa3d8d377f5e7ce17a4 100644 --- a/Readme.md +++ b/Readme.md @@ -31,7 +31,7 @@ The project includes two main components: ### Running opendevnull ```bash -./opendevnull --syscall [options] +./opendevnull --syscall [options] Options: --reps N Number of repetitions (default: 100M) diff --git a/scripts/run.sh b/scripts/run.sh index c314fb76661dede3e70307d68a0d034947100cd3..0d8cedcfb2a01de22c2deacdac8fb4075502cabe 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -1,28 +1,95 @@ -NATIVE="./opendevnull --syscall getpid" -INTERC="./opendevnull --syscall getpid" -SC2SC="./opendevnull --syscall getpid --always_syscall" - +#!/bin/bash +SYSCALL="getpid" +BUILD=../build REPEATS=20 ARCH="X86" +NATIVE="$BUILD/opendevnull --syscall $SYSCALL" +INTERC="$BUILD/opendevnull --syscall $SYSCALL" +SC2SC="$BUILD/opendevnull --syscall $SYSCALL --always_syscall" + + +# Arrays to store output values +native_outputs=() +interc_outputs=() +sc2sc_outputs=() + +# Function to calculate statistics +calculate_stats() { + local values=("$@") + local sum=0 + local count=${#values[@]} + local min=${values[0]} + local max=${values[0]} + + # Calculate sum, min, and max + for value in "${values[@]}"; do + sum=$(echo "$sum + $value" | bc) + if (( $(echo "$value < $min" | bc -l) )); then + min=$value + fi + if (( $(echo "$value > $max" | bc -l) )); then + max=$value + fi + done + + # Calculate average + local avg=$(echo "scale=2; $sum / $count" | bc) + + # Calculate standard deviation + local variance=0 + for value in "${values[@]}"; do + variance=$(echo "$variance + ($value - $avg)^2" | bc) + done + local stddev=$(echo "scale=2; sqrt($variance / $count)" | bc) + + echo "Average: $avg, Min: $min, Max: $max, StdDev: $stddev" +} + for ((i=1; i<=REPEATS; i++)) do OUTPUT=$($NATIVE | cut -f4 --delim=" ") + native_outputs+=("$OUTPUT") echo "Native,$ARCH,"$OUTPUT done for ((i=1; i<=REPEATS; i++)) do - OUTPUT=$(LD_PRELOAD=./libeval_intercept.so $INTERC | cut -f4 --delim=" ") + OUTPUT=$(LD_PRELOAD=$BUILD/libeval_intercept.so $INTERC | cut -f4 --delim=" ") + interc_outputs+=("$OUTPUT") echo "Syscall,$ARCH,"$OUTPUT done for ((i=1; i<=REPEATS; i++)) do - OUTPUT=$(LD_PRELOAD=./libeval_intercept.so $SC2SC | cut -f4 --delim=" ") + OUTPUT=$(LD_PRELOAD=$BUILD/libeval_intercept.so $SC2SC | cut -f4 --delim=" ") + sc2sc_outputs+=("$OUTPUT") echo "Syscall2S,$ARCH,"$OUTPUT done +# Calculate and print statistics +echo "" +echo "Statistics for NATIVE mode:" +calculate_stats "${native_outputs[@]}" + +echo "" +echo "Statistics for INTERC mode:" +calculate_stats "${interc_outputs[@]}" + +echo "" +echo "Statistics for SC2SC mode:" +calculate_stats "${sc2sc_outputs[@]}" + +# Calculate overhead +native_avg=$(echo "${native_outputs[@]}" | tr ' ' '\n' | awk '{sum+=$1} END {print sum/NR}') +interc_avg=$(echo "${interc_outputs[@]}" | tr ' ' '\n' | awk '{sum+=$1} END {print sum/NR}') +sc2sc_avg=$(echo "${sc2sc_outputs[@]}" | tr ' ' '\n' | awk '{sum+=$1} END {print sum/NR}') + +overhead_interc=$(echo "scale=2; (($interc_avg - $native_avg) / $native_avg) * 100" | bc) +overhead_sc2sc=$(echo "scale=2; (($sc2sc_avg - $native_avg) / $native_avg) * 100" | bc) +echo "" +echo "Overhead of INTERC over NATIVE: $overhead_interc%" +echo "Overhead of SC2SC over NATIVE: $overhead_sc2sc%" diff --git a/src/eval.cpp b/src/eval.cpp index 8e6177e0e0eda60ff18df59799b52701beb5c2ab..13d2438fd45401ea1cbebfa89bc324cb1e8df973 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -2,72 +2,97 @@ #include #include #include -void start_interception() __attribute__((constructor)); -void stop_interception() __attribute__((destructor)); +#include -int hook_openat(int dirfd, const char *cpath, int flags, mode_t mode) { +void +start_interception() __attribute__((constructor)); +void +stop_interception() __attribute__((destructor)); - return syscall_no_intercept(SYS_openat, dirfd, cpath, flags, mode); +int +hook_openat(int dirfd, const char* cpath, int flags, mode_t mode) { + + return syscall_no_intercept(SYS_openat, dirfd, cpath, flags, mode); +} + +int +hook_getpid() { + return 42; +} + +int +hook_kill(int pid, int sig) { + return 42; } -int hook_getpid() { - return 42; +int +hook_getpriority(int which, id_t who) { + return 42; } -inline int hook(long syscall_number, long arg0, long arg1, long arg2, long arg3, - long arg4, long arg5, long *result) { +inline int +hook(long syscall_number, long arg0, long arg1, long arg2, long arg3, long arg4, + long arg5, long* result) { - switch (syscall_number) { + switch(syscall_number) { #ifdef SYS_open - case SYS_open: - *result = hook_openat(AT_FDCWD, reinterpret_cast(arg0), - static_cast(arg1), static_cast(arg2)); - break; + case SYS_open: + *result = hook_openat(AT_FDCWD, reinterpret_cast(arg0), + static_cast(arg1), + static_cast(arg2)); + break; #endif - case SYS_openat: - *result = hook_openat(static_cast(arg0), - reinterpret_cast(arg1), - static_cast(arg2), static_cast(arg3)); - break; - case SYS_getpid: - *result = hook_getpid(); - break; - default: - // ignore any other syscalls, i.e.: pass them on to the kernel - // (syscalls forwarded to the kernel that return are logged in - // hook_forwarded_syscall()) - - return 1; - } - - return 0; -} + case SYS_openat: + *result = hook_openat( + static_cast(arg0), reinterpret_cast(arg1), + static_cast(arg2), static_cast(arg3)); + break; + case SYS_getpid: + *result = hook_getpid(); + break; + case SYS_kill: + *result = + hook_kill(static_cast(arg0), static_cast(arg1)); + break; + case SYS_getpriority: + *result = + hook_getpriority(static_cast(arg0), static_cast(arg1)); + break; + default: + // ignore any other syscalls, i.e.: pass them on to the kernel + // (syscalls forwarded to the kernel that return are logged in + // hook_forwarded_syscall()) -int hook_guard_wrapper(long syscall_number, long arg0, long arg1, long arg2, - long arg3, long arg4, long arg5, - long *syscall_return_value) { + return 1; + } + + return 0; +} - int was_hooked = 1; +int +hook_guard_wrapper(long syscall_number, long arg0, long arg1, long arg2, + long arg3, long arg4, long arg5, + long* syscall_return_value) { - if (syscall_number == SYS_openat) - was_hooked = hook(syscall_number, arg0, arg1, arg2, arg3, arg4, arg5, - syscall_return_value); - else - if (syscall_number == SYS_getpid) - was_hooked = hook(syscall_number, arg0, arg1, arg2, arg3, arg4, arg5, - syscall_return_value); - return was_hooked; + int was_hooked = 1; + + if (syscall_number == SYS_openat || syscall_number == SYS_getpid || syscall_number == SYS_kill || syscall_number == SYS_getpriority) { + was_hooked = hook(syscall_number, arg0, arg1, arg2, arg3, arg4, arg5, syscall_return_value); + } + return was_hooked; } -void start_interception() { +void +start_interception() { - // Set up the callback function pointer - intercept_hook_point = hook_guard_wrapper; + // Set up the callback function pointer + intercept_hook_point = hook_guard_wrapper; } -void stop_interception() { +void +stop_interception() { - // Reset callback function pointer - intercept_hook_point = nullptr; + // Reset callback function pointer + intercept_hook_point = nullptr; } \ No newline at end of file diff --git a/src/opendevnull.cpp b/src/opendevnull.cpp index 6957eb3b9a6eb728c4af11057fb43316978d94a6..57186ab0f5cff672639ed2af4b295dcb5657edf4 100644 --- a/src/opendevnull.cpp +++ b/src/opendevnull.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include @@ -12,118 +14,160 @@ double reps = 1000.0 * 100000.0; int repext = 1000; int repint = 100000; bool always_syscall = - false; // whether to call the original syscall after the hook + false; // whether to call the original syscall after the hook bool verbose = false; // whether to print debug messages -int main(int argc, char *argv[]) { - // Parse command-line arguments - std::string syscall; - for (int i = 1; i < argc; ++i) { - std::string arg = argv[i]; - if (arg == "--syscall") { - if (i + 1 < argc) { - syscall = argv[++i]; - } else { - std::cerr << "Error: --syscall requires an argument" << std::endl; - return 1; - } - } else if (arg == "--reps") { - if (i + 1 < argc) { - reps = atof(argv[++i]); - if (reps <= 0) { - std::cerr << "Error: --reps requires a positive integer" << std::endl; - return 1; + +// Function to measure syscall time +template +double +measure_syscall_time(PreFunc pre, PostFunc post, double reps) { + const int inner_loop_size = 1000000; // Size of the inner loop (1 million) + int repext = + static_cast(reps / inner_loop_size); // Outer loop iterations + int repint = inner_loop_size; // Inner loop iterations + double remainder = std::fmod(reps, inner_loop_size); // Remaining iterations + struct timespec start, end; + clock_gettime(CLOCK_MONOTONIC, &start); + + for(int i = 0; i < repext; ++i) { + for(int j = 0; j < repint; ++j) { + auto result = pre(); + post(result); } - } else { - std::cerr << "Error: --reps requires an argument" << std::endl; - return 1; - } - } else if (arg == "--always_syscall") { - always_syscall = true; - } else if (arg == "--verbose") { - verbose = true; - } else { - std::cerr << "Error: Unknown option '" << arg << "'" << std::endl; - return 1; } - } - const int inner_loop_size = 1000000; // Size of the inner loop (1 million) - int repext = - static_cast(reps / inner_loop_size); // Outer loop iterations - int repint = inner_loop_size; // Inner loop iterations - double remainder = - std::fmod(reps, inner_loop_size); // Remaining iterations + for(int j = 0; j < remainder; ++j) { + auto result = pre(); + post(result); + } + + clock_gettime(CLOCK_MONOTONIC, &end); + return (end.tv_sec - start.tv_sec) * 1e6 + + (end.tv_nsec - start.tv_nsec) / 1e3; +} + - // Validate that --syscall is provided - if (syscall.empty()) { - std::cerr << "Error: --syscall is required" << std::endl; - return 1; - } +int +main(int argc, char* argv[]) { + // Parse command-line arguments + std::string syscall; + for(int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + if(arg == "--syscall") { + if(i + 1 < argc) { + syscall = argv[++i]; + } else { + std::cerr + << "Error: --syscall requires an argument (open|getpid|kill|getpriority)" + << std::endl; + return 1; + } + } else if(arg == "--reps") { + if(i + 1 < argc) { + reps = atof(argv[++i]); + if(reps <= 0) { + std::cerr << "Error: --reps requires a positive integer" + << std::endl; + return 1; + } + } else { + std::cerr << "Error: --reps requires an argument" << std::endl; + return 1; + } + } else if(arg == "--always_syscall") { + always_syscall = true; + } else if(arg == "--verbose") { + verbose = true; + } else { + std::cerr << "Error: Unknown option '" << arg << "'" << std::endl; + return 1; + } + } - // Handle the --syscall option - if (syscall == "open") { - struct timespec start, end; - clock_gettime(CLOCK_MONOTONIC, &start); + // Validate that --syscall is provided + if(syscall.empty()) { + std::cerr << "Error: --syscall is required" << std::endl; + return 1; + } - for (int i = 0; i < repext; ++i) { - for (int j = 0; j < repint; ++j) { + + // Handle the --syscall option + auto pre_open = []() { int fd = openat(AT_FDCWD, "/dev/null", O_RDWR, 0); - if (verbose) { - std::cout << "open() returned " << fd << std::endl; + if(verbose) { + std::cout << "openat() returned " << fd << std::endl; } + return fd; + }; + auto post_open = [](int fd) { close(fd); - } - } - for (int j = 0; j < remainder; ++j) { - int fd = openat(AT_FDCWD, "/dev/null", O_RDWR, 0); - if (verbose) { - std::cout << "open() returned " << fd << std::endl; - } - close(fd); - } + }; - clock_gettime(CLOCK_MONOTONIC, &end); - double time_taken = - (end.tv_sec - start.tv_sec) * 1e6 + (end.tv_nsec - start.tv_nsec) / 1e3; + auto pre_getpid = []() { + int ret = getpid(); + if(verbose) { + std::cout << "getpid() returned " << ret << std::endl; + } + if(always_syscall) { + syscall_no_intercept(SYS_getpid); + } + return ret; + }; - std::cout << "Mean time taken: " << time_taken / reps << " microseconds" - << std::endl; - } else if (syscall == "getpid") { - struct timespec start, end; - clock_gettime(CLOCK_MONOTONIC, &start); + auto post_getpid = [](int) { + }; - for (int i = 0; i < repext; ++i) { - for (int j = 0; j < repint; ++j) { - int ret = getpid(); - if (verbose) { - std::cout << "getpid() returned " << ret << std::endl; + auto pre_kill = []() { + int ret = kill(-1, 0); + if(verbose) { + std::cout << "kill() returned " << ret << std::endl; } - if (always_syscall) { - syscall_no_intercept(SYS_getpid); + if(always_syscall) { + syscall_no_intercept(SYS_kill, -1, 0); } - } - } + return ret; + }; - for (int j = 0; j < remainder; ++j) { - int ret = getpid(); - if (verbose) { - std::cout << "getpid() returned " << ret << std::endl; - } - if (always_syscall) { - syscall_no_intercept(SYS_getpid); - } - } + auto post_kill = [](int) { + }; - clock_gettime(CLOCK_MONOTONIC, &end); - double time_taken = - (end.tv_sec - start.tv_sec) * 1e6 + (end.tv_nsec - start.tv_nsec) / 1e3; + + // getpriority() is used to determine the page size, pre - post + auto pre_prio = []() { + int ret = getpriority(0,0); + if(verbose) { + std::cout << "getpriority() returned " << ret << std::endl; + } + if(always_syscall) { + syscall_no_intercept(SYS_getpriority, 0, 0); + } + return ret; + }; + + auto post_prio = [](int) { + }; + + double time_taken = 0; + if(syscall == "open") { + time_taken = measure_syscall_time(pre_open, post_open, reps); + } else if(syscall == "getpid") { + time_taken = measure_syscall_time(pre_getpid, post_getpid, reps); + } else if(syscall == "kill") { + time_taken = measure_syscall_time(pre_kill, post_kill, reps); + } else if(syscall == "getpriority") { + time_taken = measure_syscall_time(pre_prio, post_prio, reps); + } else { + std::cerr << "Error: Unsupported syscall '" << syscall << "'" + << std::endl; + return 1; + } std::cout << "Mean time taken: " << time_taken / reps << " microseconds" << std::endl; - } - return 0; + + return 0; }