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

Resolve "log_fd interacting with vfork/execve and syscall intercept in java"

parent 186ad3f8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
  - Directories shows . and .. to support scandir ([!248](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/248))
  - updated fmt, spdlog and pytest versions ([!249](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/249))
  - Updated Docker images for 0.9.5 ([!238](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/238))
  - Logging uses a higher FD limit ([!259](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/259))
    - Avoid throwing runtime error if the fd is invalid (may happen on destruction)
  
### Fixed
  - Dup3 is supported if O_CLOEXEC is not used (i.e. hexdump) ([!228](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/228))
+4 −9
Original line number Diff line number Diff line
@@ -168,22 +168,17 @@ log_buffer(std::FILE* fp, Buffer&& buffer) {
template <typename Buffer>
static inline void
log_buffer(int fd, Buffer&& buffer) {

    if(fd < 0) {
        throw std::runtime_error("Invalid file descriptor");
    }

    if(fd > 0) {
        ::syscall_no_intercept(SYS_write, fd, buffer.data(), buffer.size());
    }
}

static inline void
log_buffer(int fd, const void* buffer, std::size_t length) {
    if(fd < 0) {
        throw std::runtime_error("Invalid file descriptor");
    }

    if(fd > 0) {
        ::syscall_no_intercept(SYS_write, fd, buffer, length);
    }
}

/**
 * @brief convert a time_t to a tm
+1 −1
Original line number Diff line number Diff line
@@ -517,7 +517,7 @@ format_clone3_args_arg_to(FmtBuffer& buffer, const printable_arg& parg) {
    format_flag_set(buffer, ca->flags, flag_names);
   
    fmt::format_to(std::back_inserter(buffer), "|", "signal");
    format_signum_arg_to(buffer, {"", ca->exit_signal});
    format_signum_arg_to(buffer, {"", static_cast<int>(ca->exit_signal)});

    fmt::format_to(std::back_inserter(buffer), ",{}={}", "pidfd", (void*)ca->pidfd);
    fmt::format_to(std::back_inserter(buffer), ",{}={}", "child_tid", (void*)ca->child_tid);
+2 −1
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@ static ResultEntry* results = nullptr;
#ifdef GKFS_TRACE
#define DEBUG_INFO(...)                                                        \
    do {                                                                       \
        if(CTX->interception_enabled())                                        \
            LOG(DEBUG, __VA_ARGS__);                                           \
    } while(0)
#else
+60 −1
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#include <regex>
#include <filesystem>
#include <ctime>
#include <sys/resource.h>

#ifdef GKFS_ENABLE_LOGGING

@@ -336,9 +337,67 @@ logger::logger(const std::string& opts, const std::string& path,
                path);
            return;
        }
        // Pseudo protect fd to a higher fd with dup2

        struct rlimit rlim;
        if(getrlimit(RLIMIT_NOFILE, &rlim) == -1) {
            perror("GekkoFS Log: getrlimit(RLIMIT_NOFILE) failed");
            log_fd_ = fd;
            fprintf(stderr,
                    "GekkoFS Log: Using original FD %d due to getrlimit error.\n",
                    log_fd_);
            return; // Or error
        }

        int target_fd = -1;
        if(rlim.rlim_cur >
           25000) { // It shouldn't be too high, if not we have memory issues
            target_fd = 24000;
        } else if(rlim.rlim_cur > 3) { // If limit is small, pick the highest
                                       // possible that's not 0,1,2
            target_fd = rlim.rlim_cur - 1;
        } else {
            fprintf(stderr,
                    "GekkoFS Log: RLIMIT_NOFILE is too small (%llu) to pick a high FD. Using original FD %d.\n",
                    (unsigned long long) rlim.rlim_cur, fd);
            log_fd_ = fd;

            return;
        }

        // Check if target_fd is already the original_fd
        if(target_fd == fd) {
            log_fd_ = fd;
        } else {
            // Duplicate original_fd to target_fd.
            // dup2 will close target_fd if it's already open.
            if(dup2(fd, target_fd) == -1) {
                fprintf(stderr, "GekkoFS Log: dup2 error for : %d.\n",
                        target_fd);
                perror("GekkoFS Log: dup2 failed");
                // Failed to move to high FD, try to use original_fd or error
                // out
                close(fd); // Close the one we opened
                return;
            }
            // Now that original_fd is duplicated to target_fd, we can close
            // original_fd. All writes should go to target_fd.
            if(close(fd) == -1) {
                perror("GekkoFS Log: Failed to close original_fd after dup2");
            }
            log_fd_ = target_fd;
        }

        flags = fcntl(log_fd_, F_GETFD);
        if(flags == -1) {
            perror("GekkoFS Log: fcntl(F_GETFD) failed on new log FD");
        } else {
            if(fcntl(log_fd_, F_SETFD, flags | FD_CLOEXEC) == -1) {
                perror("GekkoFS Log: fcntl failed on new log FD");
            }
        }
    }


#ifdef GKFS_ENABLE_LOGGING
    const auto log_hermes_message =
Loading