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

fix syscall tls recursion

parent 73227dff
Loading
Loading
Loading
Loading
Loading
+48 −25
Original line number Original line Diff line number Diff line
@@ -36,7 +36,7 @@


  SPDX-License-Identifier: LGPL-3.0-or-later
  SPDX-License-Identifier: LGPL-3.0-or-later
*/
*/

#include <pthread.h>
#include <client/intercept.hpp>
#include <client/intercept.hpp>
#include <client/preload.hpp>
#include <client/preload.hpp>
#include <client/hooks.hpp>
#include <client/hooks.hpp>
@@ -74,7 +74,13 @@ void (*intercept_hook_point_post_kernel)(long syscall_number, long arg0,
#endif
#endif
namespace {
namespace {


thread_local bool reentrance_guard_flag;
static pthread_key_t reentrance_guard_key;
static pthread_once_t key_once_control = PTHREAD_ONCE_INIT;
static void make_key() {
    // This function will be called exactly once per process.
    pthread_key_create(&reentrance_guard_key, NULL);
}

thread_local gkfs::syscall::info saved_syscall_info;
thread_local gkfs::syscall::info saved_syscall_info;


constexpr void
constexpr void
@@ -533,7 +539,8 @@ hook(long syscall_number, long arg0, long arg1, long arg2, long arg3, long arg4,


        case SYS_execve:
        case SYS_execve:
            // If we do not set this to false, we are in trouble with vforks
            // If we do not set this to false, we are in trouble with vforks
            reentrance_guard_flag = false;
pthread_once(&key_once_control, make_key);
            pthread_setspecific(reentrance_guard_key, NULL);
    		*result = syscall_no_intercept_wrapper(
    		*result = syscall_no_intercept_wrapper(
                    syscall_number, reinterpret_cast<const char*>(arg0),
                    syscall_number, reinterpret_cast<const char*>(arg0),
                    reinterpret_cast<const char* const*>(arg1),
                    reinterpret_cast<const char* const*>(arg1),
@@ -543,7 +550,8 @@ hook(long syscall_number, long arg0, long arg1, long arg2, long arg3, long arg4,
#ifdef SYS_execveat
#ifdef SYS_execveat
        case SYS_execveat:
        case SYS_execveat:
            // If we do not set this to false, we are in trouble with vforks
            // If we do not set this to false, we are in trouble with vforks
            reentrance_guard_flag = false;
pthread_once(&key_once_control, make_key);
            pthread_setspecific(reentrance_guard_key, NULL);
	    *result = syscall_no_intercept_wrapper(
	    *result = syscall_no_intercept_wrapper(
                    syscall_number, arg0, reinterpret_cast<const char*>(arg1),
                    syscall_number, arg0, reinterpret_cast<const char*>(arg1),
                    reinterpret_cast<const char* const*>(arg2),
                    reinterpret_cast<const char* const*>(arg2),
@@ -1011,12 +1019,19 @@ socketcall_wrapper(long syscall_number, long& arg0, long& arg1, long& arg2,
}
}
#endif
#endif



void
void
hook_forwarded_syscall(long syscall_number, long arg0, long arg1, long arg2,
hook_forwarded_syscall(long syscall_number, long arg0, long arg1, long arg2,
                       long arg3, long arg4, long arg5, long result) {
                       long arg3, long arg4, long arg5, long result) {
    
    
    pthread_once(&key_once_control, make_key);
    if (pthread_getspecific(reentrance_guard_key) != NULL) {
        return;
    }
    pthread_setspecific(reentrance_guard_key, (void*) 1);


    if(::get_current_syscall_info() == gkfs::syscall::no_info) {
    if(::get_current_syscall_info() == gkfs::syscall::no_info) {
        pthread_setspecific(reentrance_guard_key, NULL);
        return;
        return;
    }
    }


@@ -1029,6 +1044,8 @@ hook_forwarded_syscall(long syscall_number, long arg0, long arg1, long arg2,
        syscall_number, args, result);
        syscall_number, args, result);


    ::reset_current_syscall_info();
    ::reset_current_syscall_info();
    
    pthread_setspecific(reentrance_guard_key, NULL);
}
}


void
void
@@ -1042,12 +1059,13 @@ hook_clone_at_child(unsigned long flags, void* child_stack, int* ptid,
            static_cast<long>(newtls),    0};
            static_cast<long>(newtls),    0};
#endif
#endif


    reentrance_guard_flag = true;
    pthread_once(&key_once_control, make_key);
    pthread_setspecific(reentrance_guard_key, (void*) 1);


    LOG(SYSCALL, ::get_current_syscall_info() | gkfs::syscall::executed,
    LOG(SYSCALL, ::get_current_syscall_info() | gkfs::syscall::executed,
        SYS_clone, args, 0);
        SYS_clone, args, 0);


    reentrance_guard_flag = false;
    pthread_setspecific(reentrance_guard_key, NULL);
}
}


void
void
@@ -1061,18 +1079,20 @@ hook_clone_at_parent(unsigned long flags, void* child_stack, int* ptid,
            static_cast<long>(newtls),    0};
            static_cast<long>(newtls),    0};
#endif
#endif


    reentrance_guard_flag = true;
    pthread_once(&key_once_control, make_key);
    pthread_setspecific(reentrance_guard_key, (void*) 1);


    LOG(SYSCALL, ::get_current_syscall_info() | gkfs::syscall::executed,
    LOG(SYSCALL, ::get_current_syscall_info() | gkfs::syscall::executed,
        SYS_clone, args, returned_pid);
        SYS_clone, args, returned_pid);


    reentrance_guard_flag = false;
    pthread_setspecific(reentrance_guard_key, NULL);
}
}


} // namespace
} // namespace


