falcosecurity / plugin-sdk-cpp

Falco plugins SDK for C++
Apache License 2.0
3 stars 10 forks source link

Plugin is instantiated once by each mixin #23

Closed brodeuralexis closed 1 year ago

brodeuralexis commented 1 year ago

Describe the bug

Each mixin creates its own instance of the plugin, preventing the use of class member storage to share information.

How to reproduce it

#include "falcosecurity/sdk.h"

#include <iostream>

using _et = falcosecurity::event_type;
constexpr auto PPME_SYSCALL_OPEN_E = (_et)2;
constexpr auto PPME_SYSCALL_OPEN_X = (_et)3;
constexpr auto PPME_SYSCALL_OPENAT_E = (_et)102;
constexpr auto PPME_SYSCALL_OPENAT_X = (_et)103;
constexpr auto PPME_SYSCALL_OPENAT_2_E = (_et)306;
constexpr auto PPME_SYSCALL_OPENAT_2_X = (_et)307;
constexpr auto PPME_SYSCALL_OPENAT2_E = (_et)326;
constexpr auto PPME_SYSCALL_OPENAT2_X = (_et)327;
constexpr auto PPME_SYSCALL_OPEN_BY_HANDLE_AT_E = (_et)336;
constexpr auto PPME_SYSCALL_OPEN_BY_HANDLE_AT_X = (_et)337;

class EventSource {
public:
    virtual ~EventSource() noexcept = default;

    falcosecurity::result_code next_event(falcosecurity::event_writer& evt)
    {
        return falcosecurity::_internal::SS_PLUGIN_TIMEOUT;
    }
};

class Plugin {
public:
    virtual ~Plugin() noexcept = default;

    uint32_t get_id()
    {
        return 999;
    }

    std::string get_name()
    {
        return "test";
    }

    std::string get_version()
    {
        return "0.1.0";
    }

    std::string get_description()
    {
        return "test";
    }

    std::string get_contact()
    {
        return "brodeuralexis@gmail.com";
    }

    falcosecurity::init_schema get_init_schema()
    {
        return { falcosecurity::_internal::SS_PLUGIN_SCHEMA_NONE, "" };
    }

    std::string get_event_source()
    {
        return "test";
    }

    bool init(falcosecurity::init_input& in)
    {
        return true;
    }

    void destroy()
    {
    }

    std::vector<falcosecurity::event_type> get_parse_event_types()
    {
        return {
            PPME_SYSCALL_OPEN_E,
            PPME_SYSCALL_OPEN_X,
            PPME_SYSCALL_OPENAT_E,
            PPME_SYSCALL_OPENAT_X,
            PPME_SYSCALL_OPENAT_2_E,
            PPME_SYSCALL_OPENAT_2_X,
            PPME_SYSCALL_OPENAT2_E,
            PPME_SYSCALL_OPENAT2_X,
            PPME_SYSCALL_OPEN_BY_HANDLE_AT_E,
            PPME_SYSCALL_OPEN_BY_HANDLE_AT_X,
        };
    }

    // (optional)
    std::vector<std::string> get_parse_event_sources() { return { "syscall" }; }

    bool parse_event(const falcosecurity::parse_event_input& in)
    {
        std::clog << "parse: " << (void*)this << std::endl;
        return true;
    }

    std::unique_ptr<EventSource> open(const std::string& params)
    {
        std::clog << "open: " << (void*)this << std::endl;
        return std::make_unique<EventSource>();
    }
};

FALCOSECURITY_PLUGIN(Plugin);
FALCOSECURITY_PLUGIN_EVENT_SOURCING(Plugin, EventSource);
FALCOSECURITY_PLUGIN_EVENT_PARSING(Plugin);

Expected behaviour

I expect for both the open: 0x[...] and parse: 0x[...] lines in the screenshot below to contain a pointer to the same instance.

Screenshots

Screenshot from 2023-08-18 18-53-36

Environment

From binary releases directly from the Falco website. Configuration copied to /etc and binaries copied to /usr/local, everything with root owner and group.

Additional context

brodeuralexis commented 1 year ago

After more work with the Falco SDK, I will close this issue as this is not a problem with the SDK, but Falco itself as I've had the same behaviour where plugin_init was called twice, once for each plugin capability using Zig and plugin_types.h and plugin_api.h directly.

I've worked around the problem by reference counting a global plugin instance, which will work if we do not consider the fact that a plugin could be initialized with 2 different configuration values. In that case, a map of the hash of the config to reference counted plugins might work.