Compare commits

...

32 Commits
v0.7.3 ... 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
88 changed files with 1385 additions and 638 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 }}

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
@ -15,7 +16,7 @@ GO ?= $(shell which go)
CURL ?= $(shell which curl) CURL ?= $(shell which curl)
PATCH ?= $(shell which patch) 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
@ -35,7 +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/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,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

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

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

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

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

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
const (
// MaxHandle is the largest value that an Handle can hold // MaxHandle is the largest value that an Handle can hold
const MaxHandle = 256 - 1 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.
@ -23,6 +24,7 @@ limitations under the License.
typedef void* library_handle_t; typedef void* library_handle_t;
#endif #endif
#include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -59,12 +61,10 @@ static inline size_t plugin_loader_strlcpy(char *dst, const char *src, size_t si
return srcsize; return srcsize;
} }
static inline void err_prepend(char* s, const char* prefix, const char* sep) static inline void err_prepend(char* s, const char* prefix, const char* sep) {
{
char tmp[PLUGIN_MAX_ERRLEN]; char tmp[PLUGIN_MAX_ERRLEN];
size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN); size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
if (*s != '\0') if(*s != '\0') {
{
plugin_loader_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); prefix_len += strlen(sep);
} }
@ -72,17 +72,14 @@ static inline void err_prepend(char* s, const char* prefix, const char* sep)
plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN); plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
} }
static inline void err_append(char* s, const char* suffix, const char* sep) static inline void err_append(char* s, const char* suffix, const char* sep) {
{ if(*s != '\0') {
if (*s != '\0') strlcat(s, sep, PLUGIN_MAX_ERRLEN);
{
strncat(s, sep, PLUGIN_MAX_ERRLEN - strlen(sep));
} }
strncat(s, suffix, PLUGIN_MAX_ERRLEN - strlen(suffix)); strlcat(s, suffix, PLUGIN_MAX_ERRLEN);
} }
static void* getsym(library_handle_t handle, const char* name) static void* getsym(library_handle_t handle, const char* name) {
{
#ifdef _WIN32 #ifdef _WIN32
return (void*)GetProcAddress(handle, name); return (void*)GetProcAddress(handle, name);
#else #else
@ -91,16 +88,13 @@ static void* getsym(library_handle_t handle, const char* name)
} }
// 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); plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
return NULL; return NULL;
} }
@ -108,29 +102,24 @@ plugin_handle_t* plugin_load(const char* path, char* err)
// 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
| FORMAT_MESSAGE_IGNORE_INSERTS;
LPTSTR msg_buf = 0; LPTSTR msg_buf = 0;
if (FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR) &msg_buf, 0, NULL) && msg_buf) if(FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR)&msg_buf, 0, NULL) && msg_buf) {
{
plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN); plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
LocalFree(msg_buf); 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); plugin_loader_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;
@ -164,35 +153,63 @@ plugin_handle_t* plugin_load(const char* path, char* err)
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);
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; 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); plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
return NULL; 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); plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
return NULL; return NULL;
} }
ret->api = *api; ret->api = *api;
// todo: remove this if/when we get to API version 4
uint32_t major, minor, patch;
const char* ver;
if(api->get_required_api_version == NULL) {
plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
return NULL;
}
ver = api->get_required_api_version();
if(sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3) {
snprintf(err,
PLUGIN_MAX_ERRLEN,
"plugin provided an invalid required API version: '%s'",
ver);
return NULL;
}
// API 3.10 introduced dump_state in the middle of the plugin_api struct.
// Fix up older 3.x plugins by shifting the fields by one
if(major == 3 && minor < 10) {
size_t from_offset = offsetof(plugin_api, dump_state);
size_t to_offset = offsetof(plugin_api, set_config);
size_t size = sizeof(plugin_api) - to_offset;
char* api_ptr = (char*)&ret->api;
memmove(api_ptr + to_offset, api_ptr + from_offset, size);
ret->api.dump_state = NULL;
}
return ret; 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
@ -203,8 +220,7 @@ void plugin_unload(plugin_handle_t* 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,
@ -227,98 +243,103 @@ 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); plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
return false; 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,
"plugin provided an invalid required API version: '%s'",
ver);
return false; 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"; failmsg = "framework's minor is less than the requested one";
} } else if(PLUGIN_API_VERSION_MINOR == minor && PLUGIN_API_VERSION_PATCH < patch) {
else if(PLUGIN_API_VERSION_MINOR == minor && PLUGIN_API_VERSION_PATCH < patch)
{
failmsg = "framework's patch is less than the requested one"; 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",
ver,
PLUGIN_API_VERSION_STR,
failmsg);
return false; return false;
} }
return true; return true;
} }
plugin_caps_t plugin_get_capabilities(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; plugin_caps_t caps = CAP_NONE;
plugin_loader_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) if(h->api.open != NULL && h->api.close != NULL && h->api.next_batch != NULL) {
{
bool has_id = h->api.get_id != NULL && h->api.get_id() != 0; bool has_id = h->api.get_id != NULL && h->api.get_id() != 0;
bool has_source = h->api.get_event_source != NULL && strlen(h->api.get_event_source()) > 0; bool has_source = h->api.get_event_source != NULL && strlen(h->api.get_event_source()) > 0;
if ((has_id && has_source) || (!has_id && !has_source)) if((has_id && has_source) || (!has_id && !has_source)) {
{
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_SOURCING); caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_SOURCING);
} } else {
else
{
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN); 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)", ", "); 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) {
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); 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)", ", "); 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.get_fields != NULL && h->api.extract_fields != NULL) {
{
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_EXTRACTION); caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_EXTRACTION);
} } else if(h->api.extract_fields != NULL) {
else if (h->api.get_fields != NULL || h->api.extract_fields != NULL)
{
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN); 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)", ", "); err_append(err,
"must implement both 'plugin_get_fields' and 'plugin_extract_fields' (field "
"extraction)",
", ");
} }
if (h->api.parse_event != 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_PARSING);
} }
if (h->api.get_async_events != NULL && h->api.set_async_event_handler != 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_ASYNC);
} } else if(h->api.set_async_event_handler != NULL) {
else if (h->api.get_async_events != NULL || h->api.set_async_event_handler != NULL)
{
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN); 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)", ", "); err_append(err,
"must implement both 'plugin_get_async_events' and "
"'plugin_set_async_event_handler' (async events)",
", ");
}
if(h->api.capture_open != NULL && h->api.capture_close != NULL) {
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_CAPTURE_LISTENING);
} else if(h->api.capture_open != NULL) {
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
err_append(err,
"must implement both 'plugin_capture_open' and 'plugin_capture_close' (capture "
"listening)",
", ");
} }
return caps; return caps;
@ -327,15 +348,13 @@ plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h, char* err)
// 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);

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,13 +37,13 @@ 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,8 +52,7 @@ 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

