Compare commits

...

40 Commits
v0.7.1 ... main

Author SHA1 Message Date
dependabot[bot] 12d8e63d34 build(deps): bump github/codeql-action in the actions group
Bumps the actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 3.28.19 to 3.29.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](fca7ace96b...ce28f5bb42)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 15:37:22 +02:00
Leonardo Grasso d608d7282e fix(.github): goreleaser deprecated --rm-dist in favor of --clean
See d18adfb57e

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2025-06-12 12:52:11 +02:00
Leonardo Grasso 3fdac75fd0 chore(pkg/sdk): rework handling of value offset arrays
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2025-06-11 10:15:06 +02:00
Gerald Combs b7bb92fafe update(pkg/sdk) Use a name that more closely matches the C API
Signed-off-by: Gerald Combs <gerald@wireshark.org>
2025-06-11 10:15:06 +02:00
Gerald Combs 8f53f05a62 update(pkg/sdk): Free our offset arrays when we free other memory
Signed-off-by: Gerald Combs <gerald@wireshark.org>
2025-06-11 10:15:06 +02:00
Leonardo Grasso 7c1d5695b4 new(pkg/sdk): field offset support
Co-authored-by: Gerald Combs <gerald@wireshark.org>
Co-authored-by: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2025-06-11 10:15:06 +02:00
Leonardo Grasso f5474a80f2 build: upgrade to go 1.17
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2025-06-11 10:15:06 +02:00
Leonardo Grasso 69176a7e5d update(Makefile): pin libs version
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2025-06-11 10:15:06 +02:00
Gerald Combs a202a120f9 update(api): Add value offset support
Add support for setting value offsets during extraction.

Signed-off-by: Gerald Combs <gerald@wireshark.org>
2025-06-11 10:15:06 +02:00
dependabot[bot] 6ac3b4df0a build(deps): bump github/codeql-action in the actions group
Bumps the actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 3.28.18 to 3.28.19
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](ff0a06e83c...fca7ace96b)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.28.19
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-10 11:02:59 +02:00
dependabot[bot] c61e9d1502 build(deps): bump github/codeql-action in the actions group
Bumps the actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 3.28.17 to 3.28.18
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](60168efe1c...ff0a06e83c)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.28.18
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 10:03:00 +02:00
dependabot[bot] 85cf8fd4c4 build(deps): bump the actions group across 1 directory with 3 updates
Bumps the actions group with 3 updates in the / directory: [actions/setup-go](https://github.com/actions/setup-go), [github/codeql-action](https://github.com/github/codeql-action) and [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action).


Updates `actions/setup-go` from 5.4.0 to 5.5.0
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](0aaccfd150...d35c59abb0)

Updates `github/codeql-action` from 3.28.12 to 3.28.17
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](5f8171a638...60168efe1c)

Updates `goreleaser/goreleaser-action` from 6.2.1 to 6.3.0
- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)
- [Commits](90a3faa9d0...9c156ee8a1)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: 5.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: github/codeql-action
  dependency-version: 3.28.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: goreleaser/goreleaser-action
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-12 14:31:24 +02:00
dependabot[bot] f412a34986 build(deps): bump the actions group with 2 updates
Bumps the actions group with 2 updates: [actions/setup-go](https://github.com/actions/setup-go) and [github/codeql-action](https://github.com/github/codeql-action).


Updates `actions/setup-go` from 5.3.0 to 5.4.0
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](f111f3307d...0aaccfd150)

Updates `github/codeql-action` from 3.28.11 to 3.28.12
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](6bb031afdd...5f8171a638)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-24 12:43:17 +01:00
Leonardo Grasso cf6f8ab52e fix(pkg/loader): isolate CGO inside an .so from the outer one
See https://github.com/falcosecurity/plugins/pull/683

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2025-03-21 19:06:32 +01:00
dependabot[bot] 3b45fdb759 build(deps): bump github/codeql-action in the actions group
Bumps the actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 3.28.10 to 3.28.11
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](b56ba49b26...6bb031afdd)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-21 12:08:32 +01:00
dependabot[bot] e6d0e188aa build(deps): bump github/codeql-action in the actions group
Bumps the actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 3.28.9 to 3.28.10
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](9e8d0789d4...b56ba49b26)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 10:00:14 +01:00
dependabot[bot] 32963fb3d2 build(deps): bump goreleaser/goreleaser-action in the actions group
Bumps the actions group with 1 update: [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action).


Updates `goreleaser/goreleaser-action` from 6.1.0 to 6.2.1
- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)
- [Commits](9ed2f89a66...90a3faa9d0)

---
updated-dependencies:
- dependency-name: goreleaser/goreleaser-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 12:33:31 +01:00
dependabot[bot] d861afb22d build(deps): bump github/codeql-action in the actions group
Bumps the actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 3.28.8 to 3.28.9
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](dd746615b3...9e8d0789d4)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-10 18:28:53 +01:00
dependabot[bot] 167ec5a390 build(deps): bump the actions group across 1 directory with 2 updates
Bumps the actions group with 2 updates in the / directory: [actions/setup-go](https://github.com/actions/setup-go) and [github/codeql-action](https://github.com/github/codeql-action).


Updates `actions/setup-go` from 5.2.0 to 5.3.0
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](3041bf56c9...f111f3307d)

Updates `github/codeql-action` from 3.28.1 to 3.28.8
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](b6a472f63d...dd746615b3)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-04 16:56:15 +01:00
dependabot[bot] e69d2950eb build(deps): bump github/codeql-action in the actions group
Bumps the actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 3.28.0 to 3.28.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](48ab28a6f5...b6a472f63d)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 10:26:48 +01:00
dependabot[bot] 13ebd8dc96 build(deps): bump the actions group across 1 directory with 2 updates
Bumps the actions group with 2 updates in the / directory: [actions/setup-go](https://github.com/actions/setup-go) and [github/codeql-action](https://github.com/github/codeql-action).


Updates `actions/setup-go` from 5.1.0 to 5.2.0
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](41dfa10bad...3041bf56c9)

Updates `github/codeql-action` from 3.27.6 to 3.28.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](aa57810251...48ab28a6f5)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-07 16:41:37 +01:00
dependabot[bot] fda10fc439 build(deps): bump github/codeql-action in the actions group
Bumps the actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 3.27.4 to 3.27.6
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](ea9e4e3799...aa57810251)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-10 13:21:02 +01:00
dependabot[bot] 7e92b1b241 build(deps): bump github/codeql-action in the actions group
Bumps the actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 3.27.1 to 3.27.4
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](4f3212b617...ea9e4e3799)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-18 17:26:12 +01:00
dependabot[bot] 5a1efd0257 build(deps): bump the actions group across 1 directory with 4 updates
Bumps the actions group with 4 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [actions/setup-go](https://github.com/actions/setup-go), [github/codeql-action](https://github.com/github/codeql-action) and [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action).


Updates `actions/checkout` from 4.2.1 to 4.2.2
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](eef61447b9...11bd71901b)

Updates `actions/setup-go` from 5.0.2 to 5.1.0
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](0a12ed9d6a...41dfa10bad)

Updates `github/codeql-action` from 3.26.13 to 3.27.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](f779452ac5...4f3212b617)

Updates `goreleaser/goreleaser-action` from 6.0.0 to 6.1.0
- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)
- [Commits](286f3b13b1...9ed2f89a66)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: goreleaser/goreleaser-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-16 06:04:04 +01:00
dependabot[bot] 7955010144 build(deps): bump github/codeql-action in the actions group
Bumps the actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 3.26.12 to 3.26.13
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](c36620d31a...f779452ac5)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-21 13:03:59 +02:00
cpanato faca7745ba add dependabot config
Signed-off-by: cpanato <ctadeu@gmail.com>
2024-10-09 16:52:14 +02:00
cpanato 024430afc9 fix goreleaser
Signed-off-by: cpanato <ctadeu@gmail.com>
2024-10-09 16:52:14 +02:00
cpanato e6084751c5 use git hash instead of tags
Signed-off-by: cpanato <ctadeu@gmail.com>
2024-10-09 16:52:14 +02:00
GLVS Kiriti ede33484c2 Feature: Added a job in ci which builds the all examples
Signed-off-by: GLVS Kiriti <glvskiriti2003369@gmail.com>
2024-07-18 17:40:33 +02:00
Jason Dellaluce 40ff9af243 fix(symbols/extract): solve deadlock scenario when releasing async worker
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-06-11 15:04:40 +02:00
Jason Dellaluce 98fd1a5dcd fix(pkg/cgo): solve data races when assigning/deleting and accessing handles
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-06-11 15:04:40 +02:00
Leonardo Grasso 2eb4a3106b docs: add SPDX license identifier
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-11-23 16:54:46 +01:00
Leonardo Grasso 9130ff4b53 build: patch `plugin_loader.c` to use an internal `strlcpy` impl
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-30 16:16:26 +02:00
Leonardo Grasso c36a0e0259 chore(pkg/sdk): removing "strlcpy.h" copy
We can't declare this func, since it may be already declared. We will switch to a internal declaration only for the plugin loader.

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-30 16:16:26 +02:00
Leonardo Grasso 64aa8490f4 fix(pkg/sdk): correct compilation error with glibc 2.38
This commits aims to fix the following compilation error: "static declaration of ‘strlcpy’ follows non-static declaration".

In glibc 2.38, the strlcpy and strlcat functions have been added. However, the glibc declaration for strlcpy is non-static.

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-29 17:26:22 +02:00
Leonardo Grasso 64ea3ace4e build: cgocheck > 1 mode is no longer supported at runtime
Use GODEBUG=cgocheck=1 instead.

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-29 17:26:22 +02:00
Andrea Terzolo 9cd2769c2f cleanup: add some comments and rename vars in `SetRequiredAPIVersion`
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-11 08:45:46 +02:00
Andrea Terzolo c43c0044a1 chore: add .vscode to the gitignore
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-11 08:45:46 +02:00
Leonardo Grasso 1a38f04582 fix(README.md): license badge link
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-06-06 17:00:40 +02:00
Leonardo Grasso 18133edb5c docs(README.md): add scope and status badges
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-06-06 17:00:40 +02:00
91 changed files with 1579 additions and 672 deletions

22
.github/dependabot.yaml vendored Normal file
View File

@ -0,0 +1,22 @@
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
groups:
gomod:
update-types:
- "patch"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
groups:
actions:
update-types:
- "minor"
- "patch"

View File

@ -2,7 +2,8 @@ name: CI
on: on:
pull_request: pull_request:
branches: [main] branches:
- main
jobs: jobs:
run-tests: run-tests:
@ -10,12 +11,27 @@ jobs:
steps: steps:
- name: Checkout plugin-sdk-go - name: Checkout plugin-sdk-go
uses: actions/checkout@v3 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Golang - name: Setup Golang
uses: actions/setup-go@v4 uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with: with:
go-version: '^1.19' go-version: '^1.19'
- name: Run tests - name: Run tests
run: go test ./... run: go test ./...
build-example-plugins:
runs-on: ubuntu-latest
steps:
- name: Checkout plugin-sdk-go
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Golang
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: '^1.19'
- name: Build all example plugins
run: make examples

View File

@ -1,22 +1,12 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL" name: "CodeQL"
on: on:
push: push:
branches: [ main ] branches:
- main
pull_request: pull_request:
# The branches below must be a subset of the branches above branches:
branches: [ main ] - main
schedule: schedule:
- cron: '45 5 * * 2' - cron: '45 5 * * 2'
@ -32,40 +22,21 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
language: [ 'go' ] language:
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - 'go'
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v2 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v1 uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v1 uses: github/codeql-action/autobuild@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1 uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0

View File

@ -7,23 +7,25 @@ on:
jobs: jobs:
release: release:
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
permissions:
contents: write
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v3 uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with: with:
go-version: 1.17 go-version: 1.17
- name: Run GoReleaser - name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3 uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0
with: with:
distribution: goreleaser args: release --clean --timeout 60m
version: v1.10.3
args: release --rm-dist --timeout 60m
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.gitignore vendored
View File

@ -1 +1,2 @@
*~ *~
.vscode

View File

