LCOV - code coverage report
Current view: top level - src/client - intercept.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 272 376 72.3 %
Date: 2024-04-23 00:09:24 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   Copyright 2018-2024, Barcelona Supercomputing Center (BSC), Spain
       3             :   Copyright 2015-2024, Johannes Gutenberg Universitaet Mainz, Germany
       4             : 
       5             :   This software was partially supported by the
       6             :   EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
       7             : 
       8             :   This software was partially supported by the
       9             :   ADA-FS project under the SPPEXA project funded by the DFG.
      10             : 
      11             :   This file is part of GekkoFS' POSIX interface.
      12             : 
      13             :   GekkoFS' POSIX interface is free software: you can redistribute it and/or
      14             :   modify it under the terms of the GNU Lesser General Public License as
      15             :   published by the Free Software Foundation, either version 3 of the License,
      16             :   or (at your option) any later version.
      17             : 
      18             :   GekkoFS' POSIX interface is distributed in the hope that it will be useful,
      19             :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      20             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      21             :   GNU Lesser General Public License for more details.
      22             : 
      23             :   You should have received a copy of the GNU Lesser General Public License
      24             :   along with GekkoFS' POSIX interface.  If not, see
      25             :   <https://www.gnu.org/licenses/>.
      26             : 
      27             :   SPDX-License-Identifier: LGPL-3.0-or-later
      28             : */
      29             : 
      30             : #include <client/intercept.hpp>
      31             : #include <client/preload.hpp>
      32             : #include <client/hooks.hpp>
      33             : #include <client/logging.hpp>
      34             : 
      35             : #include <optional>
      36             : #include <fmt/format.h>
      37             : 
      38             : #include <cerrno>
      39             : 
      40             : extern "C" {
      41             : #include <syscall.h>
      42             : #include <sys/types.h>
      43             : #include <sys/socket.h>
      44             : #include <printf.h>
      45             : }
      46             : 
      47             : 
      48             : #ifdef BYPASS_SYSCALL
      49             : int (*intercept_hook_point)(long syscall_number, long arg0, long arg1,
      50             :                             long arg2, long arg3, long arg4, long arg5,
      51             :                             long* result){};
      52             : 
      53             : void (*intercept_hook_point_clone_child)(unsigned long flags, void* child_stack,
      54             :                                          int* ptid, int* ctid, long newtls){};
      55             : 
      56             : void (*intercept_hook_point_clone_parent)(unsigned long flags,
      57             :                                           void* child_stack, int* ptid,
      58             :                                           int* ctid, long newtls,
      59             :                                           long returned_pid){};
      60             : 
      61             : void (*intercept_hook_point_post_kernel)(long syscall_number, long arg0,
      62             :                                          long arg1, long arg2, long arg3,
      63             :                                          long arg4, long arg5, long result){};
      64             : #endif
      65             : namespace {
      66             : 
      67             : thread_local bool reentrance_guard_flag;
      68             : thread_local gkfs::syscall::info saved_syscall_info;
      69             : 
      70             : constexpr void
      71    14111112 : save_current_syscall_info(gkfs::syscall::info info) {
      72    14111112 :     saved_syscall_info = info;
      73             : }
      74             : 
      75             : constexpr void
      76    14107536 : reset_current_syscall_info() {
      77    14107536 :     saved_syscall_info = gkfs::syscall::no_info;
      78             : }
      79             : 
      80             : inline gkfs::syscall::info
      81    28216582 : get_current_syscall_info() {
      82    28216582 :     return saved_syscall_info;
      83             : }
      84             : 
      85             : 
      86             : /*
      87             :  * hook_internal -- interception hook for internal syscalls
      88             :  *
      89             :  * This hook is basically used to keep track of file descriptors created
      90             :  * internally by the library itself. This is important because some
      91             :  * applications (e.g. ssh) may attempt to close all open file descriptors
      92             :  * which would leave the library internals in an inconsistent state.
      93             :  * We forward syscalls to the kernel but we keep track of any syscalls that may
      94             :  * create or destroy a file descriptor so that we can mark them as 'internal'.
      95             :  */
      96             : inline int
      97     3419195 : hook_internal(long syscall_number, long arg0, long arg1, long arg2, long arg3,
      98             :               long arg4, long arg5, long* result) {
      99             : 
     100             : #if defined(GKFS_ENABLE_LOGGING) && defined(GKFS_DEBUG_BUILD)
     101     3419195 :     const long args[gkfs::syscall::MAX_ARGS] = {arg0, arg1, arg2,
     102     3419195 :                                                 arg3, arg4, arg5};
     103             : #endif
     104             : 
     105     3419195 :     LOG(SYSCALL,
     106             :         gkfs::syscall::from_internal_code | gkfs::syscall::to_hook |
     107             :                 gkfs::syscall::not_executed,
     108     3419263 :         syscall_number, args);
     109             : 
     110     3419263 :     switch(syscall_number) {
     111             : #ifdef SYS_open
     112           0 :         case SYS_open:
     113           0 :             *result = syscall_no_intercept_wrapper(
     114             :                     syscall_number, reinterpret_cast<char*>(arg0),
     115             :                     static_cast<int>(arg1), static_cast<mode_t>(arg2));
     116             : 
     117           0 :             if(*result > 0) {
     118           0 :                 *result = CTX->register_internal_fd(*result);
     119             :             }
     120             : 
     121             :             break;
     122             : #endif
     123             : #ifdef SYS_creat
     124           0 :         case SYS_creat:
     125           0 :             *result = syscall_no_intercept_wrapper(
     126             :                     syscall_number, reinterpret_cast<const char*>(arg0),
     127             :                     O_WRONLY | O_CREAT | O_TRUNC, static_cast<mode_t>(arg1));
     128           0 :             if(*result > 0) {
     129           0 :                 *result = CTX->register_internal_fd(*result);
     130             :             }
     131             : 
     132             :             break;
     133             : #endif
     134        3249 :         case SYS_openat:
     135        3249 :             *result = syscall_no_intercept_wrapper(
     136             :                     syscall_number, static_cast<int>(arg0),
     137             :                     reinterpret_cast<const char*>(arg1), static_cast<int>(arg2),
     138             :                     static_cast<mode_t>(arg3));
     139        3249 :             if(*result > 0) {
     140        2732 :                 *result = CTX->register_internal_fd(*result);
     141             :             }
     142             :             break;
     143             : #ifdef SYS_epoll_create
     144        1076 :         case SYS_epoll_create:
     145        1076 :             *result = syscall_no_intercept_wrapper(syscall_number,
     146             :                                                    static_cast<int>(arg0));
     147        1076 :             if(*result > 0) {
     148        1076 :                 *result = CTX->register_internal_fd(*result);
     149             :             }
     150             : 
     151             :             break;
     152             : #endif
     153         269 :         case SYS_epoll_create1:
     154         269 :             *result = syscall_no_intercept_wrapper(syscall_number,
     155             :                                                    static_cast<int>(arg0));
     156         269 :             if(*result > 0) {
     157         269 :                 *result = CTX->register_internal_fd(*result);
     158             :             }
     159             : 
     160             :             break;
     161             : 
     162           0 :         case SYS_dup:
     163           0 :             *result = syscall_no_intercept_wrapper(
     164             :                     syscall_number, static_cast<unsigned int>(arg0));
     165           0 :             if(*result > 0) {
     166           0 :                 *result = CTX->register_internal_fd(*result);
     167             :             }
     168             :             break;
     169             : #ifdef SYS_dup2
     170           0 :         case SYS_dup2:
     171           0 :             *result = syscall_no_intercept_wrapper(
     172             :                     syscall_number, static_cast<unsigned int>(arg0),
     173             :                     static_cast<unsigned int>(arg1));
     174           0 :             if(*result > 0) {
     175           0 :                 *result = CTX->register_internal_fd(*result);
     176             :             }
     177             :             break;
     178             : #endif
     179           0 :         case SYS_dup3:
     180           0 :             *result = syscall_no_intercept_wrapper(
     181             :                     syscall_number, static_cast<unsigned int>(arg0),
     182             :                     static_cast<unsigned int>(arg1), static_cast<int>(arg2));
     183             : 
     184           0 :             if(*result > 0) {
     185           0 :                 *result = CTX->register_internal_fd(*result);
     186             :             }
     187             :             break;
     188             : #ifdef SYS_inotify_init
     189           0 :         case SYS_inotify_init:
     190           0 :             *result = syscall_no_intercept_wrapper(syscall_number);
     191             : 
     192           0 :             if(*result >= 0) {
     193           0 :                 *result = CTX->register_internal_fd(*result);
     194             :             }
     195             : 
     196             :             break;
     197             : #endif
     198           0 :         case SYS_inotify_init1:
     199           0 :             *result = syscall_no_intercept_wrapper(syscall_number,
     200             :                                                    static_cast<int>(arg0));
     201             : 
     202           0 :             if(*result >= 0) {
     203           0 :                 *result = CTX->register_internal_fd(*result);
     204             :             }
     205             : 
     206             :             break;
     207             : 
     208           0 :         case SYS_perf_event_open:
     209           0 :             *result = syscall_no_intercept_wrapper(
     210             :                     syscall_number,
     211             :                     reinterpret_cast<struct perf_event_attr*>(arg0),
     212             :                     static_cast<pid_t>(arg1), static_cast<int>(arg2),
     213             :                     static_cast<int>(arg3), static_cast<unsigned long>(arg4));
     214             : 
     215           0 :             if(*result >= 0) {
     216           0 :                 *result = CTX->register_internal_fd(*result);
     217             :             }
     218             :             break;
     219             : #ifdef SYS_signalfd
     220           0 :         case SYS_signalfd:
     221           0 :             *result = syscall_no_intercept_wrapper(
     222             :                     syscall_number, static_cast<int>(arg0),
     223             :                     reinterpret_cast<const sigset_t*>(arg1));
     224             : 
     225           0 :             if(*result >= 0) {
     226           0 :                 *result = CTX->register_internal_fd(*result);
     227             :             }
     228             :             break;
     229             : #endif
     230           0 :         case SYS_signalfd4:
     231           0 :             *result = syscall_no_intercept_wrapper(
     232             :                     syscall_number, static_cast<int>(arg0),
     233             :                     reinterpret_cast<const sigset_t*>(arg1),
     234             :                     static_cast<int>(arg2));
     235             : 
     236           0 :             if(*result >= 0) {
     237           0 :                 *result = CTX->register_internal_fd(*result);
     238             :             }
     239             :             break;
     240             : 
     241           0 :         case SYS_timerfd_create:
     242           0 :             *result = syscall_no_intercept_wrapper(syscall_number,
     243             :                                                    static_cast<int>(arg0),
     244             :                                                    static_cast<int>(arg1));
     245             : 
     246           0 :             if(*result >= 0) {
     247           0 :                 *result = CTX->register_internal_fd(*result);
     248             :             }
     249             :             break;
     250             : 
     251             : 
     252        2167 :         case SYS_socket:
     253        2167 :             *result = syscall_no_intercept_wrapper(
     254             :                     syscall_number, static_cast<int>(arg0),
     255             :                     static_cast<int>(arg1), static_cast<int>(arg2));
     256             : 
     257        2167 :             if(*result >= 0) {
     258        2167 :                 *result = CTX->register_internal_fd(*result);
     259             :             }
     260             :             break;
     261             : 
     262        1076 :         case SYS_socketpair:
     263             : 
     264        1076 :             *result = syscall_no_intercept_wrapper(
     265             :                     syscall_number, static_cast<int>(arg0),
     266             :                     static_cast<int>(arg1), static_cast<int>(arg2),
     267             :                     reinterpret_cast<int*>(arg3));
     268             : 
     269        1076 :             if(*result >= 0) {
     270        1076 :                 reinterpret_cast<int*>(arg3)[0] = CTX->register_internal_fd(
     271             :                         reinterpret_cast<int*>(arg3)[0]);
     272        2152 :                 reinterpret_cast<int*>(arg3)[1] = CTX->register_internal_fd(
     273        1076 :                         reinterpret_cast<int*>(arg3)[1]);
     274             :             }
     275             : 
     276             :             break;
     277             : #ifdef SYS_pipe
     278           0 :         case SYS_pipe:
     279           0 :             *result = syscall_no_intercept_wrapper(
     280             :                     syscall_number, reinterpret_cast<int*>(arg0));
     281             : 
     282           0 :             if(*result >= 0) {
     283           0 :                 reinterpret_cast<int*>(arg0)[0] = CTX->register_internal_fd(
     284             :                         reinterpret_cast<int*>(arg0)[0]);
     285           0 :                 reinterpret_cast<int*>(arg0)[1] = CTX->register_internal_fd(
     286           0 :                         reinterpret_cast<int*>(arg0)[1]);
     287             :             }
     288             : 
     289             :             break;
     290             : #endif
     291           0 :         case SYS_pipe2:
     292             : 
     293           0 :             *result = syscall_no_intercept_wrapper(syscall_number,
     294             :                                                    reinterpret_cast<int*>(arg0),
     295             :                                                    static_cast<int>(arg1));
     296           0 :             if(*result >= 0) {
     297           0 :                 reinterpret_cast<int*>(arg0)[0] = CTX->register_internal_fd(
     298             :                         reinterpret_cast<int*>(arg0)[0]);
     299           0 :                 reinterpret_cast<int*>(arg0)[1] = CTX->register_internal_fd(
     300           0 :                         reinterpret_cast<int*>(arg0)[1]);
     301             :             }
     302             : 
     303             :             break;
     304             : #ifdef SYS_eventfd
     305           0 :         case SYS_eventfd:
     306             : 
     307           0 :             *result = syscall_no_intercept_wrapper(syscall_number,
     308             :                                                    static_cast<int>(arg0));
     309             : 
     310           0 :             if(*result >= 0) {
     311           0 :                 *result = CTX->register_internal_fd(*result);
     312             :             }
     313             :             break;
     314             : #endif
     315         269 :         case SYS_eventfd2:
     316             : 
     317         269 :             *result = syscall_no_intercept_wrapper(syscall_number,
     318             :                                                    static_cast<int>(arg0),
     319             :                                                    static_cast<int>(arg1));
     320             : 
     321         269 :             if(*result >= 0) {
     322         269 :                 *result = CTX->register_internal_fd(*result);
     323             :             }
     324             :             break;
     325             : 
     326        3228 :         case SYS_recvmsg: {
     327        3228 :             *result = syscall_no_intercept_wrapper(
     328             :                     syscall_number, static_cast<int>(arg0),
     329             :                     reinterpret_cast<struct msghdr*>(arg1),
     330             :                     static_cast<int>(arg2));
     331             : 
     332             :             // The recvmsg() syscall can receive file descriptors from another
     333             :             // process that the kernel automatically adds to the client's fds
     334             :             // as if dup2 had been called. Whenever that happens, we need to
     335             :             // make sure that we register these additional fds as internal, or
     336             :             // we could inadvertently overwrite them
     337        3228 :             if(*result >= 0) {
     338        3228 :                 auto* hdr = reinterpret_cast<struct msghdr*>(arg1);
     339        3228 :                 struct cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
     340             : 
     341        3228 :                 for(; cmsg != NULL; cmsg = CMSG_NXTHDR(hdr, cmsg)) {
     342           0 :                     if(cmsg->cmsg_type == SCM_RIGHTS) {
     343             : 
     344           0 :                         size_t nfd = cmsg->cmsg_len > CMSG_LEN(0)
     345           0 :                                              ? (cmsg->cmsg_len - CMSG_LEN(0)) /
     346             :                                                        sizeof(int)
     347             :                                              : 0;
     348             : 
     349           0 :                         int* fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
     350             : 
     351           0 :                         for(size_t i = 0; i < nfd; ++i) {
     352           0 :                             LOG(DEBUG, "recvmsg() provided extra fd {}",
     353           0 :                                 fds[i]);
     354             : 
     355             :                             // ensure we update the fds in cmsg
     356             :                             // if they have been relocated
     357           0 :                             fds[i] = CTX->register_internal_fd(fds[i]);
     358             :                         }
     359             :                     }
     360             :                 }
     361             :             }
     362             : 
     363             :             break;
     364             :         }
     365             : 
     366           0 :         case SYS_accept:
     367           0 :             *result = syscall_no_intercept_wrapper(
     368             :                     syscall_number, static_cast<int>(arg0),
     369             :                     reinterpret_cast<struct sockaddr*>(arg1),
     370             :                     reinterpret_cast<int*>(arg2));
     371             : 
     372           0 :             if(*result >= 0) {
     373           0 :                 *result = CTX->register_internal_fd(*result);
     374             :             }
     375             :             break;
     376             : 
     377           0 :         case SYS_accept4:
     378           0 :             *result = syscall_no_intercept_wrapper(
     379             :                     syscall_number, static_cast<int>(arg0),
     380             :                     reinterpret_cast<struct sockaddr*>(arg1),
     381             :                     reinterpret_cast<int*>(arg2), static_cast<int>(arg3));
     382             : 
     383           0 :             if(*result >= 0) {
     384           0 :                 *result = CTX->register_internal_fd(*result);
     385             :             }
     386             :             break;
     387             : 
     388             : 
     389        3826 :         case SYS_fcntl:
     390        3826 :             *result = syscall_no_intercept_wrapper(
     391             :                     syscall_number, static_cast<int>(arg0),
     392             :                     static_cast<int>(arg1), arg2);
     393             : 
     394        3826 :             if(*result >= 0) {
     395             : 
     396             : 
     397        3826 :                 if((static_cast<int>(arg1) == F_DUPFD ||
     398             :                     static_cast<int>(arg1) == F_DUPFD_CLOEXEC)) {
     399           0 :                     *result = CTX->register_internal_fd(*result);
     400             :                 }
     401             :             }
     402             :             break;
     403             : 
     404        4077 :         case SYS_close:
     405        4077 :             *result = syscall_no_intercept_wrapper(syscall_number,
     406             :                                                    static_cast<int>(arg0));
     407        4077 :             if(*result >= 0) {
     408        4077 :                 CTX->unregister_internal_fd(arg0);
     409             :             }
     410             :             break;
     411             : 
     412     3400026 :         default:
     413             :             // ignore any other syscalls, i.e.: pass them on to the kernel
     414             :             // (syscalls forwarded to the kernel that return are logged in
     415             :             // hook_forwarded_syscall())
     416     3400026 :             ::save_current_syscall_info(gkfs::syscall::from_internal_code |
     417             :                                         gkfs::syscall::to_kernel |
     418             :                                         gkfs::syscall::not_executed);
     419     3400026 :             return gkfs::syscall::forward_to_kernel;
     420             :     }
     421             : 
     422       19237 :     LOG(SYSCALL,
     423             :         gkfs::syscall::from_internal_code | gkfs::syscall::to_hook |
     424             :                 gkfs::syscall::executed,
     425             :         syscall_number, args, *result);
     426             : 
     427             :     return gkfs::syscall::hooked;
     428             : }
     429             : 
     430             : /*
     431             :  * hook -- interception hook for application syscalls
     432             :  *
     433             :  * This hook is used to implement any application filesystem-related syscalls.
     434             :  */
     435             : inline int
     436    11117815 : hook(long syscall_number, long arg0, long arg1, long arg2, long arg3, long arg4,
     437             :      long arg5, long* result) {
     438             : 
     439             : #if defined(GKFS_ENABLE_LOGGING) && defined(GKFS_DEBUG_BUILD)
     440    11117815 :     const long args[gkfs::syscall::MAX_ARGS] = {arg0, arg1, arg2,
     441    11117815 :                                                 arg3, arg4, arg5};
     442             : #endif
     443             : 
     444    11117815 :     LOG(SYSCALL,
     445             :         gkfs::syscall::from_external_code | gkfs::syscall::to_hook |
     446             :                 gkfs::syscall::not_executed,
     447    11122573 :         syscall_number, args);
     448             : 
     449    11122573 :     switch(syscall_number) {
     450             : 
     451           0 :         case SYS_execve:
     452           0 :             *result = syscall_no_intercept_wrapper(
     453             :                     syscall_number, reinterpret_cast<const char*>(arg0),
     454             :                     reinterpret_cast<const char* const*>(arg1),
     455             :                     reinterpret_cast<const char* const*>(arg2));
     456           0 :             break;
     457             : 
     458             : #ifdef SYS_execveat
     459           0 :         case SYS_execveat:
     460           0 :             *result = syscall_no_intercept_wrapper(
     461             :                     syscall_number, arg0, reinterpret_cast<const char*>(arg1),
     462             :                     reinterpret_cast<const char* const*>(arg2),
     463             :                     reinterpret_cast<const char* const*>(arg3), arg4);
     464           0 :             break;
     465             : #endif
     466             : #ifdef SYS_open
     467           1 :         case SYS_open:
     468           1 :             *result = gkfs::hook::hook_openat(
     469             :                     AT_FDCWD, reinterpret_cast<char*>(arg0),
     470             :                     static_cast<int>(arg1), static_cast<mode_t>(arg2));
     471           1 :             break;
     472             : #endif
     473             : #ifdef SYS_creat
     474        1004 :         case SYS_creat:
     475        1004 :             *result = gkfs::hook::hook_openat(
     476             :                     AT_FDCWD, reinterpret_cast<const char*>(arg0),
     477             :                     O_WRONLY | O_CREAT | O_TRUNC, static_cast<mode_t>(arg1));
     478        1004 :             break;
     479             : #endif
     480        8763 :         case SYS_openat:
     481        8763 :             *result = gkfs::hook::hook_openat(
     482             :                     static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
     483             :                     static_cast<int>(arg2), static_cast<mode_t>(arg3));
     484        8763 :             break;
     485             : 
     486       12724 :         case SYS_close:
     487       12724 :             *result = gkfs::hook::hook_close(static_cast<int>(arg0));
     488       12724 :             break;
     489             : #ifdef SYS_stat
     490          46 :         case SYS_stat:
     491          92 :             *result =
     492          46 :                     gkfs::hook::hook_stat(reinterpret_cast<char*>(arg0),
     493             :                                           reinterpret_cast<struct stat*>(arg1));
     494          46 :             break;
     495             : #endif
     496             : #ifdef STATX_TYPE
     497           4 :         case SYS_statx:
     498           4 :             *result = gkfs::hook::hook_statx(
     499             :                     static_cast<int>(arg0), reinterpret_cast<char*>(arg1),
     500             :                     static_cast<int>(arg2), static_cast<unsigned int>(arg3),
     501             :                     reinterpret_cast<struct statx*>(arg4));
     502           4 :             break;
     503             : #endif
     504             : #ifdef SYS_lstat
     505           2 :         case SYS_lstat:
     506           2 :             *result = gkfs::hook::hook_lstat(
     507             :                     reinterpret_cast<char*>(arg0),
     508             :                     reinterpret_cast<struct stat*>(arg1));
     509           2 :             break;
     510             : #endif
     511         291 :         case SYS_fstat:
     512         291 :             *result = gkfs::hook::hook_fstat(
     513             :                     static_cast<int>(arg0),
     514             :                     reinterpret_cast<struct stat*>(arg1));
     515         291 :             break;
     516             : 
     517           0 :         case SYS_newfstatat:
     518           0 :             *result = gkfs::hook::hook_fstatat(
     519             :                     static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
     520             :                     reinterpret_cast<struct stat*>(arg2),
     521             :                     static_cast<int>(arg3));
     522           0 :             break;
     523             : 
     524      182329 :         case SYS_read:
     525      182329 :             *result = gkfs::hook::hook_read(static_cast<unsigned int>(arg0),
     526             :                                             reinterpret_cast<void*>(arg1),
     527             :                                             static_cast<size_t>(arg2));
     528      182329 :             break;
     529             : 
     530           2 :         case SYS_pread64:
     531           2 :             *result = gkfs::hook::hook_pread(static_cast<unsigned int>(arg0),
     532             :                                              reinterpret_cast<char*>(arg1),
     533             :                                              static_cast<size_t>(arg2),
     534             :                                              static_cast<loff_t>(arg3));
     535           2 :             break;
     536             : 
     537           1 :         case SYS_readv:
     538           1 :             *result = gkfs::hook::hook_readv(
     539             :                     static_cast<unsigned long>(arg0),
     540             :                     reinterpret_cast<const struct iovec*>(arg1),
     541             :                     static_cast<unsigned long>(arg2));
     542           1 :             break;
     543             : 
     544           1 :         case SYS_preadv:
     545           1 :             *result = gkfs::hook::hook_preadv(
     546             :                     static_cast<unsigned long>(arg0),
     547             :                     reinterpret_cast<const struct iovec*>(arg1),
     548             :                     static_cast<unsigned long>(arg2),
     549             :                     static_cast<unsigned long>(arg3),
     550             :                     static_cast<unsigned long>(arg4));
     551           1 :             break;
     552             : 
     553           3 :         case SYS_pwrite64:
     554           3 :             *result = gkfs::hook::hook_pwrite(
     555             :                     static_cast<unsigned int>(arg0),
     556             :                     reinterpret_cast<const char*>(arg1),
     557             :                     static_cast<size_t>(arg2), static_cast<loff_t>(arg3));
     558           3 :             break;
     559      180426 :         case SYS_write:
     560      360852 :             *result =
     561      180426 :                     gkfs::hook::hook_write(static_cast<unsigned int>(arg0),
     562             :                                            reinterpret_cast<const char*>(arg1),
     563             :                                            static_cast<size_t>(arg2));
     564      180426 :             break;
     565             : 
     566           2 :         case SYS_writev:
     567           2 :             *result = gkfs::hook::hook_writev(
     568             :                     static_cast<unsigned long>(arg0),
     569             :                     reinterpret_cast<const struct iovec*>(arg1),
     570             :                     static_cast<unsigned long>(arg2));
     571           2 :             break;
     572             : 
     573           2 :         case SYS_pwritev:
     574           2 :             *result = gkfs::hook::hook_pwritev(
     575             :                     static_cast<unsigned long>(arg0),
     576             :                     reinterpret_cast<const struct iovec*>(arg1),
     577             :                     static_cast<unsigned long>(arg2),
     578             :                     static_cast<unsigned long>(arg3),
     579             :                     static_cast<unsigned long>(arg4));
     580           2 :             break;
     581             : #ifdef SYS_unlink
     582           6 :         case SYS_unlink:
     583           6 :             *result = gkfs::hook::hook_unlinkat(
     584             :                     AT_FDCWD, reinterpret_cast<const char*>(arg0), 0);
     585           6 :             break;
     586             : #endif
     587           1 :         case SYS_unlinkat:
     588           1 :             *result = gkfs::hook::hook_unlinkat(
     589             :                     static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
     590             :                     static_cast<int>(arg2));
     591           1 :             break;
     592             : #ifdef SYS_rmdir
     593           8 :         case SYS_rmdir:
     594           8 :             *result = gkfs::hook::hook_unlinkat(
     595             :                     AT_FDCWD, reinterpret_cast<const char*>(arg0),
     596             :                     AT_REMOVEDIR);
     597           8 :             break;
     598             : #endif
     599             : #ifdef SYS_symlink
     600           1 :         case SYS_symlink:
     601           1 :             *result = gkfs::hook::hook_symlinkat(
     602             :                     reinterpret_cast<const char*>(arg0), AT_FDCWD,
     603             :                     reinterpret_cast<const char*>(arg1));
     604           1 :             break;
     605             : #endif
     606           0 :         case SYS_symlinkat:
     607           0 :             *result = gkfs::hook::hook_symlinkat(
     608             :                     reinterpret_cast<const char*>(arg0), static_cast<int>(arg1),
     609             :                     reinterpret_cast<const char*>(arg2));
     610           0 :             break;
     611             : #ifdef SYS_access
     612           5 :         case SYS_access:
     613          10 :             *result =
     614           5 :                     gkfs::hook::hook_access(reinterpret_cast<const char*>(arg0),
     615             :                                             static_cast<int>(arg1));
     616           5 :             break;
     617             : #endif
     618           4 :         case SYS_faccessat:
     619           4 :             *result = gkfs::hook::hook_faccessat(
     620             :                     static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
     621             :                     static_cast<int>(arg2));
     622           4 :             break;
     623             : #ifdef SYS_faccessat2
     624             :         case SYS_faccessat2:
     625             :             *result = gkfs::hook::hook_faccessat2(
     626             :                     static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
     627             :                     static_cast<int>(arg2), static_cast<int>(arg3));
     628             :             break;
     629             : #endif
     630        8589 :         case SYS_lseek:
     631        8589 :             *result = gkfs::hook::hook_lseek(static_cast<unsigned int>(arg0),
     632             :                                              static_cast<off_t>(arg1),
     633             :                                              static_cast<unsigned int>(arg2));
     634        8589 :             break;
     635             : 
     636           7 :         case SYS_truncate:
     637           7 :             *result = gkfs::hook::hook_truncate(
     638             :                     reinterpret_cast<const char*>(arg0),
     639             :                     static_cast<long>(arg1));
     640           7 :             break;
     641             : 
     642           2 :         case SYS_ftruncate:
     643           2 :             *result = gkfs::hook::hook_ftruncate(
     644             :                     static_cast<unsigned int>(arg0),
     645             :                     static_cast<unsigned long>(arg1));
     646           2 :             break;
     647             : 
     648           2 :         case SYS_dup:
     649           2 :             *result = gkfs::hook::hook_dup(static_cast<unsigned int>(arg0));
     650           2 :             break;
     651             : #ifdef SYS_dup2
     652           2 :         case SYS_dup2:
     653           2 :             *result = gkfs::hook::hook_dup2(static_cast<unsigned int>(arg0),
     654             :                                             static_cast<unsigned int>(arg1));
     655           2 :             break;
     656             : #endif
     657           2 :         case SYS_dup3:
     658           2 :             *result = gkfs::hook::hook_dup3(static_cast<unsigned int>(arg0),
     659             :                                             static_cast<unsigned int>(arg1),
     660             :                                             static_cast<int>(arg2));
     661           2 :             break;
     662             : #ifdef SYS_getdents
     663           0 :         case SYS_getdents:
     664           0 :             *result = gkfs::hook::hook_getdents(
     665             :                     static_cast<unsigned int>(arg0),
     666             :                     reinterpret_cast<struct linux_dirent*>(arg1),
     667             :                     static_cast<unsigned int>(arg2));
     668           0 :             break;
     669             : #endif
     670          36 :         case SYS_getdents64:
     671          36 :             *result = gkfs::hook::hook_getdents64(
     672             :                     static_cast<unsigned int>(arg0),
     673             :                     reinterpret_cast<struct linux_dirent64*>(arg1),
     674             :                     static_cast<unsigned int>(arg2));
     675          36 :             break;
     676             : 
     677           1 :         case SYS_mkdirat:
     678           1 :             *result = gkfs::hook::hook_mkdirat(
     679             :                     static_cast<unsigned int>(arg0),
     680             :                     reinterpret_cast<const char*>(arg1),
     681             :                     static_cast<mode_t>(arg2));
     682           1 :             break;
     683             : #ifdef SYS_mkdir
     684          18 :         case SYS_mkdir:
     685          18 :             *result = gkfs::hook::hook_mkdirat(
     686             :                     AT_FDCWD, reinterpret_cast<const char*>(arg0),
     687             :                     static_cast<mode_t>(arg1));
     688          18 :             break;
     689             : #endif
     690             : #ifdef SYS_chmod
     691           1 :         case SYS_chmod:
     692           1 :             *result = gkfs::hook::hook_fchmodat(AT_FDCWD,
     693             :                                                 reinterpret_cast<char*>(arg0),
     694             :                                                 static_cast<mode_t>(arg1));
     695           1 :             break;
     696             : #endif
     697           2 :         case SYS_fchmod:
     698           2 :             *result = gkfs::hook::hook_fchmod(static_cast<unsigned int>(arg0),
     699             :                                               static_cast<mode_t>(arg1));
     700           2 :             break;
     701             : 
     702           2 :         case SYS_fchmodat:
     703           2 :             *result = gkfs::hook::hook_fchmodat(static_cast<unsigned int>(arg0),
     704             :                                                 reinterpret_cast<char*>(arg1),
     705             :                                                 static_cast<mode_t>(arg2));
     706           2 :             break;
     707             : 
     708           0 :         case SYS_flock:
     709           0 :             *result = gkfs::hook::hook_flock(static_cast<unsigned int>(arg0),
     710             :                                              static_cast<unsigned int>(arg1));
     711           0 :             break;
     712           9 :         case SYS_chdir:
     713          18 :             *result =
     714           9 :                     gkfs::hook::hook_chdir(reinterpret_cast<const char*>(arg0));
     715           9 :             break;
     716             : 
     717           3 :         case SYS_fchdir:
     718           3 :             *result = gkfs::hook::hook_fchdir(static_cast<unsigned int>(arg0));
     719           3 :             break;
     720             : 
     721           5 :         case SYS_getcwd:
     722           5 :             *result = gkfs::hook::hook_getcwd(reinterpret_cast<char*>(arg0),
     723             :                                               static_cast<unsigned long>(arg1));
     724           5 :             break;
     725             : #ifdef SYS_readlink
     726           0 :         case SYS_readlink:
     727           0 :             *result = gkfs::hook::hook_readlinkat(
     728             :                     AT_FDCWD, reinterpret_cast<const char*>(arg0),
     729             :                     reinterpret_cast<char*>(arg1), static_cast<int>(arg2));
     730           0 :             break;
     731             : #endif
     732           1 :         case SYS_readlinkat:
     733           1 :             *result = gkfs::hook::hook_readlinkat(
     734             :                     static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
     735             :                     reinterpret_cast<char*>(arg2), static_cast<int>(arg3));
     736           1 :             break;
     737             : 
     738       17160 :         case SYS_fcntl:
     739       17160 :             *result = gkfs::hook::hook_fcntl(static_cast<unsigned int>(arg0),
     740             :                                              static_cast<unsigned int>(arg1),
     741             :                                              static_cast<unsigned long>(arg2));
     742       17160 :             break;
     743             : #ifdef SYS_rename
     744          12 :         case SYS_rename:
     745          12 :             *result = gkfs::hook::hook_renameat(
     746             :                     AT_FDCWD, reinterpret_cast<const char*>(arg0), AT_FDCWD,
     747             :                     reinterpret_cast<const char*>(arg1), 0);
     748          12 :             break;
     749             : #endif
     750           2 :         case SYS_renameat:
     751           2 :             *result = gkfs::hook::hook_renameat(
     752             :                     static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
     753             :                     static_cast<int>(arg2), reinterpret_cast<const char*>(arg3),
     754             :                     0);
     755           2 :             break;
     756             : 
     757           0 :         case SYS_renameat2:
     758           0 :             *result = gkfs::hook::hook_renameat(
     759             :                     static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
     760             :                     static_cast<int>(arg2), reinterpret_cast<const char*>(arg3),
     761             :                     static_cast<unsigned int>(arg4));
     762           0 :             break;
     763             : 
     764           2 :         case SYS_fstatfs:
     765           2 :             *result = gkfs::hook::hook_fstatfs(
     766             :                     static_cast<unsigned int>(arg0),
     767             :                     reinterpret_cast<struct statfs*>(arg1));
     768           2 :             break;
     769             : 
     770           1 :         case SYS_statfs:
     771           1 :             *result = gkfs::hook::hook_statfs(
     772             :                     reinterpret_cast<const char*>(arg0),
     773             :                     reinterpret_cast<struct statfs*>(arg1));
     774           1 :             break;
     775             : 
     776           1 :         case SYS_fdatasync:
     777           1 :         case SYS_fsync:
     778           1 :             *result = gkfs::hook::hook_fsync(static_cast<unsigned int>(arg0));
     779           1 :             break;
     780             : 
     781           1 :         case SYS_getxattr:
     782           1 :             *result = gkfs::hook::hook_getxattr(
     783             :                     reinterpret_cast<const char*>(arg0),
     784             :                     reinterpret_cast<const char*>(arg1),
     785             :                     reinterpret_cast<void*>(arg2), static_cast<size_t>(arg4));
     786           1 :             break;
     787             : 
     788    10711086 :         default:
     789             :             // ignore any other syscalls, i.e.: pass them on to the kernel
     790             :             // (syscalls forwarded to the kernel that return are logged in
     791             :             // hook_forwarded_syscall())
     792    10711086 :             ::save_current_syscall_info(gkfs::syscall::from_external_code |
     793             :                                         gkfs::syscall::to_kernel |
     794             :                                         gkfs::syscall::not_executed);
     795    10711086 :             return gkfs::syscall::forward_to_kernel;
     796             :     }
     797             : 
     798      411487 :     LOG(SYSCALL,
     799             :         gkfs::syscall::from_external_code | gkfs::syscall::to_hook |
     800             :                 gkfs::syscall::executed,
     801             :         syscall_number, args, *result);
     802             : 
     803             :     return gkfs::syscall::hooked;
     804             : }
     805             : 
     806             : #ifdef SYS_socketcall
     807             : /* Wraps socketcall in powerpc9, we only change syscalls that need special
     808             :  * treatment */
     809             : long
     810             : socketcall_wrapper(long syscall_number, long& arg0, long& arg1, long& arg2,
     811             :                    long& arg3, long& arg4, long& arg5) {
     812             : 
     813             :     switch(static_cast<int>(arg0)) {
     814             :         case 1:
     815             :             syscall_number = SYS_socket;
     816             :             break;
     817             :         case 5:
     818             :             syscall_number = SYS_accept;
     819             :             break;
     820             : 
     821             :         case 17:
     822             :             syscall_number = SYS_recvmsg;
     823             :             break;
     824             :         case 18:
     825             :             syscall_number = SYS_accept4;
     826             :             break;
     827             :         case 19:
     828             :             syscall_number = SYS_recvmmsg;
     829             :             break;
     830             : 
     831             :         default:
     832             :             break;
     833             :     }
     834             :     if(syscall_number != SYS_socketcall) {
     835             :         long int* parameters = (long int*) arg1;
     836             :         arg0 = static_cast<long>(*parameters);
     837             :         parameters++;
     838             :         arg1 = static_cast<long>(*parameters);
     839             :         parameters++;
     840             :         arg2 = static_cast<long>(*parameters);
     841             :         parameters++;
     842             :         arg3 = static_cast<long>(*parameters);
     843             :         parameters++;
     844             :         arg4 = static_cast<long>(*parameters);
     845             :         parameters++;
     846             :         arg5 = static_cast<long>(*parameters);
     847             :     }
     848             : 
     849             :     return syscall_number;
     850             : }
     851             : #endif
     852             : 
     853             : 
     854             : void
     855    14108155 : hook_forwarded_syscall(long syscall_number, long arg0, long arg1, long arg2,
     856             :                        long arg3, long arg4, long arg5, long result) {
     857             : 
     858    14108155 :     if(::get_current_syscall_info() == gkfs::syscall::no_info) {
     859           0 :         return;
     860             :     }
     861             : 
     862             : #if defined(GKFS_ENABLE_LOGGING) && defined(GKFS_DEBUG_BUILD)
     863    14108155 :     const long args[gkfs::syscall::MAX_ARGS] = {arg0, arg1, arg2,
     864    14108155 :                                                 arg3, arg4, arg5};
     865             : #endif
     866             : 
     867    14108155 :     LOG(SYSCALL, ::get_current_syscall_info() | gkfs::syscall::executed,
     868    14107536 :         syscall_number, args, result);
     869             : 
     870    14107536 :     ::reset_current_syscall_info();
     871             : }
     872             : 
     873             : void
     874        1097 : hook_clone_at_child(unsigned long flags, void* child_stack, int* ptid,
     875             :                     int* ctid, long newtls) {
     876             : 
     877             : #if defined(GKFS_ENABLE_LOGGING) && defined(GKFS_DEBUG_BUILD)
     878        1097 :     const long args[gkfs::syscall::MAX_ARGS] = {
     879        1097 :             static_cast<long>(flags),     reinterpret_cast<long>(child_stack),
     880             :             reinterpret_cast<long>(ptid), reinterpret_cast<long>(ctid),
     881        1097 :             static_cast<long>(newtls),    0};
     882             : #endif
     883             : 
     884        1097 :     reentrance_guard_flag = true;
     885             : 
     886        1097 :     LOG(SYSCALL, ::get_current_syscall_info() | gkfs::syscall::executed,
     887        1097 :         SYS_clone, args, 0);
     888             : 
     889        1097 :     reentrance_guard_flag = false;
     890        1097 : }
     891             : 
     892             : void
     893        1097 : hook_clone_at_parent(unsigned long flags, void* child_stack, int* ptid,
     894             :                      int* ctid, long newtls, long returned_pid) {
     895             : 
     896             : #if defined(GKFS_ENABLE_LOGGING) && defined(GKFS_DEBUG_BUILD)
     897        1097 :     const long args[gkfs::syscall::MAX_ARGS] = {
     898        1097 :             static_cast<long>(flags),     reinterpret_cast<long>(child_stack),
     899             :             reinterpret_cast<long>(ptid), reinterpret_cast<long>(ctid),
     900        1097 :             static_cast<long>(newtls),    0};
     901             : #endif
     902             : 
     903        1097 :     reentrance_guard_flag = true;
     904             : 
     905        1097 :     LOG(SYSCALL, ::get_current_syscall_info() | gkfs::syscall::executed,
     906        1097 :         SYS_clone, args, returned_pid);
     907             : 
     908        1097 :     reentrance_guard_flag = false;
     909        1097 : }
     910             : 
     911             : } // namespace
     912             : 
     913             : namespace gkfs::preload {
     914             : 
     915             : int
     916     3282814 : internal_hook_guard_wrapper(long syscall_number, long arg0, long arg1,
     917             :                             long arg2, long arg3, long arg4, long arg5,
     918             :                             long* syscall_return_value) {
     919     3282814 :     assert(CTX->interception_enabled());
     920             : 
     921             : #ifdef SYS_socketcall
     922             :     if(syscall_number == SYS_socketcall)
     923             :         syscall_number = socketcall_wrapper(syscall_number, arg0, arg1, arg2,
     924             :                                             arg3, arg4, arg5);
     925             : #endif
     926             : 
     927     3282705 :     if(reentrance_guard_flag) {
     928           0 :         ::save_current_syscall_info(gkfs::syscall::from_internal_code |
     929             :                                     gkfs::syscall::to_kernel |
     930             :                                     gkfs::syscall::not_executed);
     931           0 :         return gkfs::syscall::forward_to_kernel;
     932             :     }
     933             : 
     934     3282705 :     int was_hooked = 0;
     935             : 
     936     3282705 :     reentrance_guard_flag = true;
     937     3282705 :     was_hooked = hook_internal(syscall_number, arg0, arg1, arg2, arg3, arg4,
     938             :                                arg5, syscall_return_value);
     939     3282717 :     reentrance_guard_flag = false;
     940             : 
     941     3282717 :     return was_hooked;
     942             : }
     943             : 
     944             : 
     945             : /*
     946             :  * hook_guard_wrapper -- a wrapper which can notice reentrance.
     947             :  *
     948             :  * The reentrance_guard_flag flag allows the library to distinguish the hooking
     949             :  * of its own syscalls. E.g. while handling an open() syscall,
     950             :  * libgkfs_intercept might call fopen(), which in turn uses an open()
     951             :  * syscall internally. This internally used open() syscall is once again
     952             :  * forwarded to libgkfs_intercept, but using this flag we can notice this
     953             :  * case of reentering itself.
     954             :  *
     955             :  * XXX This approach still contains a very significant bug, as libgkfs_intercept
     956             :  * being called inside a signal handler might easily forward a mock fd to the
     957             :  * kernel.
     958             :  */
     959             : int
     960    11255415 : hook_guard_wrapper(long syscall_number, long arg0, long arg1, long arg2,
     961             :                    long arg3, long arg4, long arg5,
     962             :                    long* syscall_return_value) {
     963             : 
     964    11255415 :     assert(CTX->interception_enabled());
     965             : 
     966             : #ifdef SYS_socketcall
     967             :     if(syscall_number == SYS_socketcall)
     968             :         syscall_number = socketcall_wrapper(syscall_number, arg0, arg1, arg2,
     969             :                                             arg3, arg4, arg5);
     970             : #endif
     971             : 
     972    11254910 :     int was_hooked = 0;
     973             : 
     974    11254910 :     if(reentrance_guard_flag) {
     975             : 
     976      136515 :         was_hooked = hook_internal(syscall_number, arg0, arg1, arg2, arg3, arg4,
     977             :                                    arg5, syscall_return_value);
     978      136515 :         return was_hooked;
     979             :     }
     980             : 
     981    11118395 :     reentrance_guard_flag = true;
     982             : 
     983    11118395 :     was_hooked = ::hook(syscall_number, arg0, arg1, arg2, arg3, arg4, arg5,
     984             :                         syscall_return_value);
     985             : 
     986    11119207 :     reentrance_guard_flag = false;
     987             : 
     988    11119207 :     return was_hooked;
     989             : }
     990             : 
     991             : void
     992         269 : start_self_interception() {
     993             : 
     994         269 :     LOG(DEBUG, "Enabling syscall interception for self");
     995             : 
     996         269 :     intercept_hook_point = internal_hook_guard_wrapper;
     997         269 :     intercept_hook_point_post_kernel = hook_forwarded_syscall;
     998         269 :     intercept_hook_point_clone_child = hook_clone_at_child;
     999         269 :     intercept_hook_point_clone_parent = hook_clone_at_parent;
    1000         269 : }
    1001             : 
    1002             : void
    1003         269 : start_interception() {
    1004             : 
    1005         269 :     assert(CTX->interception_enabled());
    1006             : 
    1007         269 :     LOG(DEBUG, "Enabling syscall interception for client process");
    1008             : 
    1009             :     // Set up the callback function pointer
    1010         269 :     intercept_hook_point = hook_guard_wrapper;
    1011         269 :     intercept_hook_point_post_kernel = hook_forwarded_syscall;
    1012         269 :     intercept_hook_point_clone_child = hook_clone_at_child;
    1013         269 :     intercept_hook_point_clone_parent = hook_clone_at_parent;
    1014         269 : }
    1015             : 
    1016             : void
    1017         269 : stop_interception() {
    1018         269 :     assert(CTX->interception_enabled());
    1019             : 
    1020         269 :     LOG(DEBUG, "Disabling syscall interception for client process");
    1021             : 
    1022             :     // Reset callback function pointer
    1023         269 :     intercept_hook_point = nullptr;
    1024         269 :     intercept_hook_point_post_kernel = nullptr;
    1025         269 :     intercept_hook_point_clone_child = nullptr;
    1026         269 :     intercept_hook_point_clone_parent = nullptr;
    1027         269 : }
    1028             : 
    1029             : } // namespace gkfs::preload

Generated by: LCOV version 1.16