Commit 39035659 authored by Ramon Nou's avatar Ramon Nou
Browse files

Enhance fd protection logic in preload initialization and destruction

parent 57304401
Loading
Loading
Loading
Loading
+38 −73
Original line number Diff line number Diff line
@@ -44,11 +44,13 @@
#include <common/path_util.hpp>
#include <client/open_dir.hpp>
#include <linux/const.h>
#include <client/logging.hpp>
#include <sstream>
std::atomic<bool> activated{false};
std::atomic<bool> initializing{false};

// Define a debug macro, can be easily disabled
// #define GKFS_TRACE
#define GKFS_TRACE

#ifdef GKFS_DEBUG_BUILD
#ifdef GKFS_TRACE
@@ -77,6 +79,21 @@ initializeGekko() {
    }
}

#define STRIP_PARENS(...) __VA_ARGS__

void log_arguments(const char* symbol) {
    LOG(DEBUG, "[BYPASS] {}", symbol);
}

// Variadic case: 1+ arguments
template <typename... Args>
void log_arguments(const char* symbol, Args&&... args) {
    std::stringstream ss;
    ss << "[BYPASS] Calling " << symbol << " with arguments: ";
    ((ss << "[" << typeid(Args).name() << "] "
        << args << " "), ...);
    LOG(DEBUG,"{}", ss.str());
}

/**
 * @brief Macro to declare and implement a wrapper for a standard library
@@ -99,6 +116,7 @@ initializeGekko() {
 * @param symbol_name The symbol name to look up with dlsym (usually the same as
 * `func_name`).
 */

#define DLSYM_WRAPPER(return_type, func_name, params, args, symbol_name)       \
    static return_type(*real_##func_name) params = nullptr;                    \
    return_type dlsym_##func_name params {                                     \
@@ -112,7 +130,7 @@ initializeGekko() {
                                   not supported */                            \
                return (return_type) - 1; /* Return error value */             \
            }                                                                  \
        }                                                                      \
        } log_arguments(symbol_name, STRIP_PARENS args);             \
        return real_##func_name args;                                          \
    }

@@ -192,7 +210,7 @@ DLSYM_WRAPPER(struct dirent64*, readdir64, (DIR * dirp), (dirp), "readdir64")
DLSYM_WRAPPER(int, closedir, (DIR * dirp), (dirp), "closedir")
DLSYM_WRAPPER(void, seekdir, (DIR * dirp, long loc), (dirp, loc), "seekdir")
DLSYM_WRAPPER(long, telldir, (DIR * dirp), (dirp), "telldir")
DLSYM_WRAPPER(int, fork, (void), (), "fork")
//DLSYM_WRAPPER(int, fork, (void), (), "fork")
DLSYM_WRAPPER(int, pipe, (int pipefd[2]), (pipefd), "pipe")
DLSYM_WRAPPER(int, dup, (int fd), (fd), "dup")
DLSYM_WRAPPER(int, dup2, (int fd, int fd2), (fd, fd2), "dup2")
@@ -327,7 +345,7 @@ is_gkfs_fd(int fd) {
}

