From 12765a4a40d0613f9c3f91a532e3debbd181a46b Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Mon, 26 Aug 2024 15:57:46 +0200 Subject: [PATCH] plugin-interface: use `extern "C"` for plugin init function Currently, smartvmi loads plugins dynamically by loading their shared object. From that shared object, the main entry function is searched. The problem with that is that the current approach depends on the hard-coded C++-mangled symbol name. This however depends on the toolchain (compiler version etc.). Specifically, when compiled on NixOS, the name didn't match the upstream source code version. As this symbol name is only relevant when loading a shared object into memory as part of the shared object's metadata analysis, this name doesn't have to be unique across plugins. Therefore, to get rid of the hardcoded symbol name, we use "extern C" to make things easier and more portable. The function was renamed from "init" to "init_plugin" to have a more expressive name. The disadvantage is that the caller can no longer implicitly verify the function signature used when the plugin was compiled. However, with a few more assertions, we can mitigate this mostly. --- plugins/apitracing/src/lib/ApiTracing.cpp | 8 ++++++-- plugins/inmemoryscanner/src/lib/InMemory.cpp | 8 ++++++-- plugins/template/src/lib/Template.cpp | 11 ++++++++--- vmicore/src/include/vmicore/plugins/IPlugin.h | 4 ++-- vmicore/src/lib/plugins/PluginSystem.cpp | 9 +++++---- vmicore/src/lib/plugins/PluginSystem.h | 2 ++ 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/plugins/apitracing/src/lib/ApiTracing.cpp b/plugins/apitracing/src/lib/ApiTracing.cpp index 5cfa0dcb..7179b401 100644 --- a/plugins/apitracing/src/lib/ApiTracing.cpp +++ b/plugins/apitracing/src/lib/ApiTracing.cpp @@ -99,10 +99,14 @@ namespace ApiTracing } } -std::unique_ptr -VmiCore::Plugin::init(PluginInterface* pluginInterface, +extern "C" std::unique_ptr +VmiCore::Plugin::init_plugin(PluginInterface* pluginInterface, std::shared_ptr config, // NOLINT(performance-unnecessary-value-param) std::vector args) { + if (pluginInterface == nullptr) { + fprintf(stderr, "Passed invalid parameter `pluginInterface`: null\n"); + return nullptr; + } return std::make_unique(pluginInterface, *config, args); } diff --git a/plugins/inmemoryscanner/src/lib/InMemory.cpp b/plugins/inmemoryscanner/src/lib/InMemory.cpp index f68c626f..be94ebbf 100644 --- a/plugins/inmemoryscanner/src/lib/InMemory.cpp +++ b/plugins/inmemoryscanner/src/lib/InMemory.cpp @@ -66,10 +66,14 @@ namespace InMemoryScanner } } -std::unique_ptr -VmiCore::Plugin::init(PluginInterface* pluginInterface, +extern "C" std::unique_ptr +VmiCore::Plugin::init_plugin(PluginInterface* pluginInterface, std::shared_ptr config, // NOLINT(performance-unnecessary-value-param) std::vector args) { + if (pluginInterface == nullptr) { + fprintf(stderr, "Passed invalid parameter `pluginInterface`: null\n"); + return nullptr; + } return std::make_unique(pluginInterface, *config, args); } diff --git a/plugins/template/src/lib/Template.cpp b/plugins/template/src/lib/Template.cpp index c2a10465..9435c3a2 100755 --- a/plugins/template/src/lib/Template.cpp +++ b/plugins/template/src/lib/Template.cpp @@ -51,12 +51,17 @@ namespace Template } } -// This is the init function. It is called by VmiCore and is responsible for creating an instance of a plugin. +// This is the init function. It is linked and called dynamically at runtime by +// VmiCore and is responsible for creating an instance of a plugin. // All plugins have to inherit from IPlugin. -std::unique_ptr -VmiCore::Plugin::init(PluginInterface* pluginInterface, +extern "C" std::unique_ptr +VmiCore::Plugin::init_plugin(PluginInterface* pluginInterface, std::shared_ptr config, // NOLINT(performance-unnecessary-value-param) std::vector args) { + if (pluginInterface == nullptr) { + fprintf(stderr, "Passed invalid parameter `pluginInterface`: null\n"); + return nullptr; + } return std::make_unique(pluginInterface, *config, args); } diff --git a/vmicore/src/include/vmicore/plugins/IPlugin.h b/vmicore/src/include/vmicore/plugins/IPlugin.h index 9b6aef11..f158db47 100644 --- a/vmicore/src/include/vmicore/plugins/IPlugin.h +++ b/vmicore/src/include/vmicore/plugins/IPlugin.h @@ -44,8 +44,8 @@ namespace VmiCore::Plugin * @param args Commandline arguments passed to this specific plugin. Elements are whitespace separated. * @return An instance of the plugin. Has to implement the IPlugin interface. Lifetime will be managed by VMICore. */ - extern std::unique_ptr - init(PluginInterface* pluginInterface, std::shared_ptr config, std::vector args); + extern "C" std::unique_ptr + init_plugin(PluginInterface* pluginInterface, std::shared_ptr config, std::vector args); } #endif // APITRACING_IPLUGIN_H diff --git a/vmicore/src/lib/plugins/PluginSystem.cpp b/vmicore/src/lib/plugins/PluginSystem.cpp index cba1bed3..0410ad37 100644 --- a/vmicore/src/lib/plugins/PluginSystem.cpp +++ b/vmicore/src/lib/plugins/PluginSystem.cpp @@ -161,10 +161,8 @@ namespace VmiCore Plugin::PluginInterface::API_VERSION)); } - auto pluginInitFunction = std::bit_cast( - dlsym(libraryHandle, - "_ZN7VmiCore6Plugin4initEPNS0_15PluginInterfaceENSt3__110shared_ptrINS0_13IPluginConfigEEENS3_" - "6vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENSB_ISD_EEEE")); + auto pluginInitFunction = std::bit_cast( + dlsym(libraryHandle, PLUGIN_INIT_FUNCTION.c_str())); dlErrorMessage = dlerror(); if (dlErrorMessage != nullptr) { @@ -172,6 +170,9 @@ namespace VmiCore } auto plugin = pluginInitFunction(dynamic_cast(this), std::move(config), args); + if (plugin == nullptr) { + throw PluginException(pluginName, fmt::format("init function returned null")); + } plugins.emplace_back(pluginName, std::move(plugin)); } diff --git a/vmicore/src/lib/plugins/PluginSystem.h b/vmicore/src/lib/plugins/PluginSystem.h index c8be60c0..51a1f56b 100644 --- a/vmicore/src/lib/plugins/PluginSystem.h +++ b/vmicore/src/lib/plugins/PluginSystem.h @@ -17,6 +17,8 @@ namespace VmiCore { + static const std::string PLUGIN_INIT_FUNCTION = "init_plugin"; + class IPluginSystem : public Plugin::PluginInterface { public: