From 5c7c4edfe45be83211d5c6217824dd4b9ec562d2 Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Sat, 10 Oct 2015 21:42:30 +0200 Subject: Implement basic `read` and `write` interposition The goal is to implement a shared library to be loaded using `LD_PRELOAD` that tracks all file changes performed by a process. This information is required to enable general purpose change logging inside a shell session. i.e. I want to be able to display diffs and before- / after-hashes of all changes performed by every single command without requiring every changed file to be known prior to execution. --- change_log.cc | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 change_log.cc diff --git a/change_log.cc b/change_log.cc new file mode 100644 index 0000000..d4c3dc4 --- /dev/null +++ b/change_log.cc @@ -0,0 +1,76 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include + +#include +#include +#include + +template +std::function get_real_function( + const std::string& symbol_name) { + + Result (*real_function)(Arguments...) = nullptr; + const void* symbol_address = dlsym(RTLD_NEXT, symbol_name.c_str()); + + std::memcpy(&real_function, &symbol_address, sizeof(symbol_address)); + + return std::function(real_function); +} + +std::string get_file_name(int fd) { + char proc_link[20]; + char file_name[256]; + + snprintf(proc_link, sizeof(proc_link), "/proc/self/fd/%d", fd); + const ssize_t name_size = readlink(proc_link, file_name, sizeof(file_name)); + + if ( name_size > 0 ) { + file_name[name_size] = '\0'; + + return std::string(file_name); + } else { + return std::string(); + } +} + +bool is_regular_file(int fd) { + struct stat fd_stat; + fstat(fd, &fd_stat); + + return S_ISREG(fd_stat.st_mode); +} + +ssize_t read(int fd, void *buffer, size_t count) { + static auto real_read = get_real_function("read"); + + const ssize_t result = real_read(fd, buffer, count); + + if ( is_regular_file(fd) ) { + std::cerr << "read size " + << count + << " of " + << get_file_name(fd) + << std::endl; + } + + return result; +} + +ssize_t write(int fd, const void* buffer, size_t count) { + static auto real_write = get_real_function("write"); + + if ( is_regular_file(fd) ) { + std::cerr << "write size " + << count + << " to " + << get_file_name(fd) + << std::endl; + } + + return real_write(fd, buffer, count); +} -- cgit v1.2.3