From 8cb2d9038a5e92212f79904353a05ba7d9f8aa5f Mon Sep 17 00:00:00 2001 From: Kostadin Shishmanov Date: Sat, 4 Nov 2023 23:00:14 +0200 Subject: [PATCH] Fix compilation with Linux 6.6 API headers Due to some changes in cn_proc.h in Linux 6.6 headers, including and using it mixed with C++ code is no longer posible without specifying that the code is C code and must be compiled with a C compiler. Isolate all process connector related code into its own C file, which is now compiled using a C compiler, and adapt it to adhere to the new changes. --- CMakeLists.txt | 4 +- src/helper/CMakeLists.txt | 1 + src/helper/pmon/nlprocexecsocket.cpp | 204 +++--------------------- src/helper/pmon/nlprocexecsocket.h | 6 - src/helper/pmon/processeventconnector.c | 193 ++++++++++++++++++++++ src/helper/pmon/processeventconnector.h | 27 ++++ 6 files changed, 244 insertions(+), 191 deletions(-) create mode 100644 src/helper/pmon/processeventconnector.c create mode 100644 src/helper/pmon/processeventconnector.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 38ab229..275f48b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.3) -project(CoreCtrl LANGUAGES CXX) -set(PROJECT_HOMEPAGE_URL "https://gitlab.com/corectrl/corectrl") +project(CoreCtrl + HOMEPAGE_URL "https://gitlab.com/corectrl/corectrl") set(PROJECT_FQDN "org.corectrl.corectrl") set(PROJECT_VERSION 1.3.7) diff --git a/src/helper/CMakeLists.txt b/src/helper/CMakeLists.txt index 2bc779f..13bdcbf 100644 --- a/src/helper/CMakeLists.txt +++ b/src/helper/CMakeLists.txt @@ -47,6 +47,7 @@ list(APPEND PROCESS_MONITOR_SRC pmon/processregistry.cpp pmon/appregistry.cpp pmon/msgdispatcher.cpp + pmon/processeventconnector.c ) list(APPEND SYSTEM_CONTROL_SRC diff --git a/src/helper/pmon/nlprocexecsocket.cpp b/src/helper/pmon/nlprocexecsocket.cpp index 947ea38..e09c5e7 100644 --- a/src/helper/pmon/nlprocexecsocket.cpp +++ b/src/helper/pmon/nlprocexecsocket.cpp @@ -4,213 +4,51 @@ #include "nlprocexecsocket.h" #include "processevent.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +extern "C" { +#include "processeventconnector.h" +} NLProcExecSocket::FDHandle::~FDHandle() { - if (fd >= 0) - close(fd); + process_event_connector_close(fd); } NLProcExecSocket::NLProcExecSocket() { - sockFd_.fd = createSocket(); + sockFd_.fd = process_event_connector_new(); if (sockFd_.fd < 0) throw std::runtime_error("Cannot create netlink socket"); - if (setTimeout(5) < 0) + if (process_event_connector_set_timeout(sockFd_.fd, 5) < 0) throw std::runtime_error("Cannot set socket timeout"); - if (installSocketFilter() < 0) + if (process_event_connector_install_filter(sockFd_.fd) < 0) throw std::runtime_error("Cannot install socket filters"); - if (bindToSocket() < 0) + if (process_event_connector_bind(sockFd_.fd) < 0) throw BindError("Cannot bind to socket"); - if (subscribeToProcEvents(true) < 0) + if (process_event_connector_subscribe(sockFd_.fd, true) < 0) throw std::runtime_error("Cannot subscribe to proc events"); } NLProcExecSocket::~NLProcExecSocket() { - subscribeToProcEvents(false); + process_event_connector_subscribe(sockFd_.fd, false); } ProcessEvent NLProcExecSocket::waitForEvent() const { - struct nlcn_msg_t - { - struct nlmsghdr nl_hdr __attribute__((aligned(NLMSG_ALIGNTO))); - struct cn_msg cn_msg; - }; - - auto const msg_size = - NLMSG_LENGTH(sizeof(struct cn_msg) + sizeof(struct proc_event)); - std::uint8_t msg_buffer[msg_size] = {0}; - auto msg = (struct nlcn_msg_t *)msg_buffer; - - ssize_t const rc = recv(sockFd_.fd, msg, msg_size, 0); - if (rc > 0) { - auto const event = ((struct proc_event *)msg->cn_msg.data); - switch (event->what) { - case proc_event::PROC_EVENT_EXEC: - return ProcessEvent{ProcessEvent::Type::EXEC, - event->event_data.exec.process_pid}; - - case proc_event::PROC_EVENT_EXIT: - return ProcessEvent{ProcessEvent::Type::EXIT, - event->event_data.exit.process_pid}; - default: - return ProcessEvent{ProcessEvent::Type::IGNORE, -1}; - } + auto event = process_event_connector_read_event(sockFd_.fd); + switch (event.type) { + case process_event_type::PROCESS_EVENT_EXEC: + return ProcessEvent{ProcessEvent::Type::EXEC, event.pid}; + break; + case process_event_type::PROCESS_EVENT_EXIT: + return ProcessEvent{ProcessEvent::Type::EXIT, event.pid}; + break; + default: + return ProcessEvent{ProcessEvent::Type::IGNORE, -1}; } - - return ProcessEvent{ProcessEvent::Type::IGNORE, -1}; -} - -inline int NLProcExecSocket::createSocket() const -{ - return socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); -} - -int NLProcExecSocket::setTimeout(unsigned int seconds) const -{ - struct timeval duration; - duration.tv_sec = seconds; - duration.tv_usec = 0; - - return setsockopt(sockFd_.fd, SOL_SOCKET, SO_RCVTIMEO, &duration, - sizeof(duration)); -} - -int NLProcExecSocket::bindToSocket() const -{ - struct sockaddr_nl sa_nl; - sa_nl.nl_family = AF_NETLINK; - sa_nl.nl_groups = CN_IDX_PROC; - sa_nl.nl_pid = 0; // 0 = lets the kernel to handle nl_pid - - return bind(sockFd_.fd, reinterpret_cast(&sa_nl), - sizeof(sa_nl)); -} - -int NLProcExecSocket::installSocketFilter() const -{ - struct sock_filter filter[] = { - // clang-format off - - // check message from kernel - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct nlmsghdr, nlmsg_pid)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 1, 0), - BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message - - // check message type NLMSG_DONE - BPF_STMT(BPF_LD | BPF_H | BPF_ABS, offsetof(struct nlmsghdr, nlmsg_type)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(NLMSG_DONE), 1, 0), - BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message - - // check proc connector event CN_IDX_PROC - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + - offsetof(struct cn_msg, id) + - offsetof(struct cb_id, idx)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(CN_IDX_PROC), 1, 0), - BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message - - // check proc connector event CN_VAL_PROC - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + - offsetof(struct cn_msg, id) + - offsetof(struct cb_id, val)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(CN_VAL_PROC), 1, 0), - BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message - - // accept exec messages from processes - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + - offsetof(struct cn_msg, data) + - offsetof(struct proc_event, what)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(proc_event::PROC_EVENT_EXEC), 0, 6), - - // processes have process_pid == process_tgid (thread group leaders) - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + - offsetof(struct cn_msg, data) + - offsetof(struct proc_event, event_data.exec.process_pid)), - BPF_STMT(BPF_ST, 0), - BPF_STMT(BPF_LDX | BPF_W | BPF_MEM, 0), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + - offsetof(struct cn_msg, data) + - offsetof(struct proc_event, event_data.exec.process_tgid)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 1), - BPF_STMT(BPF_RET | BPF_K, 0xffffffff), - - // accept exit messages from processes - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + - offsetof(struct cn_msg, data) + - offsetof(struct proc_event, what)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(proc_event::PROC_EVENT_EXIT), 0, 6), - - // processes have process_pid == process_tgid - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + - offsetof(struct cn_msg, data) + - offsetof(struct proc_event, event_data.exit.process_pid)), - BPF_STMT(BPF_ST, 0), - BPF_STMT(BPF_LDX | BPF_W | BPF_MEM, 0), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + - offsetof(struct cn_msg, data) + - offsetof(struct proc_event, event_data.exit.process_tgid)), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 1), - BPF_STMT(BPF_RET | BPF_K, 0xffffffff), - - // drop any other messages - BPF_STMT(BPF_RET | BPF_K, 0x0), - - // clang-format on - }; - - struct sock_fprog fprog; - memset(&fprog, 0, sizeof(fprog)); - fprog.filter = filter; - fprog.len = sizeof(filter) / sizeof(*filter); - - return setsockopt(sockFd_.fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, - sizeof(fprog)); -} - -int NLProcExecSocket::subscribeToProcEvents(bool subscribe) const -{ - struct nlcn_msg_t - { - struct nlmsghdr nl_hdr __attribute__((aligned(NLMSG_ALIGNTO))); - struct cn_msg cn_msg; - }; - - auto const msg_size = - NLMSG_LENGTH(sizeof(struct cn_msg) + sizeof(enum proc_cn_mcast_op)); - std::uint8_t msg_buffer[msg_size] = {0}; - auto msg = (struct nlcn_msg_t *)msg_buffer; - - msg->nl_hdr.nlmsg_len = msg_size; - msg->nl_hdr.nlmsg_pid = 0; - msg->nl_hdr.nlmsg_type = NLMSG_DONE; - - msg->cn_msg.id.idx = CN_IDX_PROC; - msg->cn_msg.id.val = CN_VAL_PROC; - msg->cn_msg.len = sizeof(enum proc_cn_mcast_op); - - auto mcast = (enum proc_cn_mcast_op *)msg->cn_msg.data; - *mcast = subscribe ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE; - - if (send(sockFd_.fd, msg, msg_size, 0) < 0) - return -1; - - return 0; } diff --git a/src/helper/pmon/nlprocexecsocket.h b/src/helper/pmon/nlprocexecsocket.h index 902e20e..be119e0 100644 --- a/src/helper/pmon/nlprocexecsocket.h +++ b/src/helper/pmon/nlprocexecsocket.h @@ -22,12 +22,6 @@ class NLProcExecSocket final ProcessEvent waitForEvent() const; private: - inline int createSocket() const; - int setTimeout(unsigned int seconds) const; - int bindToSocket() const; - int installSocketFilter() const; - int subscribeToProcEvents(bool subscribe) const; - struct FDHandle { int fd{-1}; diff --git a/src/helper/pmon/processeventconnector.c b/src/helper/pmon/processeventconnector.c new file mode 100644 index 0000000..a18070e --- /dev/null +++ b/src/helper/pmon/processeventconnector.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2023 Juan Palacios + +#include "processeventconnector.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SUBSCRIBE_MSG_SIZE \ + NLMSG_LENGTH(sizeof(struct cn_msg) + sizeof(enum proc_cn_mcast_op)) +#define READ_EVENT_MSG_SIZE \ + NLMSG_LENGTH(sizeof(struct cn_msg) + sizeof(struct proc_event)) + +int process_event_connector_new() +{ + return socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); +} + +int process_event_connector_close(int socket_fd) +{ + if (socket_fd >= 0) + return close(socket_fd); + + return 0; +} + +int process_event_connector_set_timeout(int socket_fd, unsigned int seconds) +{ + struct timeval duration; + duration.tv_sec = seconds; + duration.tv_usec = 0; + + return setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &duration, + sizeof(duration)); +} + +int process_event_connector_bind(int socket_fd) +{ + struct sockaddr_nl sa_nl; + sa_nl.nl_family = AF_NETLINK; + sa_nl.nl_groups = CN_IDX_PROC; + sa_nl.nl_pid = 0; // 0 = lets the kernel to handle nl_pid + + return bind(socket_fd, (struct sockaddr *)(&sa_nl), sizeof(sa_nl)); +} + +int process_event_connector_subscribe(int socket_fd, bool subscribe) +{ + typedef struct nlcn_msg_t + { + struct nlmsghdr nl_hdr __attribute__((aligned(NLMSG_ALIGNTO))); + struct cn_msg cn_msg; + } nlcn_msg; + + char msg_buffer[SUBSCRIBE_MSG_SIZE] = {0}; + nlcn_msg *msg = (nlcn_msg *)msg_buffer; + + msg->nl_hdr.nlmsg_len = SUBSCRIBE_MSG_SIZE; + msg->nl_hdr.nlmsg_pid = 0; + msg->nl_hdr.nlmsg_type = NLMSG_DONE; + + msg->cn_msg.id.idx = CN_IDX_PROC; + msg->cn_msg.id.val = CN_VAL_PROC; + msg->cn_msg.len = sizeof(enum proc_cn_mcast_op); + + enum proc_cn_mcast_op *mcast = (enum proc_cn_mcast_op *)msg->cn_msg.data; + *mcast = subscribe ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE; + + if (send(socket_fd, msg, SUBSCRIBE_MSG_SIZE, 0) < 0) + return -1; + + return 0; +} + +int process_event_connector_install_filter(int socket_fd) +{ + struct sock_filter filter[] = { + // clang-format off + + // check message from kernel + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct nlmsghdr, nlmsg_pid)), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 1, 0), + BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message + + // check message type NLMSG_DONE + BPF_STMT(BPF_LD | BPF_H | BPF_ABS, offsetof(struct nlmsghdr, nlmsg_type)), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(NLMSG_DONE), 1, 0), + BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message + + // check proc connector event CN_IDX_PROC + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + + offsetof(struct cn_msg, id) + + offsetof(struct cb_id, idx)), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(CN_IDX_PROC), 1, 0), + BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message + + // check proc connector event CN_VAL_PROC + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + + offsetof(struct cn_msg, id) + + offsetof(struct cb_id, val)), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(CN_VAL_PROC), 1, 0), + BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message + + // accept exec messages from processes + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + + offsetof(struct cn_msg, data) + + offsetof(struct proc_event, what)), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(PROC_EVENT_EXEC), 0, 6), + + // processes have process_pid == process_tgid (thread group leaders) + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + + offsetof(struct cn_msg, data) + + offsetof(struct proc_event, event_data.exec.process_pid)), + BPF_STMT(BPF_ST, 0), + BPF_STMT(BPF_LDX | BPF_W | BPF_MEM, 0), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + + offsetof(struct cn_msg, data) + + offsetof(struct proc_event, event_data.exec.process_tgid)), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 1), + BPF_STMT(BPF_RET | BPF_K, 0xffffffff), + + // accept exit messages from processes + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + + offsetof(struct cn_msg, data) + + offsetof(struct proc_event, what)), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(PROC_EVENT_EXIT), 0, 6), + + // processes have process_pid == process_tgid + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + + offsetof(struct cn_msg, data) + + offsetof(struct proc_event, event_data.exit.process_pid)), + BPF_STMT(BPF_ST, 0), + BPF_STMT(BPF_LDX | BPF_W | BPF_MEM, 0), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + + offsetof(struct cn_msg, data) + + offsetof(struct proc_event, event_data.exit.process_tgid)), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 1), + BPF_STMT(BPF_RET | BPF_K, 0xffffffff), + + // drop any other messages + BPF_STMT(BPF_RET | BPF_K, 0x0), + + // clang-format on + }; + + struct sock_fprog fprog; + memset(&fprog, 0, sizeof(fprog)); + fprog.filter = filter; + fprog.len = sizeof(filter) / sizeof(*filter); + + return setsockopt(socket_fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, + sizeof(fprog)); +} + +process_event process_event_connector_read_event(int socket_fd) +{ + typedef struct nlcn_msg_t + { + struct nlmsghdr nl_hdr __attribute__((aligned(NLMSG_ALIGNTO))); + struct cn_msg cn_msg; + } nlcn_msg; + + char msg_buffer[READ_EVENT_MSG_SIZE] = {0}; + nlcn_msg *msg = (nlcn_msg *)msg_buffer; + + ssize_t const rc = recv(socket_fd, msg, READ_EVENT_MSG_SIZE, 0); + if (rc > 0) { + struct proc_event *event = ((struct proc_event *)msg->cn_msg.data); + switch (event->what) { + case PROC_EVENT_EXEC: + return (process_event){.type = PROCESS_EVENT_EXEC, + .pid = event->event_data.exec.process_pid}; + + case PROC_EVENT_EXIT: + return (process_event){.type = PROCESS_EVENT_EXIT, + .pid = event->event_data.exit.process_pid}; + + default: + return (process_event){.type = PROCESS_EVENT_OTHER, .pid = -1}; + } + } + + return (process_event){.type = PROCESS_EVENT_OTHER, .pid = -1}; +} diff --git a/src/helper/pmon/processeventconnector.h b/src/helper/pmon/processeventconnector.h new file mode 100644 index 0000000..35c4b5b --- /dev/null +++ b/src/helper/pmon/processeventconnector.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2023 Juan Palacios + +#pragma once + +#include +#include + +typedef enum process_event_type_t { + PROCESS_EVENT_EXEC, + PROCESS_EVENT_EXIT, + PROCESS_EVENT_OTHER, +} process_event_type; + +typedef struct process_event_t +{ + process_event_type type; + int pid; +} process_event; + +int process_event_connector_new(); +int process_event_connector_close(int socket_fd); +int process_event_connector_set_timeout(int socket_fd, unsigned int seconds); +int process_event_connector_bind(int socket_fd); +int process_event_connector_subscribe(int socket_fd, bool subscribe); +int process_event_connector_install_filter(int socket_fd); +process_event process_event_connector_read_event(int socket_fd); -- 2.42.1