Program Listing for File syscall.hpp

Return to documentation for file (include/client/syscalls/syscall.hpp)

/*
  Copyright 2018-2024, Barcelona Supercomputing Center (BSC), Spain
  Copyright 2015-2024, Johannes Gutenberg Universitaet Mainz, Germany

  This software was partially supported by the
  EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).

  This software was partially supported by the
  ADA-FS project under the SPPEXA project funded by the DFG.

  This file is part of GekkoFS' POSIX interface.

  GekkoFS' POSIX interface is free software: you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public License as
  published by the Free Software Foundation, either version 3 of the License,
  or (at your option) any later version.

  GekkoFS' POSIX interface is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with GekkoFS' POSIX interface.  If not, see
  <https://www.gnu.org/licenses/>.

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

// This file uses special C formatting for a better overview
// clang-format off

#ifndef GKFS_SYSCALL_HPP
#define GKFS_SYSCALL_HPP

#include <client/syscalls/args.hpp>
#include <client/syscalls/rets.hpp>
#include <client/syscalls/errno.hpp>
#include <client/syscalls/detail/syscall_info.h>

namespace gkfs::syscall {

static const auto constexpr MAX_ARGS = 6u;
using arg_list = std::array<arg::desc, MAX_ARGS>;

struct descriptor : private ::syscall_info {

    long
    number() const {
        return s_nr;
    }

    const char*
    name() const {
        return s_name;
    }

    int
    num_args() const {
        return s_nargs;
    }

    arg_list
    args() const {

        std::array<arg::desc, MAX_ARGS> args;

        for(auto i = 0u; i < MAX_ARGS; ++i) {
            args[i] = {static_cast<arg::type>(s_args[i].a_type),
                       s_args[i].a_name};
        }

        return args;
    }

    ret::desc
    return_type() const {
        return ret::desc{static_cast<ret::type>(s_return_type.r_type)};
    }
};

static inline descriptor
lookup_by_number(const long syscall_number) {
    const auto* info = ::get_syscall_info(syscall_number, nullptr);
    return *reinterpret_cast<const descriptor*>(info);
}

static inline descriptor
lookup_by_number(const long syscall_number, const long argv[MAX_ARGS]) {
    const auto* info = ::get_syscall_info(syscall_number, argv);
    return *reinterpret_cast<const descriptor*>(info);
}

static inline descriptor
lookup_by_name(const std::string syscall_name) {
    const auto* info = ::get_syscall_info_by_name(syscall_name.c_str());
    return *reinterpret_cast<const descriptor*>(info);
}

static inline bool
never_returns(const long syscall_number) {
    const auto desc = lookup_by_number(syscall_number);
    return desc.return_type() == ret::none;
}

static inline bool
always_returns(const long syscall_number) {
    return !never_returns(syscall_number);
}

static inline bool
may_not_return(const long syscall_number) {
    return syscall_number == SYS_execve
#ifdef SYS_execveat
        || syscall_number == SYS_execveat
#endif
        ;
}


// information about a syscall
enum class info : int {
    unknown        = 0x00000000, // no info (reset)

    // syscall origin
    internal       = 0x00000001, // syscall originates from GekkoFS' internals
    external       = 0x00000002, // syscall originates from client application

    // syscall target
    kernel         = 0x00000010, // syscall forwarded to the kernel
    hook           = 0x00000020, // syscall handled by GekkoFS

    // syscall state
    executed       = 0x00000100, // syscall has been executed
    not_executed   = 0x00000000, // syscall has not been executed

    // masks
    origin_mask    = 0x00000003, // mask for syscall's origin information
    target_mask    = 0x7ffffefc, // mask for syscall's target information
    execution_mask = 0x00000100 // mask for syscall's execution state
};


inline constexpr info
operator&(info t1, info t2) {
    return info(static_cast<int>(t1) & static_cast<int>(t2));
}

inline constexpr info
operator|(info t1, info t2) {
    return info(static_cast<int>(t1) | static_cast<int>(t2));
}

inline constexpr info
operator^(info t1, info t2) {
    return info(static_cast<int>(t1) ^ static_cast<int>(t2));
}

inline constexpr info
operator~(info t1) {
    return info(~static_cast<int>(t1));
}

inline const info&
operator|=(info& t1, info t2) {
    return t1 = t1 | t2;
}

inline const info&
operator&=(info& t1, info t2) {
    return t1 = t1 & t2;
}

inline const info&
operator^=(info& t1, info t2) {
    return t1 = t1 ^ t2;
}


static const auto constexpr no_info            = info::unknown;
static const auto constexpr from_internal_code = info::internal;
static const auto constexpr from_external_code = info::external;
static const auto constexpr to_kernel          = info::kernel;
static const auto constexpr to_hook            = info::hook;

static const auto constexpr executed           = info::executed;
static const auto constexpr not_executed       = info::not_executed;

static const auto constexpr origin_mask        = info::origin_mask;
static const auto constexpr target_mask        = info::target_mask;
static const auto constexpr execution_mask     = info::execution_mask;

enum {
    hooked            = 0x0,
    forward_to_kernel = 0x1
};

static constexpr auto
origin(syscall::info info) {
    return info & origin_mask;
}

static constexpr auto
target(syscall::info info) {
    return info & target_mask;
}

static constexpr bool
is_handled_by_kernel(syscall::info info) {
    return (info & target_mask) == to_kernel;
}

static constexpr auto
execution_is_pending(syscall::info info) {
    return (info & execution_mask) == not_executed;
}

/*
 * error_code - examines a return value from a syscall execution
 * and returns an error code if said return value indicates an error.
 */
static inline int
error_code(long result) {
    if(result < 0 && result >= -0x1000)
        return (int) -result;

    return 0;
}

} // namespace gkfs::syscall

#endif // GKFS_SYSCALL_HPP

// clang-format on