View File

@ -1,17 +1,19 @@
diff --git a/pkg/loader/plugin_loader.c b/pkg/loader/plugin_loader.c diff --git a/pkg/loader/plugin_loader.c b/pkg/loader/plugin_loader.c
index aad119f..169f696 100644 index 2943335..7bebeeb 100644
--- a/pkg/loader/plugin_loader.c --- a/pkg/loader/plugin_loader.c
+++ b/pkg/loader/plugin_loader.c +++ b/pkg/loader/plugin_loader.c
@@ -23,23 +23,53 @@ limitations under the License. @@ -24,22 +24,52 @@ typedef HINSTANCE library_handle_t;
typedef void* library_handle_t; typedef void* library_handle_t;
#endif #endif
-#include "strlcpy.h" -#include <libscap/strl.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/plugin_loader.h>
+#include "plugin_loader.h"
+
+// note(jasondellaluce,therealbobo): implementation taken from falcosecurity/libs +// note(jasondellaluce,therealbobo): implementation taken from falcosecurity/libs
+// note(leogr): to avoid clashing with `strlcpy` introduced by glibc 2.38, +// note(leogr): to avoid clashing with `strlcpy` introduced by glibc 2.38,
+// the func has been renamed to plugin_loader_strlcpy. +// the func has been renamed to plugin_loader_strlcpy.
@ -42,14 +44,12 @@ index aad119f..169f696 100644
+ +
+ return srcsize; + return srcsize;
+} +}
+
static inline void err_prepend(char* s, const char* prefix, const char* sep) static inline void err_prepend(char* s, const char* prefix, const char* sep) {
{
char tmp[PLUGIN_MAX_ERRLEN]; char tmp[PLUGIN_MAX_ERRLEN];
- size_t prefix_len = strlcpy(tmp, prefix, 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); + size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
if (*s != '\0') if(*s != '\0') {
{
- strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len); - strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
+ plugin_loader_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); prefix_len += strlen(sep);
@ -60,66 +60,73 @@ index aad119f..169f696 100644
+ plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN); + plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
} }
static inline void err_append(char* s, const char* suffix, const char* sep) static inline void err_append(char* s, const char* suffix, const char* sep) {
@@ -71,7 +101,7 @@ plugin_handle_t* plugin_load(const char* path, char* err) @@ -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)); plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
if (!ret) if(!ret) {
{
- strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN); - strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN); + plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
return NULL; return NULL;
} }
@@ -86,7 +116,7 @@ plugin_handle_t* plugin_load(const char* path, char* err) @@ -77,14 +107,14 @@ plugin_handle_t* plugin_load(const char* path, char* err) {
FORMAT_MESSAGE_IGNORE_INSERTS;
LPTSTR msg_buf = 0; LPTSTR msg_buf = 0;
if (FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR) &msg_buf, 0, NULL) && msg_buf) if(FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR)&msg_buf, 0, NULL) && msg_buf) {
{
- strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN); - strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN); + plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
LocalFree(msg_buf); LocalFree(msg_buf);
} }
} }
@@ -94,7 +124,7 @@ plugin_handle_t* plugin_load(const char* path, char* err) #else
ret->handle = dlopen(path, RTLD_LAZY); ret->handle = dlopen(path, RTLD_LAZY);
if (ret->handle == NULL) if(ret->handle == NULL) {
{
- strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN); - strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN); + plugin_loader_strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
} }
#endif #endif
@@ -143,14 +173,14 @@ plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) @@ -135,13 +165,13 @@ plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
// alloc and init memory
err[0] = '\0'; err[0] = '\0';
if (!api) if(!api) {
{
- strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN); - 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); + plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
return NULL; 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) {
{
- strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN); - strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN); + plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
return NULL; return NULL;
} }
ret->api = *api; ret->api = *api;
@@ -203,7 +233,7 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) @@ -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; const char *ver, *failmsg;
if (h->api.get_required_api_version == NULL) if(h->api.get_required_api_version == NULL) {
{
- strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN); - 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); + plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
return false; return false;
} }
@@ -243,7 +273,7 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) @@ -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 plugin_get_capabilities(const plugin_handle_t* h, char* err) {
plugin_caps_t caps = CAP_NONE; plugin_caps_t caps = CAP_NONE;
- strlcpy(err, "", PLUGIN_MAX_ERRLEN); - strlcpy(err, "", PLUGIN_MAX_ERRLEN);
+ plugin_loader_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) 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.
@ -126,6 +156,8 @@ 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,12 +24,12 @@ 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
// //
@ -36,7 +37,8 @@ extern "C" {
// //
#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 \
PLUGIN_API_VERSION_MAJOR.PLUGIN_API_VERSION_MINOR.PLUGIN_API_VERSION_PATCH
#define PLUGIN_API_VERSION_STR EXPAND_AND_QUOTE(PLUGIN_API_VERSION) #define PLUGIN_API_VERSION_STR EXPAND_AND_QUOTE(PLUGIN_API_VERSION)
// //
@ -44,17 +46,29 @@ extern "C" {
// //
#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,13 +87,37 @@ 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);
@ -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,23 +280,48 @@ 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
@ -214,12 +334,15 @@ typedef struct ss_plugin_init_input
// 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.
@ -240,14 +363,26 @@ typedef struct ss_plugin_field_extract_input
// extract_fields() call. // extract_fields() call.
ss_plugin_extract_field* fields; ss_plugin_extract_field* fields;
// //
// 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 read operations.
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.
@ -258,24 +393,120 @@ typedef struct ss_plugin_event_parse_input
// 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
@ -412,11 +642,11 @@ typedef struct
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)
@ -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,8 +30,7 @@ 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
@ -51,8 +51,7 @@ typedef enum 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
@ -110,11 +107,7 @@ struct ss_plugin_event {
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,8 +117,7 @@ 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;
@ -136,6 +128,20 @@ typedef struct ss_plugin_byte_buffer{
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,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.

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) 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.