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

Generated by: LCOV version 1.16