~siborgium/prelockdpp

475049175a8ae75eb9c8037b214be3a1048e4ec2 — Sergey Smirnykh 2 years ago 24973dd
Use libcap (if available) to check CAP_IPC_LOCK capability

CAP_IPC_LOCK is required to bypass RLIMIT_MEMLOCK soft limit
2 files changed, 51 insertions(+), 5 deletions(-)

M CMakeLists.txt
M main.cpp
M CMakeLists.txt => CMakeLists.txt +17 -0
@@ 14,9 14,26 @@ find_package(Boost 1.70 REQUIRED)
find_package(nlohmann_json 3.10.5 REQUIRED)
find_package(fmt REQUIRED)

find_package(PkgConfig)
if (DEFINED WITH_LIBCAP)
    if (WITH_LIBCAP)
        pkg_check_modules(cap REQUIRED IMPORTED_TARGET libcap)
    else()
        message("libcap support disabled")
    endif()
else()
    pkg_check_modules(cap IMPORTED_TARGET libcap)
    set(WITH_LIBCAP "${cap_FOUND}")
endif()

add_executable(prelockdpp main.cpp)
target_compile_features(prelockdpp PRIVATE cxx_std_20)
target_link_libraries(prelockdpp PRIVATE Boost::boost nlohmann_json::nlohmann_json fmt::fmt)
target_include_directories(prelockdpp PRIVATE "${plf_colony_SOURCE_DIR}")

if (WITH_LIBCAP)
    target_compile_definitions(prelockdpp PRIVATE WITH_LIBCAP)
    target_link_libraries(prelockdpp PRIVATE cap)
endif()

install(TARGETS prelockdpp RUNTIME DESTINATION bin)

M main.cpp => main.cpp +34 -5
@@ 25,6 25,10 @@
#include <signal.h>
#include <unistd.h>

#ifdef WITH_LIBCAP
#include <sys/capability.h>
#endif

template <typename F> struct defer_impl {
    F f;
    defer_impl(F&& f): f{ f } {}


@@ 149,6 153,11 @@ struct timer_fd: public base_fd {

namespace intr = boost::intrusive;

struct mapping: intr::set_base_hook<intr::optimize_size<true>> {
    std::size_t refs;
    char* filename;
};

namespace tags {
    struct alive{};
    struct dead{};


@@ 533,12 542,9 @@ struct context {
                    }
                }

#if 0

                auto [iter, inserted] = uniq_set.emplace(uniq_id{ start_time, pid });
                assert(inserted);


#if 0
                if (!uniq_mappings.contains(*iter)) {
                    add_mappings(uniq_mappings[*iter]);
                }


@@ 685,10 691,33 @@ run_break:;

int main(int argc, char **argv) {
    try {

#ifdef WITH_LIBCAP
        {
            // we need CAP_IPC_LOCK to mlock more memory than RLIMIT_MEMLOCK
            auto cap = cap_get_proc();
            if (!cap) {
                throw errno_exception("cap_get_pid(self) failed", errno);
            }
            DEFER{ cap_free(cap); };
            cap_flag_value_t value;
            if (cap_get_flag(cap, CAP_IPC_LOCK, CAP_PERMITTED, &value)) {
                throw errno_exception("cap_get_flag(CAP_EFFECTIVE, CAP_IPC_LOCK) failed", errno);
            }
            if (value == CAP_CLEAR) {
                fmt::print(
                    stderr,
                    "The service needs CAP_IPC_LOCK capability to run as user\n"
                    "Consider using 'setcap cap_ipc_lock=+ep prelockdpp' or run the service as root\n"
                );
                return EXIT_FAILURE;
            }
        }
#endif

        config  cfg;
        context ctx{ cfg };

        // FIXME: we should ensure CAP_IPC_LOCK capability
        ctx.mlockall();

        lock_context runner{ ctx };