namespace gkfs::preload {
namespace gkfs::preload {


// This function is inside 'namespace gkfs::preload'
int
int
internal_hook_guard_wrapper(long syscall_number, long arg0, long arg1,
internal_hook_guard_wrapper(long syscall_number, long arg0, long arg1,
                            long arg2, long arg3, long arg4, long arg5,
                            long arg2, long arg3, long arg4, long arg5,
@@ -1085,7 +1105,8 @@ internal_hook_guard_wrapper(long syscall_number, long arg0, long arg1,
                                            arg3, arg4, arg5);
                                            arg3, arg4, arg5);
#endif
#endif


    if(reentrance_guard_flag) {
    pthread_once(&key_once_control, make_key);
    if (pthread_getspecific(reentrance_guard_key) != NULL) {
        ::save_current_syscall_info(gkfs::syscall::from_internal_code |
        ::save_current_syscall_info(gkfs::syscall::from_internal_code |
                                    gkfs::syscall::to_kernel |
                                    gkfs::syscall::to_kernel |
                                    gkfs::syscall::not_executed);
                                    gkfs::syscall::not_executed);
@@ -1094,15 +1115,14 @@ internal_hook_guard_wrapper(long syscall_number, long arg0, long arg1,


    int was_hooked = 0;
    int was_hooked = 0;


    reentrance_guard_flag = true;
    pthread_setspecific(reentrance_guard_key, (void*) 1);
    was_hooked = hook_internal(syscall_number, arg0, arg1, arg2, arg3, arg4,
    was_hooked = hook_internal(syscall_number, arg0, arg1, arg2, arg3, arg4,
                               arg5, syscall_return_value);
                               arg5, syscall_return_value);
    reentrance_guard_flag = false;
    pthread_setspecific(reentrance_guard_key, NULL);


    return was_hooked;
    return was_hooked;
}
}



/*
/*
 * hook_guard_wrapper -- a wrapper which can notice reentrance.
 * hook_guard_wrapper -- a wrapper which can notice reentrance.
 *
 *
@@ -1122,6 +1142,17 @@ hook_guard_wrapper(long syscall_number, long arg0, long arg1, long arg2,
                   long arg3, long arg4, long arg5,
                   long arg3, long arg4, long arg5,
                   long* syscall_return_value) {
                   long* syscall_return_value) {


    // --- START OF REVISED FIX for hook_guard_wrapper ---
    pthread_once(&key_once_control, make_key); // Ensure the key is created
    if (pthread_getspecific(reentrance_guard_key) != NULL) {
        // If the guard is set, forward the syscall to the kernel and return.
        return gkfs::syscall::forward_to_kernel;
    }
    // Set the guard to a non-NULL value.
    pthread_setspecific(reentrance_guard_key, (void*) 1);
    // --- END OF REVISED FIX for hook_guard_wrapper ---


    assert(CTX->interception_enabled());
    assert(CTX->interception_enabled());


#ifdef SYS_socketcall
#ifdef SYS_socketcall
@@ -1132,19 +1163,11 @@ hook_guard_wrapper(long syscall_number, long arg0, long arg1, long arg2,


    int was_hooked = 0;
    int was_hooked = 0;


    if(reentrance_guard_flag) {

        was_hooked = hook_internal(syscall_number, arg0, arg1, arg2, arg3, arg4,
                                   arg5, syscall_return_value);
        return was_hooked;
    }

    reentrance_guard_flag = true;

    was_hooked = ::hook(syscall_number, arg0, arg1, arg2, arg3, arg4, arg5,
    was_hooked = ::hook(syscall_number, arg0, arg1, arg2, arg3, arg4, arg5,
                        syscall_return_value);
                        syscall_return_value);


    reentrance_guard_flag = false;
    // Unset the guard before returning
    pthread_setspecific(reentrance_guard_key, NULL);


    return was_hooked;
    return was_hooked;
}
}