#define GKFS_OPERATION(name, ...)                                              \
    if(CTX->interception_enabled() && is_gkfs_fd(fd)) {                        \
    if(CTX->interception_enabled() && is_gkfs_fd(fd)) { LOG(DEBUG,"[GKFS] %d",fd); \
        return gkfs::syscall::gkfs_##name(__VA_ARGS__);                        \
    }

@@ -336,6 +354,7 @@ is_gkfs_fd(int fd) {
        std::string resolved;                                                  \
        switch(resolve_gkfs_path(dirfd, path, resolved)) {                     \
            case PathStatus::Internal:                                          \
                LOG(DEBUG,"[GKFS] {}",resolved);                                        \
                return gkfs::syscall::gkfs_##name(resolved, __VA_ARGS__);      \
            case PathStatus::Error:                                            \
                return -errno;                                                 \
@@ -349,6 +368,7 @@ is_gkfs_fd(int fd) {
        std::string resolved;                                                  \
        switch(resolve_gkfs_path(dirfd, path, resolved)) {                     \
            case PathStatus::Internal:    \
            LOG(DEBUG,"[GKFS] {}", resolved);                                     \
                return gkfs::syscall::gkfs_##name(dirfd, resolved,             \
                                                  __VA_ARGS__);                \
            case PathStatus::Error:                                            \
@@ -363,6 +383,7 @@ is_gkfs_fd(int fd) {
        std::string resolved;                                                  \
        switch(resolve_gkfs_path(dirfd, path, resolved)) {                     \
            case PathStatus::Internal:  \
            LOG(DEBUG,"[GKFS] {}", resolved);                                         \
                return gkfs::syscall::gkfs_##name(resolved);                   \
            case PathStatus::Error:                                            \
                return -errno;                                                 \
@@ -380,7 +401,6 @@ open(const char* path, int flags, ...) {
    va_start(ap, flags);
    mode_t mode = va_arg(ap, mode_t);
    va_end(ap);

    initializeGekko();
    GKFS_PATH_OPERATION(open, AT_FDCWD, path, mode, flags)
    GKFS_FALLBACK(open2, const_cast<char*>(path), flags, mode)
@@ -452,16 +472,13 @@ close_range(unsigned low, unsigned high, int flags) {

int
creat(const char* path, mode_t mode) {
    DEBUG_INFO("[BYPASS] >> Begin creat....%s %o\n", path, mode);
    initializeGekko();
    GKFS_PATH_OPERATION(create, AT_FDCWD, path, mode)
    DEBUG_INFO("[BYPASS]\t dlsym_creat (%s,%o)\n", path, mode);
    GKFS_FALLBACK(creat, path, mode);
}

int
ftruncate(int fd, off_t length) {
    DEBUG_INFO("[BYPASS] >> Begin ftruncate.... %d %ld\n", fd, length);
    initializeGekko();
    if(is_gkfs_fd(fd)) {
        std::string path_str = CTX->file_map()->get(fd)->path();
@@ -493,7 +510,6 @@ mkdir(const char* path, mode_t mode) {

int
rmdir(const char* path) {
    DEBUG_INFO("[BYPASS] >> Begin rmdir.... %s\n", path);
    initializeGekko();
    GKFS_PATH_OPERATION1(rmdir, AT_FDCWD, path)
    GKFS_FALLBACK(rmdir, path);
@@ -515,8 +531,6 @@ pwrite(int fd, const void* buf, size_t count, off_t offset) {

int
mkstemp(char* templates) {
    DEBUG_INFO("[BYPASS] >> Begin mkstemp....\n");
    DEBUG_INFO("[BYPASS]    1) templates  => %s\n", templates);
    GKFS_FALLBACK(mkstemp, templates);
}

@@ -592,7 +606,6 @@ __xstat64(int ver, const char* path, struct stat64* buf) {
int
statx(int dirfd, const char* path, int flags, unsigned int mask,
      struct statx* statxbuf) {
    DEBUG_INFO("[BYPASS] >> Begin statx....%s\n", path);
    initializeGekko();
    GKFS_PATH_OPERATION_DIR(statx, dirfd, path, flags, mask, statxbuf)
    GKFS_FALLBACK(statx, dirfd, path, flags, mask, statxbuf);
@@ -661,7 +674,6 @@ __fxstat(int ver, int fd, struct stat* buf) {

int
__fxstatat(int ver, int dfd, const char* path, struct stat* buf, int flags) {
    DEBUG_INFO("[__fxstatat ]....%s \n", path);
    initializeGekko();
    GKFS_PATH_OPERATION(stat, AT_FDCWD, path, buf)
    GKFS_FALLBACK(fxstatat, ver, dfd, path, buf, flags);
@@ -684,7 +696,6 @@ __fxstat64(int ver, int fd, struct stat64* buf) {
int
__fxstatat64(int ver, int dfd, const char* path, struct stat64* buf,
             int flags) {
    DEBUG_INFO("[__fxstatat64 ]....%s \n", path);
    initializeGekko();
    struct stat st;
    if(CTX->interception_enabled()) {
@@ -748,7 +759,6 @@ fstat(int fd, struct stat* buf) {

int
fstatat(int dfd, const char* path, struct stat* buf, int flags) {
    DEBUG_INFO("[FSTATAT from GKFS]....%s \n", path);
    initializeGekko();
    if(CTX->interception_enabled()) {
        std::string resolved;
@@ -770,7 +780,6 @@ fstatat(int dfd, const char* path, struct stat* buf, int flags) {

int
rename(const char* oldpath, const char* newpath) {
    DEBUG_INFO("[BYPASS] >> Begin rename....%s %s\n", oldpath, newpath);
    initializeGekko();
    // Is path from GekkoFS?
    if(CTX->interception_enabled()) {
@@ -801,6 +810,7 @@ rename(const char* oldpath, const char* newpath) {
    GKFS_FALLBACK(rename, oldpath, newpath);
}

/*
pid_t
fork(void) {
    // DEBUG_INFO("[BYPASS] >> Begin fork() %p\n", (void*) &activated);
@@ -825,10 +835,10 @@ fork(void) {

    return ret;
}
*/

int
pipe(int pipefd[2]) {
    DEBUG_INFO("[BYPASS] >> Begin pipe() %d - %d\n", pipefd[0], pipefd[1]);
    initializeGekko();
    GKFS_FALLBACK(pipe, pipefd);
}
@@ -851,7 +861,6 @@ dup2(int fd, int fd2) {
int
dup3(int fd, int fd2, int flags) {
    initializeGekko();
    DEBUG_INFO("[BYPASS] >> Begin dup3() %d - %d\n", fd, fd2);
    GKFS_OPERATION(dup2, fd, fd2);
    GKFS_FALLBACK(dup3, fd, fd2, flags);
}
@@ -866,8 +875,6 @@ exit(int status) {

int
chdir(const char* path) {
    DEBUG_INFO("[BYPASS] >> Begin chdir...\n");
    DEBUG_INFO("[BYPASS]    1) path %s\n", path);

    initializeGekko();
    // is the path from gekkofs
@@ -898,9 +905,6 @@ chdir(const char* path) {
int
fcntl(int fd, int cmd, long arg) // TODO
{
    DEBUG_INFO("[BYPASS] >> Begin fcntl... %d , %d ,%ld\n", fd, cmd, arg);


    initializeGekko();

    // is from gekkofs?
@@ -1003,56 +1007,24 @@ realpath(const char* path, char* resolved_path) {
           }
       }
   */
    // call the real realpath function
    char* ret = dlsym_realpath(const_cast<char*>(path), resolved_path);

    return ret;
    GKFS_FALLBACK(realpath, path, resolved_path);
}

char*
__realpath_chk(const char* path, char* resolved_path,
               __attribute__((__unused__)) size_t resolved_len) {
    DEBUG_INFO("[BYPASS] >> Begin __realpath_chk...\n");
    DEBUG_INFO("[BYPASS] 1) Path %s\n", path);


    DEBUG_INFO("[BYPASS] Begin dlsym_realpath...\n");

    return dlsym_realpath(path, resolved_path);
    GKFS_FALLBACK(realpath, path, resolved_path);
}

int
fsync(int fd) // TODO
{
    DEBUG_INFO("[BYPASS] >> Begin fsync...\n");
    DEBUG_INFO("[BYPASS] 1) fd %d\n", fd);
    int ret;

    ret = dlsym_fsync(fd);

    DEBUG_INFO("[BYPASS]\t dlsym_fsync -> %d\n", ret);


    return ret;
    GKFS_FALLBACK(fsync, fd);
}

int
flock(int fd, int operation) {
    int ret = -1;

    DEBUG_INFO("[BYPASS] >> Begin flock...\n");
    DEBUG_INFO("[BYPASS]    * fd=%d\n", fd);
    DEBUG_INFO("[BYPASS]    * operation=%d\n", operation);


    DEBUG_INFO("[BYPASS]\t try to dlsym_flock %d,%d\n", fd, operation);

    ret = dlsym_flock(fd, operation);


    DEBUG_INFO("[BYPASS] << After flock...\n");

    return ret;
    GKFS_FALLBACK(flock, fd, operation);
}

DIR*
@@ -1235,7 +1207,6 @@ closedir(DIR* dirp) {
// telldir
long
telldir(DIR* dirp) {
    DEBUG_INFO("[BYPASS] >> telldir.... %p\n", static_cast<void*>(dirp));
    long ret;
    initializeGekko();
    if(CTX->interception_enabled()) {
@@ -1255,8 +1226,6 @@ telldir(DIR* dirp) {
// seekdir
void
seekdir(DIR* dirp, long loc) {
    DEBUG_INFO("[BYPASS] >> seekdir.... %p %ld\n", static_cast<void*>(dirp),
               loc);
    initializeGekko();
    if(CTX->interception_enabled()) {
        if(CTX->file_map()->exist(dirp->fd)) {
@@ -1304,7 +1273,7 @@ fopen(const char* path, const char* mode) {
                flags = O_WRONLY | O_CREAT | O_APPEND;
            if(strchr(mode, '+'))
                flags = O_RDWR | O_CREAT;

            LOG(DEBUG,"[GEKKO] {}", resolved); 
            const int fd = gkfs::syscall::gkfs_open(resolved, 0666, flags);
            if(fd < 0)
                return nullptr;
@@ -1318,7 +1287,6 @@ fopen(const char* path, const char* mode) {

FILE*
freopen64(const char* path, const char* mode, FILE* stream) {
    DEBUG_INFO("[BYPASS] >> freopen.... %s \n", path);
    initializeGekko();
    if(CTX->interception_enabled()) {
        std::string resolved;
@@ -1333,7 +1301,7 @@ freopen64(const char* path, const char* mode, FILE* stream) {
                flags = O_WRONLY | O_CREAT | O_APPEND;
            if(strchr(mode, '+'))
                flags = O_RDWR | O_CREAT;

            LOG(DEBUG,"[GEKKO] {}", resolved); 
            const int fd = gkfs::syscall::gkfs_open(resolved, 0666, flags);
            if(fd < 0)
                return nullptr;
@@ -1349,6 +1317,7 @@ freopen64(const char* path, const char* mode, FILE* stream) {
size_t
fread(void* ptr, size_t size, size_t nmemb, FILE* stream) {
    if(CTX->interception_enabled() && CTX->file_map()->exist(stream->_fileno)) {
        LOG(DEBUG,"[GEKKO] {}", stream->_fileno); 
        return gkfs::syscall::gkfs_read(stream->_fileno, ptr, size * nmemb) /
               size;
    }
@@ -1361,6 +1330,7 @@ fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream) {

    initializeGekko();
    if(CTX->interception_enabled() && CTX->file_map()->exist(stream->_fileno)) {
        LOG(DEBUG,"[GEKKO] {}", stream->_fileno); 
        return gkfs::syscall::gkfs_write(stream->_fileno, ptr, size * nmemb) /
               size;
    }
@@ -1370,7 +1340,6 @@ fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream) {

int
fseek(FILE* stream, long int offset, int whence) {
    DEBUG_INFO("[BYPASS] >> fseek.... \n");
    initializeGekko();
    if(CTX->interception_enabled() && CTX->file_map()->exist(stream->_fileno)) {
        return gkfs::syscall::gkfs_lseek(stream->_fileno, offset, whence);
@@ -1381,7 +1350,6 @@ fseek(FILE* stream, long int offset, int whence) {

long
ftell(FILE* stream) {
    DEBUG_INFO("[BYPASS] >> ftell.... \n");
    initializeGekko();
    if(CTX->interception_enabled() && CTX->file_map()->exist(stream->_fileno)) {
        return gkfs::syscall::gkfs_lseek(stream->_fileno, 0, SEEK_CUR);
@@ -1392,7 +1360,6 @@ ftell(FILE* stream) {

void
rewind(FILE* stream) {
    DEBUG_INFO("[BYPASS] >> rewind.... \n");
    initializeGekko();
    if(CTX->interception_enabled() && CTX->file_map()->exist(stream->_fileno)) {
        gkfs::syscall::gkfs_lseek(stream->_fileno, 0, SEEK_SET);
@@ -1417,7 +1384,6 @@ fclose(FILE* stream) {
// feof implementation with lseek
int
feof(FILE* stream) {
    DEBUG_INFO("[BYPASS] >> feof.... \n");
    initializeGekko();
    if(CTX->interception_enabled() && CTX->file_map()->exist(stream->_fileno)) {
        off_t cur = gkfs::syscall::gkfs_lseek(stream->_fileno, 0, SEEK_CUR);
@@ -1453,7 +1419,6 @@ fgets(char* str, int n, FILE* stream) {
// implement fflush and bypass if gekko
int
fflush(FILE* stream) {
    DEBUG_INFO("[BYPASS] >> fflush.... \n");
    initializeGekko();
    if(CTX->interception_enabled() && CTX->file_map()->exist(stream->_fileno)) {
        // flush stream with gkfs_fsync
+31 −8
Original line number Diff line number Diff line
@@ -366,13 +366,6 @@ init_preload() {
    CTX->enable_interception();
    gkfs::preload::start_self_interception();

    CTX->enable_interception();
    gkfs::preload::start_self_interception();

    if(!init) {
        init = true;
        pthread_atfork(&at_fork_syscall, &at_parent_syscall, &at_child_syscall);
    }
    CTX->init_logging();
    // from here ownwards it is safe to print messages
    LOG(DEBUG, "Logging subsystem initialized");
@@ -472,12 +465,25 @@ destroy_preload() {
extern "C" int
gkfs_init() {
    CTX->init_logging();

    // from here ownwards it is safe to print messages
    LOG(DEBUG, "Logging subsystem initialized");
    if(gkfs::env::var_is_set(gkfs::env::PROTECT_FD)) {
        CTX->protect_fds(true);
        LOG(INFO, "Protecting user fds");
    } else {
        CTX->protect_fds(false);
        LOG(INFO, "Not protecting user fds");
    }

    if(CTX->protect_fds()) {
        CTX->protect_user_fds();
    }

    gkfs::preload::init_environment();

    if(CTX->protect_fds())
        CTX->unprotect_user_fds();

    return 0;
}

@@ -506,11 +512,28 @@ init_libc() {
    CTX->init_logging();
    // from here ownwards it is safe to print messages
    LOG(DEBUG, "Logging subsystem initialized");
    if(gkfs::env::var_is_set(gkfs::env::PROTECT_FD)) {
        CTX->protect_fds(true);
        LOG(INFO, "Protecting user fds");
    } else {
        CTX->protect_fds(false);
        LOG(INFO, "Not protecting user fds");
    }

    if(CTX->protect_fds()) {
        CTX->protect_user_fds();
    }
    
    if(!init) {
        init = true;
        pthread_atfork(&at_fork, &at_parent, &at_child);
    }

    gkfs::preload::init_environment();

    if(CTX->protect_fds()) {
        CTX->unprotect_user_fds();
    }
    CTX->enable_interception();
    if(!CTX->init_metrics()) {
        exit_error_msg(EXIT_FAILURE,