@ -1,6 +1,9 @@
project_name: plugin-sdk-go project_name: plugin-sdk-go
build: version: 2
skip: true
builds:
- skip: true
release: release:
github: github: {}
prerelease: auto prerelease: auto

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# #
# Copyright (C) 2021 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 # 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 # the License. You may obtain a copy of the License at
@ -13,8 +14,9 @@
SHELL := /bin/bash SHELL := /bin/bash
GO ?= $(shell which go) GO ?= $(shell which go)
CURL ?= $(shell which curl) CURL ?= $(shell which curl)
PATCH ?= $(shell which patch)
FALCOSECURITY_LIBS_REVISION ?= 0b9ca98fee2453a16f4538db55dcfa34bc8f5aef FALCOSECURITY_LIBS_REVISION ?= 0.21.0
FALCOSECURITY_LIBS_REPO ?= falcosecurity/libs FALCOSECURITY_LIBS_REPO ?= falcosecurity/libs
PLUGINLIB_URL=https://raw.githubusercontent.com/${FALCOSECURITY_LIBS_REPO}/${FALCOSECURITY_LIBS_REVISION}/userspace/plugin PLUGINLIB_URL=https://raw.githubusercontent.com/${FALCOSECURITY_LIBS_REPO}/${FALCOSECURITY_LIBS_REVISION}/userspace/plugin
@ -34,6 +36,9 @@ pluginlib:
$(CURL) -Lso pkg/sdk/plugin_api.h $(PLUGINLIB_URL)/plugin_api.h $(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.h $(PLUGINLIB_URL)/plugin_loader.h
$(CURL) -Lso pkg/loader/plugin_loader.c $(PLUGINLIB_URL)/plugin_loader.c $(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: clean-pluginlib:
rm -f \ rm -f \

1
OWNERS
View File

@ -7,4 +7,3 @@ emeritus_approvers:
- kris-nova - kris-nova
- mstemm - mstemm
- ldegio - ldegio

View File

@ -1,12 +1,10 @@
# plugin-sdk-go # plugin-sdk-go
[![Falco Core Repository](https://github.com/falcosecurity/evolution/blob/main/repos/badges/falco-core-blue.svg)](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#core-scope) [![Stable](https://img.shields.io/badge/status-stable-brightgreen?style=for-the-badge)](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#stable) [![License](https://img.shields.io/github/license/falcosecurity/plugin-sdk-go?style=for-the-badge)](./LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/falcosecurity/plugin-sdk-go/pkg/sdk.svg)](https://pkg.go.dev/github.com/falcosecurity/plugin-sdk-go/pkg/sdk) [![Go Reference](https://pkg.go.dev/badge/github.com/falcosecurity/plugin-sdk-go/pkg/sdk.svg)](https://pkg.go.dev/github.com/falcosecurity/plugin-sdk-go/pkg/sdk)
[![Release](https://img.shields.io/github/release/falcosecurity/plugin-sdk-go.svg?style=flat-square)](https://github.com/falcosecurity/plugin-sdk-go/releases/latest) [![Release](https://img.shields.io/github/release/falcosecurity/plugin-sdk-go.svg?style=flat-square)](https://github.com/falcosecurity/plugin-sdk-go/releases/latest)
[![Go Report Card](https://goreportcard.com/badge/github.com/falcosecurity/plugin-sdk-go?style=flat-square)](https://goreportcard.com/report/github.com/falcosecurity/plugin-sdk-go) [![Go Report Card](https://goreportcard.com/badge/github.com/falcosecurity/plugin-sdk-go?style=flat-square)](https://goreportcard.com/report/github.com/falcosecurity/plugin-sdk-go)
[![License](https://img.shields.io/github/license/falcosecurity/plugin-sdk-go?style=flat-square)](LICENSE)
Note: *The plugin system is a new feature introduced since Falco 0.31.0. You can find more detail in the original [proposal document](https://github.com/falcosecurity/falco/blob/master/proposals/20210501-plugin-system.md).*
## Introduction ## Introduction

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# #
# Copyright (C) 2022 The Falco Authors. # Copyright (C) 2023 The Falco Authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with # 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 # the License. You may obtain a copy of the License at
@ -25,5 +26,5 @@ clean:
$(OUTPUT): bench.cpp bench.go $(OUTPUT): bench.cpp bench.go
mkdir -p $(OUTPUTDIR) mkdir -p $(OUTPUTDIR)
GODEBUG=cgocheck=2 $(GO) build -buildmode=c-archive -o $(OUTPUTGO) bench.go GODEBUG=cgocheck=1 $(GO) build -buildmode=c-archive -o $(OUTPUTGO) bench.go
$(CXX) bench.cpp $(OUTPUTGO) -std=c++11 -pthread -o $(OUTPUT) $(CXX) bench.cpp $(OUTPUTGO) -std=c++11 -pthread -o $(OUTPUT)

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# #
# Copyright (C) 2021 The Falco Authors. # Copyright (C) 2023 The Falco Authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with # 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 # the License. You may obtain a copy of the License at
@ -23,4 +24,4 @@ clean:
@rm -f *.so *.h @rm -f *.so *.h
$(OUTPUT): *.go $(OUTPUT): *.go
@GODEBUG=cgocheck=2 $(GO) build -buildmode=c-shared -o $(OUTPUT) @GODEBUG=cgocheck=1 $(GO) build -buildmode=c-shared -o $(OUTPUT)

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# #
# Copyright (C) 2021 The Falco Authors. # Copyright (C) 2023 The Falco Authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with # 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 # the License. You may obtain a copy of the License at
@ -23,4 +24,4 @@ clean:
@rm -f *.so *.h @rm -f *.so *.h
$(OUTPUT): *.go $(OUTPUT): *.go
@GODEBUG=cgocheck=2 $(GO) build -buildmode=c-shared -o $(OUTPUT) @GODEBUG=cgocheck=1 $(GO) build -buildmode=c-shared -o $(OUTPUT)

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# #
# Copyright (C) 2021 The Falco Authors. # Copyright (C) 2023 The Falco Authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with # 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 # the License. You may obtain a copy of the License at
@ -23,4 +24,4 @@ clean:
@rm -f *.so *.h @rm -f *.so *.h
$(OUTPUT): *.go $(OUTPUT): *.go
@GODEBUG=cgocheck=2 $(GO) build -buildmode=c-shared -o $(OUTPUT) @GODEBUG=cgocheck=1 $(GO) build -buildmode=c-shared -o $(OUTPUT)

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: Apache-2.0
# #
# Copyright (C) 2023 The Falco Authors. # Copyright (C) 2023 The Falco Authors.
# #

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# #
# Copyright (C) 2021 The Falco Authors. # Copyright (C) 2023 The Falco Authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with # 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 # the License. You may obtain a copy of the License at
@ -23,5 +24,5 @@ clean:
@rm -f *.so *.h @rm -f *.so *.h
$(OUTPUT): *.go $(OUTPUT): *.go
@GODEBUG=cgocheck=2 $(GO) build -buildmode=c-shared -o $(OUTPUT) @GODEBUG=cgocheck=1 $(GO) build -buildmode=c-shared -o $(OUTPUT)

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

11
go.mod
View File

@ -1,9 +1,16 @@
module github.com/falcosecurity/plugin-sdk-go module github.com/falcosecurity/plugin-sdk-go
go 1.15 go 1.17
require ( require (
github.com/stretchr/testify v1.8.2 github.com/stretchr/testify v1.8.2
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonschema v1.2.0 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
)

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -16,6 +17,12 @@ limitations under the License.
package cgo package cgo
import (
"fmt"
"sync/atomic"
"unsafe"
)
// Handle is an alternative implementation of cgo.Handle introduced by // Handle is an alternative implementation of cgo.Handle introduced by
// Go 1.17, see https://pkg.go.dev/runtime/cgo. This implementation // Go 1.17, see https://pkg.go.dev/runtime/cgo. This implementation
// optimizes performance in use cases related to plugins. It is intended // optimizes performance in use cases related to plugins. It is intended
@ -42,12 +49,18 @@ package cgo
// The usage in other contexts is discuraged. // The usage in other contexts is discuraged.
type Handle uintptr type Handle uintptr
// MaxHandle is the largest value that an Handle can hold const (
const MaxHandle = 256 - 1 // MaxHandle is the largest value that an Handle can hold
MaxHandle = 256 - 1
// max number of times we're willing to iterate over the vector of reusable
// handles to do compare-and-swap before giving up
maxNewHandleRounds = 20
)
var ( var (
handles [MaxHandle + 1]interface{} // [int]interface{} handles [MaxHandle + 1]unsafe.Pointer // [int]*interface{}
noHandle int = 0 noHandle unsafe.Pointer = nil
) )
func init() { func init() {
@ -71,13 +84,30 @@ func init() {
// //
// This function is not thread-safe. // This function is not thread-safe.
func NewHandle(v interface{}) Handle { func NewHandle(v interface{}) Handle {
for i := 1; i <= MaxHandle; i++ { rounds := 0
if handles[i] == &noHandle { for h := uintptr(1); ; h++ {
handles[i] = v // we acquired ownership of an handle, return it
return Handle(i) // note: we attempt accessing slots 1..MaxHandle (included)
if atomic.CompareAndSwapPointer(&handles[h], noHandle, (unsafe.Pointer)(&v)) {
return Handle(h)
} }
// we haven't acquired a handle, but we can try with the next one
if h < MaxHandle {
continue
}
// we iterated over the whole vector of handles, so we get back to start
// and try again with another round. Once we do this too many times,
// we have no choice if not panic-ing
h = uintptr(0) // note: will be incremented when continuing
if rounds < maxNewHandleRounds {
rounds++
continue
}
panic(fmt.Sprintf("plugin-sdk-go/cgo: could not obtain a new handle after round #%d", rounds))
} }
panic("plugin-sdk-go/cgo: ran out of handle space")
} }
// Value returns the associated Go value for a valid handle. // Value returns the associated Go value for a valid handle.
@ -85,10 +115,10 @@ func NewHandle(v interface{}) Handle {
// The method panics if the handle is invalid. // The method panics if the handle is invalid.
// This function is not thread-safe. // This function is not thread-safe.
func (h Handle) Value() interface{} { func (h Handle) Value() interface{} {
if h > MaxHandle || handles[h] == &noHandle { if h > MaxHandle || atomic.LoadPointer(&handles[h]) == noHandle {
panic("plugin-sdk-go/cgo: misuse of an invalid Handle") panic(fmt.Sprintf("plugin-sdk-go/cgo: misuse (value) of an invalid Handle %d", h))
} }
return handles[h] return *(*interface{})(atomic.LoadPointer(&handles[h]))
} }
// Delete invalidates a handle. This method should only be called once // Delete invalidates a handle. This method should only be called once
@ -98,14 +128,14 @@ func (h Handle) Value() interface{} {
// The method panics if the handle is invalid. // The method panics if the handle is invalid.
// This function is not thread-safe. // This function is not thread-safe.
func (h Handle) Delete() { func (h Handle) Delete() {
if h > MaxHandle || handles[h] == &noHandle { if h > MaxHandle || atomic.LoadPointer(&handles[h]) == noHandle {
panic("plugin-sdk-go/cgo: misuse of an invalid Handle") panic(fmt.Sprintf("plugin-sdk-go/cgo: misuse (delete) of an invalid Handle %d", h))
} }
handles[h] = &noHandle atomic.StorePointer(&handles[h], noHandle)
} }
func resetHandles() { func resetHandles() {
for i := 0; i <= MaxHandle; i++ { for i := 0; i <= MaxHandle; i++ {
handles[i] = &noHandle atomic.StorePointer(&handles[i], noHandle)
} }
} }

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -18,6 +19,7 @@ package cgo
import ( import (
"reflect" "reflect"
"sync/atomic"
"testing" "testing"
) )
@ -60,7 +62,7 @@ func TestHandle(t *testing.T) {
siz := 0 siz := 0
for i := 0; i < MaxHandle; i++ { for i := 0; i < MaxHandle; i++ {
if handles[i] != &noHandle { if atomic.LoadPointer(&handles[i]) != noHandle {
siz++ siz++
} }
} }

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -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>

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2023 The Falco Authors. Copyright (C) 2023 The Falco Authors.
@ -16,165 +17,210 @@ limitations under the License.
*/ */
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
typedef HINSTANCE library_handle_t; typedef HINSTANCE library_handle_t;
#else #else
#include <dlfcn.h> #include <dlfcn.h>
typedef void* library_handle_t; typedef void* library_handle_t;
#endif #endif
#include "strlcpy.h" #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "plugin_loader.h" #include "plugin_loader.h"
static inline void err_prepend(char* s, const char* prefix, const char* sep) // note(jasondellaluce,therealbobo): implementation taken from falcosecurity/libs
{ // note(leogr): to avoid clashing with `strlcpy` introduced by glibc 2.38,
char tmp[PLUGIN_MAX_ERRLEN]; // the func has been renamed to plugin_loader_strlcpy.
size_t prefix_len = strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN); // N.B.: our building system here is not smart enough to detect if the function
if (*s != '\0') // was declared already.
{ #include <stdint.h>
strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len); #include <string.h>
prefix_len += strlen(sep); /*!
\brief Copy up to size - 1 characters from the NUL-terminated string src to dst, NUL-terminating the result.
\return The length of the source string.
*/
static inline size_t plugin_loader_strlcpy(char *dst, const char *src, size_t size) {
size_t srcsize = strlen(src);
if (size == 0) {
return srcsize;
} }
strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
strlcpy(s, tmp, PLUGIN_MAX_ERRLEN); size_t copysize = srcsize;
if (copysize > size - 1) {
copysize = size - 1;
}
memcpy(dst, src, copysize);
dst[copysize] = '\0';
return srcsize;
} }
static inline void err_append(char* s, const char* suffix, const char* sep) static inline void err_prepend(char* s, const char* prefix, const char* sep) {
{ char tmp[PLUGIN_MAX_ERRLEN];
if (*s != '\0') size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
{ if(*s != '\0') {
strncat(s, sep, PLUGIN_MAX_ERRLEN - strlen(sep)); plugin_loader_strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
} prefix_len += strlen(sep);
strncat(s, suffix, PLUGIN_MAX_ERRLEN - strlen(suffix)); }
plugin_loader_strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
} }
static void* getsym(library_handle_t handle, const char* name) 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) {
#ifdef _WIN32 #ifdef _WIN32
return (void*) GetProcAddress(handle, name); return (void*)GetProcAddress(handle, name);
#else #else
return (void*) dlsym(handle, name); return (void*)dlsym(handle, name);
#endif #endif
} }
// little hack for simplifying the plugin_load function // little hack for simplifying the plugin_load function
#define SYM_RESOLVE(h, s) \ #define SYM_RESOLVE(h, s) *(void**)(&(h->api.s)) = getsym(h->handle, "plugin_" #s)
*(void **)(&(h->api.s)) = getsym(h->handle, "plugin_"#s)
plugin_handle_t* plugin_load(const char* path, char* err) plugin_handle_t* plugin_load(const char* path, char* err) {
{ // alloc and init memory
// alloc and init memory err[0] = '\0';
err[0] = '\0'; plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
plugin_handle_t* ret = (plugin_handle_t*) calloc (1, sizeof(plugin_handle_t)); if(!ret) {
if (!ret) plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
{ return NULL;
strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN); }
return NULL;
}
// open dynamic library // open dynamic library
#ifdef _WIN32 #ifdef _WIN32
ret->handle = LoadLibrary(path); ret->handle = LoadLibrary(path);
if(ret->handle == NULL) if(ret->handle == NULL) {
{ DWORD flg = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
DWORD flg = FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_IGNORE_INSERTS;
| FORMAT_MESSAGE_FROM_SYSTEM LPTSTR msg_buf = 0;
| FORMAT_MESSAGE_IGNORE_INSERTS; if(FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR)&msg_buf, 0, NULL) && msg_buf) {
LPTSTR msg_buf = 0; plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
if (FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR) &msg_buf, 0, NULL) && msg_buf) LocalFree(msg_buf);
{ }
strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN); }
LocalFree(msg_buf);
}
}
#else #else
ret->handle = dlopen(path, RTLD_LAZY); ret->handle = dlopen(path, RTLD_LAZY);
if (ret->handle == NULL) if(ret->handle == NULL) {
{ plugin_loader_strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
strlcpy(err, (const char*) dlerror(), PLUGIN_MAX_ERRLEN); }
}
#endif #endif
// return NULL if library loading had errors // return NULL if library loading had errors
if (ret->handle == NULL) if(ret->handle == NULL) {
{ err_prepend(err, "can't load plugin dynamic library:", " ");
err_prepend(err, "can't load plugin dynamic library:", " "); free(ret);
free(ret); return NULL;
return NULL; }
}
// load all library symbols // load all library symbols
SYM_RESOLVE(ret, get_required_api_version); SYM_RESOLVE(ret, get_required_api_version);
SYM_RESOLVE(ret, get_version); SYM_RESOLVE(ret, get_version);
SYM_RESOLVE(ret, get_last_error); SYM_RESOLVE(ret, get_last_error);
SYM_RESOLVE(ret, get_name); SYM_RESOLVE(ret, get_name);
SYM_RESOLVE(ret, get_description); SYM_RESOLVE(ret, get_description);
SYM_RESOLVE(ret, get_contact); SYM_RESOLVE(ret, get_contact);
SYM_RESOLVE(ret, get_init_schema); SYM_RESOLVE(ret, get_init_schema);
SYM_RESOLVE(ret, init); SYM_RESOLVE(ret, init);
SYM_RESOLVE(ret, destroy); SYM_RESOLVE(ret, destroy);
SYM_RESOLVE(ret, get_id); SYM_RESOLVE(ret, get_id);
SYM_RESOLVE(ret, get_event_source); SYM_RESOLVE(ret, get_event_source);
SYM_RESOLVE(ret, open); SYM_RESOLVE(ret, open);
SYM_RESOLVE(ret, close); SYM_RESOLVE(ret, close);
SYM_RESOLVE(ret, next_batch); SYM_RESOLVE(ret, next_batch);
SYM_RESOLVE(ret, get_progress); SYM_RESOLVE(ret, get_progress);
SYM_RESOLVE(ret, list_open_params); SYM_RESOLVE(ret, list_open_params);
SYM_RESOLVE(ret, event_to_string); SYM_RESOLVE(ret, event_to_string);
SYM_RESOLVE(ret, get_fields); SYM_RESOLVE(ret, get_fields);
SYM_RESOLVE(ret, extract_fields); SYM_RESOLVE(ret, extract_fields);
SYM_RESOLVE(ret, get_extract_event_sources); SYM_RESOLVE(ret, get_extract_event_sources);
SYM_RESOLVE(ret, get_extract_event_types); SYM_RESOLVE(ret, get_extract_event_types);
SYM_RESOLVE(ret, get_parse_event_types); SYM_RESOLVE(ret, get_parse_event_types);
SYM_RESOLVE(ret, get_parse_event_sources); SYM_RESOLVE(ret, get_parse_event_sources);
SYM_RESOLVE(ret, parse_event); SYM_RESOLVE(ret, parse_event);
SYM_RESOLVE(ret, get_async_event_sources); SYM_RESOLVE(ret, get_async_event_sources);
SYM_RESOLVE(ret, get_async_events); SYM_RESOLVE(ret, get_async_events);
SYM_RESOLVE(ret, set_async_event_handler); SYM_RESOLVE(ret, set_async_event_handler);
return ret; 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) plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
{ // alloc and init memory
// alloc and init memory err[0] = '\0';
err[0] = '\0'; if(!api) {
if (!api) plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
{ return NULL;
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)); plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
if (!ret) if(!ret) {
{ plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN); return NULL;
return NULL; }
} ret->api = *api;
ret->api = *api;
return ret; // 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) void plugin_unload(plugin_handle_t* h) {
{ if(h) {
if (h) if(h->handle) {
{
if (h->handle)
{
#ifdef _WIN32 #ifdef _WIN32
FreeLibrary(h->handle); FreeLibrary(h->handle);
#else #else
dlclose(h->handle); dlclose(h->handle);
#endif #endif
} }
free(h); free(h);
} }
} }
bool plugin_is_loaded(const char* path) bool plugin_is_loaded(const char* path) {
{
#ifdef _WIN32 #ifdef _WIN32
/* /*
* LoadLibrary maps the module into the address space of the calling process, if necessary, * LoadLibrary maps the module into the address space of the calling process, if necessary,
@ -197,122 +243,125 @@ bool plugin_is_loaded(const char* path)
#endif #endif
} }
bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) {
{ uint32_t major, minor, patch;
uint32_t major, minor, patch; const char *ver, *failmsg;
const char *ver, *failmsg; if(h->api.get_required_api_version == NULL) {
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;
strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN); }
return false;
}
ver = h->api.get_required_api_version(); ver = h->api.get_required_api_version();
if (sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3) if(sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3) {
{ snprintf(err,
snprintf(err, PLUGIN_MAX_ERRLEN, "plugin provided an invalid required API version: '%s'", ver); PLUGIN_MAX_ERRLEN,
return false; "plugin provided an invalid required API version: '%s'",
} ver);
return false;
}
failmsg = NULL; failmsg = NULL;
if(PLUGIN_API_VERSION_MAJOR != major) /* The plugin requires a minimum framework version */
{ if(PLUGIN_API_VERSION_MAJOR != major) {
failmsg = "major versions disagree"; failmsg = "major versions disagree";
} } else if(PLUGIN_API_VERSION_MINOR < minor) {
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 minor is less than the requested one"; failmsg = "framework's patch 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) if(failmsg != NULL) {
{ snprintf(err,
snprintf(err, PLUGIN_MAX_ERRLEN, PLUGIN_MAX_ERRLEN,
"plugin required API version '%s' not compatible with the framework's API version '%s': %s", "plugin required API version '%s' not compatible with the framework's API version "
ver, PLUGIN_API_VERSION_STR, failmsg); "'%s': %s",
return false; 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) 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;
plugin_caps_t caps = CAP_NONE; bool has_source = h->api.get_event_source != NULL && strlen(h->api.get_event_source()) > 0;
strlcpy(err, "", PLUGIN_MAX_ERRLEN); 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) if(h->api.get_fields != NULL && h->api.extract_fields != NULL) {
{ caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_EXTRACTION);
bool has_id = h->api.get_id != NULL && h->api.get_id() != 0; } else if(h->api.extract_fields != NULL) {
bool has_source = h->api.get_event_source != NULL && strlen(h->api.get_event_source()) > 0; caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
if ((has_id && has_source) || (!has_id && !has_source)) err_append(err,
{ "must implement both 'plugin_get_fields' and 'plugin_extract_fields' (field "
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_SOURCING); "extraction)",
} ", ");
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) if(h->api.parse_event != NULL) {
{ caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_PARSING);
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) 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);
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_PARSING); } 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) if(h->api.capture_open != NULL && h->api.capture_close != NULL) {
{ caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_CAPTURE_LISTENING);
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_ASYNC); } else if(h->api.capture_open != NULL) {
} caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
else if (h->api.get_async_events != NULL || h->api.set_async_event_handler != NULL) err_append(err,
{ "must implement both 'plugin_capture_open' and 'plugin_capture_close' (capture "
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_BROKEN); "listening)",
err_append(err, "must implement both 'plugin_get_async_events' and 'plugin_set_async_event_handler' (async events)", ", "); ", ");
} }
return caps; return caps;
} }
// little hack for simplifying the plugin_check_required_symbols function // little hack for simplifying the plugin_check_required_symbols function
#define SYM_REQCHECK(a, e, s) \ #define SYM_REQCHECK(a, e, s) \
do { \ do { \
if(a->api.s == NULL) \ if(a->api.s == NULL) { \
{ \ snprintf(e, PLUGIN_MAX_ERRLEN, "required symbol not implemented: '%s'", #s); \
snprintf(e, PLUGIN_MAX_ERRLEN, "required symbol not implemented: '%s'", #s); \ return false; \
return false; \ } \
} \ } while(0)
} while(0)
bool plugin_check_required_symbols(const plugin_handle_t* h, char* err) 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_required_api_version); SYM_REQCHECK(h, err, get_version);
SYM_REQCHECK(h, err, get_version); SYM_REQCHECK(h, err, get_name);
SYM_REQCHECK(h, err, get_name); SYM_REQCHECK(h, err, get_description);
SYM_REQCHECK(h, err, get_description); SYM_REQCHECK(h, err, get_contact);
SYM_REQCHECK(h, err, get_contact); SYM_REQCHECK(h, err, init);
SYM_REQCHECK(h, err, init); SYM_REQCHECK(h, err, destroy);
SYM_REQCHECK(h, err, destroy); SYM_REQCHECK(h, err, get_last_error);
SYM_REQCHECK(h, err, get_last_error); return true;
return true;
} }

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2023 The Falco Authors. Copyright (C) 2023 The Falco Authors.
@ -36,14 +37,14 @@ extern "C" {
the field extraction phase the field extraction phase
* ability to inject events asynchronously in the event loop * ability to inject events asynchronously in the event loop
*/ */
typedef enum typedef enum {
{ CAP_NONE = 0,
CAP_NONE = 0, CAP_SOURCING = 1 << 0,
CAP_SOURCING = 1 << 0, CAP_EXTRACTION = 1 << 1,
CAP_EXTRACTION = 1 << 1, CAP_PARSING = 1 << 2,
CAP_PARSING = 1 << 2, CAP_ASYNC = 1 << 3,
CAP_ASYNC = 1 << 3, CAP_CAPTURE_LISTENING = 1 << 4,
CAP_BROKEN = 1 << 31, // used to report inconsistencies CAP_BROKEN = 1 << 31, // used to report inconsistencies
} plugin_caps_t; } plugin_caps_t;
/*! /*!
@ -51,14 +52,13 @@ typedef enum
Pointers to this struct must be obtained through the plugin_load() Pointers to this struct must be obtained through the plugin_load()
and released through plugin_unload(). and released through plugin_unload().
*/ */
typedef struct plugin_handle_t typedef struct plugin_handle_t {
{
#ifdef _WIN32 #ifdef _WIN32
HINSTANCE handle; ///< Handle of the dynamic library HINSTANCE handle; ///< Handle of the dynamic library
#else #else
void* handle; ///< Handle of the dynamic library void* handle; ///< Handle of the dynamic library
#endif #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; } plugin_handle_t;
/*! /*!

132
pkg/loader/strlcpy.patch Normal file
View File

@ -0,0 +1,132 @@
diff --git a/pkg/loader/plugin_loader.c b/pkg/loader/plugin_loader.c
index 2943335..7bebeeb 100644
--- a/pkg/loader/plugin_loader.c
+++ b/pkg/loader/plugin_loader.c
@@ -24,22 +24,52 @@ typedef HINSTANCE library_handle_t;
typedef void* library_handle_t;
#endif
-#include <libscap/strl.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.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.
+// N.B.: our building system here is not smart enough to detect if the function
+// was declared already.
+#include <stdint.h>
+#include <string.h>
+/*!
+ \brief Copy up to size - 1 characters from the NUL-terminated string src to dst, NUL-terminating the result.
+
+ \return The length of the source string.
+*/
+
+static inline size_t plugin_loader_strlcpy(char *dst, const char *src, size_t size) {
+ size_t srcsize = strlen(src);
+ if (size == 0) {
+ return srcsize;
+ }
+
+ size_t copysize = srcsize;
+
+ if (copysize > size - 1) {
+ copysize = size - 1;
+ }
+
+ memcpy(dst, src, copysize);
+ dst[copysize] = '\0';
+
+ 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_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;
}
@@ -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
@@ -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;
@@ -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;
}
@@ -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;
}
@@ -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;

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2025 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -33,10 +34,15 @@ import (
// todo(jasondellaluce): pull this information from falcosecurity/libs in the future // todo(jasondellaluce): pull this information from falcosecurity/libs in the future
const pluginEventCode = 322 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. // 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. // 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. // EventWriter can be used to represent events produced by a plugin.
// This interface is meant to be used in the next/next_batch. // This interface is meant to be used in the next/next_batch.
@ -179,11 +185,11 @@ type eventWriter struct {
} }
func newEventWriter(dataSize int64) (*eventWriter, error) { 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._type = pluginEventCode
evt.ts = C.uint64_t(C.UINT64_MAX) evt.ts = C.uint64_t(C.UINT64_MAX)
evt.tid = 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*, // note(jasondellaluce): CGO fails to properly encode nparams for *reasons*,
// so we're forced to write their value manually with an offset // so we're forced to write their value manually with an offset
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + 22)) = 2 *(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + 22)) = 2
@ -194,7 +200,7 @@ func newEventWriter(dataSize int64) (*eventWriter, error) {
// plugin ID value (note: putting zero makes the framework set it automatically) // 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 *(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + C.sizeof_ss_plugin_event + 8)) = 0
// create a read/writer for the data payload // 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 { if err != nil {
return nil, err return nil, err
} }
@ -213,7 +219,7 @@ func (p *eventWriter) dataLenPtr() *C.uint32_t {
func (p *eventWriter) Writer() io.Writer { func (p *eventWriter) Writer() io.Writer {
p.data.SetLen(p.dataSize) p.data.SetLen(p.dataSize)
p.data.Seek(0, io.SeekStart) p.data.Seek(0, io.SeekStart)
p.ssPluginEvt.len = (C.uint32_t)(pluginEventHeaderSize) p.ssPluginEvt.len = (C.uint32_t)(PluginEventPayloadOffset)
*p.dataLenPtr() = 0 *p.dataLenPtr() = 0
return p return p
} }
@ -251,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)) 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)) 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 return brw
} }

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2025 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -105,9 +106,26 @@ type ExtractRequest interface {
// - sdk.FieldTypeIPNet: net.IPNet, *net.IPNet // - sdk.FieldTypeIPNet: net.IPNet, *net.IPNet
SetValue(v interface{}) 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 // SetPtr sets a pointer to a ss_plugin_extract_field C structure to
// be wrapped in this instance of ExtractRequest. // be wrapped in this instance of ExtractRequest.
SetPtr(unsafe.Pointer) 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. // ExtractRequestPool represents a pool of reusable ExtractRequest objects.
@ -118,6 +136,18 @@ type ExtractRequestPool interface {
// position inside the pool. Indexes can be non-contiguous. // position inside the pool. Indexes can be non-contiguous.
Get(requestIndex int) ExtractRequest 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 // Free deallocates any memory used by the pool that can't be disposed
// through garbage collection. The behavior of Free after the first call // through garbage collection. The behavior of Free after the first call
// is undefined. // is undefined.
@ -125,7 +155,9 @@ type ExtractRequestPool interface {
} }
type extractRequestPool struct { type extractRequestPool struct {
reqs map[uint]*extractRequest reqs map[uint]*extractRequest
startArrayPtr, lengthArrayPtr unsafe.Pointer
arrayPtrCap uint32
} }
func (e *extractRequestPool) Get(requestIndex int) ExtractRequest { func (e *extractRequestPool) Get(requestIndex int) ExtractRequest {
@ -146,6 +178,31 @@ func (e *extractRequestPool) Get(requestIndex int) ExtractRequest {
return r 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() { func (e *extractRequestPool) Free() {
for _, v := range e.reqs { for _, v := range e.reqs {
for _, b := range v.resStrBufs { for _, b := range v.resStrBufs {
@ -153,6 +210,10 @@ func (e *extractRequestPool) Free() {
} }
C.free(unsafe.Pointer(v.resBuf)) C.free(unsafe.Pointer(v.resBuf))
} }
if e.arrayPtrCap > 0 {
C.free(e.startArrayPtr)
C.free(e.lengthArrayPtr)
}
} }
// NewExtractRequestPool returns a new empty ExtractRequestPool. // NewExtractRequestPool returns a new empty ExtractRequestPool.
@ -165,6 +226,10 @@ func NewExtractRequestPool() ExtractRequestPool {
type extractRequest struct { type extractRequest struct {
req *C.ss_plugin_extract_field 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 // Pointer to a C-allocated array of field_result_t
resBuf *C.field_result_t resBuf *C.field_result_t
// Length of the array pointed by resBuf // Length of the array pointed by resBuf
@ -181,6 +246,11 @@ func (e *extractRequest) SetPtr(pef unsafe.Pointer) {
e.req = (*C.ss_plugin_extract_field)(pef) 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 { func (e *extractRequest) FieldID() uint64 {
return uint64(e.req.field_id) return uint64(e.req.field_id)
} }
@ -361,3 +431,16 @@ func (e *extractRequest) SetValue(v interface{}) {
} }
*((*C.uintptr_t)(unsafe.Pointer(&e.req.res))) = *(*C.uintptr_t)(unsafe.Pointer(&e.resBuf)) *((*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)
}

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2025 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -57,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 { func getBoolResSSPluingExtractField(t *testing.T, ptr *_Ctype_ss_plugin_extract_field, index int) bool {
if ptr.res_len < (_Ctype_uint64_t)(index) { 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)) t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(ptr.res_len))
@ -95,6 +101,10 @@ func getBinResSSPluingExtractField(t *testing.T, p *_Ctype_ss_plugin_extract_fie
return buf return buf
} }
func getResSSPluginExtractOffsetFromPtr(offset *_Ctype_uint32_t) uint32 {
return uint32(*offset)
}
func assertPanic(t *testing.T, fun func()) { func assertPanic(t *testing.T, fun func()) {
defer func() { defer func() {
if r := recover(); r == nil { if r := recover(); r == nil {
@ -125,10 +135,14 @@ func TestExtractRequestSetValue(t *testing.T) {
// init test data // init test data
testStr := "test str" testStr := "test str"
testU64 := uint64(99) testU64 := uint64(99)
testU64Start := uint32(PluginEventPayloadOffset)
testU64Length := uint32(8)
testBool := true testBool := true
testIPv6 := net.IPv6loopback testIPv6 := net.IPv6loopback
testStrList := make([]string, 0) testStrList := make([]string, 0)
testU64List := make([]uint64, 0) testU64List := make([]uint64, 0)
testU64ListStart := uint32(PluginEventPayloadOffset)
testU64ListLength := uint32(0)
testBoolList := make([]bool, 0) testBoolList := make([]bool, 0)
dataArray := make([]byte, (minResultBufferLen+1)*int(len(testIPv6))) dataArray := make([]byte, (minResultBufferLen+1)*int(len(testIPv6)))
for i := 0; i < (minResultBufferLen+1)*int(len(testIPv6)); i++ { for i := 0; i < (minResultBufferLen+1)*int(len(testIPv6)); i++ {
@ -138,6 +152,7 @@ func TestExtractRequestSetValue(t *testing.T) {
for i := 0; i < minResultBufferLen+1; i++ { for i := 0; i < minResultBufferLen+1; i++ {
testStrList = append(testStrList, fmt.Sprintf("test-%d", i)) testStrList = append(testStrList, fmt.Sprintf("test-%d", i))
testU64List = append(testU64List, uint64(i)) testU64List = append(testU64List, uint64(i))
testU64ListLength += testU64Length
testBoolList = append(testBoolList, i%3 == 0) testBoolList = append(testBoolList, i%3 == 0)
testIPv6List[i] = dataArray[i*len(testIPv6) : (i+1)*len(testIPv6)] testIPv6List[i] = dataArray[i*len(testIPv6) : (i+1)*len(testIPv6)]
} }
@ -145,7 +160,11 @@ func TestExtractRequestSetValue(t *testing.T) {
// init extract requests // init extract requests
pool := NewExtractRequestPool() pool := NewExtractRequestPool()
u64Ptr, freeU64Ptr := allocSSPluginExtractField(1, FieldTypeUint64, "test.u64", "", 0, true, false) u64Ptr, freeU64Ptr := allocSSPluginExtractField(1, FieldTypeUint64, "test.u64", "", 0, true, false)
u64OffsetStartPtr := allocSSPluginExtractOffset()
u64OffsetLengthPtr := allocSSPluginExtractOffset()
u64ListPtr, freeU64ListPtr := allocSSPluginExtractField(2, FieldTypeUint64, "test.u64", "", 0, true, true) u64ListPtr, freeU64ListPtr := allocSSPluginExtractField(2, FieldTypeUint64, "test.u64", "", 0, true, true)
u64ListOffsetStartPtr := allocSSPluginExtractOffset()
u64ListOffsetLengthPtr := allocSSPluginExtractOffset()
strPtr, freeStrPtr := allocSSPluginExtractField(3, FieldTypeCharBuf, "test.str", "", 0, true, false) strPtr, freeStrPtr := allocSSPluginExtractField(3, FieldTypeCharBuf, "test.str", "", 0, true, false)
strListPtr, freeStrListPtr := allocSSPluginExtractField(4, FieldTypeCharBuf, "test.str", "", 0, true, true) strListPtr, freeStrListPtr := allocSSPluginExtractField(4, FieldTypeCharBuf, "test.str", "", 0, true, true)
boolPtr, freeBoolPtr := allocSSPluginExtractField(5, FieldTypeBool, "test.bool", "", 0, true, false) boolPtr, freeBoolPtr := allocSSPluginExtractField(5, FieldTypeBool, "test.bool", "", 0, true, false)
@ -161,7 +180,9 @@ func TestExtractRequestSetValue(t *testing.T) {
binReq := pool.Get(6) binReq := pool.Get(6)
binReqList := pool.Get(7) binReqList := pool.Get(7)
u64Req.SetPtr(unsafe.Pointer(u64Ptr)) u64Req.SetPtr(unsafe.Pointer(u64Ptr))
u64Req.SetOffsetPtrs(unsafe.Pointer(u64OffsetStartPtr), unsafe.Pointer(u64OffsetLengthPtr))
u64ReqList.SetPtr(unsafe.Pointer(u64ListPtr)) u64ReqList.SetPtr(unsafe.Pointer(u64ListPtr))
u64ReqList.SetOffsetPtrs(unsafe.Pointer(u64ListOffsetStartPtr), unsafe.Pointer(u64ListOffsetLengthPtr))
strReq.SetPtr(unsafe.Pointer(strPtr)) strReq.SetPtr(unsafe.Pointer(strPtr))
strReqList.SetPtr(unsafe.Pointer(strListPtr)) strReqList.SetPtr(unsafe.Pointer(strListPtr))
boolReq.SetPtr(unsafe.Pointer(boolPtr)) boolReq.SetPtr(unsafe.Pointer(boolPtr))
@ -222,12 +243,26 @@ func TestExtractRequestSetValue(t *testing.T) {
if getU64ResSSPluingExtractField(t, u64Ptr, 0) != testU64 { if getU64ResSSPluingExtractField(t, u64Ptr, 0) != testU64 {
t.Errorf("expected value '%d', but found '%d'", testU64, getU64ResSSPluingExtractField(t, u64Ptr, 0)) 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.SetValue(testU64List)
u64ReqList.SetValueOffset(testU64ListStart, testU64ListLength)
for i, d := range testU64List { for i, d := range testU64List {
if getU64ResSSPluingExtractField(t, u64ListPtr, i) != d { if getU64ResSSPluingExtractField(t, u64ListPtr, i) != d {
t.Errorf("expected value '%d', but found '%d'", testU64, getU64ResSSPluingExtractField(t, u64Ptr, i)) 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) strReq.SetValue(testStr)
if getStrResSSPluingExtractField(t, strPtr, 0) != testStr { if getStrResSSPluingExtractField(t, strPtr, 0) != testStr {
t.Errorf("expected value '%s', but found '%s'", testStr, getStrResSSPluingExtractField(t, strPtr, 0)) t.Errorf("expected value '%s', but found '%s'", testStr, getStrResSSPluingExtractField(t, strPtr, 0))

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2023 The Falco Authors. Copyright (C) 2023 The Falco Authors.
@ -23,38 +24,51 @@ limitations under the License.
extern "C" { extern "C" {
#endif #endif
// //
// API versions of this plugin framework // 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_MAJOR 3
#define PLUGIN_API_VERSION_MINOR 0 #define PLUGIN_API_VERSION_MINOR 11
#define PLUGIN_API_VERSION_PATCH 0 #define PLUGIN_API_VERSION_PATCH 0
// //
// Just some not so smart defines to retrieve plugin api version as string // Just some not so smart defines to retrieve plugin api version as string
// //
#define QUOTE(str) #str #define QUOTE(str) #str
#define EXPAND_AND_QUOTE(str) QUOTE(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 \
#define PLUGIN_API_VERSION_STR EXPAND_AND_QUOTE(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. // 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. // 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, // This allows discovering the fields available in the table, defining new ones,
// and obtaining accessors usable at runtime for reading and writing the fields' // and obtaining accessors usable at runtime for reading and writing the fields'
// data from each entry of a given state table. // 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 // 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 // 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 // of elements of the returned array. The array's memory is owned by the
// tables's owner. Returns NULL in case of error. // 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 // Returns an opaque pointer representing an accessor to a data field
// present in all entries of the table, given its name and type. // present in all entries of the table, given its name and type.
@ -62,7 +76,9 @@ typedef struct
// the table. The pointer is owned by the table's owner. // the table. The pointer is owned by the table's owner.
// Returns NULL in case of issues (including when the field is not defined // Returns NULL in case of issues (including when the field is not defined
// or it has a type different than the specified one). // 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, // 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. // which will then be available in all entries contained in the table.
@ -71,16 +87,40 @@ typedef struct
// the table. The pointer is owned by the table's owner. // the table. The pointer is owned by the table's owner.
// Returns NULL in case of issues (including when a field is defined multiple // Returns NULL in case of issues (including when a field is defined multiple
// times with different data types). // 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_field_t* (*add_table_field)(ss_plugin_table_t* t,
} ss_plugin_table_fields_vtable; const char* name,
ss_plugin_state_type data_type);
} ss_plugin_table_fields_vtable_ext;
// Vtable for controlling a state table for read operations. // Supported by the API but deprecated. Use the extended version ss_plugin_table_reader_vtable_ext
// todo(jasondellaluce): support looping over a table // instead. todo(jasondellaluce): when/if major changes to v4, remove this and give this name to the
typedef struct // 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. // Returns the table's name, or NULL in case of error.
// The returned pointer is owned by the table's owner. // 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 // Returns the number of entries in the table, or ((uint64_t) -1) in
// case of error. // case of error.
@ -89,18 +129,52 @@ typedef struct
// Returns an opaque pointer to an entry present in the table at the given // 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 // 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. // 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. // Reads the value of an entry field from a table's entry.
// The field accessor must be obtainied during plugin_init(). // The field accessor must be obtainied during plugin_init().
// The read value is stored in the "out" parameter. // The read value is stored in the "out" parameter.
// Returns SS_PLUGIN_SUCCESS if successful, and SS_PLUGIN_FAILURE otherwise. // 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_rc (*read_entry_field)(ss_plugin_table_t* t,
} ss_plugin_table_reader_vtable; 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. // Vtable for controlling a state table for write operations.
typedef struct typedef struct {
{
// Erases all the entries of the table. // Erases all the entries of the table.
// Returns SS_PLUGIN_SUCCESS if successful, and SS_PLUGIN_FAILURE otherwise. // Returns SS_PLUGIN_SUCCESS if successful, and SS_PLUGIN_FAILURE otherwise.
ss_plugin_rc (*clear_table)(ss_plugin_table_t* t); ss_plugin_rc (*clear_table)(ss_plugin_table_t* t);
@ -125,15 +199,21 @@ typedef struct
// with the given key. If another entry is already present with the same key, // 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 // 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, // entry's pointer. Returns an opaque pointer to the newly-added table's entry,
// or NULL in case of error. // or NULL in case of error. Every non-NULL returned entry must be released
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); // 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. // Updates a table's entry by writing a value for one of its fields.
// The field accessor must be obtainied during plugin_init(). // The field accessor must be obtainied during plugin_init().
// The written value is read from the "in" parameter. // The written value is read from the "in" parameter.
// Returns SS_PLUGIN_SUCCESS if successful, and SS_PLUGIN_FAILURE otherwise. // 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_rc (*write_entry_field)(ss_plugin_table_t* t,
} ss_plugin_table_writer_vtable; 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 // 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 // ss_plugin_init_tables_input, that can be used by the plugin to inform its
@ -142,33 +222,46 @@ typedef struct
// of implementing all the API functions. These will be used by other // of implementing all the API functions. These will be used by other
// plugins loaded by the falcosecurity libraries to interact with the state // plugins loaded by the falcosecurity libraries to interact with the state
// of a given plugin to implement cross-plugin state access. // of a given plugin to implement cross-plugin state access.
typedef struct typedef struct {
{
// The name of the state table. // The name of the state table.
const char* name; 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; ss_plugin_state_type key_type;
// //
// A non-NULL opaque pointer to the state table. // A non-NULL opaque pointer to the state table.
// This will be passed as parameters to all the callbacks defined below. // This will be passed as parameters to all the callbacks defined below.
ss_plugin_table_t* table; 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; 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; 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; 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; } 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 // This provides the plugin with callback functions implemented by its owner
// that can be used to discover, access, and define state tables. // 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 // 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 // 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 // of elements of the returned array. The array's memory is owned by the
@ -177,7 +270,9 @@ typedef struct
// //
// Returns an opaque accessor to a state table registered in the plugin's // 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. // 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 // Registers a new state table in the plugin's owner. Returns
// SS_PLUGIN_SUCCESS in case of success, and SS_PLUGIN_FAILURE otherwise. // SS_PLUGIN_SUCCESS in case of success, and SS_PLUGIN_FAILURE otherwise.
@ -185,41 +280,69 @@ typedef struct
// by other actors of the plugin's owner to interact with the state table. // 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); 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 // Supported but deprecated. Use the extended version fields_ext.
// registeted in the plugin's owner. // 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; 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; } 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 // Input passed at the plugin through plugin_init(). This contain information
// common to any plugin, and also information useful only in case the plugin // common to any plugin, and also information useful only in case the plugin
// implements a given capability. If a certain capability is not implemented // implements a given capability. If a certain capability is not implemented
// by the plugin, its information is set to NULL. // 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. // An opaque string representing the plugin init configuration.
// The format of the string is arbitrary and defined by the plugin itself. // The format of the string is arbitrary and defined by the plugin itself.
const char* config; const char* config;
// //
// The plugin's owner. Can be passed by the plugin to the callbacks available // 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. // 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; ss_plugin_owner_t* owner;
// //
// Return a string with the error that was last generated by the plugin's // Return a string with the error that was last generated by the plugin's
// owner, or NULL if no error is present. // owner, or NULL if no error is present.
// The string pointer is owned by the plugin's owenr. // 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. // 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 // 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 // capabilities. The callbacks available in this input take the plugin's owner
// as a parameter. // as a parameter.
const ss_plugin_init_tables_input* tables; 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; } ss_plugin_init_input;
// Input passed to the plugin when extracting a field from an event for // Input passed to the plugin when extracting a field from an event for
// the field extraction capability. // 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 // 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. // in this struct in order to invoke functions of its owner.
@ -228,7 +351,7 @@ typedef struct ss_plugin_field_extract_input
// Return a string with the error that was last generated by the plugin's // Return a string with the error that was last generated by the plugin's
// owner, or NULL if no error is present. // owner, or NULL if no error is present.
// The string pointer is owned by the plugin's owenr. // 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. // The length of the fields array.
uint32_t num_fields; uint32_t num_fields;
@ -238,16 +361,28 @@ typedef struct ss_plugin_field_extract_input
// extracted value as output. Memory pointers set as output must be allocated // 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 // by the plugin and must not be deallocated or modified until the next
// extract_fields() call. // 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. // 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; } ss_plugin_field_extract_input;
// Input passed to the plugin when parsing an event for the event parsing // Input passed to the plugin when parsing an event for the event parsing
// capability. // 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 // 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. // in this struct in order to invoke functions of its owner.
@ -256,26 +391,122 @@ typedef struct ss_plugin_event_parse_input
// Return a string with the error that was last generated by the plugin's // Return a string with the error that was last generated by the plugin's
// owner, or NULL if no error is present. // owner, or NULL if no error is present.
// The string pointer is owned by the plugin's owenr. // 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; 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; 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; } 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 // Function handler used by plugin for sending asynchronous events to the
// Falcosecurity libs during a live event capture. The asynchronous events // 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. // 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 // The function returns SS_PLUGIN_SUCCESS in case of success, or
// SS_PLUGIN_FAILURE otherwise. If a non-NULL char pointer is passed for // 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 // the "err" argument, it will be filled with an error message string
// in case the handler function returns SS_PLUGIN_FAILURE. The error 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 // has a max length of PLUGIN_MAX_ERRLEN (termination char included) and its
// memory must be allocated and owned by the plugin. // 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: // The struct below define the functions and arguments for plugins capabilities:
@ -307,8 +538,7 @@ typedef ss_plugin_rc (*ss_plugin_async_event_handler_t)(ss_plugin_owner_t* o, co
// //
// Plugins API vtable // Plugins API vtable
// //
typedef struct typedef struct {
{
// //
// Return the version of the plugin API used by this plugin. // Return the version of the plugin API used by this plugin.
// Required: yes // Required: yes
@ -319,7 +549,7 @@ typedef struct
// of the API they run against, and the framework will take care of checking // of the API they run against, and the framework will take care of checking
// and enforcing compatibility. // 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 // Return a string representation of a schema describing the data expected
@ -340,7 +570,7 @@ typedef struct
// This also serves as a piece of documentation for users about how the // This also serves as a piece of documentation for users about how the
// plugin needs to be configured. // 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. // Initialize the plugin and allocate its state.
@ -356,13 +586,13 @@ typedef struct
// If a non-NULL ss_plugin_t* state is returned, then subsequent invocations // 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 // of init() must not return the same ss_plugin_t* value again, if not after
// it has been disposed with destroy() first. // 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. // Destroy the plugin and, if plugin state was allocated, free it.
// Required: yes // 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 // Return a string with the error that was last generated by
@ -374,28 +604,28 @@ typedef struct
// string with more context for the error. The framework // string with more context for the error. The framework
// calls get_last_error() to access that string. // 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 // Return the name of the plugin, which will be printed when displaying
// information about the plugin. // information about the plugin.
// Required: yes // Required: yes
// //
const char *(*get_name)(); const char* (*get_name)();
// //
// Return the descriptions of the plugin, which will be printed when displaying // Return the descriptions of the plugin, which will be printed when displaying
// information about the plugin. // information about the plugin.
// Required: yes // Required: yes
// //
const char *(*get_description)(); const char* (*get_description)();
// //
// Return a string containing contact info (url, email, etc) for // Return a string containing contact info (url, email, etc) for
// the plugin authors. // the plugin authors.
// Required: yes // Required: yes
// //
const char *(*get_contact)(); const char* (*get_contact)();
// //
// Return the version of this plugin itself // Return the version of this plugin itself
@ -409,14 +639,14 @@ typedef struct
// in pre-existing capture files must always be readable by newer versions // in pre-existing capture files must always be readable by newer versions
// of the plugin. // of the plugin.
// //
const char *(*get_version)(); const char* (*get_version)();
// Event sourcing capability API // Event sourcing capability API
struct struct {
{
// //
// Return the unique ID of the plugin. // 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() // 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) // function is allowed to only return events of plugin type (code 322)
@ -543,7 +773,7 @@ typedef struct
// If the returned pointer is non-NULL, then it must be uniquely // If the returned pointer is non-NULL, then it must be uniquely
// attached to the ss_plugin_t* parameter value. The pointer must not // attached to the ss_plugin_t* parameter value. The pointer must not
// be shared across multiple distinct ss_plugin_t* values. // 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. // Return the next batch of events.
@ -571,15 +801,27 @@ typedef struct
// The value of the ss_plugin_event** output parameter must be uniquely // The value of the ss_plugin_event** output parameter must be uniquely
// attached to the ss_instance_t* parameter value. The pointer must not // attached to the ss_instance_t* parameter value. The pointer must not
// be shared across multiple distinct ss_instance_t* values. // 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 // 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. // 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 // Required: no
// //
// This function is optional--if NULL or an empty array, then: // This function is optional--if NULL or an empty array, then:
@ -587,7 +829,9 @@ typedef struct
// get_extract_event_sources (either default or custom) is compatible // get_extract_event_sources (either default or custom) is compatible
// with the "syscall" event source, otherwise // with the "syscall" event source, otherwise
// - the plugin will only receive events of plugin type (code 322). // - 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 // Return a string describing the event sources that this plugin
@ -596,9 +840,9 @@ typedef struct
// Return value: a json array of strings containing event // Return value: a json array of strings containing event
// sources returned by a plugin with event sourcing capabilities get_event_source() // sources returned by a plugin with event sourcing capabilities get_event_source()
// function, or "syscall" for indicating support to non-plugin events. // 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, // This function is optional--if NULL or an empty array, then if plugin has sourcing
// and implements a specific event source, it will only receive events matching its event source, // capability, and implements a specific event source, it will only receive events matching
// otherwise it will receive events from all event sources. // its event source, otherwise it will receive events from all event sources.
// //
const char* (*get_extract_event_sources)(); const char* (*get_extract_event_sources)();
@ -612,7 +856,7 @@ typedef struct
// "name": a string with a name for the field // "name": a string with a name for the field
// "type": one of "string", "uint64", "bool", "reltime", "abstime", // "type": one of "string", "uint64", "bool", "reltime", "abstime",
// "ipaddr", "ipnet" // "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. // that the field extracts a list of values.
// "arg": (optional) if present, notes that the field can accept // "arg": (optional) if present, notes that the field can accept
// an argument e.g. field[arg]. More precisely, the following // an argument e.g. field[arg]. More precisely, the following
@ -629,10 +873,13 @@ typedef struct
// display the field instead of the name. Used in tools // display the field instead of the name. Used in tools
// like wireshark. // like wireshark.
// "desc": a string with a description of the field // "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: // Example return value:
// [ // [
// {"type": "uint64", "name": "field1", "desc": "Describing field 1"}, // {"type": "uint64", "name": "field1", "desc": "Describing field 1", "addOutput": true},
// {"type": "string", "name": "field2", "arg": {"isRequired": true, "isIndex": true}, "desc": "Describing field 2"}, // {"type": "string", "name": "field2", "arg": {"isRequired": true, "isIndex": true},
// "desc": "Describing field 2"},
// ] // ]
const char* (*get_fields)(); const char* (*get_fields)();
@ -658,15 +905,25 @@ typedef struct
// The value of the ss_plugin_extract_field* output parameter must be // The value of the ss_plugin_extract_field* output parameter must be
// uniquely attached to the ss_plugin_t* parameter value. The pointer // uniquely attached to the ss_plugin_t* parameter value. The pointer
// must not be shared across multiple distinct ss_plugin_t* values. // 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 // Event parsing capability API
struct struct {
{
// //
// Return the list of event types that this plugin is capable of parsing. // Return the list of event types that this plugin will receive
// The event types follow the libscap specific. // 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 // Required: no
// //
@ -675,7 +932,9 @@ typedef struct
// get_parse_event_sources (either default or custom) is compatible // get_parse_event_sources (either default or custom) is compatible
// with the "syscall" event source, otherwise // with the "syscall" event source, otherwise
// - the plugin will only receive events of plugin type (code 322). // - 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 // Return a string describing the event sources that this plugin
// is capable of parsing. // is capable of parsing.
@ -685,9 +944,9 @@ typedef struct
// Return value: a json array of strings containing event // Return value: a json array of strings containing event
// sources returned by a plugin with event sourcing capabilities get_event_source() // sources returned by a plugin with event sourcing capabilities get_event_source()
// function, or "syscall" for indicating support to non-plugin events. // 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, // This function is optional--if NULL or an empty array, then if plugin has sourcing
// and implements a specific event source, it will only receive events matching its event source, // capability, and implements a specific event source, it will only receive events matching
// otherwise it will receive events from all event sources. // its event source, otherwise it will receive events from all event sources.
// //
const char* (*get_parse_event_sources)(); const char* (*get_parse_event_sources)();
// //
@ -716,12 +975,13 @@ typedef struct
// The value of the ss_plugin_event_parse_input* output parameter must be // The value of the ss_plugin_event_parse_input* output parameter must be
// uniquely attached to the ss_plugin_t* parameter value. The pointer // uniquely attached to the ss_plugin_t* parameter value. The pointer
// must not be shared across multiple distinct ss_plugin_t* values. // 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 // Async events capability API
struct struct {
{
// //
// Return a string describing the event sources for which this plugin // Return a string describing the event sources for which this plugin
// is capable of injecting async events in the event stream of a capture. // is capable of injecting async events in the event stream of a capture.
@ -798,7 +1058,78 @@ typedef struct
// //
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE. // 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; } plugin_api;

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2023 The Falco Authors. Copyright (C) 2023 The Falco Authors.
@ -29,30 +30,28 @@ typedef uint32_t ss_plugin_bool;
// The noncontinguous numbers are to maintain equality with underlying // The noncontinguous numbers are to maintain equality with underlying
// falcosecurity libs types. // falcosecurity libs types.
typedef enum ss_plugin_field_type typedef enum ss_plugin_field_type {
{
// A 64bit unsigned integer. // A 64bit unsigned integer.
FTYPE_UINT64 = 8, FTYPE_UINT64 = 8,
// A printable buffer of bytes, NULL terminated // A printable buffer of bytes, NULL terminated
FTYPE_STRING = 9, FTYPE_STRING = 9,
// A relative time. Seconds * 10^9 + nanoseconds. 64bit. // 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. // An absolute time interval. Seconds from epoch * 10^9 + nanoseconds. 64bit.
FTYPE_ABSTIME = 21, FTYPE_ABSTIME = 21,
// A boolean value, 4 bytes. // A boolean value, 4 bytes.
FTYPE_BOOL = 25, FTYPE_BOOL = 25,
// Either an IPv4 or IPv6 address. The length indicates which one it is. // 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. // 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, // The field encodes only the IP address, so this differs from FTYPE_IPADDR,
// from the way the framework perform runtime checks and comparisons. // from the way the framework perform runtime checks and comparisons.
FTYPE_IPNET = 41, FTYPE_IPNET = 41,
} ss_plugin_field_type; } ss_plugin_field_type;
// Values to return from init() / open() / next_batch() / // Values to return from init() / open() / next_batch() /
// extract_fields(). // extract_fields().
typedef enum ss_plugin_rc typedef enum ss_plugin_rc {
{
SS_PLUGIN_SUCCESS = 0, SS_PLUGIN_SUCCESS = 0,
SS_PLUGIN_FAILURE = 1, SS_PLUGIN_FAILURE = 1,
SS_PLUGIN_TIMEOUT = -1, SS_PLUGIN_TIMEOUT = -1,
@ -61,8 +60,7 @@ typedef enum ss_plugin_rc
} ss_plugin_rc; } ss_plugin_rc;
// The supported schema formats for the init configuration. // 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 // The schema is undefined and the init configuration
// is an opaque string. // is an opaque string.
SS_PLUGIN_SCHEMA_NONE = 0, SS_PLUGIN_SCHEMA_NONE = 0,
@ -78,7 +76,8 @@ typedef enum ss_plugin_schema_type
// An event is represented as a contiguous region of memory composed by // An event is represented as a contiguous region of memory composed by
// a header and a list of parameters appended, in the form of: // 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: // The event header is composed of:
// - ts: the event timestamp, in nanoseconds since the epoch. // - ts: the event timestamp, in nanoseconds since the epoch.
@ -95,8 +94,6 @@ typedef enum ss_plugin_schema_type
#if defined _MSC_VER #if defined _MSC_VER
#pragma pack(push) #pragma pack(push)
#pragma pack(1) #pragma pack(1)
#elif defined __sun
#pragma pack(1)
#else #else
#pragma pack(push, 1) #pragma pack(push, 1)
#endif #endif
@ -104,17 +101,13 @@ struct ss_plugin_event {
#ifdef PPM_ENABLE_SENTINEL #ifdef PPM_ENABLE_SENTINEL
uint32_t sentinel_begin; uint32_t sentinel_begin;
#endif #endif
uint64_t ts; /* timestamp, in nanoseconds from epoch */ uint64_t ts; /* timestamp, in nanoseconds from epoch */
uint64_t tid; /* the tid of the thread that generated this event */ uint64_t tid; /* the tid of the thread that generated this event */
uint32_t len; /* the event len, including the header */ uint32_t len; /* the event len, including the header */
uint16_t type; /* the event type */ uint16_t type; /* the event type */
uint32_t nparams; /* the number of parameters of the event */ uint32_t nparams; /* the number of parameters of the event */
}; };
#if defined __sun
#pragma pack()
#else
#pragma pack(pop) #pragma pack(pop)
#endif
typedef struct ss_plugin_event ss_plugin_event; typedef struct ss_plugin_event ss_plugin_event;
// This struct represents an event provided by the framework to the plugin // This struct represents an event provided by the framework to the plugin
@ -124,18 +117,31 @@ typedef struct ss_plugin_event ss_plugin_event;
// Might not be contiguous. // Might not be contiguous.
// - evtsrc: The name of the event's source. Can be "syscall" or any other // - evtsrc: The name of the event's source. Can be "syscall" or any other
// event source name implemented by a plugin. // event source name implemented by a plugin.
typedef struct ss_plugin_event_input typedef struct ss_plugin_event_input {
{
const ss_plugin_event* evt; const ss_plugin_event* evt;
uint64_t evtnum; uint64_t evtnum;
const char* evtsrc; const char* evtsrc;
} ss_plugin_event_input; } ss_plugin_event_input;
typedef struct ss_plugin_byte_buffer{ typedef struct ss_plugin_byte_buffer {
uint32_t len; uint32_t len;
const void* ptr; const void* ptr;
} ss_plugin_byte_buffer; } 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 // Used in extract_fields functions below to receive a field/arg
// pair and return an extracted value. // pair and return an extracted value.
// field_id: id of the field, as of its index in the list of // field_id: id of the field, as of its index in the list of
@ -174,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 // 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. // 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. // 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 // NOTE: For a given architecture, this has always the same size which
// is sizeof(uintptr_t). Adding new value types will not create breaking // 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 // changes in the plugin API. However, we must make sure that each added
// type is always a pointer. // type is always a pointer.
union union {
{
const char** str; const char** str;
uint64_t* u64; uint64_t* u64;
uint32_t* u32; uint32_t* u32;
@ -202,12 +206,21 @@ typedef struct ss_plugin_extract_field
ss_plugin_bool flist; ss_plugin_bool flist;
} ss_plugin_extract_field; } 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. // Types supported by entry fields of state tables.
// The noncontinguous numbers are to maintain equality with underlying // The noncontinguous numbers are to maintain equality with underlying
// falcosecurity libs types. // falcosecurity libs types.
// todo(jasondellaluce): should we merge this with ss_plugin_field_type? // 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_INT8 = 1,
SS_PLUGIN_ST_INT16 = 2, SS_PLUGIN_ST_INT16 = 2,
SS_PLUGIN_ST_INT32 = 3, SS_PLUGIN_ST_INT32 = 3,
@ -217,13 +230,13 @@ typedef enum ss_plugin_state_type
SS_PLUGIN_ST_UINT32 = 7, SS_PLUGIN_ST_UINT32 = 7,
SS_PLUGIN_ST_UINT64 = 8, SS_PLUGIN_ST_UINT64 = 8,
SS_PLUGIN_ST_STRING = 9, SS_PLUGIN_ST_STRING = 9,
SS_PLUGIN_ST_TABLE = 10,
SS_PLUGIN_ST_BOOL = 25 SS_PLUGIN_ST_BOOL = 25
} ss_plugin_state_type; } ss_plugin_state_type;
// Data representation of entry fields of state tables. // Data representation of entry fields of state tables.
// todo(jasondellaluce): should we merge this with what we have for field extraction? // 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; int8_t s8;
int16_t s16; int16_t s16;
int32_t s32; int32_t s32;
@ -234,33 +247,22 @@ typedef union ss_plugin_state_data
uint64_t u64; uint64_t u64;
const char* str; const char* str;
ss_plugin_bool b; ss_plugin_bool b;
ss_plugin_table_t* table;
} ss_plugin_state_data; } ss_plugin_state_data;
// Info about a state table. // Info about a state table.
typedef struct ss_plugin_table_info typedef struct ss_plugin_table_info {
{
const char* name; const char* name;
ss_plugin_state_type key_type; ss_plugin_state_type key_type;
} ss_plugin_table_info; } ss_plugin_table_info;
// Info about a data field contained in the entires of a state table. // 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; const char* name;
ss_plugin_state_type field_type; ss_plugin_state_type field_type;
ss_plugin_bool read_only; ss_plugin_bool read_only;
} ss_plugin_table_fieldinfo; } 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 // 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. // control and invoke functions of the plugin's owner from within the plugin.
typedef void ss_plugin_owner_t; typedef void ss_plugin_owner_t;
@ -284,6 +286,64 @@ typedef void ss_plugin_t;
// //
typedef void ss_instance_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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -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" {

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -54,6 +55,9 @@ func (m *testPlugin) Extract(req sdk.ExtractRequest, evt sdk.EventReader) error
switch req.FieldID() { switch req.FieldID() {
case 0: case 0:
req.SetValue(uint64(0)) req.SetValue(uint64(0))
if req.WantOffset() {
req.SetValueOffset(sdk.PluginEventPayloadOffset, 8)
}
return nil return nil
default: default:
return fmt.Errorf("unsupported field: %s", req.Field()) return fmt.Errorf("unsupported field: %s", req.Field())

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,46 +0,0 @@
/*
Copyright (C) 2023 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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
// note(jasondellaluce,therealbobo): implementation taken from falcosecurity/libs
#include <stdint.h>
#include <string.h>
/*!
\brief Copy up to size - 1 characters from the NUL-terminated string src to dst, NUL-terminating the result.
\return The length of the source string.
*/
static inline size_t strlcpy(char *dst, const char *src, size_t size) {
size_t srcsize = strlen(src);
if (size == 0) {
return srcsize;
}
size_t copysize = srcsize;
if (copysize > size - 1) {
copysize = size - 1;
}
memcpy(dst, src, copysize);
dst[copysize] = '\0';
return srcsize;
}

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -91,6 +92,10 @@ const (
// asyncBatchSize is the physical size of batches allocated // asyncBatchSize is the physical size of batches allocated
// in C memory, namely the total number of locks available // in C memory, namely the total number of locks available
asyncBatchSize = cgo.MaxHandle + 1 asyncBatchSize = cgo.MaxHandle + 1
//
// max number of seconds we're willing to wait for a worker to exit
// once released before triggering a panic
workerReleaseTimeoutInSeconds = 10
) )
var ( var (
@ -185,7 +190,9 @@ func (a *asyncContext) acquireWorker(workerIdx int32) {
for _, i := range batchIdxs { for _, i := range batchIdxs {
// reduce sync overhead by skipping unused batch slots // reduce sync overhead by skipping unused batch slots
if i > a.maxBatchIdx { if i > a.maxBatchIdx {
continue // from this point on we'll only encountered unused slots
// so we mind as well just start over
break
} }
// check for incoming request, if any, otherwise busy waits // check for incoming request, if any, otherwise busy waits
@ -199,6 +206,7 @@ func (a *asyncContext) acquireWorker(workerIdx int32) {
a.batch[i].evt, a.batch[i].evt,
uint32(a.batch[i].num_fields), uint32(a.batch[i].num_fields),
a.batch[i].fields, a.batch[i].fields,
a.batch[i].value_offsets,
), ),
) )
// processing done, return back to waiting state // processing done, return back to waiting state
@ -243,13 +251,23 @@ func (a *asyncContext) releaseWorker(workerIdx int32) {
// side, we use the first visible slot and set an exit request. The worker // side, we use the first visible slot and set an exit request. The worker
// will eventually synchronize with the used lock and stop. // will eventually synchronize with the used lock and stop.
idx := a.workerIdxToBatchIdxs(workerIdx)[0] idx := a.workerIdxToBatchIdxs(workerIdx)[0]
waitStartTime := time.Now()
for !atomic.CompareAndSwapInt32((*int32)(&a.batch[idx].lock), state_unused, state_exit_req) { for !atomic.CompareAndSwapInt32((*int32)(&a.batch[idx].lock), state_unused, state_exit_req) {
// spin // spinning, but let's yield first
runtime.Gosched()
if time.Since(waitStartTime).Seconds() > workerReleaseTimeoutInSeconds {
panic("plugin-sdk-go/sdk/symbols/extract: async worker release timeout expired (1)")
}
} }
// wait for worker exiting // wait for worker exiting
waitStartTime = time.Now()
for atomic.LoadInt32((*int32)(&a.batch[idx].lock)) != state_exit_ack { for atomic.LoadInt32((*int32)(&a.batch[idx].lock)) != state_exit_ack {
// spin // spinning, but let's yield first
runtime.Gosched()
if time.Since(waitStartTime).Seconds() > workerReleaseTimeoutInSeconds {
panic("plugin-sdk-go/sdk/symbols/extract: async worker release timeout expired (2)")
}
} }
// restore first worker slot // restore first worker slot

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -54,7 +55,8 @@ void async_deinit()
extern int32_t plugin_extract_fields_sync(ss_plugin_t *s, extern int32_t plugin_extract_fields_sync(ss_plugin_t *s,
const ss_plugin_event_input *evt, const ss_plugin_event_input *evt,
uint32_t num_fields, 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 // This is the plugin API function. If s_async_ctx_batch is
// non-NULL, it calls the async extractor function. Otherwise, it // non-NULL, it calls the async extractor function. Otherwise, it
@ -77,7 +79,7 @@ FALCO_PLUGIN_SDK_PUBLIC int32_t plugin_extract_fields(ss_plugin_t *s,
if (s_async_ctx_batch == NULL if (s_async_ctx_batch == NULL
|| atomic_load_explicit(&s_async_ctx_batch[(size_t)s - 1].lock, memory_order_seq_cst) != WAIT) || 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 // Set input data
@ -85,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].evt = evt;
s_async_ctx_batch[(size_t)s - 1].num_fields = in->num_fields; 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].fields = in->fields;
s_async_ctx_batch[(size_t)s - 1].value_offsets = in->value_offsets;
// notify data request // notify data request
atomic_store_explicit(&s_async_ctx_batch[(size_t)s - 1].lock, DATA_REQ, memory_order_seq_cst); atomic_store_explicit(&s_async_ctx_batch[(size_t)s - 1].lock, DATA_REQ, memory_order_seq_cst);

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2025 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -27,6 +28,7 @@ limitations under the License.
package extract package extract
/* /*
#include <stdlib.h>
#include "extract.h" #include "extract.h"
*/ */
import "C" import "C"
@ -38,20 +40,34 @@ import (
) )
//export plugin_extract_fields_sync //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) pHandle := cgo.Handle(plgState)
extract := pHandle.Value().(sdk.Extractor) extract := pHandle.Value().(sdk.Extractor)
extrReqs := pHandle.Value().(sdk.ExtractRequests) 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] flds := (*[1 << 28]C.struct_ss_plugin_extract_field)(unsafe.Pointer(fields))[:numFields:numFields]
var i uint32 var i uint32
var extrReq sdk.ExtractRequest var extrReq sdk.ExtractRequest
if offsets != nil {
extrReqs.ExtractRequests().MakeOffsetArrayPtrs(unsafe.Pointer(offsets), numFields)
}
for i = 0; i < numFields; i++ { for i = 0; i < numFields; i++ {
flds[i].res_len = (C.uint64_t)(0) flds[i].res_len = (C.uint64_t)(0)
extrReq = extrReqs.ExtractRequests().Get(int(flds[i].field_id)) extrReq = extrReqs.ExtractRequests().Get(int(flds[i].field_id))
extrReq.SetPtr(unsafe.Pointer(&flds[i])) 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))) err := extract.Extract(extrReq, sdk.NewEventReader(unsafe.Pointer(evt)))
if err != nil { if err != nil {
pHandle.Value().(sdk.LastError).SetLastError(err) pHandle.Value().(sdk.LastError).SetLastError(err)

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -29,6 +30,7 @@ typedef struct async_extractor_info
const ss_plugin_event_input *evt; const ss_plugin_event_input *evt;
uint32_t num_fields; uint32_t num_fields;
ss_plugin_extract_field *fields; ss_plugin_extract_field *fields;
ss_plugin_extract_value_offsets *value_offsets;
// output data // output data
int32_t rc; int32_t rc;

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -76,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()) { func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event_input, func()) {
ret := &_Ctype_struct_ss_plugin_event_input{} ret := &_Ctype_struct_ss_plugin_event_input{}
evts, _ := sdk.NewEventWriters(1, int64(len(data))) evts, _ := sdk.NewEventWriters(1, int64(len(data)))
@ -117,11 +126,22 @@ func TestExtract(t *testing.T) {
// panic // panic
badHandle := cgo.NewHandle(1) badHandle := cgo.NewHandle(1)
assertPanic(t, func() { 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 // 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 { if res != sdk.SSPluginSuccess {
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res) t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
} else if sample.lastErr != nil { } else if sample.lastErr != nil {
@ -130,7 +150,7 @@ func TestExtract(t *testing.T) {
// error // error
sample.err = errTest 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 { if res != sdk.SSPluginFailure {
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginFailure, res) t.Errorf("(res): expected %d, but found %d", sdk.SSPluginFailure, res)
} else if sample.lastErr != errTest { } else if sample.lastErr != errTest {

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -117,17 +118,21 @@ func splitVersionString(version string) (string, string, string) {
func SetRequiredAPIVersion(apiVer string) { func SetRequiredAPIVersion(apiVer string) {
if apiVer != "" { if apiVer != "" {
requiredMajor, requiredMinor, requiredPatch := splitVersionString(apiVer) pluginRequiredMajor, pluginRequiredMinor, pluginRequiredPatch := splitVersionString(apiVer)
pluginMajor, pluginMinor, pluginPatch := splitVersionString(C.GoString(C.get_default_required_api_version())) sdkRequiredMajor, sdkRequiredMinor, sdkRequiredPatch := splitVersionString(C.GoString(C.get_default_required_api_version()))
if pluginMajor != requiredMajor { // The plugin should always require a version lower or equal to the one required by the SDK
panic("Plugin SDK Go required API version incompatible major number. Expected: Major version should be equal to " + pluginMajor + " but got " + requiredMajor) // because the SDK couldn't support features coming from new framework versions.
// On the other side the plugin could require a lower version because maybe it doesn't
// need all features provided by the framework.
if sdkRequiredMajor != pluginRequiredMajor {
panic("Incompatible required Major version between SDK and the plugin. Major SDK version is equal to " + sdkRequiredMajor + " but the plugin uses " + pluginRequiredMajor + ". The 2 Major versions should be equal.")
} }
if pluginMinor < requiredMinor { if sdkRequiredMinor < pluginRequiredMinor {
panic("Plugin SDK Go required API version incompatible minor number. Expected: Minor version should be less than/equal to " + pluginMinor + " but got " + requiredMinor) panic("The plugin requires a Minor version greater than the SDK one. Minor SDK version is equal to " + sdkRequiredMinor + " but the plugin uses " + pluginRequiredMinor + ". The plugin should always require a Minor version lower or equal to the SDK one.")
} }
if pluginMinor == requiredMinor && pluginPatch < requiredPatch { if sdkRequiredMinor == pluginRequiredMinor && sdkRequiredPatch < pluginRequiredPatch {
panic("Plugin SDK Go required API version incompatible patch number. Expected: Patch version should be less than/equal to " + pluginPatch + " but got " + requiredPatch) panic("The plugin requires a Patch version greater than the SDK one. Patch SDK version is equal to " + sdkRequiredPatch + " but the plugin uses " + pluginRequiredPatch + ". The plugin should always require a Patch version lower or equal to the SDK one.")
} }
} }
pRequiredAPIVersion.Write(apiVer) pRequiredAPIVersion.Write(apiVer)

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -29,10 +30,6 @@ import (
var testStr = "test" var testStr = "test"
var testU32 = uint32(1) var testU32 = uint32(1)
var testStrSlice = []string{"hello", "world"} var testStrSlice = []string{"hello", "world"}
var testCurAPIVerMajor = 3
var testCurAPIVerMinor = 0
var testCurAPIVerPatch = 0
var testCurAPIVer = testFormatVer(testCurAPIVerMajor, testCurAPIVerMinor, testCurAPIVerPatch)
func testFormatVer(major, minor, patch int) string { func testFormatVer(major, minor, patch int) string {
return fmt.Sprintf("%d.%d.%d", major, minor, patch) return fmt.Sprintf("%d.%d.%d", major, minor, patch)
@ -46,7 +43,7 @@ func TestInfo(t *testing.T) {
SetId(testU32) SetId(testU32)
resU32 = plugin_get_id() resU32 = plugin_get_id()
if resU32 != testU32 { if resU32 != testU32 {
t.Errorf("(id) expected %d, but found %d", testU32, resU32) t.Errorf("(plugin id) expected %d, but found %d", testU32, resU32)
} }
SetName(testStr) SetName(testStr)
@ -73,12 +70,6 @@ func TestInfo(t *testing.T) {
t.Errorf("(version) expected %s, but found %s", testStr, resStr) t.Errorf("(version) expected %s, but found %s", testStr, resStr)
} }
SetRequiredAPIVersion(testCurAPIVer)
resStr = ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
if resStr != testCurAPIVer {
t.Errorf("(requiredApiVersion) expected %s, but found %s", testStr, resStr)
}
SetEventSource(testStr) SetEventSource(testStr)
resStr = ptr.GoString(unsafe.Pointer(plugin_get_event_source())) resStr = ptr.GoString(unsafe.Pointer(plugin_get_event_source()))
if resStr != testStr { if resStr != testStr {
@ -113,52 +104,108 @@ func TestInfo(t *testing.T) {
} }
} }
func TestSemver(t *testing.T) { func TestSplitVersionString(t *testing.T) {
t.Run("success_check", func(t *testing.T) { t.Run("invalid version string 1", func(t *testing.T) {
panicFunc := func() { panicFunc := func() {
SetRequiredAPIVersion(testCurAPIVer) splitVersionString("2..1..2")
}
assert.Panics(t, panicFunc)
})
t.Run("invalid version string 2", func(t *testing.T) {
panicFunc := func() {
splitVersionString("2.2.3..32")
}
assert.Panics(t, panicFunc)
})
t.Run("invalid version string 3", func(t *testing.T) {
panicFunc := func() {
splitVersionString("2.2.3.")
}
assert.Panics(t, panicFunc)
})
t.Run("invalid version string 4", func(t *testing.T) {
panicFunc := func() {
splitVersionString("2..2.3")
}
assert.Panics(t, panicFunc)
})
t.Run("valid version string", func(t *testing.T) {
panicFunc := func() {
splitVersionString("2.2.3")
} }
assert.NotPanics(t, panicFunc) assert.NotPanics(t, panicFunc)
}) })
t.Run("default_version", func(t *testing.T) { t.Run("check split version string", func(t *testing.T) {
version := "" major, minor, patch := splitVersionString("2.4.3")
panicFunc := func() { if major != "2" {
SetRequiredAPIVersion(version) t.Errorf("(Major) expected %s, but found %s", "2", major)
} }
assert.NotPanics(t, panicFunc) if minor != "4" {
}) t.Errorf("(Minor) expected %s, but found %s", "4", minor)
t.Run("invalid_version", func(t *testing.T) {
version := "invalid"
errMsg := "Incorrect format. Expected: Semantic Versioning: X.Y.Z"
panicFunc := func() {
SetRequiredAPIVersion(version)
} }
assert.PanicsWithValue(t, errMsg, panicFunc) if patch != "3" {
}) t.Errorf("(Patch) expected %s, but found %s", "3", patch)
}
t.Run("incompatible_major_number", func(t *testing.T) { })
v := testFormatVer(testCurAPIVerMajor+1, testCurAPIVerMinor, testCurAPIVerPatch) }
panicFunc := func() {
SetRequiredAPIVersion(v) func TestSemver(t *testing.T) {
// Get the SDK required version
// we set an empty string to obtain the default SDK version
SetRequiredAPIVersion("")
versionSDK := ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
var majorSDK, minorSDK, patchSDK int
nums, err := fmt.Sscanf(versionSDK, "%d.%d.%d", &majorSDK, &minorSDK, &patchSDK)
if nums != 3 || err != nil {
t.Errorf("Unable to obtain the default SDK version")
}
// plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch == SDK Patch
t.Run("plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch == SDK Patch", func(t *testing.T) {
SetRequiredAPIVersion(testFormatVer(majorSDK, minorSDK, patchSDK))
requiredAPIVersion := ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
expectedRequiredAPIVersion := testFormatVer(majorSDK, minorSDK, patchSDK)
if expectedRequiredAPIVersion != requiredAPIVersion {
t.Errorf("(requiredApiVersion) expected %s, but found %s", expectedRequiredAPIVersion, requiredAPIVersion)
}
})
// plguin Major > SDK Major
t.Run("plguin Major > SDK Major", func(t *testing.T) {
panicFunc := func() {
SetRequiredAPIVersion(testFormatVer(majorSDK+1, minorSDK, patchSDK))
}
assert.PanicsWithValue(t, fmt.Sprintf("Incompatible required Major version between SDK and the plugin. Major SDK version is equal to %d but the plugin uses %d. The 2 Major versions should be equal.", majorSDK, majorSDK+1), panicFunc)
})
// plguin Major == SDK Major && plguin Minor > SDK Minor
t.Run("plguin Major == SDK Major && plguin Minor > SDK Minor", func(t *testing.T) {
panicFunc := func() {
SetRequiredAPIVersion(testFormatVer(majorSDK, minorSDK+1, patchSDK))
}
assert.PanicsWithValue(t, fmt.Sprintf("The plugin requires a Minor version greater than the SDK one. Minor SDK version is equal to %d but the plugin uses %d. The plugin should always require a Minor version lower or equal to the SDK one.", minorSDK, minorSDK+1), panicFunc)
})
// plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch > SDK Patch
t.Run("plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch > SDK Patch", func(t *testing.T) {
panicFunc := func() {
SetRequiredAPIVersion(testFormatVer(majorSDK, minorSDK, patchSDK+1))
}
assert.PanicsWithValue(t, fmt.Sprintf("The plugin requires a Patch version greater than the SDK one. Patch SDK version is equal to %d but the plugin uses %d. The plugin should always require a Patch version lower or equal to the SDK one.", patchSDK, patchSDK+1), panicFunc)
})
t.Run("empty plugin version", func(t *testing.T) {
// This should set as default the SDK required version since we don't provide the required plugin version
SetRequiredAPIVersion("")
requiredAPIVersion := ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
expectedRequiredAPIVersion := testFormatVer(majorSDK, minorSDK, patchSDK)
if expectedRequiredAPIVersion != requiredAPIVersion {
t.Errorf("(requiredApiVersion) expected %s, but found %s", expectedRequiredAPIVersion, requiredAPIVersion)
} }
assert.Panics(t, panicFunc)
})
t.Run("incompatible_minor_number", func(t *testing.T) {
v := testFormatVer(testCurAPIVerMajor, testCurAPIVerMinor+1, testCurAPIVerPatch)
panicFunc := func() {
SetRequiredAPIVersion(v)
}
assert.Panics(t, panicFunc)
})
t.Run("incompatible_patch_number", func(t *testing.T) {
v := testFormatVer(testCurAPIVerMajor, testCurAPIVerMinor, testCurAPIVerPatch+1)
panicFunc := func() {
SetRequiredAPIVersion(v)
}
assert.Panics(t, panicFunc)
}) })
} }

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.