Compare commits
13 Commits
Author | SHA1 | Date |
---|---|---|
|
12d8e63d34 | |
|
d608d7282e | |
|
3fdac75fd0 | |
|
b7bb92fafe | |
|
8f53f05a62 | |
|
7c1d5695b4 | |
|
f5474a80f2 | |
|
69176a7e5d | |
|
a202a120f9 | |
|
6ac3b4df0a | |
|
c61e9d1502 | |
|
85cf8fd4c4 | |
|
f412a34986 |
|
@ -14,7 +14,7 @@ jobs:
|
|||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: '^1.19'
|
||||
|
||||
|
@ -29,7 +29,7 @@ jobs:
|
|||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: '^1.19'
|
||||
|
||||
|
|
|
@ -31,12 +31,12 @@ jobs:
|
|||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
|
||||
uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
|
||||
uses: github/codeql-action/autobuild@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
|
||||
uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
||||
|
|
|
@ -19,13 +19,13 @@ jobs:
|
|||
fetch-depth: 0
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: 1.17
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@90a3faa9d0182683851fbfa97ca1a2cb983bfca3 # v6.2.1
|
||||
uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0
|
||||
with:
|
||||
args: release --rm-dist --timeout 60m
|
||||
args: release --clean --timeout 60m
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
6
Makefile
6
Makefile
|
@ -1,6 +1,6 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (C) 2023 The Falco Authors.
|
||||
# Copyright (C) 2025 The Falco Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
|
@ -16,7 +16,7 @@ GO ?= $(shell which go)
|
|||
CURL ?= $(shell which curl)
|
||||
PATCH ?= $(shell which patch)
|
||||
|
||||
FALCOSECURITY_LIBS_REVISION ?= 0b9ca98fee2453a16f4538db55dcfa34bc8f5aef
|
||||
FALCOSECURITY_LIBS_REVISION ?= 0.21.0
|
||||
FALCOSECURITY_LIBS_REPO ?= falcosecurity/libs
|
||||
PLUGINLIB_URL=https://raw.githubusercontent.com/${FALCOSECURITY_LIBS_REPO}/${FALCOSECURITY_LIBS_REVISION}/userspace/plugin
|
||||
|
||||
|
@ -36,7 +36,9 @@ pluginlib:
|
|||
$(CURL) -Lso pkg/sdk/plugin_api.h $(PLUGINLIB_URL)/plugin_api.h
|
||||
$(CURL) -Lso pkg/loader/plugin_loader.h $(PLUGINLIB_URL)/plugin_loader.h
|
||||
$(CURL) -Lso pkg/loader/plugin_loader.c $(PLUGINLIB_URL)/plugin_loader.c
|
||||
$(PATCH) -p1 < pkg/loader/plugin_api_include.patch
|
||||
$(PATCH) -p1 < pkg/loader/strlcpy.patch
|
||||
$(PATCH) -p1 < pkg/sdk/plugin_types_include.patch
|
||||
|
||||
clean-pluginlib:
|
||||
rm -f \
|
||||
|
|
11
go.mod
11
go.mod
|
@ -1,9 +1,16 @@
|
|||
module github.com/falcosecurity/plugin-sdk-go
|
||||
|
||||
go 1.15
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
diff --git a/pkg/loader/plugin_loader.h b/pkg/loader/plugin_loader.h
|
||||
index e6e8333..8db0d70 100644
|
||||
--- a/pkg/loader/plugin_loader.h
|
||||
+++ b/pkg/loader/plugin_loader.h
|
||||
@@ -18,7 +18,7 @@ limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
-#include <plugin/plugin_api.h>
|
||||
+#include "plugin_api.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
|
@ -17,13 +17,14 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
typedef HINSTANCE library_handle_t;
|
||||
#include <windows.h>
|
||||
typedef HINSTANCE library_handle_t;
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
typedef void* library_handle_t;
|
||||
#include <dlfcn.h>
|
||||
typedef void* library_handle_t;
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -60,152 +61,166 @@ static inline size_t plugin_loader_strlcpy(char *dst, const char *src, size_t si
|
|||
return srcsize;
|
||||
}
|
||||
|
||||
static inline void err_prepend(char* s, const char* prefix, const char* sep)
|
||||
{
|
||||
char tmp[PLUGIN_MAX_ERRLEN];
|
||||
size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
|
||||
if (*s != '\0')
|
||||
{
|
||||
plugin_loader_strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
prefix_len += strlen(sep);
|
||||
}
|
||||
plugin_loader_strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
|
||||
static inline void err_prepend(char* s, const char* prefix, const char* sep) {
|
||||
char tmp[PLUGIN_MAX_ERRLEN];
|
||||
size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
|
||||
if(*s != '\0') {
|
||||
plugin_loader_strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
prefix_len += strlen(sep);
|
||||
}
|
||||
plugin_loader_strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
|
||||
}
|
||||
|
||||
static inline void err_append(char* s, const char* suffix, const char* sep)
|
||||
{
|
||||
if (*s != '\0')
|
||||
{
|
||||
strncat(s, sep, PLUGIN_MAX_ERRLEN - strlen(sep));
|
||||
}
|
||||
strncat(s, suffix, PLUGIN_MAX_ERRLEN - strlen(suffix));
|
||||
static inline void err_append(char* s, const char* suffix, const char* sep) {
|
||||
if(*s != '\0') {
|
||||
strlcat(s, sep, PLUGIN_MAX_ERRLEN);
|
||||
}
|
||||
strlcat(s, suffix, PLUGIN_MAX_ERRLEN);
|
||||
}
|
||||
|
||||
static void* getsym(library_handle_t handle, const char* name)
|
||||
{
|
||||
static void* getsym(library_handle_t handle, const char* name) {
|
||||
#ifdef _WIN32
|
||||
return (void*) GetProcAddress(handle, name);
|
||||
return (void*)GetProcAddress(handle, name);
|
||||
#else
|
||||
return (void*) dlsym(handle, name);
|
||||
return (void*)dlsym(handle, name);
|
||||
#endif
|
||||
}
|
||||
|
||||
// little hack for simplifying the plugin_load function
|
||||
#define SYM_RESOLVE(h, s) \
|
||||
*(void **)(&(h->api.s)) = getsym(h->handle, "plugin_"#s)
|
||||
#define SYM_RESOLVE(h, s) *(void**)(&(h->api.s)) = getsym(h->handle, "plugin_" #s)
|
||||
|
||||
plugin_handle_t* plugin_load(const char* path, char* err)
|
||||
{
|
||||
// alloc and init memory
|
||||
err[0] = '\0';
|
||||
plugin_handle_t* ret = (plugin_handle_t*) calloc (1, sizeof(plugin_handle_t));
|
||||
if (!ret)
|
||||
{
|
||||
plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
plugin_handle_t* plugin_load(const char* path, char* err) {
|
||||
// alloc and init memory
|
||||
err[0] = '\0';
|
||||
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
|
||||
if(!ret) {
|
||||
plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// open dynamic library
|
||||
// open dynamic library
|
||||
#ifdef _WIN32
|
||||
ret->handle = LoadLibrary(path);
|
||||
if(ret->handle == NULL)
|
||||
{
|
||||
DWORD flg = FORMAT_MESSAGE_ALLOCATE_BUFFER
|
||||
| FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
LPTSTR msg_buf = 0;
|
||||
if (FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR) &msg_buf, 0, NULL) && msg_buf)
|
||||
{
|
||||
plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
|
||||
LocalFree(msg_buf);
|
||||
}
|
||||
}
|
||||
ret->handle = LoadLibrary(path);
|
||||
if(ret->handle == NULL) {
|
||||
DWORD flg = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
LPTSTR msg_buf = 0;
|
||||
if(FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR)&msg_buf, 0, NULL) && msg_buf) {
|
||||
plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
|
||||
LocalFree(msg_buf);
|
||||
}
|
||||
}
|
||||
#else
|
||||
ret->handle = dlopen(path, RTLD_LAZY|RTLD_DEEPBIND);
|
||||
if (ret->handle == NULL)
|
||||
{
|
||||
plugin_loader_strlcpy(err, (const char*) dlerror(), PLUGIN_MAX_ERRLEN);
|
||||
}
|
||||
ret->handle = dlopen(path, RTLD_LAZY);
|
||||
if(ret->handle == NULL) {
|
||||
plugin_loader_strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
// return NULL if library loading had errors
|
||||
if (ret->handle == NULL)
|
||||
{
|
||||
err_prepend(err, "can't load plugin dynamic library:", " ");
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
// return NULL if library loading had errors
|
||||
if(ret->handle == NULL) {
|
||||
err_prepend(err, "can't load plugin dynamic library:", " ");
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// load all library symbols
|
||||
SYM_RESOLVE(ret, get_required_api_version);
|
||||
SYM_RESOLVE(ret, get_version);
|
||||
SYM_RESOLVE(ret, get_last_error);
|
||||
SYM_RESOLVE(ret, get_name);
|
||||
SYM_RESOLVE(ret, get_description);
|
||||
SYM_RESOLVE(ret, get_contact);
|
||||
SYM_RESOLVE(ret, get_init_schema);
|
||||
SYM_RESOLVE(ret, init);
|
||||
SYM_RESOLVE(ret, destroy);
|
||||
SYM_RESOLVE(ret, get_id);
|
||||
SYM_RESOLVE(ret, get_event_source);
|
||||
SYM_RESOLVE(ret, open);
|
||||
SYM_RESOLVE(ret, close);
|
||||
SYM_RESOLVE(ret, next_batch);
|
||||
SYM_RESOLVE(ret, get_progress);
|
||||
SYM_RESOLVE(ret, list_open_params);
|
||||
SYM_RESOLVE(ret, event_to_string);
|
||||
SYM_RESOLVE(ret, get_fields);
|
||||
SYM_RESOLVE(ret, extract_fields);
|
||||
SYM_RESOLVE(ret, get_extract_event_sources);
|
||||
SYM_RESOLVE(ret, get_extract_event_types);
|
||||
SYM_RESOLVE(ret, get_parse_event_types);
|
||||
SYM_RESOLVE(ret, get_parse_event_sources);
|
||||
SYM_RESOLVE(ret, parse_event);
|
||||
SYM_RESOLVE(ret, get_async_event_sources);
|
||||
SYM_RESOLVE(ret, get_async_events);
|
||||
SYM_RESOLVE(ret, set_async_event_handler);
|
||||
return ret;
|
||||
// load all library symbols
|
||||
SYM_RESOLVE(ret, get_required_api_version);
|
||||
SYM_RESOLVE(ret, get_version);
|
||||
SYM_RESOLVE(ret, get_last_error);
|
||||
SYM_RESOLVE(ret, get_name);
|
||||
SYM_RESOLVE(ret, get_description);
|
||||
SYM_RESOLVE(ret, get_contact);
|
||||
SYM_RESOLVE(ret, get_init_schema);
|
||||
SYM_RESOLVE(ret, init);
|
||||
SYM_RESOLVE(ret, destroy);
|
||||
SYM_RESOLVE(ret, get_id);
|
||||
SYM_RESOLVE(ret, get_event_source);
|
||||
SYM_RESOLVE(ret, open);
|
||||
SYM_RESOLVE(ret, close);
|
||||
SYM_RESOLVE(ret, next_batch);
|
||||
SYM_RESOLVE(ret, get_progress);
|
||||
SYM_RESOLVE(ret, list_open_params);
|
||||
SYM_RESOLVE(ret, event_to_string);
|
||||
SYM_RESOLVE(ret, get_fields);
|
||||
SYM_RESOLVE(ret, extract_fields);
|
||||
SYM_RESOLVE(ret, get_extract_event_sources);
|
||||
SYM_RESOLVE(ret, get_extract_event_types);
|
||||
SYM_RESOLVE(ret, get_parse_event_types);
|
||||
SYM_RESOLVE(ret, get_parse_event_sources);
|
||||
SYM_RESOLVE(ret, parse_event);
|
||||
SYM_RESOLVE(ret, get_async_event_sources);
|
||||
SYM_RESOLVE(ret, get_async_events);
|
||||
SYM_RESOLVE(ret, set_async_event_handler);
|
||||
SYM_RESOLVE(ret, dump_state);
|
||||
SYM_RESOLVE(ret, set_config);
|
||||
SYM_RESOLVE(ret, get_metrics);
|
||||
SYM_RESOLVE(ret, capture_open);
|
||||
SYM_RESOLVE(ret, capture_close);
|
||||
return ret;
|
||||
}
|
||||
|
||||
plugin_handle_t* plugin_load_api(const plugin_api* api, char* err)
|
||||
{
|
||||
// alloc and init memory
|
||||
err[0] = '\0';
|
||||
if (!api)
|
||||
{
|
||||
plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
|
||||
// alloc and init memory
|
||||
err[0] = '\0';
|
||||
if(!api) {
|
||||
plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plugin_handle_t* ret = (plugin_handle_t*) calloc (1, sizeof(plugin_handle_t));
|
||||
if (!ret)
|
||||
{
|
||||
plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
ret->api = *api;
|
||||
return ret;
|
||||
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
|
||||
if(!ret) {
|
||||
plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
ret->api = *api;
|
||||
|
||||
// todo: remove this if/when we get to API version 4
|
||||
uint32_t major, minor, patch;
|
||||
const char* ver;
|
||||
if(api->get_required_api_version == NULL) {
|
||||
plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ver = api->get_required_api_version();
|
||||
if(sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3) {
|
||||
snprintf(err,
|
||||
PLUGIN_MAX_ERRLEN,
|
||||
"plugin provided an invalid required API version: '%s'",
|
||||
ver);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// API 3.10 introduced dump_state in the middle of the plugin_api struct.
|
||||
// Fix up older 3.x plugins by shifting the fields by one
|
||||
if(major == 3 && minor < 10) {
|
||||
size_t from_offset = offsetof(plugin_api, dump_state);
|
||||
size_t to_offset = offsetof(plugin_api, set_config);
|
||||
size_t size = sizeof(plugin_api) - to_offset;
|
||||
char* api_ptr = (char*)&ret->api;
|
||||
memmove(api_ptr + to_offset, api_ptr + from_offset, size);
|
||||
ret->api.dump_state = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void plugin_unload(plugin_handle_t* h)
|
||||
{
|
||||
if (h)
|
||||
{
|
||||
if (h->handle)
|
||||
{
|
||||
void plugin_unload(plugin_handle_t* h) {
|
||||
if(h) {
|
||||
if(h->handle) {
|
||||
#ifdef _WIN32
|
||||
FreeLibrary(h->handle);
|
||||
FreeLibrary(h->handle);
|
||||
#else
|
||||
dlclose(h->handle);
|
||||
dlclose(h->handle);
|
||||
#endif
|
||||
}
|
||||
free(h);
|
||||
}
|
||||
}
|
||||
free(h);
|
||||
}
|
||||
}
|
||||
|
||||
bool plugin_is_loaded(const char* path)
|
||||
{
|
||||
bool plugin_is_loaded(const char* path) {
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
* LoadLibrary maps the module into the address space of the calling process, if necessary,
|
||||
|
@ -228,122 +243,125 @@ bool plugin_is_loaded(const char* path)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool plugin_check_required_api_version(const plugin_handle_t* h, char* err)
|
||||
{
|
||||
uint32_t major, minor, patch;
|
||||
const char *ver, *failmsg;
|
||||
if (h->api.get_required_api_version == NULL)
|
||||
{
|
||||
plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||
return false;
|
||||
}
|
||||
bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) {
|
||||
uint32_t major, minor, patch;
|
||||
const char *ver, *failmsg;
|
||||
if(h->api.get_required_api_version == NULL) {
|
||||
plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||
return false;
|
||||
}
|
||||
|
||||
ver = h->api.get_required_api_version();
|
||||
if (sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3)
|
||||
{
|
||||
snprintf(err, PLUGIN_MAX_ERRLEN, "plugin provided an invalid required API version: '%s'", ver);
|
||||
return false;
|
||||
}
|
||||
ver = h->api.get_required_api_version();
|
||||
if(sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3) {
|
||||
snprintf(err,
|
||||
PLUGIN_MAX_ERRLEN,
|
||||
"plugin provided an invalid required API version: '%s'",
|
||||
ver);
|
||||
return false;
|
||||
}
|
||||
|
||||
failmsg = NULL;
|
||||
if(PLUGIN_API_VERSION_MAJOR != major)
|
||||
{
|
||||
failmsg = "major versions disagree";
|
||||
}
|
||||
else if(PLUGIN_API_VERSION_MINOR < minor)
|
||||
{
|
||||
failmsg = "framework's minor is less than the requested one";
|
||||
}
|
||||
else if(PLUGIN_API_VERSION_MINOR == minor && PLUGIN_API_VERSION_PATCH < patch)
|
||||
{
|
||||
failmsg = "framework's patch is less than the requested one";
|
||||
}
|
||||
failmsg = NULL;
|
||||
/* The plugin requires a minimum framework version */
|
||||
if(PLUGIN_API_VERSION_MAJOR != major) {
|
||||
failmsg = "major versions disagree";
|
||||
} else if(PLUGIN_API_VERSION_MINOR < minor) {
|
||||
failmsg = "framework's minor is less than the requested one";
|
||||
} else if(PLUGIN_API_VERSION_MINOR == minor && PLUGIN_API_VERSION_PATCH < patch) {
|
||||
failmsg = "framework's patch is less than the requested one";
|
||||
}
|
||||
|
||||
if (failmsg != NULL)
|
||||
{
|
||||
snprintf(err, PLUGIN_MAX_ERRLEN,
|
||||
"plugin required API version '%s' not compatible with the framework's API version '%s': %s",
|
||||
ver, PLUGIN_API_VERSION_STR, failmsg);
|
||||
return false;
|
||||
}
|
||||
if(failmsg != NULL) {
|
||||
snprintf(err,
|
||||
PLUGIN_MAX_ERRLEN,
|
||||
"plugin required API version '%s' not compatible with the framework's API version "
|
||||
"'%s': %s",
|
||||
ver,
|
||||
PLUGIN_API_VERSION_STR,
|
||||
failmsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h, char* err) {
|
||||
plugin_caps_t caps = CAP_NONE;
|
||||
plugin_loader_strlcpy(err, "", PLUGIN_MAX_ERRLEN);
|
||||
|
||||
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h, char* err)
|
||||
{
|
||||
plugin_caps_t caps = CAP_NONE;
|
||||
plugin_loader_strlcpy(err, "", PLUGIN_MAX_ERRLEN);
|
||||
if(h->api.open != NULL && h->api.close != NULL && h->api.next_batch != NULL) {
|
||||
bool has_id = h->api.get_id != NULL && h->api.get_id() != 0;
|
||||
bool has_source = h->api.get_event_source != NULL && strlen(h->api.get_event_source()) > 0;
|
||||
if((has_id && has_source) || (!has_id && !has_source)) {
|
||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_SOURCING);
|
||||
} else {
|
||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
|
||||
err_append(err,
|
||||
"must implement both 'plugin_get_id' and 'plugin_get_event_source' or "
|
||||
"neither (event sourcing)",
|
||||
", ");
|
||||
}
|
||||
} else if(h->api.open != NULL || h->api.close != NULL || h->api.next_batch != NULL) {
|
||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
|
||||
err_append(err,
|
||||
"must implement all of 'plugin_open', 'plugin_close', and 'plugin_next_batch' "
|
||||
"(event sourcing)",
|
||||
", ");
|
||||
}
|
||||
|
||||
if (h->api.open != NULL && h->api.close != NULL && h->api.next_batch != NULL)
|
||||
{
|
||||
bool has_id = h->api.get_id != NULL && h->api.get_id() != 0;
|
||||
bool has_source = h->api.get_event_source != NULL && strlen(h->api.get_event_source()) > 0;
|
||||
if ((has_id && has_source) || (!has_id && !has_source))
|
||||
{
|
||||
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_SOURCING);
|
||||
}
|
||||
else
|
||||
{
|
||||
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_BROKEN);
|
||||
err_append(err, "must implement both 'plugin_get_id' and 'plugin_get_event_source' or neither (event sourcing)", ", ");
|
||||
}
|
||||
}
|
||||
else if (h->api.open != NULL || h->api.close != NULL || h->api.next_batch != NULL
|
||||
|| h->api.get_id != NULL || h->api.get_event_source != NULL)
|
||||
{
|
||||
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_BROKEN);
|
||||
err_append(err, "must implement all of 'plugin_open', 'plugin_close', and 'plugin_next_batch' (event sourcing)", ", ");
|
||||
}
|
||||
if(h->api.get_fields != NULL && h->api.extract_fields != NULL) {
|
||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_EXTRACTION);
|
||||
} else if(h->api.extract_fields != NULL) {
|
||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
|
||||
err_append(err,
|
||||
"must implement both 'plugin_get_fields' and 'plugin_extract_fields' (field "
|
||||
"extraction)",
|
||||
", ");
|
||||
}
|
||||
|
||||
if (h->api.get_fields != NULL && h->api.extract_fields != NULL)
|
||||
{
|
||||
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_EXTRACTION);
|
||||
}
|
||||
else if (h->api.get_fields != NULL || h->api.extract_fields != NULL)
|
||||
{
|
||||
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_BROKEN);
|
||||
err_append(err, "must implement both 'plugin_get_fields' and 'plugin_extract_fields' (field extraction)", ", ");
|
||||
}
|
||||
if(h->api.parse_event != NULL) {
|
||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_PARSING);
|
||||
}
|
||||
|
||||
if (h->api.parse_event != NULL)
|
||||
{
|
||||
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_PARSING);
|
||||
}
|
||||
if(h->api.get_async_events != NULL && h->api.set_async_event_handler != NULL) {
|
||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_ASYNC);
|
||||
} else if(h->api.set_async_event_handler != NULL) {
|
||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
|
||||
err_append(err,
|
||||
"must implement both 'plugin_get_async_events' and "
|
||||
"'plugin_set_async_event_handler' (async events)",
|
||||
", ");
|
||||
}
|
||||
|
||||
if (h->api.get_async_events != NULL && h->api.set_async_event_handler != NULL)
|
||||
{
|
||||
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_ASYNC);
|
||||
}
|
||||
else if (h->api.get_async_events != NULL || h->api.set_async_event_handler != NULL)
|
||||
{
|
||||
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_BROKEN);
|
||||
err_append(err, "must implement both 'plugin_get_async_events' and 'plugin_set_async_event_handler' (async events)", ", ");
|
||||
}
|
||||
if(h->api.capture_open != NULL && h->api.capture_close != NULL) {
|
||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_CAPTURE_LISTENING);
|
||||
} else if(h->api.capture_open != NULL) {
|
||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
|
||||
err_append(err,
|
||||
"must implement both 'plugin_capture_open' and 'plugin_capture_close' (capture "
|
||||
"listening)",
|
||||
", ");
|
||||
}
|
||||
|
||||
return caps;
|
||||
return caps;
|
||||
}
|
||||
|
||||
// little hack for simplifying the plugin_check_required_symbols function
|
||||
#define SYM_REQCHECK(a, e, s) \
|
||||
do { \
|
||||
if(a->api.s == NULL) \
|
||||
{ \
|
||||
snprintf(e, PLUGIN_MAX_ERRLEN, "required symbol not implemented: '%s'", #s); \
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
#define SYM_REQCHECK(a, e, s) \
|
||||
do { \
|
||||
if(a->api.s == NULL) { \
|
||||
snprintf(e, PLUGIN_MAX_ERRLEN, "required symbol not implemented: '%s'", #s); \
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
bool plugin_check_required_symbols(const plugin_handle_t* h, char* err)
|
||||
{
|
||||
SYM_REQCHECK(h, err, get_required_api_version);
|
||||
SYM_REQCHECK(h, err, get_version);
|
||||
SYM_REQCHECK(h, err, get_name);
|
||||
SYM_REQCHECK(h, err, get_description);
|
||||
SYM_REQCHECK(h, err, get_contact);
|
||||
SYM_REQCHECK(h, err, init);
|
||||
SYM_REQCHECK(h, err, destroy);
|
||||
SYM_REQCHECK(h, err, get_last_error);
|
||||
return true;
|
||||
bool plugin_check_required_symbols(const plugin_handle_t* h, char* err) {
|
||||
SYM_REQCHECK(h, err, get_required_api_version);
|
||||
SYM_REQCHECK(h, err, get_version);
|
||||
SYM_REQCHECK(h, err, get_name);
|
||||
SYM_REQCHECK(h, err, get_description);
|
||||
SYM_REQCHECK(h, err, get_contact);
|
||||
SYM_REQCHECK(h, err, init);
|
||||
SYM_REQCHECK(h, err, destroy);
|
||||
SYM_REQCHECK(h, err, get_last_error);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -37,14 +37,14 @@ extern "C" {
|
|||
the field extraction phase
|
||||
* ability to inject events asynchronously in the event loop
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
CAP_NONE = 0,
|
||||
CAP_SOURCING = 1 << 0,
|
||||
CAP_EXTRACTION = 1 << 1,
|
||||
CAP_PARSING = 1 << 2,
|
||||
CAP_ASYNC = 1 << 3,
|
||||
CAP_BROKEN = 1 << 31, // used to report inconsistencies
|
||||
typedef enum {
|
||||
CAP_NONE = 0,
|
||||
CAP_SOURCING = 1 << 0,
|
||||
CAP_EXTRACTION = 1 << 1,
|
||||
CAP_PARSING = 1 << 2,
|
||||
CAP_ASYNC = 1 << 3,
|
||||
CAP_CAPTURE_LISTENING = 1 << 4,
|
||||
CAP_BROKEN = 1 << 31, // used to report inconsistencies
|
||||
} plugin_caps_t;
|
||||
|
||||
/*!
|
||||
|
@ -52,14 +52,13 @@ typedef enum
|
|||
Pointers to this struct must be obtained through the plugin_load()
|
||||
and released through plugin_unload().
|
||||
*/
|
||||
typedef struct plugin_handle_t
|
||||
{
|
||||
typedef struct plugin_handle_t {
|
||||
#ifdef _WIN32
|
||||
HINSTANCE handle; ///< Handle of the dynamic library
|
||||
HINSTANCE handle; ///< Handle of the dynamic library
|
||||
#else
|
||||
void* handle; ///< Handle of the dynamic library
|
||||
void* handle; ///< Handle of the dynamic library
|
||||
#endif
|
||||
plugin_api api; ///< The vtable method of the plugin that define its API
|
||||
plugin_api api; ///< The vtable method of the plugin that define its API
|
||||
} plugin_handle_t;
|
||||
|
||||
/*!
|
||||
|
@ -77,7 +76,7 @@ plugin_handle_t* plugin_load_api(const plugin_api* api, char* err);
|
|||
plugin_handle_t* plugin_load(const char* path, char* err);
|
||||
|
||||
/*!
|
||||
\brief Destroys a plugin_handle_t* previously allocated by
|
||||
\brief Destroys a plugin_handle_t* previously allocated by
|
||||
invoking plugin_load().
|
||||
*/
|
||||
void plugin_unload(plugin_handle_t* h);
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
diff --git a/pkg/loader/plugin_loader.c b/pkg/loader/plugin_loader.c
|
||||
index aad119f..169f696 100644
|
||||
index 2943335..7bebeeb 100644
|
||||
--- a/pkg/loader/plugin_loader.c
|
||||
+++ b/pkg/loader/plugin_loader.c
|
||||
@@ -23,23 +23,53 @@ limitations under the License.
|
||||
typedef void* library_handle_t;
|
||||
@@ -24,22 +24,52 @@ typedef HINSTANCE library_handle_t;
|
||||
typedef void* library_handle_t;
|
||||
#endif
|
||||
|
||||
-#include "strlcpy.h"
|
||||
-#include <libscap/strl.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "plugin_loader.h"
|
||||
|
||||
-#include <plugin/plugin_loader.h>
|
||||
+#include "plugin_loader.h"
|
||||
+
|
||||
+// note(jasondellaluce,therealbobo): implementation taken from falcosecurity/libs
|
||||
+// note(leogr): to avoid clashing with `strlcpy` introduced by glibc 2.38,
|
||||
+// the func has been renamed to plugin_loader_strlcpy.
|
||||
|
@ -42,84 +44,89 @@ index aad119f..169f696 100644
|
|||
+
|
||||
+ return srcsize;
|
||||
+}
|
||||
+
|
||||
static inline void err_prepend(char* s, const char* prefix, const char* sep)
|
||||
{
|
||||
char tmp[PLUGIN_MAX_ERRLEN];
|
||||
- size_t prefix_len = strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
|
||||
+ size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
|
||||
if (*s != '\0')
|
||||
{
|
||||
- strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
+ plugin_loader_strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
prefix_len += strlen(sep);
|
||||
}
|
||||
- strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
- strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
+ plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
|
||||
|
||||
static inline void err_prepend(char* s, const char* prefix, const char* sep) {
|
||||
char tmp[PLUGIN_MAX_ERRLEN];
|
||||
- size_t prefix_len = strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
|
||||
+ size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
|
||||
if(*s != '\0') {
|
||||
- strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
+ plugin_loader_strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
prefix_len += strlen(sep);
|
||||
}
|
||||
- strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
- strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||
+ plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
|
||||
}
|
||||
|
||||
static inline void err_append(char* s, const char* suffix, const char* sep)
|
||||
@@ -71,7 +101,7 @@ plugin_handle_t* plugin_load(const char* path, char* err)
|
||||
plugin_handle_t* ret = (plugin_handle_t*) calloc (1, sizeof(plugin_handle_t));
|
||||
if (!ret)
|
||||
{
|
||||
- strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
static inline void err_append(char* s, const char* suffix, const char* sep) {
|
||||
@@ -65,7 +95,7 @@ plugin_handle_t* plugin_load(const char* path, char* err) {
|
||||
err[0] = '\0';
|
||||
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
|
||||
if(!ret) {
|
||||
- strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -86,7 +116,7 @@ plugin_handle_t* plugin_load(const char* path, char* err)
|
||||
LPTSTR msg_buf = 0;
|
||||
if (FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR) &msg_buf, 0, NULL) && msg_buf)
|
||||
{
|
||||
- strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
|
||||
LocalFree(msg_buf);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +124,7 @@ plugin_handle_t* plugin_load(const char* path, char* err)
|
||||
ret->handle = dlopen(path, RTLD_LAZY|RTLD_DEEPBIND);
|
||||
if (ret->handle == NULL)
|
||||
{
|
||||
- strlcpy(err, (const char*) dlerror(), PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, (const char*) dlerror(), PLUGIN_MAX_ERRLEN);
|
||||
}
|
||||
@@ -77,14 +107,14 @@ plugin_handle_t* plugin_load(const char* path, char* err) {
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
LPTSTR msg_buf = 0;
|
||||
if(FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR)&msg_buf, 0, NULL) && msg_buf) {
|
||||
- strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
|
||||
LocalFree(msg_buf);
|
||||
}
|
||||
}
|
||||
#else
|
||||
ret->handle = dlopen(path, RTLD_LAZY);
|
||||
if(ret->handle == NULL) {
|
||||
- strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -143,14 +173,14 @@ plugin_handle_t* plugin_load_api(const plugin_api* api, char* err)
|
||||
err[0] = '\0';
|
||||
if (!api)
|
||||
{
|
||||
- strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
@@ -135,13 +165,13 @@ plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
|
||||
// alloc and init memory
|
||||
err[0] = '\0';
|
||||
if(!api) {
|
||||
- strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plugin_handle_t* ret = (plugin_handle_t*) calloc (1, sizeof(plugin_handle_t));
|
||||
if (!ret)
|
||||
{
|
||||
- strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
ret->api = *api;
|
||||
@@ -203,7 +233,7 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err)
|
||||
const char *ver, *failmsg;
|
||||
if (h->api.get_required_api_version == NULL)
|
||||
{
|
||||
- strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||
return false;
|
||||
}
|
||||
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
|
||||
if(!ret) {
|
||||
- strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
ret->api = *api;
|
||||
@@ -150,7 +180,7 @@ plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
|
||||
uint32_t major, minor, patch;
|
||||
const char* ver;
|
||||
if(api->get_required_api_version == NULL) {
|
||||
- strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -243,7 +273,7 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err)
|
||||
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h, char* err)
|
||||
{
|
||||
plugin_caps_t caps = CAP_NONE;
|
||||
- strlcpy(err, "", PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, "", PLUGIN_MAX_ERRLEN);
|
||||
@@ -217,7 +247,7 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) {
|
||||
uint32_t major, minor, patch;
|
||||
const char *ver, *failmsg;
|
||||
if(h->api.get_required_api_version == NULL) {
|
||||
- strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (h->api.open != NULL && h->api.close != NULL && h->api.next_batch != NULL)
|
||||
{
|
||||
@@ -256,7 +286,7 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) {
|
||||
|
||||
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h, char* err) {
|
||||
plugin_caps_t caps = CAP_NONE;
|
||||
- strlcpy(err, "", PLUGIN_MAX_ERRLEN);
|
||||
+ plugin_loader_strlcpy(err, "", PLUGIN_MAX_ERRLEN);
|
||||
|
||||
if(h->api.open != NULL && h->api.close != NULL && h->api.next_batch != NULL) {
|
||||
bool has_id = h->api.get_id != NULL && h->api.get_id() != 0;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
Copyright (C) 2025 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -34,10 +34,15 @@ import (
|
|||
// todo(jasondellaluce): pull this information from falcosecurity/libs in the future
|
||||
const pluginEventCode = 322
|
||||
|
||||
// pluginEventHeaderSize is the size of a scap event header, plus the
|
||||
// todo(leogr): replace this with PLUGIN_EVENT_PAYLOAD_OFFSET from "plugin_api.h"
|
||||
|
||||
// PluginEventPayloadOffset is the size of a scap event header, plus the
|
||||
// params lenght and the plugin ID integers of a PPME_PLUGINEVENT_E event.
|
||||
// In other words, this is the size of a plugin event with an empty data payload.
|
||||
const pluginEventHeaderSize = C.sizeof_ss_plugin_event + 4 + 4 + 4
|
||||
//
|
||||
// 26 bytes for the event header, plus 2*4 bytes for the parameter lengths,
|
||||
// plus 4 bytes for the plugin ID.
|
||||
const PluginEventPayloadOffset = C.sizeof_ss_plugin_event + 4 + 4 + 4
|
||||
|
||||
// EventWriter can be used to represent events produced by a plugin.
|
||||
// This interface is meant to be used in the next/next_batch.
|
||||
|
@ -180,11 +185,11 @@ type eventWriter struct {
|
|||
}
|
||||
|
||||
func newEventWriter(dataSize int64) (*eventWriter, error) {
|
||||
evt := (*C.ss_plugin_event)(C.calloc(1, C.size_t(dataSize+pluginEventHeaderSize)))
|
||||
evt := (*C.ss_plugin_event)(C.calloc(1, C.size_t(dataSize+PluginEventPayloadOffset)))
|
||||
evt._type = pluginEventCode
|
||||
evt.ts = C.uint64_t(C.UINT64_MAX)
|
||||
evt.tid = C.uint64_t(C.UINT64_MAX)
|
||||
evt.len = (C.uint32_t)(pluginEventHeaderSize)
|
||||
evt.len = (C.uint32_t)(PluginEventPayloadOffset)
|
||||
// note(jasondellaluce): CGO fails to properly encode nparams for *reasons*,
|
||||
// so we're forced to write their value manually with an offset
|
||||
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + 22)) = 2
|
||||
|
@ -195,7 +200,7 @@ func newEventWriter(dataSize int64) (*eventWriter, error) {
|
|||
// plugin ID value (note: putting zero makes the framework set it automatically)
|
||||
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + C.sizeof_ss_plugin_event + 8)) = 0
|
||||
// create a read/writer for the data payload
|
||||
brw, err := ptr.NewBytesReadWriter(unsafe.Pointer(uintptr(unsafe.Pointer(evt))+pluginEventHeaderSize), int64(dataSize), int64(dataSize))
|
||||
brw, err := ptr.NewBytesReadWriter(unsafe.Pointer(uintptr(unsafe.Pointer(evt))+PluginEventPayloadOffset), int64(dataSize), int64(dataSize))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -214,7 +219,7 @@ func (p *eventWriter) dataLenPtr() *C.uint32_t {
|
|||
func (p *eventWriter) Writer() io.Writer {
|
||||
p.data.SetLen(p.dataSize)
|
||||
p.data.Seek(0, io.SeekStart)
|
||||
p.ssPluginEvt.len = (C.uint32_t)(pluginEventHeaderSize)
|
||||
p.ssPluginEvt.len = (C.uint32_t)(PluginEventPayloadOffset)
|
||||
*p.dataLenPtr() = 0
|
||||
return p
|
||||
}
|
||||
|
@ -252,7 +257,7 @@ func (e *eventReader) Reader() io.ReadSeeker {
|
|||
panic(fmt.Sprintf("plugin-sdk-go/sdk: reveived extraction request for non-plugin event (code=%d)", e.evt._type))
|
||||
}
|
||||
datalen := *(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(e.evt)) + C.sizeof_ss_plugin_event + 4))
|
||||
brw, _ := ptr.NewBytesReadWriter(unsafe.Pointer(uintptr(unsafe.Pointer(e.evt))+pluginEventHeaderSize), int64(datalen), int64(datalen))
|
||||
brw, _ := ptr.NewBytesReadWriter(unsafe.Pointer(uintptr(unsafe.Pointer(e.evt))+PluginEventPayloadOffset), int64(datalen), int64(datalen))
|
||||
return brw
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
Copyright (C) 2025 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -106,9 +106,26 @@ type ExtractRequest interface {
|
|||
// - sdk.FieldTypeIPNet: net.IPNet, *net.IPNet
|
||||
SetValue(v interface{})
|
||||
//
|
||||
// TODO SetValueOffsets sets the start offset and length of one or
|
||||
// more fields. The start offset for each field must be from the
|
||||
// beginning of the event to the start of the field data.
|
||||
// sdk.PluginEventPayloadOffset should be used to get the event
|
||||
// header size. {0,0} can be used to indicate that the field doesn't
|
||||
// correspond to any bytes in the event or log data.
|
||||
SetValueOffset(start, length uint32)
|
||||
//
|
||||
// SetPtr sets a pointer to a ss_plugin_extract_field C structure to
|
||||
// be wrapped in this instance of ExtractRequest.
|
||||
SetPtr(unsafe.Pointer)
|
||||
//
|
||||
// SetOffsetPtrs sets the pointers to the memory locations that will
|
||||
// hold the values set by SetValueOffset.
|
||||
SetOffsetPtrs(startPtr, lengthPtr unsafe.Pointer)
|
||||
//
|
||||
// WantOffset returns true if the caller is requesting the offset
|
||||
// for the current field.
|
||||
//
|
||||
WantOffset() bool
|
||||
}
|
||||
|
||||
// ExtractRequestPool represents a pool of reusable ExtractRequest objects.
|
||||
|
@ -119,6 +136,18 @@ type ExtractRequestPool interface {
|
|||
// position inside the pool. Indexes can be non-contiguous.
|
||||
Get(requestIndex int) ExtractRequest
|
||||
//
|
||||
// MakeOffsetArrayPtrs allocates and initializes the start offset and length arrays,
|
||||
// then assigns their pointers to the provided ss_plugin_extract_value_offsets structure.
|
||||
// These arrays track field boundaries for extracted values.
|
||||
//
|
||||
// This function must be called before using any ExtractRequest returned by Get,
|
||||
// as the arrays are uninitialized until this point.
|
||||
//
|
||||
// Parameters:
|
||||
// - extractValueOffsets: pointer to ss_plugin_extract_value_offsets structure to populate
|
||||
// - cap: required capacity for the offset arrays
|
||||
MakeOffsetArrayPtrs(extractValueOffsets unsafe.Pointer, cap uint32)
|
||||
//
|
||||
// Free deallocates any memory used by the pool that can't be disposed
|
||||
// through garbage collection. The behavior of Free after the first call
|
||||
// is undefined.
|
||||
|
@ -126,7 +155,9 @@ type ExtractRequestPool interface {
|
|||
}
|
||||
|
||||
type extractRequestPool struct {
|
||||
reqs map[uint]*extractRequest
|
||||
reqs map[uint]*extractRequest
|
||||
startArrayPtr, lengthArrayPtr unsafe.Pointer
|
||||
arrayPtrCap uint32
|
||||
}
|
||||
|
||||
func (e *extractRequestPool) Get(requestIndex int) ExtractRequest {
|
||||
|
@ -147,6 +178,31 @@ func (e *extractRequestPool) Get(requestIndex int) ExtractRequest {
|
|||
return r
|
||||
}
|
||||
|
||||
func (e *extractRequestPool) MakeOffsetArrayPtrs(extractValueOffsets unsafe.Pointer, cap uint32) {
|
||||
// If we need more capacity, free old arrays and allocate new ones
|
||||
if cap > e.arrayPtrCap {
|
||||
// Free existing arrays if they exist
|
||||
if e.arrayPtrCap > 0 {
|
||||
C.free(e.startArrayPtr)
|
||||
C.free(e.lengthArrayPtr)
|
||||
}
|
||||
|
||||
// Allocate new arrays with required capacity - calloc zeros the memory
|
||||
e.startArrayPtr = unsafe.Pointer(C.calloc(C.size_t(cap), C.sizeof_uint32_t))
|
||||
e.lengthArrayPtr = unsafe.Pointer(C.calloc(C.size_t(cap), C.sizeof_uint32_t))
|
||||
|
||||
e.arrayPtrCap = cap
|
||||
} else {
|
||||
// Capacity is sufficient, just zero the arrays for fresh extraction request
|
||||
size := C.size_t(cap) * C.sizeof_uint32_t
|
||||
C.memset(e.startArrayPtr, 0, size)
|
||||
C.memset(e.lengthArrayPtr, 0, size)
|
||||
}
|
||||
|
||||
(*C.ss_plugin_extract_value_offsets)(extractValueOffsets).start = (*C.uint32_t)(e.startArrayPtr)
|
||||
(*C.ss_plugin_extract_value_offsets)(extractValueOffsets).length = (*C.uint32_t)(e.lengthArrayPtr)
|
||||
}
|
||||
|
||||
func (e *extractRequestPool) Free() {
|
||||
for _, v := range e.reqs {
|
||||
for _, b := range v.resStrBufs {
|
||||
|
@ -154,6 +210,10 @@ func (e *extractRequestPool) Free() {
|
|||
}
|
||||
C.free(unsafe.Pointer(v.resBuf))
|
||||
}
|
||||
if e.arrayPtrCap > 0 {
|
||||
C.free(e.startArrayPtr)
|
||||
C.free(e.lengthArrayPtr)
|
||||
}
|
||||
}
|
||||
|
||||
// NewExtractRequestPool returns a new empty ExtractRequestPool.
|
||||
|
@ -166,6 +226,10 @@ func NewExtractRequestPool() ExtractRequestPool {
|
|||
|
||||
type extractRequest struct {
|
||||
req *C.ss_plugin_extract_field
|
||||
// Pointer to the field's offset
|
||||
resOffsetStart *C.uint32_t
|
||||
// Pointer to the field's length
|
||||
resOffsetLength *C.uint32_t
|
||||
// Pointer to a C-allocated array of field_result_t
|
||||
resBuf *C.field_result_t
|
||||
// Length of the array pointed by resBuf
|
||||
|
@ -182,6 +246,11 @@ func (e *extractRequest) SetPtr(pef unsafe.Pointer) {
|
|||
e.req = (*C.ss_plugin_extract_field)(pef)
|
||||
}
|
||||
|
||||
func (e *extractRequest) SetOffsetPtrs(startPtr, lengthPtr unsafe.Pointer) {
|
||||
e.resOffsetStart = (*C.uint32_t)(startPtr)
|
||||
e.resOffsetLength = (*C.uint32_t)(lengthPtr)
|
||||
}
|
||||
|
||||
func (e *extractRequest) FieldID() uint64 {
|
||||
return uint64(e.req.field_id)
|
||||
}
|
||||
|
@ -362,3 +431,16 @@ func (e *extractRequest) SetValue(v interface{}) {
|
|||
}
|
||||
*((*C.uintptr_t)(unsafe.Pointer(&e.req.res))) = *(*C.uintptr_t)(unsafe.Pointer(&e.resBuf))
|
||||
}
|
||||
|
||||
func (e *extractRequest) WantOffset() bool {
|
||||
return e.resOffsetStart != nil && e.resOffsetLength != nil
|
||||
}
|
||||
|
||||
func (e *extractRequest) SetValueOffset(start, length uint32) {
|
||||
if !e.WantOffset() {
|
||||
return
|
||||
}
|
||||
|
||||
*e.resOffsetStart = C.uint32_t(start)
|
||||
*e.resOffsetLength = C.uint32_t(length)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
Copyright (C) 2025 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -58,6 +58,11 @@ func allocSSPluginExtractField(fid, ftype uint32, fname, farg_key string, farg_i
|
|||
}
|
||||
}
|
||||
|
||||
func allocSSPluginExtractOffset() *_Ctype_uint32_t {
|
||||
var offset _Ctype_uint32_t = _Ctype_uint32_t(0)
|
||||
return &offset
|
||||
}
|
||||
|
||||
func getBoolResSSPluingExtractField(t *testing.T, ptr *_Ctype_ss_plugin_extract_field, index int) bool {
|
||||
if ptr.res_len < (_Ctype_uint64_t)(index) {
|
||||
t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(ptr.res_len))
|
||||
|
@ -96,6 +101,10 @@ func getBinResSSPluingExtractField(t *testing.T, p *_Ctype_ss_plugin_extract_fie
|
|||
return buf
|
||||
}
|
||||
|
||||
func getResSSPluginExtractOffsetFromPtr(offset *_Ctype_uint32_t) uint32 {
|
||||
return uint32(*offset)
|
||||
}
|
||||
|
||||
func assertPanic(t *testing.T, fun func()) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
|
@ -126,10 +135,14 @@ func TestExtractRequestSetValue(t *testing.T) {
|
|||
// init test data
|
||||
testStr := "test str"
|
||||
testU64 := uint64(99)
|
||||
testU64Start := uint32(PluginEventPayloadOffset)
|
||||
testU64Length := uint32(8)
|
||||
testBool := true
|
||||
testIPv6 := net.IPv6loopback
|
||||
testStrList := make([]string, 0)
|
||||
testU64List := make([]uint64, 0)
|
||||
testU64ListStart := uint32(PluginEventPayloadOffset)
|
||||
testU64ListLength := uint32(0)
|
||||
testBoolList := make([]bool, 0)
|
||||
dataArray := make([]byte, (minResultBufferLen+1)*int(len(testIPv6)))
|
||||
for i := 0; i < (minResultBufferLen+1)*int(len(testIPv6)); i++ {
|
||||
|
@ -139,6 +152,7 @@ func TestExtractRequestSetValue(t *testing.T) {
|
|||
for i := 0; i < minResultBufferLen+1; i++ {
|
||||
testStrList = append(testStrList, fmt.Sprintf("test-%d", i))
|
||||
testU64List = append(testU64List, uint64(i))
|
||||
testU64ListLength += testU64Length
|
||||
testBoolList = append(testBoolList, i%3 == 0)
|
||||
testIPv6List[i] = dataArray[i*len(testIPv6) : (i+1)*len(testIPv6)]
|
||||
}
|
||||
|
@ -146,7 +160,11 @@ func TestExtractRequestSetValue(t *testing.T) {
|
|||
// init extract requests
|
||||
pool := NewExtractRequestPool()
|
||||
u64Ptr, freeU64Ptr := allocSSPluginExtractField(1, FieldTypeUint64, "test.u64", "", 0, true, false)
|
||||
u64OffsetStartPtr := allocSSPluginExtractOffset()
|
||||
u64OffsetLengthPtr := allocSSPluginExtractOffset()
|
||||
u64ListPtr, freeU64ListPtr := allocSSPluginExtractField(2, FieldTypeUint64, "test.u64", "", 0, true, true)
|
||||
u64ListOffsetStartPtr := allocSSPluginExtractOffset()
|
||||
u64ListOffsetLengthPtr := allocSSPluginExtractOffset()
|
||||
strPtr, freeStrPtr := allocSSPluginExtractField(3, FieldTypeCharBuf, "test.str", "", 0, true, false)
|
||||
strListPtr, freeStrListPtr := allocSSPluginExtractField(4, FieldTypeCharBuf, "test.str", "", 0, true, true)
|
||||
boolPtr, freeBoolPtr := allocSSPluginExtractField(5, FieldTypeBool, "test.bool", "", 0, true, false)
|
||||
|
@ -162,7 +180,9 @@ func TestExtractRequestSetValue(t *testing.T) {
|
|||
binReq := pool.Get(6)
|
||||
binReqList := pool.Get(7)
|
||||
u64Req.SetPtr(unsafe.Pointer(u64Ptr))
|
||||
u64Req.SetOffsetPtrs(unsafe.Pointer(u64OffsetStartPtr), unsafe.Pointer(u64OffsetLengthPtr))
|
||||
u64ReqList.SetPtr(unsafe.Pointer(u64ListPtr))
|
||||
u64ReqList.SetOffsetPtrs(unsafe.Pointer(u64ListOffsetStartPtr), unsafe.Pointer(u64ListOffsetLengthPtr))
|
||||
strReq.SetPtr(unsafe.Pointer(strPtr))
|
||||
strReqList.SetPtr(unsafe.Pointer(strListPtr))
|
||||
boolReq.SetPtr(unsafe.Pointer(boolPtr))
|
||||
|
@ -223,12 +243,26 @@ func TestExtractRequestSetValue(t *testing.T) {
|
|||
if getU64ResSSPluingExtractField(t, u64Ptr, 0) != testU64 {
|
||||
t.Errorf("expected value '%d', but found '%d'", testU64, getU64ResSSPluingExtractField(t, u64Ptr, 0))
|
||||
}
|
||||
u64Req.SetValueOffset(testU64Start, testU64Length)
|
||||
if getResSSPluginExtractOffsetFromPtr(u64OffsetStartPtr) != testU64Start {
|
||||
t.Errorf("expected start offset '%d', but found '%d'", testU64Start, getResSSPluginExtractOffsetFromPtr(u64OffsetStartPtr))
|
||||
}
|
||||
if getResSSPluginExtractOffsetFromPtr(u64OffsetLengthPtr) != testU64Length {
|
||||
t.Errorf("expected length '%d', but found '%d'", testU64Length, getResSSPluginExtractOffsetFromPtr(u64OffsetLengthPtr))
|
||||
}
|
||||
u64ReqList.SetValue(testU64List)
|
||||
u64ReqList.SetValueOffset(testU64ListStart, testU64ListLength)
|
||||
for i, d := range testU64List {
|
||||
if getU64ResSSPluingExtractField(t, u64ListPtr, i) != d {
|
||||
t.Errorf("expected value '%d', but found '%d'", testU64, getU64ResSSPluingExtractField(t, u64Ptr, i))
|
||||
}
|
||||
}
|
||||
if getResSSPluginExtractOffsetFromPtr(u64ListOffsetStartPtr) != testU64ListStart {
|
||||
t.Errorf("expected start offset '%d', but found '%d'", testU64ListStart, getResSSPluginExtractOffsetFromPtr(u64ListOffsetStartPtr))
|
||||
}
|
||||
if getResSSPluginExtractOffsetFromPtr(u64ListOffsetLengthPtr) != testU64ListLength {
|
||||
t.Errorf("expected length '%d', but found '%d'", testU64ListLength, getResSSPluginExtractOffsetFromPtr(u64ListOffsetLengthPtr))
|
||||
}
|
||||
strReq.SetValue(testStr)
|
||||
if getStrResSSPluingExtractField(t, strPtr, 0) != testStr {
|
||||
t.Errorf("expected value '%s', but found '%s'", testStr, getStrResSSPluingExtractField(t, strPtr, 0))
|
||||
|
|
|
@ -24,38 +24,51 @@ limitations under the License.
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// API versions of this plugin framework
|
||||
//
|
||||
// todo(jasondellaluce): when/if major changes to v4, check and solve all todos
|
||||
#define PLUGIN_API_VERSION_MAJOR 3
|
||||
#define PLUGIN_API_VERSION_MINOR 0
|
||||
#define PLUGIN_API_VERSION_MINOR 11
|
||||
#define PLUGIN_API_VERSION_PATCH 0
|
||||
|
||||
//
|
||||
// Just some not so smart defines to retrieve plugin api version as string
|
||||
//
|
||||
#define QUOTE(str) #str
|
||||
#define EXPAND_AND_QUOTE(str) QUOTE(str)
|
||||
#define PLUGIN_API_VERSION PLUGIN_API_VERSION_MAJOR.PLUGIN_API_VERSION_MINOR.PLUGIN_API_VERSION_PATCH
|
||||
#define PLUGIN_API_VERSION_STR EXPAND_AND_QUOTE(PLUGIN_API_VERSION)
|
||||
#define QUOTE(str) #str
|
||||
#define EXPAND_AND_QUOTE(str) QUOTE(str)
|
||||
#define PLUGIN_API_VERSION \
|
||||
PLUGIN_API_VERSION_MAJOR.PLUGIN_API_VERSION_MINOR.PLUGIN_API_VERSION_PATCH
|
||||
#define PLUGIN_API_VERSION_STR EXPAND_AND_QUOTE(PLUGIN_API_VERSION)
|
||||
|
||||
//
|
||||
// The max length of errors returned by a plugin in some of its API symbols.
|
||||
//
|
||||
#define PLUGIN_MAX_ERRLEN 1024
|
||||
#define PLUGIN_MAX_ERRLEN 1024
|
||||
|
||||
// Supported by the API but deprecated. Use the extended version ss_plugin_table_reader_vtable_ext
|
||||
// instead. todo(jasondellaluce): when/if major changes to v4, remove this and give this name to the
|
||||
// associated *_ext struct.
|
||||
typedef struct {
|
||||
const ss_plugin_table_fieldinfo* (*list_table_fields)(ss_plugin_table_t* t, uint32_t* nfields);
|
||||
ss_plugin_table_field_t* (*get_table_field)(ss_plugin_table_t* t,
|
||||
const char* name,
|
||||
ss_plugin_state_type data_type);
|
||||
ss_plugin_table_field_t* (*add_table_field)(ss_plugin_table_t* t,
|
||||
const char* name,
|
||||
ss_plugin_state_type data_type);
|
||||
} ss_plugin_table_fields_vtable;
|
||||
|
||||
// Vtable for controlling and the fields for the entries of a state table.
|
||||
// This allows discovering the fields available in the table, defining new ones,
|
||||
// and obtaining accessors usable at runtime for reading and writing the fields'
|
||||
// data from each entry of a given state table.
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
// Returns a pointer to an array containing info about all the fields
|
||||
// available in the entries of the table. nfields will be filled with the number
|
||||
// of elements of the returned array. The array's memory is owned by the
|
||||
// tables's owner. Returns NULL in case of error.
|
||||
ss_plugin_table_fieldinfo* (*list_table_fields)(ss_plugin_table_t* t, uint32_t* nfields);
|
||||
const ss_plugin_table_fieldinfo* (*list_table_fields)(ss_plugin_table_t* t, uint32_t* nfields);
|
||||
//
|
||||
// Returns an opaque pointer representing an accessor to a data field
|
||||
// present in all entries of the table, given its name and type.
|
||||
|
@ -63,7 +76,9 @@ typedef struct
|
|||
// the table. The pointer is owned by the table's owner.
|
||||
// Returns NULL in case of issues (including when the field is not defined
|
||||
// or it has a type different than the specified one).
|
||||
ss_plugin_table_field_t* (*get_table_field)(ss_plugin_table_t* t, const char* name, ss_plugin_state_type data_type);
|
||||
ss_plugin_table_field_t* (*get_table_field)(ss_plugin_table_t* t,
|
||||
const char* name,
|
||||
ss_plugin_state_type data_type);
|
||||
//
|
||||
// Defines a new field in the table given its name and data type,
|
||||
// which will then be available in all entries contained in the table.
|
||||
|
@ -72,16 +87,40 @@ typedef struct
|
|||
// the table. The pointer is owned by the table's owner.
|
||||
// Returns NULL in case of issues (including when a field is defined multiple
|
||||
// times with different data types).
|
||||
ss_plugin_table_field_t* (*add_table_field)(ss_plugin_table_t* t, const char* name, ss_plugin_state_type data_type);
|
||||
} ss_plugin_table_fields_vtable;
|
||||
ss_plugin_table_field_t* (*add_table_field)(ss_plugin_table_t* t,
|
||||
const char* name,
|
||||
ss_plugin_state_type data_type);
|
||||
} ss_plugin_table_fields_vtable_ext;
|
||||
|
||||
// Vtable for controlling a state table for read operations.
|
||||
// todo(jasondellaluce): support looping over a table
|
||||
typedef struct
|
||||
{
|
||||
// Supported by the API but deprecated. Use the extended version ss_plugin_table_reader_vtable_ext
|
||||
// instead. todo(jasondellaluce): when/if major changes to v4, remove this and give this name to the
|
||||
// associated *_ext struct.
|
||||
typedef struct {
|
||||
const char* (*get_table_name)(ss_plugin_table_t* t);
|
||||
uint64_t (*get_table_size)(ss_plugin_table_t* t);
|
||||
ss_plugin_table_entry_t* (*get_table_entry)(ss_plugin_table_t* t,
|
||||
const ss_plugin_state_data* key);
|
||||
ss_plugin_rc (*read_entry_field)(ss_plugin_table_t* t,
|
||||
ss_plugin_table_entry_t* e,
|
||||
const ss_plugin_table_field_t* f,
|
||||
ss_plugin_state_data* out);
|
||||
} ss_plugin_table_reader_vtable;
|
||||
|
||||
// Opaque pointer to the state data relative to a state table iteration.
|
||||
// This is passed initially by the invoker when starting the iteration, and
|
||||
// is then dispatched to the iterator for each of the entries of the table.
|
||||
typedef void ss_plugin_table_iterator_state_t;
|
||||
|
||||
// Iterator function callback used by a plugin for looping through all the
|
||||
// entries of a given state table. Returns true if the iteration should
|
||||
// proceed to the next element, or false in case of break out.
|
||||
typedef ss_plugin_bool (*ss_plugin_table_iterator_func_t)(ss_plugin_table_iterator_state_t* s,
|
||||
ss_plugin_table_entry_t* e);
|
||||
|
||||
typedef struct {
|
||||
// Returns the table's name, or NULL in case of error.
|
||||
// The returned pointer is owned by the table's owner.
|
||||
const char* (*get_table_name)(ss_plugin_table_t* t);
|
||||
const char* (*get_table_name)(ss_plugin_table_t* t);
|
||||
//
|
||||
// Returns the number of entries in the table, or ((uint64_t) -1) in
|
||||
// case of error.
|
||||
|
@ -90,18 +129,52 @@ typedef struct
|
|||
// Returns an opaque pointer to an entry present in the table at the given
|
||||
// key, or NULL in case of issues (including if no entry is found at the
|
||||
// given key). The returned pointer is owned by the table's owner.
|
||||
ss_plugin_table_entry_t* (*get_table_entry)(ss_plugin_table_t* t, const ss_plugin_state_data* key);
|
||||
// Every non-NULL returned entry must be released by invoking release_table_entry()
|
||||
// once it becomes no more used by the invoker.
|
||||
ss_plugin_table_entry_t* (*get_table_entry)(ss_plugin_table_t* t,
|
||||
const ss_plugin_state_data* key);
|
||||
//
|
||||
// Reads the value of an entry field from a table's entry.
|
||||
// The field accessor must be obtainied during plugin_init().
|
||||
// The read value is stored in the "out" parameter.
|
||||
// Returns SS_PLUGIN_SUCCESS if successful, and SS_PLUGIN_FAILURE otherwise.
|
||||
ss_plugin_rc (*read_entry_field)(ss_plugin_table_t* t, ss_plugin_table_entry_t* e, const ss_plugin_table_field_t* f, ss_plugin_state_data* out);
|
||||
} ss_plugin_table_reader_vtable;
|
||||
ss_plugin_rc (*read_entry_field)(ss_plugin_table_t* t,
|
||||
ss_plugin_table_entry_t* e,
|
||||
const ss_plugin_table_field_t* f,
|
||||
ss_plugin_state_data* out);
|
||||
//
|
||||
// Releases a table entry obtained by from previous invocation of get_table_entry().
|
||||
// After being released, the same table entry cannot be reused by the invoker.
|
||||
// However, the same entry can be re-obtained through an invocation of get_table_entry().
|
||||
void (*release_table_entry)(ss_plugin_table_t* t, ss_plugin_table_entry_t* e);
|
||||
//
|
||||
// Iterates through all the entries of a table, invoking the interation
|
||||
// callback function for each of them. Returns false in case of failure or
|
||||
// iteration break-out, and true otherwise.
|
||||
ss_plugin_bool (*iterate_entries)(ss_plugin_table_t* t,
|
||||
ss_plugin_table_iterator_func_t it,
|
||||
ss_plugin_table_iterator_state_t* s);
|
||||
} ss_plugin_table_reader_vtable_ext;
|
||||
|
||||
// Supported by the API but deprecated. Use the extended version ss_plugin_table_writer_vtable_ext
|
||||
// instead. todo(jasondellaluce): when/if major changes to v4, remove this and give this name to the
|
||||
// associated *_ext struct.
|
||||
typedef struct {
|
||||
ss_plugin_rc (*clear_table)(ss_plugin_table_t* t);
|
||||
ss_plugin_rc (*erase_table_entry)(ss_plugin_table_t* t, const ss_plugin_state_data* key);
|
||||
ss_plugin_table_entry_t* (*create_table_entry)(ss_plugin_table_t* t);
|
||||
void (*destroy_table_entry)(ss_plugin_table_t* t, ss_plugin_table_entry_t* e);
|
||||
ss_plugin_table_entry_t* (*add_table_entry)(ss_plugin_table_t* t,
|
||||
const ss_plugin_state_data* key,
|
||||
ss_plugin_table_entry_t* entry);
|
||||
ss_plugin_rc (*write_entry_field)(ss_plugin_table_t* t,
|
||||
ss_plugin_table_entry_t* e,
|
||||
const ss_plugin_table_field_t* f,
|
||||
const ss_plugin_state_data* in);
|
||||
} ss_plugin_table_writer_vtable;
|
||||
|
||||
// Vtable for controlling a state table for write operations.
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
// Erases all the entries of the table.
|
||||
// Returns SS_PLUGIN_SUCCESS if successful, and SS_PLUGIN_FAILURE otherwise.
|
||||
ss_plugin_rc (*clear_table)(ss_plugin_table_t* t);
|
||||
|
@ -126,15 +199,21 @@ typedef struct
|
|||
// with the given key. If another entry is already present with the same key,
|
||||
// it gets replaced. After insertion, table will be come the owner of the
|
||||
// entry's pointer. Returns an opaque pointer to the newly-added table's entry,
|
||||
// or NULL in case of error.
|
||||
ss_plugin_table_entry_t* (*add_table_entry)(ss_plugin_table_t* t, const ss_plugin_state_data* key, ss_plugin_table_entry_t* entry);
|
||||
// or NULL in case of error. Every non-NULL returned entry must be released
|
||||
// by invoking release_table_entry() once it becomes no more used by the invoker.
|
||||
ss_plugin_table_entry_t* (*add_table_entry)(ss_plugin_table_t* t,
|
||||
const ss_plugin_state_data* key,
|
||||
ss_plugin_table_entry_t* entry);
|
||||
//
|
||||
// Updates a table's entry by writing a value for one of its fields.
|
||||
// The field accessor must be obtainied during plugin_init().
|
||||
// The written value is read from the "in" parameter.
|
||||
// Returns SS_PLUGIN_SUCCESS if successful, and SS_PLUGIN_FAILURE otherwise.
|
||||
ss_plugin_rc (*write_entry_field)(ss_plugin_table_t* t, ss_plugin_table_entry_t* e, const ss_plugin_table_field_t* f, const ss_plugin_state_data* in);
|
||||
} ss_plugin_table_writer_vtable;
|
||||
ss_plugin_rc (*write_entry_field)(ss_plugin_table_t* t,
|
||||
ss_plugin_table_entry_t* e,
|
||||
const ss_plugin_table_field_t* f,
|
||||
const ss_plugin_state_data* in);
|
||||
} ss_plugin_table_writer_vtable_ext;
|
||||
|
||||
// Plugin-provided input passed to the add_table() callback of
|
||||
// ss_plugin_init_tables_input, that can be used by the plugin to inform its
|
||||
|
@ -143,33 +222,46 @@ typedef struct
|
|||
// of implementing all the API functions. These will be used by other
|
||||
// plugins loaded by the falcosecurity libraries to interact with the state
|
||||
// of a given plugin to implement cross-plugin state access.
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
// The name of the state table.
|
||||
const char* name;
|
||||
//
|
||||
// The type of the sta table's key.
|
||||
// The type of the state table's key.
|
||||
ss_plugin_state_type key_type;
|
||||
//
|
||||
// A non-NULL opaque pointer to the state table.
|
||||
// This will be passed as parameters to all the callbacks defined below.
|
||||
ss_plugin_table_t* table;
|
||||
//
|
||||
// Vtable for controlling read operations on the state table.
|
||||
// Supported but deprecated. Use the extended version reader_ext.
|
||||
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||
// give this name to the associated *_ext pointer.
|
||||
ss_plugin_table_reader_vtable reader;
|
||||
//
|
||||
// Vtable for controlling write operations on the state table.
|
||||
// Supported but deprecated. Use the extended version writer_ext.
|
||||
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||
// give this name to the associated *_ext pointer.
|
||||
ss_plugin_table_writer_vtable writer;
|
||||
//
|
||||
// Vtable for controlling operations related to fields on the state table.
|
||||
// Supported but deprecated. Use the extended version fields_ext.
|
||||
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||
// give this name to the associated *_ext pointer.
|
||||
ss_plugin_table_fields_vtable fields;
|
||||
//
|
||||
// Vtable for controlling read operations on the state table.
|
||||
ss_plugin_table_reader_vtable_ext* reader_ext;
|
||||
//
|
||||
// Vtable for controlling write operations on the state table.
|
||||
ss_plugin_table_writer_vtable_ext* writer_ext;
|
||||
//
|
||||
// Vtable for controlling operations related to fields on the state table.
|
||||
ss_plugin_table_fields_vtable_ext* fields_ext;
|
||||
} ss_plugin_table_input;
|
||||
|
||||
// Initialization-time input related to the event parsing capability.
|
||||
// Initialization-time input related to the event parsing or field extraction capability.
|
||||
// This provides the plugin with callback functions implemented by its owner
|
||||
// that can be used to discover, access, and define state tables.
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
// Returns a pointer to an array containing info about all the tables
|
||||
// registered in the plugin's owner. ntables will be filled with the number
|
||||
// of elements of the returned array. The array's memory is owned by the
|
||||
|
@ -178,7 +270,9 @@ typedef struct
|
|||
//
|
||||
// Returns an opaque accessor to a state table registered in the plugin's
|
||||
// owner, given its name and key type. Returns NULL if an case of error.
|
||||
ss_plugin_table_t* (*get_table)(ss_plugin_owner_t* o, const char* name, ss_plugin_state_type key_type);
|
||||
ss_plugin_table_t* (*get_table)(ss_plugin_owner_t* o,
|
||||
const char* name,
|
||||
ss_plugin_state_type key_type);
|
||||
//
|
||||
// Registers a new state table in the plugin's owner. Returns
|
||||
// SS_PLUGIN_SUCCESS in case of success, and SS_PLUGIN_FAILURE otherwise.
|
||||
|
@ -186,41 +280,69 @@ typedef struct
|
|||
// by other actors of the plugin's owner to interact with the state table.
|
||||
ss_plugin_rc (*add_table)(ss_plugin_owner_t* o, const ss_plugin_table_input* in);
|
||||
//
|
||||
// Vtable for controlling operations related to fields on the state tables
|
||||
// registeted in the plugin's owner.
|
||||
// Supported but deprecated. Use the extended version fields_ext.
|
||||
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||
// give this name to the associated *_ext pointer.
|
||||
ss_plugin_table_fields_vtable fields;
|
||||
//
|
||||
// Vtable for controlling operations related to fields on the state tables
|
||||
// registered in the plugin's owner.
|
||||
ss_plugin_table_fields_vtable_ext* fields_ext;
|
||||
//
|
||||
// Vtable for controlling read operations on the state tables registered
|
||||
// in the plugin's owner.
|
||||
ss_plugin_table_reader_vtable_ext* reader_ext;
|
||||
//
|
||||
// Vtable for controlling write operations on the state tables registered
|
||||
// in the plugin's owner.
|
||||
ss_plugin_table_writer_vtable_ext* writer_ext;
|
||||
} ss_plugin_init_tables_input;
|
||||
|
||||
// Function used by plugin for sending messages to the framework-provided logger
|
||||
// Arguments:
|
||||
// - component: name of the component that is logging
|
||||
// (if set to NULL automatically falls back to the plugin name in the log)
|
||||
// - msg: message to log
|
||||
// (it doesn't have to be '\n' terminated)
|
||||
// - sev: message severity as defined in ss_plugin_log_severity
|
||||
typedef void (*ss_plugin_log_fn_t)(ss_plugin_owner_t* o,
|
||||
const char* component,
|
||||
const char* msg,
|
||||
ss_plugin_log_severity sev);
|
||||
|
||||
// Input passed at the plugin through plugin_init(). This contain information
|
||||
// common to any plugin, and also information useful only in case the plugin
|
||||
// implements a given capability. If a certain capability is not implemented
|
||||
// by the plugin, its information is set to NULL.
|
||||
typedef struct ss_plugin_init_input
|
||||
{
|
||||
typedef struct ss_plugin_init_input {
|
||||
// An opaque string representing the plugin init configuration.
|
||||
// The format of the string is arbitrary and defined by the plugin itself.
|
||||
const char* config;
|
||||
//
|
||||
// The plugin's owner. Can be passed by the plugin to the callbacks available
|
||||
// in this struct in order to invoke functions of its owner.
|
||||
// It doesn't change during the whole plugin's lifecycle, it's safe to store it in the state
|
||||
ss_plugin_owner_t* owner;
|
||||
//
|
||||
// Return a string with the error that was last generated by the plugin's
|
||||
// owner, or NULL if no error is present.
|
||||
// The string pointer is owned by the plugin's owenr.
|
||||
const char *(*get_owner_last_error)(ss_plugin_owner_t *o);
|
||||
const char* (*get_owner_last_error)(ss_plugin_owner_t* o);
|
||||
//
|
||||
// Init input related to the event parsing or field extraction capability.
|
||||
// It's set to NULL if the plugin does not implement at least one of the two
|
||||
// capabilities. The callbacks available in this input take the plugin's owner
|
||||
// as a parameter.
|
||||
const ss_plugin_init_tables_input* tables;
|
||||
//
|
||||
// Log function passed to the plugin through the init input
|
||||
// It doesn't change during the whole plugin's lifecycle, it's safe to store it in the state
|
||||
ss_plugin_log_fn_t log_fn;
|
||||
} ss_plugin_init_input;
|
||||
|
||||
// Input passed to the plugin when extracting a field from an event for
|
||||
// the field extraction capability.
|
||||
typedef struct ss_plugin_field_extract_input
|
||||
{
|
||||
typedef struct ss_plugin_field_extract_input {
|
||||
//
|
||||
// The plugin's owner. Can be passed by the plugin to the callbacks available
|
||||
// in this struct in order to invoke functions of its owner.
|
||||
|
@ -229,7 +351,7 @@ typedef struct ss_plugin_field_extract_input
|
|||
// Return a string with the error that was last generated by the plugin's
|
||||
// owner, or NULL if no error is present.
|
||||
// The string pointer is owned by the plugin's owenr.
|
||||
const char *(*get_owner_last_error)(ss_plugin_owner_t *o);
|
||||
const char* (*get_owner_last_error)(ss_plugin_owner_t* o);
|
||||
//
|
||||
// The length of the fields array.
|
||||
uint32_t num_fields;
|
||||
|
@ -239,16 +361,28 @@ typedef struct ss_plugin_field_extract_input
|
|||
// extracted value as output. Memory pointers set as output must be allocated
|
||||
// by the plugin and must not be deallocated or modified until the next
|
||||
// extract_fields() call.
|
||||
ss_plugin_extract_field *fields;
|
||||
ss_plugin_extract_field* fields;
|
||||
//
|
||||
// Supported but deprecated. Use the extended version table_reader_ext.
|
||||
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||
// give this name to the associated *_ext pointer.
|
||||
ss_plugin_table_reader_vtable table_reader;
|
||||
//
|
||||
// Vtable for controlling a state table for read operations.
|
||||
ss_plugin_table_reader_vtable table_reader;
|
||||
ss_plugin_table_reader_vtable_ext* table_reader_ext;
|
||||
|
||||
// An array of ss_plugin_extract_value_offsets structs. The start
|
||||
// and length in each entry should be set to nullptr, and as with
|
||||
// the "fields" member, memory pointers set as output must be
|
||||
// allocated by the plugin and must not be deallocated or modified
|
||||
// until the next extract_fields() call.
|
||||
// This member is optional, and might be ignored by extractors.
|
||||
ss_plugin_extract_value_offsets* value_offsets;
|
||||
} ss_plugin_field_extract_input;
|
||||
|
||||
// Input passed to the plugin when parsing an event for the event parsing
|
||||
// capability.
|
||||
typedef struct ss_plugin_event_parse_input
|
||||
{
|
||||
typedef struct ss_plugin_event_parse_input {
|
||||
//
|
||||
// The plugin's owner. Can be passed by the plugin to the callbacks available
|
||||
// in this struct in order to invoke functions of its owner.
|
||||
|
@ -257,26 +391,122 @@ typedef struct ss_plugin_event_parse_input
|
|||
// Return a string with the error that was last generated by the plugin's
|
||||
// owner, or NULL if no error is present.
|
||||
// The string pointer is owned by the plugin's owenr.
|
||||
const char *(*get_owner_last_error)(ss_plugin_owner_t *o);
|
||||
const char* (*get_owner_last_error)(ss_plugin_owner_t* o);
|
||||
//
|
||||
// Vtable for controlling a state table for read operations.
|
||||
// Supported but deprecated. Use the extended version table_reader_ext.
|
||||
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||
// give this name to the associated *_ext pointer.
|
||||
ss_plugin_table_reader_vtable table_reader;
|
||||
//
|
||||
// Vtable for controlling a state table for write operations.
|
||||
// Supported but deprecated. Use the extended version table_writer_ext.
|
||||
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||
// give this name to the associated *_ext pointer.
|
||||
ss_plugin_table_writer_vtable table_writer;
|
||||
//
|
||||
// Vtable for controlling a state table for read operations.
|
||||
ss_plugin_table_reader_vtable_ext* table_reader_ext;
|
||||
//
|
||||
// Vtable for controlling a state table for write operations.
|
||||
ss_plugin_table_writer_vtable_ext* table_writer_ext;
|
||||
} ss_plugin_event_parse_input;
|
||||
|
||||
// Input passed to the plugin when setting a new configuration
|
||||
typedef struct ss_plugin_set_config_input {
|
||||
//
|
||||
// An opaque string representing the new configuration provided by the framework
|
||||
const char* config;
|
||||
} ss_plugin_set_config_input;
|
||||
|
||||
//
|
||||
// An opaque pointer representing a routine subscribed in the framework-provided thread pool
|
||||
typedef void ss_plugin_routine_t;
|
||||
|
||||
//
|
||||
// An opaque pointer representing the state of the routine on each iteration
|
||||
typedef void ss_plugin_routine_state_t;
|
||||
|
||||
//
|
||||
// The function executed by the routine on each iteration.
|
||||
// Arguments:
|
||||
// - s: the plugin state, returned by init(). Can be NULL.
|
||||
// - i: the routine state, provided by the plugin when the routine is subscribed
|
||||
//
|
||||
// Return value: Returning false causes the routine to be unsubcribed from the thread pool.
|
||||
typedef ss_plugin_bool (*ss_plugin_routine_fn_t)(ss_plugin_t* s, ss_plugin_routine_state_t* i);
|
||||
|
||||
//
|
||||
// Vtable used by the plugin to subscribe and unsubscribe recurring loop-like routines
|
||||
// to the framework-provide thread pool
|
||||
typedef struct {
|
||||
//
|
||||
// Subscribes a routine to the framework-provided thread pool.
|
||||
// Arguments:
|
||||
// - o: the plugin's owner
|
||||
// - f: the function executed by the routine on each iteration
|
||||
// - i: the routine's state
|
||||
//
|
||||
// Return value: A routine handle that can be used to later unsubscribe the routine. Returns
|
||||
// null in case of failure.
|
||||
ss_plugin_routine_t* (*subscribe)(ss_plugin_owner_t* o,
|
||||
ss_plugin_routine_fn_t f,
|
||||
ss_plugin_routine_state_t* i);
|
||||
|
||||
//
|
||||
// Unsubscribes a routine from the framework-provided thread pool.
|
||||
// Arguments:
|
||||
// - o: the plugin's owner
|
||||
// - r: the routine's handle
|
||||
//
|
||||
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||
ss_plugin_rc (*unsubscribe)(ss_plugin_owner_t* o, ss_plugin_routine_t* r);
|
||||
} ss_plugin_routine_vtable;
|
||||
|
||||
// Input passed to the plugin when the framework start and stops the capture.
|
||||
typedef struct ss_plugin_capture_listen_input {
|
||||
//
|
||||
// The plugin's owner. Can be passed by the plugin to the callbacks available
|
||||
// in this struct in order to invoke functions of its owner.
|
||||
ss_plugin_owner_t* owner;
|
||||
//
|
||||
// Vtable containing callbacks that can be used by the plugin
|
||||
// for subscribing and unsubscribing routines to the framework's thread pool.
|
||||
ss_plugin_routine_vtable* routine;
|
||||
//
|
||||
// Vtable for controlling a state table for read operations.
|
||||
ss_plugin_table_reader_vtable_ext* table_reader_ext;
|
||||
//
|
||||
// Vtable for controlling a state table for write operations.
|
||||
ss_plugin_table_writer_vtable_ext* table_writer_ext;
|
||||
//
|
||||
// Return a string with the error that was last generated by the plugin's
|
||||
// owner, or NULL if no error is present.
|
||||
// The string pointer is owned by the plugin's owenr.
|
||||
const char* (*get_owner_last_error)(ss_plugin_owner_t* o);
|
||||
} ss_plugin_capture_listen_input;
|
||||
|
||||
//
|
||||
// Function handler used by plugin for sending asynchronous events to the
|
||||
// Falcosecurity libs during a live event capture. The asynchronous events
|
||||
// must be encoded as an async event type (code 402) as for the libscap specific.
|
||||
//
|
||||
// The plugin framework will automatically set the plugin ID of the produced
|
||||
// async event depending on the running event source in which the event will
|
||||
// be injected into. The event's thread ID can be set to control the system
|
||||
// thread associated, with value (uint64_t) -1) representing no thread
|
||||
// association. The event's timestamp can be set to forcefully specify
|
||||
// the timestamp of the phenomena that the event represents, and value
|
||||
// (uint64_t) -1) will cause the plugin framework to automatically assign
|
||||
// a timestamp as the time in which the event is received asynchronously.
|
||||
//
|
||||
// The function returns SS_PLUGIN_SUCCESS in case of success, or
|
||||
// SS_PLUGIN_FAILURE otherwise. If a non-NULL char pointer is passed for
|
||||
// the "err" argument, it will be filled with an error message string
|
||||
// in case the handler function returns SS_PLUGIN_FAILURE. The error string
|
||||
// has a max length of PLUGIN_MAX_ERRLEN (termination char included) and its
|
||||
// memory must be allocated and owned by the plugin.
|
||||
typedef ss_plugin_rc (*ss_plugin_async_event_handler_t)(ss_plugin_owner_t* o, const ss_plugin_event *evt, char* err);
|
||||
typedef ss_plugin_rc (*ss_plugin_async_event_handler_t)(ss_plugin_owner_t* o,
|
||||
const ss_plugin_event* evt,
|
||||
char* err);
|
||||
|
||||
//
|
||||
// The struct below define the functions and arguments for plugins capabilities:
|
||||
|
@ -308,8 +538,7 @@ typedef ss_plugin_rc (*ss_plugin_async_event_handler_t)(ss_plugin_owner_t* o, co
|
|||
//
|
||||
// Plugins API vtable
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
//
|
||||
// Return the version of the plugin API used by this plugin.
|
||||
// Required: yes
|
||||
|
@ -320,7 +549,7 @@ typedef struct
|
|||
// of the API they run against, and the framework will take care of checking
|
||||
// and enforcing compatibility.
|
||||
//
|
||||
const char *(*get_required_api_version)();
|
||||
const char* (*get_required_api_version)();
|
||||
|
||||
//
|
||||
// Return a string representation of a schema describing the data expected
|
||||
|
@ -341,7 +570,7 @@ typedef struct
|
|||
// This also serves as a piece of documentation for users about how the
|
||||
// plugin needs to be configured.
|
||||
//
|
||||
const char *(*get_init_schema)(ss_plugin_schema_type *schema_type);
|
||||
const char* (*get_init_schema)(ss_plugin_schema_type* schema_type);
|
||||
|
||||
//
|
||||
// Initialize the plugin and allocate its state.
|
||||
|
@ -353,17 +582,17 @@ typedef struct
|
|||
// by the framework and passed to the other plugin functions.
|
||||
// If rc is SS_PLUGIN_FAILURE, this function may return NULL or a state to
|
||||
// later retrieve the error string.
|
||||
//
|
||||
//
|
||||
// If a non-NULL ss_plugin_t* state is returned, then subsequent invocations
|
||||
// of init() must not return the same ss_plugin_t* value again, if not after
|
||||
// it has been disposed with destroy() first.
|
||||
ss_plugin_t *(*init)(const ss_plugin_init_input *input, ss_plugin_rc *rc);
|
||||
ss_plugin_t* (*init)(const ss_plugin_init_input* input, ss_plugin_rc* rc);
|
||||
|
||||
//
|
||||
// Destroy the plugin and, if plugin state was allocated, free it.
|
||||
// Required: yes
|
||||
//
|
||||
void (*destroy)(ss_plugin_t *s);
|
||||
void (*destroy)(ss_plugin_t* s);
|
||||
|
||||
//
|
||||
// Return a string with the error that was last generated by
|
||||
|
@ -375,28 +604,28 @@ typedef struct
|
|||
// string with more context for the error. The framework
|
||||
// calls get_last_error() to access that string.
|
||||
//
|
||||
const char *(*get_last_error)(ss_plugin_t *s);
|
||||
const char* (*get_last_error)(ss_plugin_t* s);
|
||||
|
||||
//
|
||||
// Return the name of the plugin, which will be printed when displaying
|
||||
// information about the plugin.
|
||||
// Required: yes
|
||||
//
|
||||
const char *(*get_name)();
|
||||
const char* (*get_name)();
|
||||
|
||||
//
|
||||
// Return the descriptions of the plugin, which will be printed when displaying
|
||||
// information about the plugin.
|
||||
// Required: yes
|
||||
//
|
||||
const char *(*get_description)();
|
||||
const char* (*get_description)();
|
||||
|
||||
//
|
||||
// Return a string containing contact info (url, email, etc) for
|
||||
// the plugin authors.
|
||||
// Required: yes
|
||||
//
|
||||
const char *(*get_contact)();
|
||||
const char* (*get_contact)();
|
||||
|
||||
//
|
||||
// Return the version of this plugin itself
|
||||
|
@ -410,15 +639,15 @@ typedef struct
|
|||
// in pre-existing capture files must always be readable by newer versions
|
||||
// of the plugin.
|
||||
//
|
||||
const char *(*get_version)();
|
||||
const char* (*get_version)();
|
||||
|
||||
// Event sourcing capability API
|
||||
struct
|
||||
{
|
||||
struct {
|
||||
//
|
||||
// Return the unique ID of the plugin.
|
||||
// Required: yes if get_event_source is defined and returns a non-empty string, no otherwise.
|
||||
//
|
||||
// Required: yes if get_event_source is defined and returns a non-empty string, no
|
||||
// otherwise.
|
||||
//
|
||||
// If the plugin has a specific ID and event source, then its next_batch()
|
||||
// function is allowed to only return events of plugin type (code 322)
|
||||
// with its own plugin ID and event source.
|
||||
|
@ -434,7 +663,7 @@ typedef struct
|
|||
// Return a string representing the name of the event source generated
|
||||
// by this plugin.
|
||||
// Required: yes if get_id is defined and returns a non-zero number, no otherwise.
|
||||
//
|
||||
//
|
||||
// If the plugin has a specific ID and event source, then its next_batch()
|
||||
// function is allowed to only return events of plugin type (code 322)
|
||||
// with its own plugin ID and event source.
|
||||
|
@ -525,7 +754,7 @@ typedef struct
|
|||
// event sourcing capability. Even if defined, this function is not
|
||||
// used by the framework if the plugin does not implement a specific
|
||||
// event source (get_id() is zero or get_event_source() is empty).
|
||||
//
|
||||
//
|
||||
// Required: no
|
||||
//
|
||||
// Arguments:
|
||||
|
@ -544,7 +773,7 @@ typedef struct
|
|||
// If the returned pointer is non-NULL, then it must be uniquely
|
||||
// attached to the ss_plugin_t* parameter value. The pointer must not
|
||||
// be shared across multiple distinct ss_plugin_t* values.
|
||||
const char* (*event_to_string)(ss_plugin_t *s, const ss_plugin_event_input *evt);
|
||||
const char* (*event_to_string)(ss_plugin_t* s, const ss_plugin_event_input* evt);
|
||||
|
||||
//
|
||||
// Return the next batch of events.
|
||||
|
@ -572,15 +801,27 @@ typedef struct
|
|||
// The value of the ss_plugin_event** output parameter must be uniquely
|
||||
// attached to the ss_instance_t* parameter value. The pointer must not
|
||||
// be shared across multiple distinct ss_instance_t* values.
|
||||
ss_plugin_rc (*next_batch)(ss_plugin_t* s, ss_instance_t* h, uint32_t *nevts, ss_plugin_event ***evts);
|
||||
ss_plugin_rc (*next_batch)(ss_plugin_t* s,
|
||||
ss_instance_t* h,
|
||||
uint32_t* nevts,
|
||||
ss_plugin_event*** evts);
|
||||
};
|
||||
|
||||
// Field extraction capability API
|
||||
struct
|
||||
{
|
||||
struct {
|
||||
//
|
||||
// Return the list of event types that this plugin can consume
|
||||
// Return the list of event types that this plugin will receive
|
||||
// for field extraction. The event types follow the libscap specific.
|
||||
// This will be invoked only once by the framework after the plugin's
|
||||
// initialization. Events that are not included in the returned list
|
||||
// will not be received by the plugin.
|
||||
//
|
||||
// This is a non-functional filter that should not influence the plugin's
|
||||
// functional behavior. Instead, this is a performance optimization
|
||||
// with the goal of avoiding unnecessary communication between the
|
||||
// framework and the plugin for events that are known to be not used for
|
||||
// field extraction.
|
||||
//
|
||||
// Required: no
|
||||
//
|
||||
// This function is optional--if NULL or an empty array, then:
|
||||
|
@ -588,7 +829,9 @@ typedef struct
|
|||
// get_extract_event_sources (either default or custom) is compatible
|
||||
// with the "syscall" event source, otherwise
|
||||
// - the plugin will only receive events of plugin type (code 322).
|
||||
uint16_t* (*get_extract_event_types)(uint32_t* numtypes);
|
||||
// todo(jasondellaluce): when/if major changes to v4, reorder the arguments
|
||||
// and put ss_plugin_t* as first
|
||||
uint16_t* (*get_extract_event_types)(uint32_t* numtypes, ss_plugin_t* s);
|
||||
|
||||
//
|
||||
// Return a string describing the event sources that this plugin
|
||||
|
@ -597,9 +840,9 @@ typedef struct
|
|||
// Return value: a json array of strings containing event
|
||||
// sources returned by a plugin with event sourcing capabilities get_event_source()
|
||||
// function, or "syscall" for indicating support to non-plugin events.
|
||||
// This function is optional--if NULL or an empty array, then if plugin has sourcing capability,
|
||||
// and implements a specific event source, it will only receive events matching its event source,
|
||||
// otherwise it will receive events from all event sources.
|
||||
// This function is optional--if NULL or an empty array, then if plugin has sourcing
|
||||
// capability, and implements a specific event source, it will only receive events matching
|
||||
// its event source, otherwise it will receive events from all event sources.
|
||||
//
|
||||
const char* (*get_extract_event_sources)();
|
||||
|
||||
|
@ -613,7 +856,7 @@ typedef struct
|
|||
// "name": a string with a name for the field
|
||||
// "type": one of "string", "uint64", "bool", "reltime", "abstime",
|
||||
// "ipaddr", "ipnet"
|
||||
// "isList: (optional) If present and set to true, notes
|
||||
// "isList: (optional) if present and set to true, notes
|
||||
// that the field extracts a list of values.
|
||||
// "arg": (optional) if present, notes that the field can accept
|
||||
// an argument e.g. field[arg]. More precisely, the following
|
||||
|
@ -630,10 +873,13 @@ typedef struct
|
|||
// display the field instead of the name. Used in tools
|
||||
// like wireshark.
|
||||
// "desc": a string with a description of the field
|
||||
// "addOutput": (optional) if true, suggest this field to be appended to the
|
||||
// output string for compatible event sources.
|
||||
// Example return value:
|
||||
// [
|
||||
// {"type": "uint64", "name": "field1", "desc": "Describing field 1"},
|
||||
// {"type": "string", "name": "field2", "arg": {"isRequired": true, "isIndex": true}, "desc": "Describing field 2"},
|
||||
// {"type": "uint64", "name": "field1", "desc": "Describing field 1", "addOutput": true},
|
||||
// {"type": "string", "name": "field2", "arg": {"isRequired": true, "isIndex": true},
|
||||
// "desc": "Describing field 2"},
|
||||
// ]
|
||||
const char* (*get_fields)();
|
||||
|
||||
|
@ -659,15 +905,25 @@ typedef struct
|
|||
// The value of the ss_plugin_extract_field* output parameter must be
|
||||
// uniquely attached to the ss_plugin_t* parameter value. The pointer
|
||||
// must not be shared across multiple distinct ss_plugin_t* values.
|
||||
ss_plugin_rc (*extract_fields)(ss_plugin_t *s, const ss_plugin_event_input *evt, const ss_plugin_field_extract_input* in);
|
||||
ss_plugin_rc (*extract_fields)(ss_plugin_t* s,
|
||||
const ss_plugin_event_input* evt,
|
||||
const ss_plugin_field_extract_input* in);
|
||||
};
|
||||
|
||||
// Event parsing capability API
|
||||
struct
|
||||
{
|
||||
struct {
|
||||
//
|
||||
// Return the list of event types that this plugin is capable of parsing.
|
||||
// The event types follow the libscap specific.
|
||||
// Return the list of event types that this plugin will receive
|
||||
// for event parsing. The event types follow the libscap specific.
|
||||
// This will be invoked only once by the framework after the plugin's
|
||||
// initialization. Events that are not included in the returned list
|
||||
// will not be received by the plugin.
|
||||
//
|
||||
// This is a non-functional filter that should not influence the plugin's
|
||||
// functional behavior. Instead, this is a performance optimization
|
||||
// with the goal of avoiding unnecessary communication between the
|
||||
// framework and the plugin for events that are known to be not used for
|
||||
// event parsing.
|
||||
//
|
||||
// Required: no
|
||||
//
|
||||
|
@ -676,7 +932,9 @@ typedef struct
|
|||
// get_parse_event_sources (either default or custom) is compatible
|
||||
// with the "syscall" event source, otherwise
|
||||
// - the plugin will only receive events of plugin type (code 322).
|
||||
uint16_t* (*get_parse_event_types)(uint32_t* numtypes);
|
||||
// todo(jasondellaluce): when/if major changes to v4, reorder the arguments
|
||||
// and put ss_plugin_t* as first
|
||||
uint16_t* (*get_parse_event_types)(uint32_t* numtypes, ss_plugin_t* s);
|
||||
//
|
||||
// Return a string describing the event sources that this plugin
|
||||
// is capable of parsing.
|
||||
|
@ -686,9 +944,9 @@ typedef struct
|
|||
// Return value: a json array of strings containing event
|
||||
// sources returned by a plugin with event sourcing capabilities get_event_source()
|
||||
// function, or "syscall" for indicating support to non-plugin events.
|
||||
// This function is optional--if NULL or an empty array, then if plugin has sourcing capability,
|
||||
// and implements a specific event source, it will only receive events matching its event source,
|
||||
// otherwise it will receive events from all event sources.
|
||||
// This function is optional--if NULL or an empty array, then if plugin has sourcing
|
||||
// capability, and implements a specific event source, it will only receive events matching
|
||||
// its event source, otherwise it will receive events from all event sources.
|
||||
//
|
||||
const char* (*get_parse_event_sources)();
|
||||
//
|
||||
|
@ -717,16 +975,17 @@ typedef struct
|
|||
// The value of the ss_plugin_event_parse_input* output parameter must be
|
||||
// uniquely attached to the ss_plugin_t* parameter value. The pointer
|
||||
// must not be shared across multiple distinct ss_plugin_t* values.
|
||||
ss_plugin_rc (*parse_event)(ss_plugin_t *s, const ss_plugin_event_input *evt, const ss_plugin_event_parse_input* in);
|
||||
ss_plugin_rc (*parse_event)(ss_plugin_t* s,
|
||||
const ss_plugin_event_input* evt,
|
||||
const ss_plugin_event_parse_input* in);
|
||||
};
|
||||
|
||||
// Async events capability API
|
||||
struct
|
||||
{
|
||||
struct {
|
||||
//
|
||||
// Return a string describing the event sources for which this plugin
|
||||
// is capable of injecting async events in the event stream of a capture.
|
||||
//
|
||||
//
|
||||
// Required: no
|
||||
//
|
||||
// Return value: a json array of strings containing event
|
||||
|
@ -785,9 +1044,9 @@ typedef struct
|
|||
// expressed in the list returned by get_async_events(). The name
|
||||
// of an async event acts as a contract on the encoding of the data
|
||||
// payload of all async events with the same name.
|
||||
//
|
||||
//
|
||||
// Required: yes
|
||||
//
|
||||
//
|
||||
// Arguments:
|
||||
// - owner: Opaque pointer to the plugin's owner. Must be passed
|
||||
// as an argument to the async event function handler.
|
||||
|
@ -799,7 +1058,78 @@ typedef struct
|
|||
//
|
||||
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||
//
|
||||
ss_plugin_rc (*set_async_event_handler)(ss_plugin_t* s, ss_plugin_owner_t* owner, const ss_plugin_async_event_handler_t handler);
|
||||
ss_plugin_rc (*set_async_event_handler)(ss_plugin_t* s,
|
||||
ss_plugin_owner_t* owner,
|
||||
const ss_plugin_async_event_handler_t handler);
|
||||
|
||||
//
|
||||
// Called by the framework when a capture file dump is requested.
|
||||
//
|
||||
// Required: no
|
||||
// Arguments:
|
||||
// - s: the plugin state, returned by init(). Can be NULL.
|
||||
// - owner: Opaque pointer to the plugin's owner. Must be passed
|
||||
// as an argument to the async event function handler.
|
||||
// - handler: Function handler to be used for sending events to be dumped
|
||||
// to the plugin's owner. The handler must be invoked with
|
||||
// the same owner opaque pointer passed to this function, and with
|
||||
// an event pointer owned and controlled by the plugin. The event
|
||||
// pointer is not retained by the handler after it returns.
|
||||
//
|
||||
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||
ss_plugin_rc (*dump_state)(ss_plugin_t* s,
|
||||
ss_plugin_owner_t* owner,
|
||||
const ss_plugin_async_event_handler_t handler);
|
||||
};
|
||||
|
||||
// Sets a new plugin configuration when provided by the framework.
|
||||
// Required: no
|
||||
// Arguments:
|
||||
// - s: the plugin state, returned by init(). Can be NULL.
|
||||
// - i: configuration input provided by the framework.
|
||||
//
|
||||
// Return value: A ss_plugin_rc with value SS_PLUGIN_SUCCESS if the config is accepted
|
||||
// or SS_PLUGIN_FAILURE if the config is rejected.
|
||||
// If rejected the plugin should provide context in the string returned by get_last_error().
|
||||
ss_plugin_rc (*set_config)(ss_plugin_t* s, const ss_plugin_set_config_input* i);
|
||||
|
||||
//
|
||||
// Return an updated set of metrics provided by this plugin.
|
||||
// Required: no
|
||||
// Arguments:
|
||||
// - s: the plugin state, returned by init(). Can be NULL.
|
||||
// - num_metrics: lenght of the returned metrics array.
|
||||
//
|
||||
// Return value: Pointer to the first element of the metrics array.
|
||||
// 'num_metrics' must be set to the lenght of the array before returning
|
||||
// and it can be set to 0 if no metrics are provided.
|
||||
ss_plugin_metric* (*get_metrics)(ss_plugin_t* s, uint32_t* num_metrics);
|
||||
|
||||
// Capture listening capability API
|
||||
struct {
|
||||
//
|
||||
// Called by the framework when the event capture opens.
|
||||
//
|
||||
// Required: no
|
||||
// Arguments:
|
||||
// - s: the plugin state, returned by init(). Can be NULL.
|
||||
// - i: input containing vtables for performing table operations and subscribe/unsubscribe
|
||||
// async routines
|
||||
//
|
||||
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||
ss_plugin_rc (*capture_open)(ss_plugin_t* s, const ss_plugin_capture_listen_input* i);
|
||||
|
||||
//
|
||||
// Called by the framework when the event capture closes.
|
||||
//
|
||||
// Required: yes if capture_open is defined
|
||||
// Arguments:
|
||||
// - s: the plugin state, returned by init(). Can be NULL.
|
||||
// - i: input containing vtables for performing table operations and subscribe/unsubscribe
|
||||
// async routines
|
||||
//
|
||||
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||
ss_plugin_rc (*capture_close)(ss_plugin_t* s, const ss_plugin_capture_listen_input* i);
|
||||
};
|
||||
} plugin_api;
|
||||
|
||||
|
|
|
@ -30,30 +30,28 @@ typedef uint32_t ss_plugin_bool;
|
|||
|
||||
// The noncontinguous numbers are to maintain equality with underlying
|
||||
// falcosecurity libs types.
|
||||
typedef enum ss_plugin_field_type
|
||||
{
|
||||
typedef enum ss_plugin_field_type {
|
||||
// A 64bit unsigned integer.
|
||||
FTYPE_UINT64 = 8,
|
||||
FTYPE_UINT64 = 8,
|
||||
// A printable buffer of bytes, NULL terminated
|
||||
FTYPE_STRING = 9,
|
||||
FTYPE_STRING = 9,
|
||||
// A relative time. Seconds * 10^9 + nanoseconds. 64bit.
|
||||
FTYPE_RELTIME = 20,
|
||||
FTYPE_RELTIME = 20,
|
||||
// An absolute time interval. Seconds from epoch * 10^9 + nanoseconds. 64bit.
|
||||
FTYPE_ABSTIME = 21,
|
||||
FTYPE_ABSTIME = 21,
|
||||
// A boolean value, 4 bytes.
|
||||
FTYPE_BOOL = 25,
|
||||
FTYPE_BOOL = 25,
|
||||
// Either an IPv4 or IPv6 address. The length indicates which one it is.
|
||||
FTYPE_IPADDR = 40,
|
||||
FTYPE_IPADDR = 40,
|
||||
// Either an IPv4 or IPv6 network. The length indicates which one it is.
|
||||
// The field encodes only the IP address, so this differs from FTYPE_IPADDR,
|
||||
// from the way the framework perform runtime checks and comparisons.
|
||||
FTYPE_IPNET = 41,
|
||||
FTYPE_IPNET = 41,
|
||||
} ss_plugin_field_type;
|
||||
|
||||
// Values to return from init() / open() / next_batch() /
|
||||
// extract_fields().
|
||||
typedef enum ss_plugin_rc
|
||||
{
|
||||
typedef enum ss_plugin_rc {
|
||||
SS_PLUGIN_SUCCESS = 0,
|
||||
SS_PLUGIN_FAILURE = 1,
|
||||
SS_PLUGIN_TIMEOUT = -1,
|
||||
|
@ -62,8 +60,7 @@ typedef enum ss_plugin_rc
|
|||
} ss_plugin_rc;
|
||||
|
||||
// The supported schema formats for the init configuration.
|
||||
typedef enum ss_plugin_schema_type
|
||||
{
|
||||
typedef enum ss_plugin_schema_type {
|
||||
// The schema is undefined and the init configuration
|
||||
// is an opaque string.
|
||||
SS_PLUGIN_SCHEMA_NONE = 0,
|
||||
|
@ -79,7 +76,8 @@ typedef enum ss_plugin_schema_type
|
|||
// An event is represented as a contiguous region of memory composed by
|
||||
// a header and a list of parameters appended, in the form of:
|
||||
//
|
||||
// | evt header | len param 1 (2B/4B) | ... | len param N (2B/4B) | data param 1 | ... | data param N |
|
||||
// | evt header | len param 1 (2B/4B) | ... | len param N (2B/4B) | data param 1 | ... | data param
|
||||
// N |
|
||||
//
|
||||
// The event header is composed of:
|
||||
// - ts: the event timestamp, in nanoseconds since the epoch.
|
||||
|
@ -96,8 +94,6 @@ typedef enum ss_plugin_schema_type
|
|||
#if defined _MSC_VER
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
#elif defined __sun
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
@ -105,17 +101,13 @@ struct ss_plugin_event {
|
|||
#ifdef PPM_ENABLE_SENTINEL
|
||||
uint32_t sentinel_begin;
|
||||
#endif
|
||||
uint64_t ts; /* timestamp, in nanoseconds from epoch */
|
||||
uint64_t tid; /* the tid of the thread that generated this event */
|
||||
uint32_t len; /* the event len, including the header */
|
||||
uint16_t type; /* the event type */
|
||||
uint64_t ts; /* timestamp, in nanoseconds from epoch */
|
||||
uint64_t tid; /* the tid of the thread that generated this event */
|
||||
uint32_t len; /* the event len, including the header */
|
||||
uint16_t type; /* the event type */
|
||||
uint32_t nparams; /* the number of parameters of the event */
|
||||
};
|
||||
#if defined __sun
|
||||
#pragma pack()
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
typedef struct ss_plugin_event ss_plugin_event;
|
||||
|
||||
// This struct represents an event provided by the framework to the plugin
|
||||
|
@ -125,18 +117,31 @@ typedef struct ss_plugin_event ss_plugin_event;
|
|||
// Might not be contiguous.
|
||||
// - evtsrc: The name of the event's source. Can be "syscall" or any other
|
||||
// event source name implemented by a plugin.
|
||||
typedef struct ss_plugin_event_input
|
||||
{
|
||||
typedef struct ss_plugin_event_input {
|
||||
const ss_plugin_event* evt;
|
||||
uint64_t evtnum;
|
||||
const char* evtsrc;
|
||||
} ss_plugin_event_input;
|
||||
|
||||
typedef struct ss_plugin_byte_buffer{
|
||||
typedef struct ss_plugin_byte_buffer {
|
||||
uint32_t len;
|
||||
const void* ptr;
|
||||
} ss_plugin_byte_buffer;
|
||||
|
||||
// Used in extract_fields_and_offsets to receive field value offsets
|
||||
// along with field data.
|
||||
// Extraction functions that support offsets should be set these to an
|
||||
// array of zero-indexed start offsets and lengths of each returned
|
||||
// value in the event or log data. {0, 0} can be used to indicate that
|
||||
// there are no valid offsets, e.g. if the value was generated or
|
||||
// computed from other data.
|
||||
// Extraction functions might not support offsets. In order to detect
|
||||
// this, callers should initialize the start and length to nullptr.
|
||||
typedef struct ss_plugin_extract_value_offsets {
|
||||
uint32_t* start;
|
||||
uint32_t* length;
|
||||
} ss_plugin_extract_value_offsets;
|
||||
|
||||
// Used in extract_fields functions below to receive a field/arg
|
||||
// pair and return an extracted value.
|
||||
// field_id: id of the field, as of its index in the list of
|
||||
|
@ -145,16 +150,16 @@ typedef struct ss_plugin_byte_buffer{
|
|||
// arg_key: the field argument, if a 'key' argument has been specified
|
||||
// for the field (isKey=true), otherwise it's NULL.
|
||||
// For example:
|
||||
// * if the field specified by the user is foo.bar[pippo], arg_key
|
||||
// * if the field specified by the user is foo.bar[pippo], arg_key
|
||||
// will be the string "pippo"
|
||||
// * if the field specified by the user is foo.bar, arg will be NULL
|
||||
// arg_index: the field argument, if a 'index' argument has been specified
|
||||
// for the field (isIndex=true), otherwise it's 0.
|
||||
// For example:
|
||||
// * if the field specified by the user is foo.bar[1], arg_index
|
||||
// will be the uint64_t '1'.
|
||||
// * if the field specified by the user is foo.bar[1], arg_index
|
||||
// will be the uint64_t '1'.
|
||||
// Please note the ambiguity with a 0
|
||||
// argument which could be a real argument of just the default
|
||||
// argument which could be a real argument of just the default
|
||||
// value to point out the absence. The `arg_present` field resolves
|
||||
// this ambiguity.
|
||||
// arg_present: helps to understand if the arg is there since arg_index is
|
||||
|
@ -175,14 +180,12 @@ typedef struct ss_plugin_byte_buffer{
|
|||
// If the field is a list type, then res_len can must be any value from 0 to N, depending
|
||||
// on how many values can be extracted from a given event.
|
||||
// Setting res_len to 0 means that no value of this field can be extracted from a given event.
|
||||
typedef struct ss_plugin_extract_field
|
||||
{
|
||||
typedef struct ss_plugin_extract_field {
|
||||
// NOTE: For a given architecture, this has always the same size which
|
||||
// is sizeof(uintptr_t). Adding new value types will not create breaking
|
||||
// changes in the plugin API. However, we must make sure that each added
|
||||
// type is always a pointer.
|
||||
union
|
||||
{
|
||||
union {
|
||||
const char** str;
|
||||
uint64_t* u64;
|
||||
uint32_t* u32;
|
||||
|
@ -203,12 +206,21 @@ typedef struct ss_plugin_extract_field
|
|||
ss_plugin_bool flist;
|
||||
} ss_plugin_extract_field;
|
||||
|
||||
// Opaque a pointer to a state table. The falcosecurity libs define stateful
|
||||
// components in the form of tables.
|
||||
typedef void ss_plugin_table_t;
|
||||
|
||||
// Opaque a pointer to an entry of a state table.
|
||||
typedef void ss_plugin_table_entry_t;
|
||||
|
||||
// Opaque accessor to a data field available in the entries of a state table.
|
||||
typedef void ss_plugin_table_field_t;
|
||||
|
||||
// Types supported by entry fields of state tables.
|
||||
// The noncontinguous numbers are to maintain equality with underlying
|
||||
// falcosecurity libs types.
|
||||
// todo(jasondellaluce): should we merge this with ss_plugin_field_type?
|
||||
typedef enum ss_plugin_state_type
|
||||
{
|
||||
typedef enum ss_plugin_state_type {
|
||||
SS_PLUGIN_ST_INT8 = 1,
|
||||
SS_PLUGIN_ST_INT16 = 2,
|
||||
SS_PLUGIN_ST_INT32 = 3,
|
||||
|
@ -218,13 +230,13 @@ typedef enum ss_plugin_state_type
|
|||
SS_PLUGIN_ST_UINT32 = 7,
|
||||
SS_PLUGIN_ST_UINT64 = 8,
|
||||
SS_PLUGIN_ST_STRING = 9,
|
||||
SS_PLUGIN_ST_TABLE = 10,
|
||||
SS_PLUGIN_ST_BOOL = 25
|
||||
} ss_plugin_state_type;
|
||||
|
||||
// Data representation of entry fields of state tables.
|
||||
// todo(jasondellaluce): should we merge this with what we have for field extraction?
|
||||
typedef union ss_plugin_state_data
|
||||
{
|
||||
typedef union ss_plugin_state_data {
|
||||
int8_t s8;
|
||||
int16_t s16;
|
||||
int32_t s32;
|
||||
|
@ -235,33 +247,22 @@ typedef union ss_plugin_state_data
|
|||
uint64_t u64;
|
||||
const char* str;
|
||||
ss_plugin_bool b;
|
||||
ss_plugin_table_t* table;
|
||||
} ss_plugin_state_data;
|
||||
|
||||
// Info about a state table.
|
||||
typedef struct ss_plugin_table_info
|
||||
{
|
||||
typedef struct ss_plugin_table_info {
|
||||
const char* name;
|
||||
ss_plugin_state_type key_type;
|
||||
} ss_plugin_table_info;
|
||||
|
||||
// Info about a data field contained in the entires of a state table.
|
||||
typedef struct ss_plugin_table_fieldinfo
|
||||
{
|
||||
typedef struct ss_plugin_table_fieldinfo {
|
||||
const char* name;
|
||||
ss_plugin_state_type field_type;
|
||||
ss_plugin_bool read_only;
|
||||
} ss_plugin_table_fieldinfo;
|
||||
|
||||
// Opaque a pointer to a state table. The falcosecurity libs define stateful
|
||||
// components in the form of tables.
|
||||
typedef void ss_plugin_table_t;
|
||||
|
||||
// Opaque a pointer to an entry of a state table.
|
||||
typedef void ss_plugin_table_entry_t;
|
||||
|
||||
// Opaque accessor to a data field available in the entries of a state table.
|
||||
typedef void ss_plugin_table_field_t;
|
||||
|
||||
// Opaque pointer to the owner of a plugin. It can be used to invert the
|
||||
// control and invoke functions of the plugin's owner from within the plugin.
|
||||
typedef void ss_plugin_owner_t;
|
||||
|
@ -285,6 +286,64 @@ typedef void ss_plugin_t;
|
|||
//
|
||||
typedef void ss_instance_t;
|
||||
|
||||
//
|
||||
// Severity available in the logging facility provided by the framework
|
||||
typedef enum ss_plugin_log_severity {
|
||||
SS_PLUGIN_LOG_SEV_FATAL = 1,
|
||||
SS_PLUGIN_LOG_SEV_CRITICAL = 2,
|
||||
SS_PLUGIN_LOG_SEV_ERROR = 3,
|
||||
SS_PLUGIN_LOG_SEV_WARNING = 4,
|
||||
SS_PLUGIN_LOG_SEV_NOTICE = 5,
|
||||
SS_PLUGIN_LOG_SEV_INFO = 6,
|
||||
SS_PLUGIN_LOG_SEV_DEBUG = 7,
|
||||
SS_PLUGIN_LOG_SEV_TRACE = 8,
|
||||
} ss_plugin_log_severity;
|
||||
|
||||
// Types supported by the by the metric values
|
||||
typedef enum ss_plugin_metric_value_type {
|
||||
SS_PLUGIN_METRIC_VALUE_TYPE_U32 = 0,
|
||||
SS_PLUGIN_METRIC_VALUE_TYPE_S32 = 1,
|
||||
SS_PLUGIN_METRIC_VALUE_TYPE_U64 = 2,
|
||||
SS_PLUGIN_METRIC_VALUE_TYPE_S64 = 3,
|
||||
SS_PLUGIN_METRIC_VALUE_TYPE_D = 4,
|
||||
SS_PLUGIN_METRIC_VALUE_TYPE_F = 5,
|
||||
SS_PLUGIN_METRIC_VALUE_TYPE_I = 6,
|
||||
} ss_plugin_metric_value_type;
|
||||
|
||||
// Data representation of metric values
|
||||
typedef union ss_plugin_metric_value {
|
||||
uint32_t u32;
|
||||
int32_t s32;
|
||||
uint64_t u64;
|
||||
int64_t s64;
|
||||
double d;
|
||||
float f;
|
||||
int i;
|
||||
} ss_plugin_metric_value;
|
||||
|
||||
// Metric types
|
||||
typedef enum ss_plugin_metric_type {
|
||||
SS_PLUGIN_METRIC_TYPE_MONOTONIC = 0,
|
||||
SS_PLUGIN_METRIC_TYPE_NON_MONOTONIC = 1,
|
||||
} ss_plugin_metric_type;
|
||||
|
||||
//
|
||||
// Struct representing a metric to be provided to the plugin framework
|
||||
typedef struct ss_plugin_metric {
|
||||
//
|
||||
// Opaque string representing the metric name
|
||||
const char* name;
|
||||
//
|
||||
// Metric type
|
||||
ss_plugin_metric_type type;
|
||||
//
|
||||
// Metric numeric value
|
||||
ss_plugin_metric_value value;
|
||||
//
|
||||
// Metric value data type
|
||||
ss_plugin_metric_value_type value_type;
|
||||
} ss_plugin_metric;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
diff --git a/pkg/sdk/plugin_api.h b/pkg/sdk/plugin_api.h
|
||||
index 0c877a2..54949b3 100644
|
||||
--- a/pkg/sdk/plugin_api.h
|
||||
+++ b/pkg/sdk/plugin_api.h
|
||||
@@ -18,7 +18,7 @@ limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
-#include <plugin/plugin_types.h>
|
||||
+#include "plugin_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
|
@ -55,6 +55,9 @@ func (m *testPlugin) Extract(req sdk.ExtractRequest, evt sdk.EventReader) error
|
|||
switch req.FieldID() {
|
||||
case 0:
|
||||
req.SetValue(uint64(0))
|
||||
if req.WantOffset() {
|
||||
req.SetValueOffset(sdk.PluginEventPayloadOffset, 8)
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unsupported field: %s", req.Field())
|
||||
|
|
|
@ -206,6 +206,7 @@ func (a *asyncContext) acquireWorker(workerIdx int32) {
|
|||
a.batch[i].evt,
|
||||
uint32(a.batch[i].num_fields),
|
||||
a.batch[i].fields,
|
||||
a.batch[i].value_offsets,
|
||||
),
|
||||
)
|
||||
// processing done, return back to waiting state
|
||||
|
|
|
@ -55,7 +55,8 @@ void async_deinit()
|
|||
extern int32_t plugin_extract_fields_sync(ss_plugin_t *s,
|
||||
const ss_plugin_event_input *evt,
|
||||
uint32_t num_fields,
|
||||
ss_plugin_extract_field *fields);
|
||||
ss_plugin_extract_field *fields,
|
||||
ss_plugin_extract_value_offsets *offsets);
|
||||
|
||||
// This is the plugin API function. If s_async_ctx_batch is
|
||||
// non-NULL, it calls the async extractor function. Otherwise, it
|
||||
|
@ -78,7 +79,7 @@ FALCO_PLUGIN_SDK_PUBLIC int32_t plugin_extract_fields(ss_plugin_t *s,
|
|||
if (s_async_ctx_batch == NULL
|
||||
|| atomic_load_explicit(&s_async_ctx_batch[(size_t)s - 1].lock, memory_order_seq_cst) != WAIT)
|
||||
{
|
||||
return plugin_extract_fields_sync(s, evt, in->num_fields, in->fields);
|
||||
return plugin_extract_fields_sync(s, evt, in->num_fields, in->fields, in->value_offsets);
|
||||
}
|
||||
|
||||
// Set input data
|
||||
|
@ -86,6 +87,7 @@ FALCO_PLUGIN_SDK_PUBLIC int32_t plugin_extract_fields(ss_plugin_t *s,
|
|||
s_async_ctx_batch[(size_t)s - 1].evt = evt;
|
||||
s_async_ctx_batch[(size_t)s - 1].num_fields = in->num_fields;
|
||||
s_async_ctx_batch[(size_t)s - 1].fields = in->fields;
|
||||
s_async_ctx_batch[(size_t)s - 1].value_offsets = in->value_offsets;
|
||||
|
||||
// notify data request
|
||||
atomic_store_explicit(&s_async_ctx_batch[(size_t)s - 1].lock, DATA_REQ, memory_order_seq_cst);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
Copyright (C) 2023 The Falco Authors.
|
||||
Copyright (C) 2025 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -28,6 +28,7 @@ limitations under the License.
|
|||
package extract
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include "extract.h"
|
||||
*/
|
||||
import "C"
|
||||
|
@ -39,20 +40,34 @@ import (
|
|||
)
|
||||
|
||||
//export plugin_extract_fields_sync
|
||||
func plugin_extract_fields_sync(plgState C.uintptr_t, evt *C.ss_plugin_event_input, numFields uint32, fields *C.ss_plugin_extract_field) int32 {
|
||||
func plugin_extract_fields_sync(plgState C.uintptr_t, evt *C.ss_plugin_event_input, numFields uint32, fields *C.ss_plugin_extract_field, offsets *C.ss_plugin_extract_value_offsets) int32 {
|
||||
pHandle := cgo.Handle(plgState)
|
||||
extract := pHandle.Value().(sdk.Extractor)
|
||||
extrReqs := pHandle.Value().(sdk.ExtractRequests)
|
||||
|
||||
// https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices
|
||||
// https://go.dev/wiki/cgo#turning-c-arrays-into-go-slices
|
||||
flds := (*[1 << 28]C.struct_ss_plugin_extract_field)(unsafe.Pointer(fields))[:numFields:numFields]
|
||||
var i uint32
|
||||
var extrReq sdk.ExtractRequest
|
||||
|
||||
if offsets != nil {
|
||||
extrReqs.ExtractRequests().MakeOffsetArrayPtrs(unsafe.Pointer(offsets), numFields)
|
||||
}
|
||||
|
||||
for i = 0; i < numFields; i++ {
|
||||
flds[i].res_len = (C.uint64_t)(0)
|
||||
extrReq = extrReqs.ExtractRequests().Get(int(flds[i].field_id))
|
||||
extrReq.SetPtr(unsafe.Pointer(&flds[i]))
|
||||
|
||||
if offsets == nil {
|
||||
extrReq.SetOffsetPtrs(nil, nil)
|
||||
} else {
|
||||
extrReq.SetOffsetPtrs(
|
||||
unsafe.Add(unsafe.Pointer(offsets.start), i*C.sizeof_uint32_t),
|
||||
unsafe.Add(unsafe.Pointer(offsets.length), i*C.sizeof_uint32_t),
|
||||
)
|
||||
}
|
||||
|
||||
err := extract.Extract(extrReq, sdk.NewEventReader(unsafe.Pointer(evt)))
|
||||
if err != nil {
|
||||
pHandle.Value().(sdk.LastError).SetLastError(err)
|
||||
|
|
|
@ -30,6 +30,7 @@ typedef struct async_extractor_info
|
|||
const ss_plugin_event_input *evt;
|
||||
uint32_t num_fields;
|
||||
ss_plugin_extract_field *fields;
|
||||
ss_plugin_extract_value_offsets *value_offsets;
|
||||
|
||||
// output data
|
||||
int32_t rc;
|
||||
|
|
|
@ -77,6 +77,14 @@ func allocSSPluginExtractField(fid, ftype uint32, fname, farg string) (*_Ctype_s
|
|||
}
|
||||
}
|
||||
|
||||
func allocSSPluginExtractValueOffsets(start *uint32, length *uint32) (*_Ctype_ss_plugin_extract_value_offsets) {
|
||||
ret := &_Ctype_ss_plugin_extract_value_offsets{}
|
||||
ret.start = (*_Ctype_uint32_t)(start)
|
||||
ret.length = (*_Ctype_uint32_t)(length)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event_input, func()) {
|
||||
ret := &_Ctype_struct_ss_plugin_event_input{}
|
||||
evts, _ := sdk.NewEventWriters(1, int64(len(data)))
|
||||
|
@ -118,11 +126,22 @@ func TestExtract(t *testing.T) {
|
|||
// panic
|
||||
badHandle := cgo.NewHandle(1)
|
||||
assertPanic(t, func() {
|
||||
plugin_extract_fields_sync(_Ctype_uintptr_t(badHandle), event, 1, field)
|
||||
plugin_extract_fields_sync(_Ctype_uintptr_t(badHandle), event, 1, field, nil)
|
||||
})
|
||||
|
||||
// success
|
||||
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field)
|
||||
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field, nil)
|
||||
if res != sdk.SSPluginSuccess {
|
||||
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
|
||||
} else if sample.lastErr != nil {
|
||||
t.Errorf("(lastErr): should be nil")
|
||||
}
|
||||
|
||||
// success + offsets
|
||||
val_start := uint32(0)
|
||||
val_length := uint32(8)
|
||||
offsets := allocSSPluginExtractValueOffsets(&val_start, &val_length)
|
||||
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field, offsets)
|
||||
if res != sdk.SSPluginSuccess {
|
||||
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
|
||||
} else if sample.lastErr != nil {
|
||||
|
@ -131,7 +150,7 @@ func TestExtract(t *testing.T) {
|
|||
|
||||
// error
|
||||
sample.err = errTest
|
||||
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field)
|
||||
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field, nil)
|
||||
if res != sdk.SSPluginFailure {
|
||||
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginFailure, res)
|
||||
} else if sample.lastErr != errTest {
|
||||
|
|
Loading…
Reference in New Issue