Compare commits

..

78 Commits
v0.6.1 ... main

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


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

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

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

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

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


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

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

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


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

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

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


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

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

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

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

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


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

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

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

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

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


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

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

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


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

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

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


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

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

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


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

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

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


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

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

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

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


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

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

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


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

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

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

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


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

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

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


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

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

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


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

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

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

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

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

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


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

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

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

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

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

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

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-29 17:26:22 +02:00
Andrea Terzolo 9cd2769c2f cleanup: add some comments and rename vars in `SetRequiredAPIVersion`
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-11 08:45:46 +02:00
Andrea Terzolo c43c0044a1 chore: add .vscode to the gitignore
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-11 08:45:46 +02:00
Leonardo Grasso 1a38f04582 fix(README.md): license badge link
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-06-06 17:00:40 +02:00
Leonardo Grasso 18133edb5c docs(README.md): add scope and status badges
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-06-06 17:00:40 +02:00
Jason Dellaluce 9a9dc4288a update: drop go.uber.org/multierr dependency
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-24 18:56:07 +02:00
Jason Dellaluce 7b2cafbb8d fix(pkg/sdk): solve test issues
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-19 09:56:04 +02:00
Jason Dellaluce 401e4d02e0 update(examples): bump go sums
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-19 09:56:04 +02:00
Jason Dellaluce ace67303af fix(pkg/sdk): properly align results when setting extract values
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-19 09:56:04 +02:00
Jason Dellaluce 76e31c63c5 update(pkg/loader): cleanup loader
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce fc6f7fb3d1 update(benchmarks/async): sync with new API defs
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce 38733055ee update(examples/full): add test ruleset and extract fields for all supported types
Co-authored-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce 5e5da37395 update(pkg/sdk/symbols/info): sync with new API defs
Co-authored-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce be201d72ac update(pkg/sdk/symbols/evtstr): sync with new API defs
Co-authored-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce 4c944ba0f0 update(pkg/sdk/symbols/extract): sync with new API defs
Co-authored-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce 33a5a80a44 update(pkg/sdk/symbols/nextbatch): sync with new API defs
Co-authored-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce 20d960fdb4 update(pkg/sdk/symbols/initialize): sync with new API defs
Co-authored-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce 2eb0c61922 update(pkg/loader): sync loader with new API defs
Co-authored-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce fe10de21ed update: bump libs dep to 0b9ca98fee2453a16f4538db55dcfa34bc8f5aef
Co-authored-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce 979fc36c78 update(sdk): sync event writing primitives with new API definitions
Co-authored-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce f1de2c9de8 update(sdk): sync extraction primitives with new field types
Co-authored-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce be971a90dd update: bumpt libs dep to 118114bc456f139f7729061d7120022f832e9efb
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Jason Dellaluce 079755064b update: bump go mod and sum files
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-05-18 10:23:03 +02:00
Roberto Scolaro 55e9d809dc fix: bumped minor version
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-05-16 10:30:26 +02:00
Roberto Scolaro 13612c304e test(pkg/sdk): added missing tests
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-05-16 10:30:26 +02:00
Roberto Scolaro 85b034dc52 fix: refactor of ss_plugin_byte_buffer
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-05-16 10:30:26 +02:00
Roberto Scolaro b68cf68689 chore(pkg/sdk): refactor + cleanup
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-05-16 10:30:26 +02:00
Roberto Scolaro 8beb7b8c68 feat(pkg/sdk): support for variable size type
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-05-16 10:30:26 +02:00
Roberto Scolaro 0aa96151a6 feat(pkg/sdk): initial new types support
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-05-16 10:30:26 +02:00
Rohith-Raju 452df6bdaf made changes as per review requests
Signed-off-by: Rohith-Raju <rohithraju488@gmail.com>
2023-05-02 12:34:49 +02:00
Rohith-Raju 24a8aaee77 minor changes
Signed-off-by: Rohith-Raju <rohithraju488@gmail.com>
2023-05-02 12:34:49 +02:00
Rohith-Raju 255177d4b7 Added tests and made changes as per review request
Signed-off-by: Rohith-Raju <rohithraju488@gmail.com>
2023-05-02 12:34:49 +02:00
Rohith-Raju 95d8cfcd97 cosmetic changes
Signed-off-by: Rohith-Raju <rohithraju488@gmail.com>
2023-05-02 12:34:49 +02:00
Rohith-Raju 13b461eb01 revert unwanted
Signed-off-by: Rohith-Raju <rohithraju488@gmail.com>
2023-05-02 12:34:49 +02:00
Rohith-Raju 6fdfd31005 merge-conflicts
Signed-off-by: Rohith-Raju <rohithraju488@gmail.com>
2023-05-02 12:34:49 +02:00
Rohith-Raju aa8e5cecdd tidy
Signed-off-by: Rohith-Raju <rohithraju488@gmail.com>
2023-05-02 12:34:49 +02:00
Rohith-Raju 60a09e9ff8 cosmetic changes
Signed-off-by: Rohith-Raju <rohithraju488@gmail.com>
2023-05-02 12:34:49 +02:00
Rohith-Raju 662472b510 semver check for get_required_api_version
Signed-off-by: Rohith-Raju <rohithraju488@gmail.com>
2023-05-02 12:34:49 +02:00
cappellinsamuele c2c8a3e406 cleanup(build.sh): build.sh removed since it is not used anymore
Signed-off-by: cappellinsamuele <cappellinsamuele@gmail.com>
2023-04-11 17:52:06 +02:00
cappellinsamuele 5885ebe25a chore(ci): updated setup-go action and job rename
Signed-off-by: cappellinsamuele <cappellinsamuele@gmail.com>
2023-04-05 18:39:56 +02:00
cappellinsamuele bd1eead4c4 update(ci): porting tests from test-infra.
Signed-off-by: cappellinsamuele <cappellinsamuele@gmail.com>
2023-04-05 18:39:56 +02:00
Jason Dellaluce 3352b0e7f4 test(sdk/symbols/extract): fix async tests
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-08 18:57:09 +01:00
Jason Dellaluce 260e4c2e40 update(pkg/cgo): set MaxHandle to 255
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-08 18:57:09 +01:00
98 changed files with 2880 additions and 653 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"

37
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,37 @@
name: CI
on:
pull_request:
branches:
- main
jobs:
run-tests:
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: Run tests
run: go test ./...
build-example-plugins:
runs-on: ubuntu-latest
steps:
- name: Checkout plugin-sdk-go
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Golang
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: '^1.19'
- name: Build all example plugins
run: make examples

View File

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

View File

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

1
.gitignore vendored
View File

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

View File

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

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# #
# Copyright (C) 2021 The Falco Authors. # Copyright (C) 2025 The Falco Authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at # the License. You may obtain a copy of the License at
@ -13,8 +14,9 @@
SHELL := /bin/bash SHELL := /bin/bash
GO ?= $(shell which go) GO ?= $(shell which go)
CURL ?= $(shell which curl) CURL ?= $(shell which curl)
PATCH ?= $(shell which patch)
FALCOSECURITY_LIBS_REVISION ?= 000eb27573af74168510e4836330ff6958c3f355 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
@ -30,13 +32,16 @@ clean: clean-pluginlib $(examples_clean)
.PHONY: pluginlib .PHONY: pluginlib
pluginlib: pluginlib:
@$(CURL) -Lso pkg/sdk/plugin_types.h $(PLUGINLIB_URL)/plugin_types.h $(CURL) -Lso pkg/sdk/plugin_types.h $(PLUGINLIB_URL)/plugin_types.h
@$(CURL) -Lso pkg/sdk/plugin_api.h $(PLUGINLIB_URL)/plugin_api.h $(CURL) -Lso pkg/sdk/plugin_api.h $(PLUGINLIB_URL)/plugin_api.h
@$(CURL) -Lso pkg/loader/plugin_loader.h $(PLUGINLIB_URL)/plugin_loader.h $(CURL) -Lso pkg/loader/plugin_loader.h $(PLUGINLIB_URL)/plugin_loader.h
@$(CURL) -Lso pkg/loader/plugin_loader.c $(PLUGINLIB_URL)/plugin_loader.c $(CURL) -Lso pkg/loader/plugin_loader.c $(PLUGINLIB_URL)/plugin_loader.c
$(PATCH) -p1 < pkg/loader/plugin_api_include.patch
$(PATCH) -p1 < pkg/loader/strlcpy.patch
$(PATCH) -p1 < pkg/sdk/plugin_types_include.patch
clean-pluginlib: clean-pluginlib:
@rm -f \ rm -f \
pkg/sdk/plugin_types.h \ pkg/sdk/plugin_types.h \
pkg/sdk/plugin_api.h \ pkg/sdk/plugin_api.h \
pkg/loader/plugin_loader.h \ pkg/loader/plugin_loader.h \

1
OWNERS
View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -23,14 +24,14 @@ limitations under the License.
#include <vector> #include <vector>
#include <string> #include <string>
#include "../../pkg/sdk/plugin_types.h" #include "../../pkg/sdk/plugin_api.h"
// defined in Go and exported from bench.go // defined in Go and exported from bench.go
extern "C" extern "C"
{ {
void plugin_destroy(ss_plugin_t*); void plugin_destroy(ss_plugin_t*);
ss_plugin_t* plugin_init(const char*, ss_plugin_rc*); ss_plugin_t* plugin_init(const ss_plugin_init_input *input, ss_plugin_rc *rc);
ss_plugin_rc plugin_extract_fields(ss_plugin_t*, const ss_plugin_event*, uint32_t, ss_plugin_extract_field*); ss_plugin_rc plugin_extract_fields(ss_plugin_t*, const ss_plugin_event_input*, const ss_plugin_field_extract_input*);
} }
// global benchmark options // global benchmark options
@ -111,13 +112,16 @@ static void benchmark(ss_plugin_t *plugin) noexcept
e.arg_present = false; e.arg_present = false;
e.ftype = FTYPE_UINT64; e.ftype = FTYPE_UINT64;
e.flist = false; e.flist = false;
ss_plugin_field_extract_input in;
in.fields = &e;
in.num_fields = 1;
// request multiple extractions and compute total execution time // request multiple extractions and compute total execution time
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
ss_plugin_rc rc = SS_PLUGIN_FAILURE; ss_plugin_rc rc = SS_PLUGIN_FAILURE;
for (int i = 0; i < g_niterations; i++) for (int i = 0; i < g_niterations; i++)
{ {
rc = plugin_extract_fields(plugin, NULL, 1, &e); rc = plugin_extract_fields(plugin, NULL, &in);
if (rc != SS_PLUGIN_SUCCESS) if (rc != SS_PLUGIN_SUCCESS)
{ {
fprintf(stderr, "plugin %" PRIu64 ": plugin_extract_fields failure: %d\n", (uint64_t) plugin, rc); fprintf(stderr, "plugin %" PRIu64 ": plugin_extract_fields failure: %d\n", (uint64_t) plugin, rc);
@ -146,7 +150,9 @@ int main(int argc, char** argv)
for (int i = 0; i < g_parallelism; ++i) for (int i = 0; i < g_parallelism; ++i)
{ {
ss_plugin_rc rc = SS_PLUGIN_FAILURE; ss_plugin_rc rc = SS_PLUGIN_FAILURE;
plugins.push_back(plugin_init(g_use_async ? "async" : "", &rc)); ss_plugin_init_input in;
in.config = g_use_async ? "async" : "";
plugins.push_back(plugin_init(&in, &rc));
if (rc != SS_PLUGIN_SUCCESS) if (rc != SS_PLUGIN_SUCCESS)
{ {
fprintf(stderr, "can't initialize plugin"); fprintf(stderr, "can't initialize plugin");
@ -166,4 +172,4 @@ int main(int argc, char** argv)
} }
return 0; return 0;
} }

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,8 +1,22 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,3 +0,0 @@
#!/bin/sh
go test ./...

View File

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

View File

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

View File

@ -1,8 +1,22 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

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

View File

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

View File

@ -1,8 +1,22 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

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

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -28,6 +29,7 @@ import (
"encoding/gob" "encoding/gob"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net"
"time" "time"
"github.com/alecthomas/jsonschema" "github.com/alecthomas/jsonschema"
@ -54,7 +56,8 @@ type MyPluginConfig struct {
// State variables to store in the plugin must be defined here. // State variables to store in the plugin must be defined here.
type MyPlugin struct { type MyPlugin struct {
plugins.BasePlugin plugins.BasePlugin
config MyPluginConfig config MyPluginConfig
initTime time.Time
} }
// Defining a type for the plugin source capture instances returned by Open(). // Defining a type for the plugin source capture instances returned by Open().
@ -127,6 +130,7 @@ func (m *MyPlugin) InitSchema() *sdk.SchemaInfo {
// always well-formed according to the provided schema. // always well-formed according to the provided schema.
// This method is mandatory. // This method is mandatory.
func (m *MyPlugin) Init(config string) error { func (m *MyPlugin) Init(config string) error {
m.initTime = time.Now()
// Deserialize the config json. Ignoring the error // Deserialize the config json. Ignoring the error
// and not validating the config values is possible // and not validating the config values is possible
// due to the schema defined through InitSchema(), // due to the schema defined through InitSchema(),
@ -143,6 +147,13 @@ func (m *MyPlugin) Fields() []sdk.FieldEntry {
return []sdk.FieldEntry{ return []sdk.FieldEntry{
{Type: "uint64", Name: "example.count", Display: "Counter value", Desc: "Current value of the internal counter"}, {Type: "uint64", Name: "example.count", Display: "Counter value", Desc: "Current value of the internal counter"},
{Type: "string", Name: "example.countstr", Display: "Counter string value", Desc: "String represetation of current value of the internal counter"}, {Type: "string", Name: "example.countstr", Display: "Counter string value", Desc: "String represetation of current value of the internal counter"},
{Type: "bool", Name: "example.oddcount", Display: "Counter value is odd", Desc: "True if the current value of the internal counter is an odd number"},
{Type: "reltime", Name: "example.initduration", Display: "Time since init", Desc: "Time since the plugin was initialized"},
{Type: "abstime", Name: "example.evttime", Display: "Event timestamp", Desc: "Event timestamp"},
{Type: "ipaddr", Name: "example.ipv4addr", Display: "Sample IPv4 address", Desc: "A sample IPv4 address"},
{Type: "ipaddr", Name: "example.ipv6addr", Display: "Sample IPv6 address", Desc: "A sample IPv6 address"},
{Type: "ipnet", Name: "example.ipv4net", Display: "Sample IPv4 network", Desc: "A sample IPv4 network"},
{Type: "ipnet", Name: "example.ipv6net", Display: "Sample IPv6 network", Desc: "A sample IPv6 network"},
} }
} }
@ -156,13 +167,44 @@ func (m *MyPlugin) Extract(req sdk.ExtractRequest, evt sdk.EventReader) error {
return err return err
} }
switch req.FieldID() { switch req.Field() {
case 0: case "example.count":
req.SetValue(value) req.SetValue(value)
return nil return nil
case 1: case "example.countstr":
req.SetValue(fmt.Sprintf("%d", value)) req.SetValue(fmt.Sprintf("%d", value))
return nil return nil
case "example.oddcount":
req.SetValue((value%2 == 1))
return nil
case "example.initduration":
req.SetValue(time.Since(m.initTime))
return nil
case "example.evttime":
req.SetValue(time.Unix(0, int64(evt.Timestamp())))
return nil
case "example.ipv4addr":
req.SetValue(net.IPv4allsys.To4())
return nil
case "example.ipv6addr":
req.SetValue(net.IPv6loopback)
return nil
case "example.ipv4net":
_, n, err := net.ParseCIDR("192.0.2.1/24")
if err == nil {
req.SetValue(n)
} else {
println(err.Error())
}
return nil
case "example.ipv6net":
_, n, err := net.ParseCIDR("2002::1234:abcd:ffff:c0a8:101/64")
if err == nil {
req.SetValue(n)
} else {
println(err.Error())
}
return nil
default: default:
return fmt.Errorf("unsupported field: %s", req.Field()) return fmt.Errorf("unsupported field: %s", req.Field())
} }

View File

@ -0,0 +1,45 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright (C) 2023 The Falco Authors.
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
- rule: Sample plugin rule
desc: Some sample rule for testing
condition:
evt.num > 0 and evt.num < 5
and example.count > 0
and example.oddcount = true
and example.initduration exists
and example.evttime exists
and example.ipv4addr = "224.0.0.1"
and example.ipv6addr = "::1"
and example.ipv4net = "192.0.3.1/16"
and example.ipv6net = "2002::1234:abcd:ffff:c0a8:102:ffff/32"
output: Some event (
example.count=%example.count,
example.countstr=%example.countstr,
example.oddcount=%example.oddcount,
example.initduration=%example.initduration,
example.evttime=%example.evttime,
evt.time=%evt.rawtime,
example.ipv4addr=%example.ipv4addr,
example.ipv6addr=%example.ipv6addr,
example.ipv4net=%example.ipv4net,
example.ipv6net=%example.ipv6net
info=%evt.plugininfo
plugin=%evt.pluginname)
priority: CRITICAL
source: example

View File

@ -5,6 +5,6 @@ replace github.com/falcosecurity/plugin-sdk-go => ../../
go 1.15 go 1.15
require ( require (
github.com/alecthomas/jsonschema v0.0.0-20211228220459-151e3c21f49d github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b
github.com/falcosecurity/plugin-sdk-go v0.0.0-00010101000000-000000000000 github.com/falcosecurity/plugin-sdk-go v0.0.0-00010101000000-000000000000
) )

View File

@ -1,16 +1,27 @@
github.com/alecthomas/jsonschema v0.0.0-20211228220459-151e3c21f49d h1:4BQNwS4T13UU3Yee4GfzZH3Q9SNpKeJvLigfw8fDjX0= github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b h1:doCpXjVwui6HUN+xgNsNS3SZ0/jUZ68Eb+mJRNOZfog=
github.com/alecthomas/jsonschema v0.0.0-20211228220459-151e3c21f49d/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60= github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk= github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709 h1:Ko2LQMrRU+Oy/+EDBwX7eZ2jp3C47eDBB8EIhKTun+I=
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

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

View File

@ -1,8 +1,22 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

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.

12
go.mod
View File

@ -1,8 +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/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/stretchr/testify v1.8.2
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
)

15
go.sum
View File

@ -1,10 +1,16 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@ -12,3 +18,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

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

View File

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

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2022 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -45,9 +46,9 @@ static const char *__get_init_schema(plugin_api* p, ss_plugin_schema_type *s)
return p->get_init_schema(s); return p->get_init_schema(s);
} }
static ss_plugin_t* __init(plugin_api* p, const char *cfg, ss_plugin_rc *rc) static ss_plugin_t* __init(plugin_api* p, const ss_plugin_init_input *in, ss_plugin_rc *rc)
{ {
return p->init(cfg, rc); return p->init(in, rc);
} }
static void __destroy(plugin_api* p, ss_plugin_t* s) static void __destroy(plugin_api* p, ss_plugin_t* s)
@ -80,19 +81,19 @@ static const char* __get_progress(plugin_api* p, ss_plugin_t* s, ss_instance_t*
return p->get_progress(s, h, r); return p->get_progress(s, h, r);
} }
static const char* __event_to_string(plugin_api* p, ss_plugin_t *s, const ss_plugin_event *e) static const char* __event_to_string(plugin_api* p, ss_plugin_t *s, const ss_plugin_event_input *e)
{ {
return p->event_to_string(s, e); return p->event_to_string(s, e);
} }
static ss_plugin_rc __next_batch(plugin_api* p, ss_plugin_t* s, ss_instance_t* h, uint32_t *n, ss_plugin_event **e) static ss_plugin_rc __next_batch(plugin_api* p, ss_plugin_t* s, ss_instance_t* h, uint32_t *n, ss_plugin_event ***e)
{ {
return p->next_batch(s, h, n, e); return p->next_batch(s, h, n, e);
} }
static ss_plugin_rc __extract_fields(plugin_api* p, ss_plugin_t *s, const ss_plugin_event *e, uint32_t n, ss_plugin_extract_field *f) static ss_plugin_rc __extract_fields(plugin_api* p, ss_plugin_t *s, const ss_plugin_event_input *e, ss_plugin_field_extract_input *in)
{ {
return p->extract_fields(s, e, n, f); return p->extract_fields(s, e, in);
} }
*/ */
@ -109,6 +110,12 @@ import (
"github.com/xeipuuv/gojsonschema" "github.com/xeipuuv/gojsonschema"
) )
// todo(jasondellaluce,therealbobo): the loader must support the new features of
// the plugin API:
// - event parsing capability
// - async events capability
// - get_extract_event_types
var ( var (
errNotInitialized = errors.New("plugin is not initialized") errNotInitialized = errors.New("plugin is not initialized")
errNoSourcingCap = errors.New("plugin does not support event sourcing capability") errNoSourcingCap = errors.New("plugin does not support event sourcing capability")
@ -117,15 +124,26 @@ var (
// Plugin represents a Falcosecurity Plugin loaded from an external shared // Plugin represents a Falcosecurity Plugin loaded from an external shared
// dynamic library // dynamic library
type Plugin struct { type Plugin struct {
m sync.Mutex m sync.Mutex
handle *C.plugin_handle_t handle *C.plugin_handle_t
state *C.ss_plugin_t state *C.ss_plugin_t
caps C.plugin_caps_t caps C.plugin_caps_t
info plugins.Info info plugins.Info
initSchema *sdk.SchemaInfo initSchema *sdk.SchemaInfo
fields []sdk.FieldEntry fields []sdk.FieldEntry
validated bool validated bool
validErr error validErr error
capBrokenErr error
}
func errAppend(left, right error) error {
if left == nil {
return right
}
if right == nil {
return left
}
return fmt.Errorf("%s, %s", left.Error(), right.Error())
} }
// NewValidPlugin is the same as NewPlugin(), but returns an error if // NewValidPlugin is the same as NewPlugin(), but returns an error if
@ -170,7 +188,10 @@ func NewPlugin(path string) (*Plugin, error) {
} }
// get supported capabilities // get supported capabilities
p.caps = C.plugin_get_capabilities(p.handle) p.caps = C.plugin_get_capabilities(p.handle, errBuf)
if p.caps&C.CAP_BROKEN != 0 {
p.capBrokenErr = errors.New(C.GoString(errBuf))
}
// read static info (if available) // read static info (if available)
p.info = plugins.Info{ p.info = plugins.Info{
@ -178,9 +199,9 @@ func NewPlugin(path string) (*Plugin, error) {
RequiredAPIVersion: C.GoString(C.__get_info_str(p.handle.api.get_required_api_version)), RequiredAPIVersion: C.GoString(C.__get_info_str(p.handle.api.get_required_api_version)),
Name: C.GoString(C.__get_info_str(p.handle.api.get_name)), Name: C.GoString(C.__get_info_str(p.handle.api.get_name)),
Description: C.GoString(C.__get_info_str(p.handle.api.get_description)), Description: C.GoString(C.__get_info_str(p.handle.api.get_description)),
EventSource: C.GoString(C.__get_info_str(p.handle.api.anon0.get_event_source)),
Contact: C.GoString(C.__get_info_str(p.handle.api.get_contact)), Contact: C.GoString(C.__get_info_str(p.handle.api.get_contact)),
ID: uint32(C.__get_info_u32(p.handle.api.anon0.get_id)), ID: uint32(C.__get_info_u32(p.handle.api.anon0.get_id)),
EventSource: C.GoString(C.__get_info_str(p.handle.api.anon0.get_event_source)),
ExtractEventSources: []string{}, ExtractEventSources: []string{},
} }
if p.handle.api.get_init_schema != nil { if p.handle.api.get_init_schema != nil {
@ -193,19 +214,23 @@ func NewPlugin(path string) (*Plugin, error) {
} }
// get static info related to extraction capability (if available) // get static info related to extraction capability (if available)
if p.HasCapExtraction() && p.handle.api.anon1.get_extract_event_sources != nil {
str := C.GoString(C.__get_info_str(p.handle.api.anon1.get_extract_event_sources))
if err := json.Unmarshal(([]byte)(str), &p.info.ExtractEventSources); err != nil {
// capability is considered not supported if data is corrupted
p.caps ^= C.CAP_EXTRACTION
}
}
if p.HasCapExtraction() { if p.HasCapExtraction() {
// capability is considered not supported if data is corrupted
if p.handle.api.anon1.get_extract_event_sources != nil {
str := C.GoString(C.__get_info_str(p.handle.api.anon1.get_extract_event_sources))
if err := json.Unmarshal(([]byte)(str), &p.info.ExtractEventSources); err != nil {
p.caps &= ^C.CAP_EXTRACTION
p.caps |= C.CAP_BROKEN
p.capBrokenErr = errAppend(p.capBrokenErr, errors.New("get_extract_event_sources does not return a well-formed json array"))
}
}
str := C.GoString(C.__get_info_str(p.handle.api.anon1.get_fields)) str := C.GoString(C.__get_info_str(p.handle.api.anon1.get_fields))
if err := json.Unmarshal(([]byte)(str), &p.fields); err != nil { if err := json.Unmarshal(([]byte)(str), &p.fields); err != nil {
// capability is considered not supported if data is corrupted p.caps &= ^C.CAP_EXTRACTION
p.caps ^= C.CAP_EXTRACTION p.caps |= C.CAP_BROKEN
p.capBrokenErr = errAppend(p.capBrokenErr, errors.New("get_fields does not return a well-formed json array"))
} }
} }
return p, nil return p, nil
@ -234,9 +259,9 @@ func (p *Plugin) validate() error {
p.validErr = errors.New(C.GoString(errBuf)) p.validErr = errors.New(C.GoString(errBuf))
return p.validErr return p.validErr
} }
if p.caps == C.CAP_NONE { if (p.caps & ^C.CAP_BROKEN) == C.CAP_NONE {
p.validErr = errors.New("plugin supports no capability") p.validErr = errors.New("plugin supports no capability")
return p.validErr return errAppend(p.validErr, p.capBrokenErr)
} }
p.validated = true p.validated = true
} }
@ -252,6 +277,16 @@ func (p *Plugin) Validate() error {
return p.validate() return p.validate()
} }
// HasCapBroken returns true if the plugin has any of its capabilities broken.
func (p *Plugin) HasCapBroken() bool {
return p.caps&C.CAP_BROKEN != 0
}
// CapBrokenError returns a non-nil error if HasCapBroken returns true.
func (p *Plugin) CapBrokenError() error {
return p.capBrokenErr
}
// HasCapExtraction returns true if the plugin supports the // HasCapExtraction returns true if the plugin supports the
// field extraction capability. // field extraction capability.
func (p *Plugin) HasCapExtraction() bool { func (p *Plugin) HasCapExtraction() bool {
@ -349,8 +384,14 @@ func (p *Plugin) Init(config string) error {
return fmt.Errorf("invalid plugin config: %s", err.Error()) return fmt.Errorf("invalid plugin config: %s", err.Error())
} }
// todo(jasondelluce,therealbobo): support owner pointer and implement table access
in := C.ss_plugin_init_input{}
in.owner = nil
in.get_owner_last_error = nil
in.tables = nil
in.config = C.CString(config)
rc := C.ss_plugin_rc(sdk.SSPluginSuccess) rc := C.ss_plugin_rc(sdk.SSPluginSuccess)
p.state = (*C.ss_plugin_t)(C.__init(&p.handle.api, C.CString(config), (*C.ss_plugin_rc)(&rc))) p.state = (*C.ss_plugin_t)(C.__init(&p.handle.api, &in, (*C.ss_plugin_rc)(&rc)))
if rc == C.ss_plugin_rc(sdk.SSPluginSuccess) { if rc == C.ss_plugin_rc(sdk.SSPluginSuccess) {
return nil return nil
} }

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,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.
@ -16,117 +17,210 @@ limitations under the License.
*/ */
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
typedef HINSTANCE library_handle_t; typedef HINSTANCE library_handle_t;
#else #else
#include <dlfcn.h> #include <dlfcn.h>
typedef void* library_handle_t; typedef void* library_handle_t;
#endif #endif
#include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "plugin_loader.h" #include "plugin_loader.h"
static inline void add_str_prefix(char* s, const char* prefix) // note(jasondellaluce,therealbobo): implementation taken from falcosecurity/libs
{ // note(leogr): to avoid clashing with `strlcpy` introduced by glibc 2.38,
char tmp[PLUGIN_MAX_ERRLEN]; // the func has been renamed to plugin_loader_strlcpy.
strncpy(tmp, prefix, PLUGIN_MAX_ERRLEN - 1); // N.B.: our building system here is not smart enough to detect if the function
strncat(tmp, s, PLUGIN_MAX_ERRLEN - 1); // was declared already.
strcpy(s, tmp); #include <stdint.h>
#include <string.h>
/*!
\brief Copy up to size - 1 characters from the NUL-terminated string src to dst, NUL-terminating the result.
\return The length of the source string.
*/
static inline size_t plugin_loader_strlcpy(char *dst, const char *src, size_t size) {
size_t srcsize = strlen(src);
if (size == 0) {
return srcsize;
}
size_t copysize = srcsize;
if (copysize > size - 1) {
copysize = size - 1;
}
memcpy(dst, src, copysize);
dst[copysize] = '\0';
return srcsize;
} }
static void* getsym(library_handle_t handle, const char* name) static inline void err_prepend(char* s, const char* prefix, const char* sep) {
{ char tmp[PLUGIN_MAX_ERRLEN];
size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
if(*s != '\0') {
plugin_loader_strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
prefix_len += strlen(sep);
}
plugin_loader_strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
}
static inline void err_append(char* s, const char* suffix, const char* sep) {
if(*s != '\0') {
strlcat(s, sep, PLUGIN_MAX_ERRLEN);
}
strlcat(s, suffix, PLUGIN_MAX_ERRLEN);
}
static void* getsym(library_handle_t handle, const char* name) {
#ifdef _WIN32 #ifdef _WIN32
return (void*) GetProcAddress(handle, name); return (void*)GetProcAddress(handle, name);
#else #else
return (void*) dlsym(handle, name); return (void*)dlsym(handle, name);
#endif #endif
} }
// little hack for simplifying the plugin_load function // little hack for simplifying the plugin_load function
#define SYM_RESOLVE(h, s) \ #define SYM_RESOLVE(h, s) *(void**)(&(h->api.s)) = getsym(h->handle, "plugin_" #s)
*(void **)(&(h->api.s)) = getsym(h->handle, "plugin_"#s)
plugin_handle_t* plugin_load(const char* path, char* err) plugin_handle_t* plugin_load(const char* path, char* err) {
{ // alloc and init memory
// alloc and init memory err[0] = '\0';
strcpy(err, ""); 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) {
plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
return NULL;
}
// open dynamic library // open dynamic library
#ifdef _WIN32 #ifdef _WIN32
ret->handle = LoadLibrary(path); ret->handle = LoadLibrary(path);
if(ret->handle == NULL) if(ret->handle == NULL) {
{ DWORD flg = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
DWORD flg = FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_IGNORE_INSERTS;
| FORMAT_MESSAGE_FROM_SYSTEM LPTSTR msg_buf = 0;
| FORMAT_MESSAGE_IGNORE_INSERTS; if(FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR)&msg_buf, 0, NULL) && msg_buf) {
LPTSTR msg_buf = 0; plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
if (FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR) &msg_buf, 0, NULL) && msg_buf) LocalFree(msg_buf);
{ }
strncpy(err, msg_buf, PLUGIN_MAX_ERRLEN -1 ); }
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);
strncpy(err, (const char*) dlerror(), PLUGIN_MAX_ERRLEN - 1); }
}
#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:", " ");
add_str_prefix(err, "can't load plugin dynamic library: "); free(ret);
free(ret); return NULL;
return NULL; }
}
// load all library symbols // load all library symbols
SYM_RESOLVE(ret, get_required_api_version); SYM_RESOLVE(ret, get_required_api_version);
SYM_RESOLVE(ret, get_version); SYM_RESOLVE(ret, get_version);
SYM_RESOLVE(ret, get_last_error); SYM_RESOLVE(ret, get_last_error);
SYM_RESOLVE(ret, get_name); SYM_RESOLVE(ret, get_name);
SYM_RESOLVE(ret, get_description); SYM_RESOLVE(ret, get_description);
SYM_RESOLVE(ret, get_contact); SYM_RESOLVE(ret, get_contact);
SYM_RESOLVE(ret, get_init_schema); SYM_RESOLVE(ret, get_init_schema);
SYM_RESOLVE(ret, init); SYM_RESOLVE(ret, init);
SYM_RESOLVE(ret, destroy); SYM_RESOLVE(ret, destroy);
SYM_RESOLVE(ret, get_id); SYM_RESOLVE(ret, get_id);
SYM_RESOLVE(ret, get_event_source); SYM_RESOLVE(ret, get_event_source);
SYM_RESOLVE(ret, open); SYM_RESOLVE(ret, open);
SYM_RESOLVE(ret, close); SYM_RESOLVE(ret, close);
SYM_RESOLVE(ret, next_batch); SYM_RESOLVE(ret, next_batch);
SYM_RESOLVE(ret, get_progress); SYM_RESOLVE(ret, get_progress);
SYM_RESOLVE(ret, list_open_params); SYM_RESOLVE(ret, list_open_params);
SYM_RESOLVE(ret, event_to_string); SYM_RESOLVE(ret, event_to_string);
SYM_RESOLVE(ret, get_fields); SYM_RESOLVE(ret, get_fields);
SYM_RESOLVE(ret, extract_fields); SYM_RESOLVE(ret, extract_fields);
SYM_RESOLVE(ret, get_extract_event_sources); SYM_RESOLVE(ret, get_extract_event_sources);
return ret; SYM_RESOLVE(ret, get_extract_event_types);
SYM_RESOLVE(ret, get_parse_event_types);
SYM_RESOLVE(ret, get_parse_event_sources);
SYM_RESOLVE(ret, parse_event);
SYM_RESOLVE(ret, get_async_event_sources);
SYM_RESOLVE(ret, get_async_events);
SYM_RESOLVE(ret, set_async_event_handler);
SYM_RESOLVE(ret, dump_state);
SYM_RESOLVE(ret, set_config);
SYM_RESOLVE(ret, get_metrics);
SYM_RESOLVE(ret, capture_open);
SYM_RESOLVE(ret, capture_close);
return ret;
} }
void plugin_unload(plugin_handle_t* h) plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
{ // alloc and init memory
if (h) err[0] = '\0';
{ if(!api) {
if (h->handle) plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
{ return NULL;
}
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
if(!ret) {
plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
return NULL;
}
ret->api = *api;
// todo: remove this if/when we get to API version 4
uint32_t major, minor, patch;
const char* ver;
if(api->get_required_api_version == NULL) {
plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
return NULL;
}
ver = api->get_required_api_version();
if(sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3) {
snprintf(err,
PLUGIN_MAX_ERRLEN,
"plugin provided an invalid required API version: '%s'",
ver);
return NULL;
}
// API 3.10 introduced dump_state in the middle of the plugin_api struct.
// Fix up older 3.x plugins by shifting the fields by one
if(major == 3 && minor < 10) {
size_t from_offset = offsetof(plugin_api, dump_state);
size_t to_offset = offsetof(plugin_api, set_config);
size_t size = sizeof(plugin_api) - to_offset;
char* api_ptr = (char*)&ret->api;
memmove(api_ptr + to_offset, api_ptr + from_offset, size);
ret->api.dump_state = NULL;
}
return ret;
}
void plugin_unload(plugin_handle_t* h) {
if(h) {
if(h->handle) {
#ifdef _WIN32 #ifdef _WIN32
FreeLibrary(h->handle); FreeLibrary(h->handle);
#else #else
dlclose(h->handle); dlclose(h->handle);
#endif #endif
} }
free(h); free(h);
} }
} }
bool plugin_is_loaded(const char* path) bool plugin_is_loaded(const char* path) {
{
#ifdef _WIN32 #ifdef _WIN32
/* /*
* LoadLibrary maps the module into the address space of the calling process, if necessary, * LoadLibrary maps the module into the address space of the calling process, if necessary,
@ -149,89 +243,125 @@ bool plugin_is_loaded(const char* path)
#endif #endif
} }
bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) {
{ uint32_t major, minor, patch;
uint32_t major, minor, patch; const char *ver, *failmsg;
const char *ver, *failmsg; if(h->api.get_required_api_version == NULL) {
if (h->api.get_required_api_version == NULL) plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
{ return false;
strncpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN - 1); }
return false;
}
ver = h->api.get_required_api_version(); ver = h->api.get_required_api_version();
if (sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3) if(sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3) {
{ snprintf(err,
snprintf(err, PLUGIN_MAX_ERRLEN, "plugin provided an invalid required API version: '%s'", ver); PLUGIN_MAX_ERRLEN,
return false; "plugin provided an invalid required API version: '%s'",
} ver);
return false;
}
failmsg = NULL; failmsg = NULL;
if(PLUGIN_API_VERSION_MAJOR != major) /* The plugin requires a minimum framework version */
{ if(PLUGIN_API_VERSION_MAJOR != major) {
failmsg = "major versions disagree"; failmsg = "major versions disagree";
} } else if(PLUGIN_API_VERSION_MINOR < minor) {
else if(PLUGIN_API_VERSION_MINOR < minor) failmsg = "framework's minor is less than the requested one";
{ } else if(PLUGIN_API_VERSION_MINOR == minor && PLUGIN_API_VERSION_PATCH < patch) {
failmsg = "framework's minor is less than the requested one"; failmsg = "framework's patch is less than the requested one";
} }
else if(PLUGIN_API_VERSION_MINOR == minor && PLUGIN_API_VERSION_PATCH < patch)
{
failmsg = "framework's patch is less than the requested one";
}
if (failmsg != NULL) if(failmsg != NULL) {
{ snprintf(err,
snprintf(err, PLUGIN_MAX_ERRLEN, PLUGIN_MAX_ERRLEN,
"plugin required API version '%s' not compatible with the framework's API version '%s': %s", "plugin required API version '%s' not compatible with the framework's API version "
ver, PLUGIN_API_VERSION_STR, failmsg); "'%s': %s",
return false; ver,
} PLUGIN_API_VERSION_STR,
failmsg);
return false;
}
return true; return true;
} }
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h) 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);
if (h->api.get_id != NULL if(h->api.open != NULL && h->api.close != NULL && h->api.next_batch != NULL) {
&& h->api.get_event_source != NULL bool has_id = h->api.get_id != NULL && h->api.get_id() != 0;
&& h->api.open != NULL bool has_source = h->api.get_event_source != NULL && strlen(h->api.get_event_source()) > 0;
&& h->api.close != NULL if((has_id && has_source) || (!has_id && !has_source)) {
&& h->api.next_batch != NULL) caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_SOURCING);
{ } else {
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_SOURCING); caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
} err_append(err,
"must implement both 'plugin_get_id' and 'plugin_get_event_source' or "
"neither (event sourcing)",
", ");
}
} else if(h->api.open != NULL || h->api.close != NULL || h->api.next_batch != NULL) {
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
err_append(err,
"must implement all of 'plugin_open', 'plugin_close', and 'plugin_next_batch' "
"(event sourcing)",
", ");
}
if (h->api.get_fields != NULL if(h->api.get_fields != NULL && h->api.extract_fields != NULL) {
&& h->api.extract_fields != NULL) caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_EXTRACTION);
{ } else if(h->api.extract_fields != NULL) {
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_EXTRACTION); 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)",
", ");
}
return caps; if(h->api.parse_event != NULL) {
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_PARSING);
}
if(h->api.get_async_events != NULL && h->api.set_async_event_handler != NULL) {
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_ASYNC);
} else if(h->api.set_async_event_handler != NULL) {
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
err_append(err,
"must implement both 'plugin_get_async_events' and "
"'plugin_set_async_event_handler' (async events)",
", ");
}
if(h->api.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;
} }
// 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, "symbol not implemented: %s", #s); \ return false; \
return false; \ } \
} \ } while(0)
} while(0)
bool plugin_check_required_symbols(const plugin_handle_t* h, char* err) bool plugin_check_required_symbols(const plugin_handle_t* h, char* err) {
{ SYM_REQCHECK(h, err, get_required_api_version);
SYM_REQCHECK(h, err, get_required_api_version); SYM_REQCHECK(h, err, get_version);
SYM_REQCHECK(h, err, get_version); SYM_REQCHECK(h, err, get_name);
SYM_REQCHECK(h, err, get_name); SYM_REQCHECK(h, err, get_description);
SYM_REQCHECK(h, err, get_description); SYM_REQCHECK(h, err, get_contact);
SYM_REQCHECK(h, err, get_contact); SYM_REQCHECK(h, err, init);
SYM_REQCHECK(h, err, init); SYM_REQCHECK(h, err, destroy);
SYM_REQCHECK(h, err, destroy); SYM_REQCHECK(h, err, get_last_error);
SYM_REQCHECK(h, err, get_last_error); return true;
return true;
} }

View File

@ -1,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.
@ -19,16 +20,12 @@ limitations under the License.
#include "plugin_api.h" #include "plugin_api.h"
#include <stdbool.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/*!
\brief The maximum length of the error strings written by the plugin loader
*/
#define PLUGIN_MAX_ERRLEN 2048
/*! /*!
\brief This enums the capabilities supported by plugins. \brief This enums the capabilities supported by plugins.
Each plugin can support one or more of these, in which case the enum flags Each plugin can support one or more of these, in which case the enum flags
@ -36,12 +33,18 @@ extern "C" {
Currently, the supported capabilities are: Currently, the supported capabilities are:
* ability to source events and provide them to the event loop * ability to source events and provide them to the event loop
* ability to extract fields from events created by other plugins * ability to extract fields from events created by other plugins
* ability to parse events from the event loop (at most once) before
the field extraction phase
* 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_ASYNC = 1 << 3,
CAP_CAPTURE_LISTENING = 1 << 4,
CAP_BROKEN = 1 << 31, // used to report inconsistencies
} plugin_caps_t; } plugin_caps_t;
/*! /*!
@ -49,16 +52,22 @@ typedef enum
Pointers to this struct must be obtained through the plugin_load() Pointers to this struct must be obtained through the plugin_load()
and released through plugin_unload(). and released through plugin_unload().
*/ */
typedef struct plugin_handle_t typedef struct plugin_handle_t {
{
#ifdef _WIN32 #ifdef _WIN32
HINSTANCE handle; ///< Handle of the dynamic library HINSTANCE handle; ///< Handle of the dynamic library
#else #else
void* handle; ///< Handle of the dynamic library void* handle; ///< Handle of the dynamic library
#endif #endif
plugin_api api; ///< The vtable method of the plugin that define its API plugin_api api; ///< The vtable method of the plugin that define its API
} plugin_handle_t; } plugin_handle_t;
/*!
\brief Uses the given plugin api and returns a plugin_handle_t*
representing the loaded plugin. In case of error, returns NULL and fills
the err string up to PLUGIN_MAX_ERRLEN chars.
*/
plugin_handle_t* plugin_load_api(const plugin_api* api, char* err);
/*! /*!
\brief Loads a dynamic library from the given path and returns a \brief Loads a dynamic library from the given path and returns a
plugin_handle_t* representing the loaded plugin. In case of error, plugin_handle_t* representing the loaded plugin. In case of error,
@ -67,7 +76,7 @@ typedef struct plugin_handle_t
plugin_handle_t* plugin_load(const char* path, char* err); plugin_handle_t* plugin_load(const char* path, char* err);
/*! /*!
\brief Destroys a plugin_handle_t* previously allocated by \brief Destroys a plugin_handle_t* previously allocated by
invoking plugin_load(). invoking plugin_load().
*/ */
void plugin_unload(plugin_handle_t* h); void plugin_unload(plugin_handle_t* h);
@ -92,9 +101,12 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err);
bool plugin_check_required_symbols(const plugin_handle_t* h, char* err); bool plugin_check_required_symbols(const plugin_handle_t* h, char* err);
/*! /*!
\brief Returns the capabilities supported by the given plugin handle \brief Returns the capabilities supported by the given plugin handle.
In case of inconsistencies, the result will have the CAP_BROKEN bit set
and the err string will be filled up to PLUGIN_MAX_ERRLEN chars representing
the error encountered.
*/ */
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h); plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h, char* err);
#ifdef __cplusplus #ifdef __cplusplus
} }

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

@ -0,0 +1,132 @@
diff --git a/pkg/loader/plugin_loader.c b/pkg/loader/plugin_loader.c
index 2943335..7bebeeb 100644
--- a/pkg/loader/plugin_loader.c
+++ b/pkg/loader/plugin_loader.c
@@ -24,22 +24,52 @@ typedef HINSTANCE library_handle_t;
typedef void* library_handle_t;
#endif
-#include <libscap/strl.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <plugin/plugin_loader.h>
+#include "plugin_loader.h"
+
+// note(jasondellaluce,therealbobo): implementation taken from falcosecurity/libs
+// note(leogr): to avoid clashing with `strlcpy` introduced by glibc 2.38,
+// the func has been renamed to plugin_loader_strlcpy.
+// N.B.: our building system here is not smart enough to detect if the function
+// was declared already.
+#include <stdint.h>
+#include <string.h>
+/*!
+ \brief Copy up to size - 1 characters from the NUL-terminated string src to dst, NUL-terminating the result.
+
+ \return The length of the source string.
+*/
+
+static inline size_t plugin_loader_strlcpy(char *dst, const char *src, size_t size) {
+ size_t srcsize = strlen(src);
+ if (size == 0) {
+ return srcsize;
+ }
+
+ size_t copysize = srcsize;
+
+ if (copysize > size - 1) {
+ copysize = size - 1;
+ }
+
+ memcpy(dst, src, copysize);
+ dst[copysize] = '\0';
+
+ return srcsize;
+}
static inline void err_prepend(char* s, const char* prefix, const char* sep) {
char tmp[PLUGIN_MAX_ERRLEN];
- size_t prefix_len = strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
+ size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
if(*s != '\0') {
- strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
+ plugin_loader_strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
prefix_len += strlen(sep);
}
- strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
- strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
+ plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
}
static inline void err_append(char* s, const char* suffix, const char* sep) {
@@ -65,7 +95,7 @@ plugin_handle_t* plugin_load(const char* path, char* err) {
err[0] = '\0';
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
if(!ret) {
- strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
return NULL;
}
@@ -77,14 +107,14 @@ plugin_handle_t* plugin_load(const char* path, char* err) {
FORMAT_MESSAGE_IGNORE_INSERTS;
LPTSTR msg_buf = 0;
if(FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR)&msg_buf, 0, NULL) && msg_buf) {
- strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
LocalFree(msg_buf);
}
}
#else
ret->handle = dlopen(path, RTLD_LAZY);
if(ret->handle == NULL) {
- strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
}
#endif
@@ -135,13 +165,13 @@ plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
// alloc and init memory
err[0] = '\0';
if(!api) {
- strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
return NULL;
}
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
if(!ret) {
- strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
return NULL;
}
ret->api = *api;
@@ -150,7 +180,7 @@ plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
uint32_t major, minor, patch;
const char* ver;
if(api->get_required_api_version == NULL) {
- strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
return NULL;
}
@@ -217,7 +247,7 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) {
uint32_t major, minor, patch;
const char *ver, *failmsg;
if(h->api.get_required_api_version == NULL) {
- strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
return false;
}
@@ -256,7 +286,7 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) {
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h, char* err) {
plugin_caps_t caps = CAP_NONE;
- strlcpy(err, "", PLUGIN_MAX_ERRLEN);
+ plugin_loader_strlcpy(err, "", PLUGIN_MAX_ERRLEN);
if(h->api.open != NULL && h->api.close != NULL && h->api.next_batch != NULL) {
bool has_id = h->api.get_id != NULL && h->api.get_id() != 0;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2025 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -29,6 +30,20 @@ import (
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr" "github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
) )
// pluginEventCode is the event code for the PPME_PLUGINEVENT_E scap event.
// todo(jasondellaluce): pull this information from falcosecurity/libs in the future
const pluginEventCode = 322
// todo(leogr): replace this with PLUGIN_EVENT_PAYLOAD_OFFSET from "plugin_api.h"
// PluginEventPayloadOffset is the size of a scap event header, plus the
// params lenght and the plugin ID integers of a PPME_PLUGINEVENT_E event.
// In other words, this is the size of a plugin event with an empty data payload.
//
// 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.
// //
@ -113,7 +128,8 @@ type EventWriters interface {
} }
type eventWriters struct { type eventWriters struct {
evts []*eventWriter evts []*eventWriter
evtPtrs **C.ss_plugin_event
} }
// NewEventWriters creates a new instance of sdk.EventWriters. // NewEventWriters creates a new instance of sdk.EventWriters.
@ -129,16 +145,16 @@ func NewEventWriters(size, dataSize int64) (EventWriters, error) {
} }
ret := &eventWriters{ ret := &eventWriters{
evts: make([]*eventWriter, size), evts: make([]*eventWriter, size),
evtPtrs: (**C.ss_plugin_event)(C.malloc((C.size_t)(size * C.sizeof_uintptr_t))),
} }
pluginEvtArray := (*C.ss_plugin_event)(C.malloc((C.size_t)(size * C.sizeof_ss_plugin_event)))
var err error var err error
for i := range ret.evts { for i := range ret.evts {
// get i-th element of pluginEvtArray if ret.evts[i], err = newEventWriter(dataSize); err != nil {
evtPtr := unsafe.Pointer(uintptr(unsafe.Pointer(pluginEvtArray)) + uintptr(i*C.sizeof_ss_plugin_event))
if ret.evts[i], err = newEventWriter(evtPtr, dataSize); err != nil {
return nil, err return nil, err
} }
*(**C.ss_plugin_event)(unsafe.Pointer(uintptr(unsafe.Pointer(ret.evtPtrs)) + uintptr(i*C.sizeof_uintptr_t))) = ret.evts[i].ssPluginEvt
} }
return ret, nil return ret, nil
} }
@ -159,37 +175,52 @@ func (p *eventWriters) Free() {
} }
func (p *eventWriters) ArrayPtr() unsafe.Pointer { func (p *eventWriters) ArrayPtr() unsafe.Pointer {
return p.evts[0].ssPluginEvt return unsafe.Pointer(p.evtPtrs)
} }
type eventWriter struct { type eventWriter struct {
data ptr.BytesReadWriter data ptr.BytesReadWriter
dataSize int64 dataSize int64
ssPluginEvt unsafe.Pointer ssPluginEvt *C.ss_plugin_event
} }
func newEventWriter(evtPtr unsafe.Pointer, dataSize int64) (*eventWriter, error) { func newEventWriter(dataSize int64) (*eventWriter, error) {
evt := (*C.ss_plugin_event)(evtPtr) evt := (*C.ss_plugin_event)(C.calloc(1, C.size_t(dataSize+PluginEventPayloadOffset)))
evt._type = pluginEventCode
evt.ts = C.uint64_t(C.UINT64_MAX) evt.ts = C.uint64_t(C.UINT64_MAX)
evt.data = (*C.uint8_t)(C.malloc(C.size_t(dataSize))) evt.tid = C.uint64_t(C.UINT64_MAX)
evt.datalen = 0 evt.len = (C.uint32_t)(PluginEventPayloadOffset)
brw, err := ptr.NewBytesReadWriter(unsafe.Pointer(evt.data), int64(dataSize), int64(dataSize)) // note(jasondellaluce): CGO fails to properly encode nparams for *reasons*,
// so we're forced to write their value manually with an offset
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + 22)) = 2
// plugin ID size (4 bytes)
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + C.sizeof_ss_plugin_event + 0)) = 4
// data payload size (0 bytes for now)
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + C.sizeof_ss_plugin_event + 4)) = 0
// plugin ID value (note: putting zero makes the framework set it automatically)
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + C.sizeof_ss_plugin_event + 8)) = 0
// create a read/writer for the data payload
brw, err := ptr.NewBytesReadWriter(unsafe.Pointer(uintptr(unsafe.Pointer(evt))+PluginEventPayloadOffset), int64(dataSize), int64(dataSize))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &eventWriter{ return &eventWriter{
ssPluginEvt: evtPtr, ssPluginEvt: evt,
data: brw, data: brw,
dataSize: dataSize, dataSize: dataSize,
}, nil }, nil
} }
func (p *eventWriter) dataLenPtr() *C.uint32_t {
return (*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(p.ssPluginEvt)) + C.sizeof_ss_plugin_event + 4))
}
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)
(*C.ss_plugin_event)(p.ssPluginEvt).datalen = 0 p.ssPluginEvt.len = (C.uint32_t)(PluginEventPayloadOffset)
*p.dataLenPtr() = 0
return p return p
} }
@ -198,7 +229,8 @@ func (p *eventWriter) Write(data []byte) (n int, err error) {
if err != nil { if err != nil {
return return
} }
(*C.ss_plugin_event)(p.ssPluginEvt).datalen += C.uint32_t(n) p.ssPluginEvt.len += C.uint32_t(n)
*p.dataLenPtr() += C.uint32_t(n)
return return
} }
@ -207,26 +239,30 @@ func (p *eventWriter) SetTimestamp(value uint64) {
} }
func (p *eventWriter) free() { func (p *eventWriter) free() {
C.free(unsafe.Pointer((*C.ss_plugin_event)(p.ssPluginEvt).data)) C.free(unsafe.Pointer(p.ssPluginEvt))
p.data = nil p.data = nil
} }
type eventReader C.ss_plugin_event type eventReader C.ss_plugin_event_input
// NewEventReader wraps a pointer to a ss_plugin_event C structure to create // NewEventReader wraps a pointer to a ss_plugin_event_input C structure to create
// a new instance of EventReader. It's not possible to check that the pointer is valid. // a new instance of EventReader. It's not possible to check that the pointer is valid.
// Passing an invalid pointer may cause undefined behavior. // Passing an invalid pointer may cause undefined behavior.
func NewEventReader(ssPluginEvt unsafe.Pointer) EventReader { func NewEventReader(ssPluginEvtInput unsafe.Pointer) EventReader {
return (*eventReader)(ssPluginEvt) return (*eventReader)(ssPluginEvtInput)
} }
func (e *eventReader) Reader() io.ReadSeeker { func (e *eventReader) Reader() io.ReadSeeker {
brw, _ := ptr.NewBytesReadWriter(unsafe.Pointer(e.data), int64(e.datalen), int64(e.datalen)) if e.evt._type != pluginEventCode {
panic(fmt.Sprintf("plugin-sdk-go/sdk: reveived extraction request for non-plugin event (code=%d)", e.evt._type))
}
datalen := *(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(e.evt)) + C.sizeof_ss_plugin_event + 4))
brw, _ := ptr.NewBytesReadWriter(unsafe.Pointer(uintptr(unsafe.Pointer(e.evt))+PluginEventPayloadOffset), int64(datalen), int64(datalen))
return brw return brw
} }
func (e *eventReader) Timestamp() uint64 { func (e *eventReader) Timestamp() uint64 {
return uint64(e.ts) return uint64(e.evt.ts)
} }
func (e *eventReader) EventNum() uint64 { func (e *eventReader) EventNum() uint64 {

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.
@ -28,11 +29,17 @@ package sdk
typedef union { typedef union {
const char* str; const char* str;
uint64_t u64; uint64_t u64;
uint32_t u32;
ss_plugin_bool boolean;
ss_plugin_byte_buffer buf;
} field_result_t; } field_result_t;
*/ */
import "C" import "C"
import ( import (
"net"
"reflect"
"time"
"unsafe" "unsafe"
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr" "github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
@ -53,8 +60,14 @@ type ExtractRequest interface {
FieldID() uint64 FieldID() uint64
// //
// FieldType returns the type of the field for which the value extraction // FieldType returns the type of the field for which the value extraction
// is requested. For now, only sdk.FieldTypeUint64 and // is requested. For now, the supported types are:
// sdk.FieldTypeCharBuf are supported. // - sdk.FieldTypeBool
// - sdk.FieldTypeUint64
// - sdk.FieldTypeCharBuf
// - sdk.FieldTypeRelTime
// - sdk.FieldTypeAbsTime
// - sdk.FieldTypeIPAddr
// - sdk.FieldTypeIPNet
FieldType() uint32 FieldType() uint32
// //
// Field returns the name of the field for which the value extraction // Field returns the name of the field for which the value extraction
@ -80,11 +93,39 @@ type ExtractRequest interface {
// The underlying type of v must be compatible with the field type // The underlying type of v must be compatible with the field type
// associated to this extract request (as the returned by FieldType()), // associated to this extract request (as the returned by FieldType()),
// otherwise SetValue will panic. // otherwise SetValue will panic.
//
// Coherently to the FieldType of the extraction request, this function
// panics if the passed value is not one of the following types (or slices
// of them, in case IsList() returns true):
// - sdk.FieldTypeBool: bool
// - sdk.FieldTypeUint64: uint64
// - sdk.FieldTypeCharBuf: string
// - sdk.FieldTypeRelTime: time.Duration, *time.Duration
// - sdk.FieldTypeAbsTime: time.Time, *time.Time
// - sdk.FieldTypeIPAddr: net.IP, *net.IP
// - 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.
@ -95,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.
@ -102,7 +155,9 @@ type ExtractRequestPool interface {
} }
type extractRequestPool struct { type extractRequestPool struct {
reqs map[uint]*extractRequest reqs map[uint]*extractRequest
startArrayPtr, lengthArrayPtr unsafe.Pointer
arrayPtrCap uint32
} }
func (e *extractRequestPool) Get(requestIndex int) ExtractRequest { func (e *extractRequestPool) Get(requestIndex int) ExtractRequest {
@ -112,12 +167,42 @@ func (e *extractRequestPool) Get(requestIndex int) ExtractRequest {
resBuf: (*C.field_result_t)(C.malloc((C.size_t)(minResultBufferLen * C.sizeof_field_result_t))), resBuf: (*C.field_result_t)(C.malloc((C.size_t)(minResultBufferLen * C.sizeof_field_result_t))),
resBufLen: minResultBufferLen, resBufLen: minResultBufferLen,
resStrBufs: []StringBuffer{&ptr.StringBuffer{}}, resStrBufs: []StringBuffer{&ptr.StringBuffer{}},
resValPtrs: make([]unsafe.Pointer, minResultBufferLen),
}
for i := 0; i < minResultBufferLen; i++ {
ptr := (*C.field_result_t)(unsafe.Pointer(uintptr(unsafe.Pointer(r.resBuf)) + uintptr(i*C.sizeof_field_result_t)))
r.resValPtrs[i] = unsafe.Pointer(ptr)
} }
e.reqs[uint(requestIndex)] = r e.reqs[uint(requestIndex)] = r
} }
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 {
@ -125,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.
@ -137,18 +226,31 @@ 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
resBufLen uint32 resBufLen uint32
// List of StringBuffer to return string results // List of StringBuffer to return string results
resStrBufs []StringBuffer resStrBufs []StringBuffer
// List of BytesReadWriter to return binary results
resBinBufs []ptr.BytesReadWriter
// List of *field_result_t to be filled with the values of a request
resValPtrs []unsafe.Pointer
} }
func (e *extractRequest) SetPtr(pef unsafe.Pointer) { 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)
} }
@ -170,52 +272,175 @@ func (e *extractRequest) ArgIndex() uint64 {
} }
func (e *extractRequest) ArgPresent() bool { func (e *extractRequest) ArgPresent() bool {
return bool(e.req.arg_present) return e.req.arg_present != 0
} }
func (e *extractRequest) IsList() bool { func (e *extractRequest) IsList() bool {
return bool(e.req.flist) return e.req.flist != 0
}
func (e *extractRequest) boolToU32(v bool) uint32 {
if v {
return uint32(1)
}
return uint32(0)
}
func (e *extractRequest) resizeResValPtrs(length, dataSize int) []unsafe.Pointer {
if e.resBufLen < uint32(length) {
C.free(unsafe.Pointer(e.resBuf))
e.resBufLen = uint32(length)
e.resBuf = (*C.field_result_t)(C.malloc((C.size_t)(e.resBufLen * C.sizeof_field_result_t)))
e.resValPtrs = make([]unsafe.Pointer, length)
}
// we need to recompute the pointers everytime, because
// the same extractRequest can be reused with different dataSizes.
for i := 0; i < length; i++ {
e.resValPtrs[i] = unsafe.Pointer(uintptr(unsafe.Pointer(e.resBuf)) + uintptr(i*dataSize))
}
e.req.res_len = (C.uint64_t)(length)
return e.resValPtrs[:length]
} }
func (e *extractRequest) SetValue(v interface{}) { func (e *extractRequest) SetValue(v interface{}) {
switch e.FieldType() { switch e.FieldType() {
case FieldTypeUint64: case FieldTypeBool:
if e.req.flist { if e.IsList() {
if e.resBufLen < uint32(len(v.([]uint64))) { for i, ptr := range e.resizeResValPtrs(len(v.([]bool)), C.sizeof_uint32_t) {
C.free(unsafe.Pointer(e.resBuf)) *((*C.uint32_t)(ptr)) = (C.uint32_t)(e.boolToU32((v.([]bool))[i]))
e.resBufLen = uint32(len(v.([]uint64)))
e.resBuf = (*C.field_result_t)(C.malloc((C.size_t)(e.resBufLen * C.sizeof_field_result_t)))
} }
for i, val := range v.([]uint64) {
*((*C.uint64_t)(unsafe.Pointer(uintptr(unsafe.Pointer(e.resBuf)) + uintptr(i*C.sizeof_field_result_t)))) = (C.uint64_t)(val)
}
e.req.res_len = (C.uint64_t)(len(v.([]uint64)))
} else { } else {
*((*C.uint64_t)(unsafe.Pointer(e.resBuf))) = (C.uint64_t)(v.(uint64)) ptr := e.resizeResValPtrs(1, C.sizeof_uint32_t)[0]
e.req.res_len = (C.uint64_t)(1) *((*C.uint32_t)(ptr)) = (C.uint32_t)(e.boolToU32(v.(bool)))
}
case FieldTypeUint64:
if e.IsList() {
for i, ptr := range e.resizeResValPtrs(len(v.([]uint64)), C.sizeof_uint64_t) {
*((*C.uint64_t)(ptr)) = (C.uint64_t)((v.([]uint64))[i])
}
} else {
ptr := e.resizeResValPtrs(1, C.sizeof_uint64_t)[0]
*((*C.uint64_t)(ptr)) = (C.uint64_t)(v.(uint64))
} }
case FieldTypeCharBuf: case FieldTypeCharBuf:
if e.req.flist { if e.IsList() {
if e.resBufLen < uint32(len(v.([]string))) { for i, out := range e.resizeResValPtrs(len(v.([]string)), C.sizeof_uintptr_t) {
C.free(unsafe.Pointer(e.resBuf))
e.resBufLen = uint32(len(v.([]string)))
e.resBuf = (*C.field_result_t)(C.malloc((C.size_t)(e.resBufLen * C.sizeof_field_result_t)))
}
for i, val := range v.([]string) {
if len(e.resStrBufs) <= i { if len(e.resStrBufs) <= i {
e.resStrBufs = append(e.resStrBufs, &ptr.StringBuffer{}) e.resStrBufs = append(e.resStrBufs, &ptr.StringBuffer{})
} }
e.resStrBufs[i].Write(val) e.resStrBufs[i].Write(v.([]string)[i])
*((**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(e.resBuf)) + uintptr(i*C.sizeof_field_result_t)))) = (*C.char)(e.resStrBufs[i].CharPtr()) *((**C.char)(out)) = (*C.char)(e.resStrBufs[i].CharPtr())
} }
e.req.res_len = (C.uint64_t)(len(v.([]string)))
} else { } else {
out := e.resizeResValPtrs(1, C.sizeof_uintptr_t)[0]
e.resStrBufs[0].Write(v.(string)) e.resStrBufs[0].Write(v.(string))
*((**C.char)(unsafe.Pointer(e.resBuf))) = (*C.char)(e.resStrBufs[0].CharPtr()) *((**C.char)(out)) = (*C.char)(e.resStrBufs[0].CharPtr())
e.req.res_len = (C.uint64_t)(1) }
case FieldTypeRelTime:
if e.IsList() {
if val, ok := v.([]time.Duration); ok {
for i, ptr := range e.resizeResValPtrs(len(val), C.sizeof_uint64_t) {
*((*C.uint64_t)(ptr)) = (C.uint64_t)(val[i].Nanoseconds())
}
} else {
for i, ptr := range e.resizeResValPtrs(len(v.([]*time.Duration)), C.sizeof_uint64_t) {
*((*C.uint64_t)(ptr)) = (C.uint64_t)(v.([]*time.Duration)[i].Nanoseconds())
}
}
} else {
ptr := e.resizeResValPtrs(1, C.sizeof_uint64_t)[0]
if val, ok := v.(time.Duration); ok {
*((*C.uint64_t)(ptr)) = (C.uint64_t)(val.Nanoseconds())
} else {
*((*C.uint64_t)(ptr)) = (C.uint64_t)(v.(*time.Duration).Nanoseconds())
}
}
case FieldTypeAbsTime:
if e.IsList() {
if val, ok := v.([]time.Time); ok {
for i, ptr := range e.resizeResValPtrs(len(val), C.sizeof_uint64_t) {
*((*C.uint64_t)(ptr)) = (C.uint64_t)(val[i].UnixNano())
}
} else {
for i, ptr := range e.resizeResValPtrs(len(v.([]*time.Time)), C.sizeof_uint64_t) {
*((*C.uint64_t)(ptr)) = (C.uint64_t)(v.([]*time.Time)[i].UnixNano())
}
}
} else {
ptr := e.resizeResValPtrs(1, C.sizeof_uint64_t)[0]
if val, ok := v.(time.Time); ok {
*((*C.uint64_t)(ptr)) = (C.uint64_t)(val.UnixNano())
} else {
*((*C.uint64_t)(ptr)) = (C.uint64_t)(v.(*time.Time).UnixNano())
}
}
case FieldTypeIPAddr:
if e.IsList() {
if val, ok := v.([]net.IP); ok {
for i, ptr := range e.resizeResValPtrs(len(val), C.sizeof_struct_ss_plugin_byte_buffer) {
val := ([]byte)((val)[i])
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
}
} else {
for i, ptr := range e.resizeResValPtrs(len(v.([]*net.IP)), C.sizeof_struct_ss_plugin_byte_buffer) {
val := ([]byte)(*(v.([]*net.IP))[i])
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
}
}
} else {
var val []byte
ptr := e.resizeResValPtrs(1, C.sizeof_struct_ss_plugin_byte_buffer)[0]
if ipv, ok := v.(net.IP); ok {
val = ([]byte)(ipv)
} else {
val = ([]byte)(*(v.(*net.IP)))
}
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
}
case FieldTypeIPNet:
if e.IsList() {
if ipv, ok := v.([]net.IPNet); ok {
for i, ptr := range e.resizeResValPtrs(len(ipv), C.sizeof_struct_ss_plugin_byte_buffer) {
val := ([]byte)((ipv)[i].IP)
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
}
} else {
for i, ptr := range e.resizeResValPtrs(len(v.([]*net.IPNet)), C.sizeof_struct_ss_plugin_byte_buffer) {
val := ([]byte)((v.([]*net.IPNet))[i].IP)
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
}
}
} else {
var val []byte
ptr := e.resizeResValPtrs(1, C.sizeof_struct_ss_plugin_byte_buffer)[0]
if ipv, ok := v.(net.IPNet); ok {
val = ([]byte)(ipv.IP)
} else {
val = ([]byte)(v.(*net.IPNet).IP)
}
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
} }
default: default:
panic("plugin-sdk-go/sdk: called SetValue with unsupported field type") panic("plugin-sdk-go/sdk: called SetValue with unsupported field type")
} }
*((*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.
@ -18,18 +19,26 @@ package sdk
import ( import (
"fmt" "fmt"
"net"
"testing" "testing"
"unsafe" "unsafe"
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr" "github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
) )
func boolToUint32(v bool) _Ctype_uint32_t {
if v {
return _Ctype_uint32_t(1)
}
return _Ctype_uint32_t(0)
}
func allocSSPluginExtractField(fid, ftype uint32, fname, farg_key string, farg_index uint64, farg_present bool, list bool) (*_Ctype_ss_plugin_extract_field, func()) { func allocSSPluginExtractField(fid, ftype uint32, fname, farg_key string, farg_index uint64, farg_present bool, list bool) (*_Ctype_ss_plugin_extract_field, func()) {
ret := &_Ctype_ss_plugin_extract_field{} ret := &_Ctype_ss_plugin_extract_field{}
ret.field_id = _Ctype_uint32_t(fid) ret.field_id = _Ctype_uint32_t(fid)
ret.ftype = _Ctype_uint32_t(ftype) ret.ftype = _Ctype_uint32_t(ftype)
ret.arg_present = _Ctype__Bool(farg_present) ret.arg_present = boolToUint32(farg_present)
ret.flist = _Ctype__Bool(list) ret.flist = boolToUint32(list)
ret.arg_index = _Ctype_uint64_t(farg_index) ret.arg_index = _Ctype_uint64_t(farg_index)
argKeyBuf := ptr.StringBuffer{} argKeyBuf := ptr.StringBuffer{}
@ -49,18 +58,51 @@ func allocSSPluginExtractField(fid, ftype uint32, fname, farg_key string, farg_i
} }
} }
func allocSSPluginExtractOffset() *_Ctype_uint32_t {
var offset _Ctype_uint32_t = _Ctype_uint32_t(0)
return &offset
}
func getBoolResSSPluingExtractField(t *testing.T, ptr *_Ctype_ss_plugin_extract_field, index int) bool {
if ptr.res_len < (_Ctype_uint64_t)(index) {
t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(ptr.res_len))
}
value := (uint32)(*((*_Ctype_uint32_t)(unsafe.Pointer(uintptr(*(*_Ctype_uintptr_t)(unsafe.Pointer(&ptr.res))) + uintptr(index*_Ciconst_sizeof_uint32_t)))))
return value != uint32(0)
}
func getStrResSSPluingExtractField(t *testing.T, p *_Ctype_ss_plugin_extract_field, index int) string { func getStrResSSPluingExtractField(t *testing.T, p *_Ctype_ss_plugin_extract_field, index int) string {
if p.res_len < (_Ctype_uint64_t)(index) { if p.res_len < (_Ctype_uint64_t)(index) {
t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(p.res_len)) t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(p.res_len))
} }
return ptr.GoString(unsafe.Pointer((*((**_Ctype_char)(unsafe.Pointer(uintptr(*(*_Ctype_uintptr_t)(unsafe.Pointer(&p.res))) + uintptr(index*_Ciconst_sizeof_field_result_t))))))) return ptr.GoString(unsafe.Pointer((*((**_Ctype_char)(unsafe.Pointer(uintptr(*(*_Ctype_uintptr_t)(unsafe.Pointer(&p.res))) + uintptr(index*_Ciconst_sizeof_uintptr_t)))))))
} }
func getU64ResSSPluingExtractField(t *testing.T, ptr *_Ctype_ss_plugin_extract_field, index int) uint64 { func getU64ResSSPluingExtractField(t *testing.T, ptr *_Ctype_ss_plugin_extract_field, index int) uint64 {
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))
} }
return (uint64)(*((*_Ctype_uint64_t)(unsafe.Pointer(uintptr(*(*_Ctype_uintptr_t)(unsafe.Pointer(&ptr.res))) + uintptr(index*_Ciconst_sizeof_field_result_t))))) return (uint64)(*((*_Ctype_uint64_t)(unsafe.Pointer(uintptr(*(*_Ctype_uintptr_t)(unsafe.Pointer(&ptr.res))) + uintptr(index*_Ciconst_sizeof_uint64_t)))))
}
func getBinResSSPluingExtractField(t *testing.T, p *_Ctype_ss_plugin_extract_field, index int) []byte {
if p.res_len < (_Ctype_uint64_t)(index) {
t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(p.res_len))
}
bufListPtr := *(*unsafe.Pointer)(unsafe.Pointer(&p.res))
curBufPtr := (unsafe.Pointer)(unsafe.Pointer(uintptr(bufListPtr) + uintptr(index*_Ciconst_sizeof_field_result_t)))
size := *(*uint32)(curBufPtr)
buf := make([]byte, size)
ptrBytes := *(*unsafe.Pointer)(unsafe.Pointer(uintptr(curBufPtr) + uintptr(8)))
for i := 0; i < int(size); i++ {
buf[i] = *(*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(ptrBytes)) + uintptr(i)))
}
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()) {
@ -93,27 +135,60 @@ 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
testIPv6 := net.IPv6loopback
testStrList := make([]string, 0) testStrList := make([]string, 0)
testU64List := make([]uint64, 0) testU64List := make([]uint64, 0)
for i := 0; i < minResultBufferLen+1; i++ { // cause a list resizing testU64ListStart := uint32(PluginEventPayloadOffset)
testU64ListLength := uint32(0)
testBoolList := make([]bool, 0)
dataArray := make([]byte, (minResultBufferLen+1)*int(len(testIPv6)))
for i := 0; i < (minResultBufferLen+1)*int(len(testIPv6)); i++ {
dataArray[i] = byte(i)
}
testIPv6List := make([]net.IP, minResultBufferLen+1)
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)
testIPv6List[i] = dataArray[i*len(testIPv6) : (i+1)*len(testIPv6)]
} }
// 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)
boolListPtr, freeBoolListPtr := allocSSPluginExtractField(6, FieldTypeBool, "test.bool", "", 0, true, true)
binPtr, freeBinPtr := allocSSPluginExtractField(7, FieldTypeIPAddr, "test.ipv6addr", "", 0, true, false)
binListPtr, freeBinListPtr := allocSSPluginExtractField(8, FieldTypeIPAddr, "test.ipv6addr", "", 0, true, true)
u64Req := pool.Get(0) u64Req := pool.Get(0)
u64ReqList := pool.Get(1) u64ReqList := pool.Get(1)
strReq := pool.Get(2) strReq := pool.Get(2)
strReqList := pool.Get(3) strReqList := pool.Get(3)
boolReq := pool.Get(4)
boolReqList := pool.Get(5)
binReq := pool.Get(6)
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))
boolReqList.SetPtr(unsafe.Pointer(boolListPtr))
binReq.SetPtr(unsafe.Pointer(binPtr))
binReqList.SetPtr(unsafe.Pointer(binListPtr))
// check that info is passed-through correctly // check that info is passed-through correctly
if u64Req.FieldID() != 1 { if u64Req.FieldID() != 1 {
@ -144,9 +219,23 @@ func TestExtractRequestSetValue(t *testing.T) {
// check panics // check panics
assertPanic(t, func() { assertPanic(t, func() {
u64Req.SetValue("test") u64Req.SetValue("test")
u64Req.SetValue(bool(true))
boolReq.SetValue([]byte{0x41, 0x41, 0x41, 0x41})
}) })
assertPanic(t, func() { assertPanic(t, func() {
strReq.SetValue(uint64(1)) strReq.SetValue(uint64(1))
strReq.SetValue(bool(true))
boolReq.SetValue([]byte{0x41, 0x41, 0x41, 0x41})
})
assertPanic(t, func() {
boolReq.SetValue(uint64(1))
boolReq.SetValue("test")
boolReq.SetValue([]byte{0x41, 0x41, 0x41, 0x41})
})
assertPanic(t, func() {
binReq.SetValue(uint64(1))
binReq.SetValue("test")
binReq.SetValue(bool(true))
}) })
// check set correct values // check set correct values
@ -154,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))
@ -170,10 +273,49 @@ func TestExtractRequestSetValue(t *testing.T) {
t.Errorf("expected value '%s', but found '%s'", s, getStrResSSPluingExtractField(t, strPtr, i)) t.Errorf("expected value '%s', but found '%s'", s, getStrResSSPluingExtractField(t, strPtr, i))
} }
} }
boolReq.SetValue(testBool)
if getBoolResSSPluingExtractField(t, boolPtr, 0) != testBool {
t.Errorf("expected value '%v', but found '%v'", testBool, getBoolResSSPluingExtractField(t, boolPtr, 0))
}
boolReqList.SetValue(testBoolList)
for i, b := range testBoolList {
if getBoolResSSPluingExtractField(t, boolListPtr, i) != b {
t.Errorf("expected value '%v', but found '%v' at index %d", b, getBoolResSSPluingExtractField(t, boolPtr, i), i)
}
}
binReq.SetValue(testIPv6)
testIPv6res := getBinResSSPluingExtractField(t, binPtr, 0)
if len(testIPv6res) != len(testIPv6) {
t.Errorf("expected value '%v', but found '%v'", testIPv6, getBinResSSPluingExtractField(t, binPtr, 0))
} else {
for i := 0; i < len(testIPv6); i++ {
if testIPv6[i] != testIPv6res[i] {
t.Errorf("expected value '%v', but found '%v'", testIPv6, getBinResSSPluingExtractField(t, binPtr, 0))
}
}
}
binReqList.SetValue(testIPv6List)
for i, s := range testIPv6List {
testIPv6res := getBinResSSPluingExtractField(t, binListPtr, i)
if len(testIPv6res) != len(s) {
t.Errorf("expected size '%v', but found '%v'", len(s), len(testIPv6res))
} else {
for k := 0; k < len(s); k++ {
if s[k] != testIPv6res[k] {
t.Errorf("expected value '%v', but found '%v'", s, testIPv6res)
}
}
}
}
pool.Free() pool.Free()
freeU64Ptr() freeU64Ptr()
freeU64ListPtr() freeU64ListPtr()
freeStrPtr() freeStrPtr()
freeStrListPtr() freeStrListPtr()
freeBoolPtr()
freeBoolListPtr()
freeBinPtr()
freeBinListPtr()
} }

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.

File diff suppressed because it is too large Load Diff

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.
@ -21,21 +22,36 @@ limitations under the License.
extern "C" { extern "C" {
#endif #endif
#include <stdbool.h>
#include <inttypes.h> #include <inttypes.h>
// An implementation-independent representation of boolean.
// A 4-byte representation is equal to how bools are encoded in falcosecurity libs.
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.
FTYPE_UINT64 = 8, FTYPE_UINT64 = 8,
FTYPE_STRING = 9 // A printable buffer of bytes, NULL terminated
FTYPE_STRING = 9,
// A relative time. Seconds * 10^9 + nanoseconds. 64bit.
FTYPE_RELTIME = 20,
// An absolute time interval. Seconds from epoch * 10^9 + nanoseconds. 64bit.
FTYPE_ABSTIME = 21,
// A boolean value, 4 bytes.
FTYPE_BOOL = 25,
// Either an IPv4 or IPv6 address. The length indicates which one it is.
FTYPE_IPADDR = 40,
// Either an IPv4 or IPv6 network. The length indicates which one it is.
// The field encodes only the IP address, so this differs from FTYPE_IPADDR,
// from the way the framework perform runtime checks and comparisons.
FTYPE_IPNET = 41,
} ss_plugin_field_type; } ss_plugin_field_type;
// Values to return from init() / open() / next_batch() / // Values to return from init() / open() / next_batch() /
// extract_fields(). // extract_fields().
typedef enum ss_plugin_rc typedef enum ss_plugin_rc {
{
SS_PLUGIN_SUCCESS = 0, SS_PLUGIN_SUCCESS = 0,
SS_PLUGIN_FAILURE = 1, SS_PLUGIN_FAILURE = 1,
SS_PLUGIN_TIMEOUT = -1, SS_PLUGIN_TIMEOUT = -1,
@ -44,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,
@ -57,26 +72,75 @@ typedef enum ss_plugin_schema_type
} ss_plugin_schema_type; } ss_plugin_schema_type;
// This struct represents an event returned by the plugin, and is used // This struct represents an event returned by the plugin, and is used
// below in next_batch(). // below in next_batch(). It observes the event specifics of libscap.
// - evtnum: incremented for each event returned. Might not be contiguous. // An event is represented as a contiguous region of memory composed by
// - data: pointer to a memory buffer pointer. The plugin will set it // a header and a list of parameters appended, in the form of:
// to point to the memory containing the next event.
// - datalen: pointer to a 32bit integer. The plugin will set it the size of the
// buffer pointed by data.
// - ts: the event timestamp, in nanoseconds since the epoch.
// Can be (uint64_t)-1, in which case the engine will automatically
// fill the event time with the current time.
// //
// Note: event numbers are assigned by the plugin // | evt header | len param 1 (2B/4B) | ... | len param N (2B/4B) | data param 1 | ... | data param
// framework. Therefore, there isn't any need to fill in evtnum when // N |
// returning an event via plugin_next_batch. It will be ignored. //
typedef struct ss_plugin_event // The event header is composed of:
{ // - ts: the event timestamp, in nanoseconds since the epoch.
// Can be (uint64_t)-1, in which case the framework will automatically
// fill the event time with the current time.
// - tid: the tid of the thread that generated this event.
// Can be (uint64_t)-1 in case no thread is specified, such as when generating
// a plugin event (type code 322).
// - len: the event len, including the header
// - type: the type of the event, as per the ones supported by the libscap specifics.
// This dictates the number and kind of parameters, and whether the lenght is
// encoded as a 2 bytes or 4 bytes integer.
// - nparams: the number of parameters of the event
#if defined _MSC_VER
#pragma pack(push)
#pragma pack(1)
#else
#pragma pack(push, 1)
#endif
struct ss_plugin_event {
#ifdef PPM_ENABLE_SENTINEL
uint32_t sentinel_begin;
#endif
uint64_t ts; /* timestamp, in nanoseconds from epoch */
uint64_t tid; /* the tid of the thread that generated this event */
uint32_t len; /* the event len, including the header */
uint16_t type; /* the event type */
uint32_t nparams; /* the number of parameters of the event */
};
#pragma pack(pop)
typedef struct ss_plugin_event ss_plugin_event;
// This struct represents an event provided by the framework to the plugin
// as a read-only input.
// - evt: a pointer to the header of the provided event.
// - evtnum: assigned by the framework and incremented for each event.
// Might not be contiguous.
// - evtsrc: The name of the event's source. Can be "syscall" or any other
// event source name implemented by a plugin.
typedef struct ss_plugin_event_input {
const ss_plugin_event* evt;
uint64_t evtnum; uint64_t evtnum;
const uint8_t *data; const char* evtsrc;
uint32_t datalen; } ss_plugin_event_input;
uint64_t ts;
} ss_plugin_event; typedef struct ss_plugin_byte_buffer {
uint32_t len;
const void* ptr;
} ss_plugin_byte_buffer;
// Used in extract_fields_and_offsets to receive field value offsets
// along with field data.
// Extraction functions that support offsets should be set these to an
// array of zero-indexed start offsets and lengths of each returned
// value in the event or log data. {0, 0} can be used to indicate that
// there are no valid offsets, e.g. if the value was generated or
// computed from other data.
// Extraction functions might not support offsets. In order to detect
// this, callers should initialize the start and length to nullptr.
typedef struct ss_plugin_extract_value_offsets {
uint32_t* start;
uint32_t* length;
} ss_plugin_extract_value_offsets;
// Used in extract_fields functions below to receive a field/arg // Used in extract_fields functions below to receive a field/arg
// pair and return an extracted value. // pair and return an extracted value.
@ -86,16 +150,16 @@ typedef struct ss_plugin_event
// arg_key: the field argument, if a 'key' argument has been specified // arg_key: the field argument, if a 'key' argument has been specified
// for the field (isKey=true), otherwise it's NULL. // for the field (isKey=true), otherwise it's NULL.
// For example: // For example:
// * if the field specified by the user is foo.bar[pippo], arg_key // * if the field specified by the user is foo.bar[pippo], arg_key
// will be the string "pippo" // will be the string "pippo"
// * if the field specified by the user is foo.bar, arg will be NULL // * if the field specified by the user is foo.bar, arg will be NULL
// arg_index: the field argument, if a 'index' argument has been specified // arg_index: the field argument, if a 'index' argument has been specified
// for the field (isIndex=true), otherwise it's 0. // for the field (isIndex=true), otherwise it's 0.
// For example: // For example:
// * if the field specified by the user is foo.bar[1], arg_index // * if the field specified by the user is foo.bar[1], arg_index
// will be the uint64_t '1'. // will be the uint64_t '1'.
// Please note the ambiguity with a 0 // Please note the ambiguity with a 0
// argument which could be a real argument of just the default // argument which could be a real argument of just the default
// value to point out the absence. The `arg_present` field resolves // value to point out the absence. The `arg_present` field resolves
// this ambiguity. // this ambiguity.
// arg_present: helps to understand if the arg is there since arg_index is // arg_present: helps to understand if the arg is there since arg_index is
@ -116,16 +180,17 @@ typedef struct ss_plugin_event
// 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;
ss_plugin_bool* boolean;
ss_plugin_byte_buffer* buf;
} res; } res;
uint64_t res_len; uint64_t res_len;
@ -136,16 +201,77 @@ typedef struct ss_plugin_extract_field
const char* field; const char* field;
const char* arg_key; const char* arg_key;
uint64_t arg_index; uint64_t arg_index;
bool arg_present; ss_plugin_bool arg_present;
uint32_t ftype; uint32_t ftype;
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.
// The noncontinguous numbers are to maintain equality with underlying
// falcosecurity libs types.
// todo(jasondellaluce): should we merge this with ss_plugin_field_type?
typedef enum ss_plugin_state_type {
SS_PLUGIN_ST_INT8 = 1,
SS_PLUGIN_ST_INT16 = 2,
SS_PLUGIN_ST_INT32 = 3,
SS_PLUGIN_ST_INT64 = 4,
SS_PLUGIN_ST_UINT8 = 5,
SS_PLUGIN_ST_UINT16 = 6,
SS_PLUGIN_ST_UINT32 = 7,
SS_PLUGIN_ST_UINT64 = 8,
SS_PLUGIN_ST_STRING = 9,
SS_PLUGIN_ST_TABLE = 10,
SS_PLUGIN_ST_BOOL = 25
} ss_plugin_state_type;
// Data representation of entry fields of state tables.
// todo(jasondellaluce): should we merge this with what we have for field extraction?
typedef union ss_plugin_state_data {
int8_t s8;
int16_t s16;
int32_t s32;
int64_t s64;
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
const char* str;
ss_plugin_bool b;
ss_plugin_table_t* table;
} ss_plugin_state_data;
// Info about a state table.
typedef struct ss_plugin_table_info {
const char* name;
ss_plugin_state_type key_type;
} ss_plugin_table_info;
// Info about a data field contained in the entires of a state table.
typedef struct ss_plugin_table_fieldinfo {
const char* name;
ss_plugin_state_type field_type;
ss_plugin_bool read_only;
} ss_plugin_table_fieldinfo;
// Opaque pointer to the owner of a plugin. It can be used to invert the
// control and invoke functions of the plugin's owner from within the plugin.
typedef void ss_plugin_owner_t;
// //
// This is the opaque pointer to the state of a plugin. // This is the opaque pointer to the state of a plugin.
// It points to any data that might be needed plugin-wise. It is // It points to any data that might be needed plugin-wise. It is
// allocated by init() and must be destroyed by destroy(). // allocated by init() and must be destroyed by destroy().
// It is defined as void because the engine doesn't care what it is // It is defined as void because the framework doesn't care what it is
// and it treats is as opaque. // and it treats is as opaque.
// //
typedef void ss_plugin_t; typedef void ss_plugin_t;
@ -155,11 +281,69 @@ typedef void ss_plugin_t;
// plugin. // plugin.
// It points to any data that is needed while a capture is running. It is // It points to any data that is needed while a capture is running. It is
// allocated by open() and must be destroyed by close(). // allocated by open() and must be destroyed by close().
// It is defined as void because the engine doesn't care what it is // It is defined as void because the framework doesn't care what it is
// and it treats is as opaque. // and it treats is as opaque.
// //
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,5 +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.
@ -48,10 +50,22 @@ const DefaultEvtSize uint32 = 256 * 1024
const DefaultBatchSize uint32 = 128 const DefaultBatchSize uint32 = 128
// The full set of values that can be returned in the ftype // The full set of values that can be returned in the ftype
// member of ss_plugin_extract_field structs. // member of ss_plugin_extract_field structs (ppm_events_public.h).
const ( const (
FieldTypeUint64 uint32 = 8 // A 64bit unsigned integer.
FieldTypeCharBuf uint32 = 9 // A printable buffer of bytes, NULL terminated FieldTypeUint64 uint32 = 8
// A printable buffer of bytes, NULL terminated.
FieldTypeCharBuf uint32 = 9
// A relative time. Seconds * 10^9 + nanoseconds. 64bit.
FieldTypeRelTime uint32 = 20
// An absolute time interval. Seconds from epoch * 10^9 + nanoseconds. 64bit.
FieldTypeAbsTime uint32 = 21
// A boolean value, 4 bytes.
FieldTypeBool uint32 = 25
// Either an IPv4 or IPv6 address. The length indicates which one it is.
FieldTypeIPAddr uint32 = 40
// Either an IPv4 or IPv6 network. The length indicates which one it is.
FieldTypeIPNet uint32 = 41
) )
// FieldEntry represents a single field entry that a plugin with field extraction // FieldEntry represents a single field entry that a plugin with field extraction

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.
@ -38,7 +39,7 @@ import (
) )
//export plugin_event_to_string //export plugin_event_to_string
func plugin_event_to_string(pState C.uintptr_t, evt *C.ss_plugin_event) *C.char { func plugin_event_to_string(pState C.uintptr_t, evt *C.ss_plugin_event_input) *C.char {
buf := cgo.Handle(pState).Value().(sdk.StringerBuffer).StringerBuffer() buf := cgo.Handle(pState).Value().(sdk.StringerBuffer).StringerBuffer()
stringer, ok := cgo.Handle(pState).Value().(sdk.Stringer) stringer, ok := cgo.Handle(pState).Value().(sdk.Stringer)
if ok { if ok {

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.
@ -39,15 +40,16 @@ type sampleEvtStr struct {
expectedData []byte expectedData []byte
} }
func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event, func()) { func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event_input, func()) {
ret := &_Ctype_struct_ss_plugin_event{} ret := &_Ctype_struct_ss_plugin_event_input{}
evts, _ := sdk.NewEventWriters(1, int64(len(data)))
evt := evts.Get(0)
evt.Writer().Write(data)
ret.evt = *(**_Ctype_struct_ss_plugin_event)(evts.ArrayPtr())
ret.evtnum = _Ctype_uint64_t(num) ret.evtnum = _Ctype_uint64_t(num)
ret.ts = _Ctype_uint64_t(ts)
ret.data = (*_Ctype_uint8_t)(&data[0])
ret.datalen = _Ctype_uint32_t(len(data))
return ret, func() { return ret, func() {
// nothing to deallocate here evts.Free()
} }
} }

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.
@ -27,6 +28,8 @@ import (
"github.com/falcosecurity/plugin-sdk-go/pkg/sdk" "github.com/falcosecurity/plugin-sdk-go/pkg/sdk"
) )
const testAsyncMaxPlugins = 32 // note: must be <= cgo.MaxHandle
type sampleAsyncExtract struct { type sampleAsyncExtract struct {
sampleExtract sampleExtract
counter uint64 counter uint64
@ -156,7 +159,7 @@ func TestAsyncExtract(t *testing.T) {
} }
// run with increasing number of concurrent consumers // run with increasing number of concurrent consumers
for i := 1; i <= cgo.MaxHandle; i *= 2 { for i := 1; i <= testAsyncMaxPlugins; i *= 2 {
// run with increasing number of extractions // run with increasing number of extractions
for j := 1; j < 10000; j *= 10 { for j := 1; j < 10000; j *= 10 {
workload(i, j) workload(i, j)
@ -165,64 +168,77 @@ func TestAsyncExtract(t *testing.T) {
} }
func TestStartStopAsync(t *testing.T) { func TestStartStopAsync(t *testing.T) {
nPlugins := cgo.MaxHandle nPlugins := testAsyncMaxPlugins
testWithMockPlugins(nPlugins, func(handles []cgo.Handle) { // checking that an odd or event number of plugins is not relevant
// test unbalanced start/stop calls for i := nPlugins - 1; i <= nPlugins+1; i++ {
assertPanic(t, func() { t.Run(fmt.Sprintf("unbalanced-startstop#%d", i), func(t *testing.T) {
a := asyncContext{} testWithMockPlugins(nPlugins, func(handles []cgo.Handle) {
a.StopAsync(handles[0], testReleaseAsyncBatch) // test unbalanced start/stop calls
}) assertPanic(t, func() {
assertPanic(t, func() { a := asyncContext{}
a := asyncContext{} a.StopAsync(handles[0], testReleaseAsyncBatch)
a.StartAsync(handles[0], testAllocAsyncBatch) })
a.StopAsync(handles[0], testReleaseAsyncBatch) assertPanic(t, func() {
a.StopAsync(handles[0], testReleaseAsyncBatch) a := asyncContext{}
a.StartAsync(handles[0], testAllocAsyncBatch)
a.StopAsync(handles[0], testReleaseAsyncBatch)
a.StopAsync(handles[0], testReleaseAsyncBatch)
})
// test with bad start/stop-handle pair
assertPanic(t, func() {
a := asyncContext{}
a.StartAsync(handles[0], testAllocAsyncBatch)
a.StartAsync(handles[1], testAllocAsyncBatch)
a.StopAsync(handles[0], testReleaseAsyncBatch)
a.StopAsync(handles[0], testReleaseAsyncBatch)
})
})
}) })
// test with bad start/stop-handle pair t.Run(fmt.Sprintf("inconsistent-async#%d", i), func(t *testing.T) {
assertPanic(t, func() { testWithMockPlugins(nPlugins, func(handles []cgo.Handle) {
a := asyncContext{} // test with inconsistent enabled values
a.StartAsync(handles[0], testAllocAsyncBatch) a := asyncContext{}
a.StartAsync(handles[1], testAllocAsyncBatch) enabled := false
a.StopAsync(handles[0], testReleaseAsyncBatch) for i := 0; i < nPlugins; i++ {
a.StopAsync(handles[0], testReleaseAsyncBatch) a.SetAsync(enabled)
}) a.StartAsync(handles[i], testAllocAsyncBatch)
enabled = !enabled
// test with inconsistent enabled values
a := asyncContext{}
enabled := true
for i := 0; i < nPlugins; i++ {
a.SetAsync(enabled)
a.StartAsync(handles[i], testAllocAsyncBatch)
enabled = !enabled
}
for i := 0; i < nPlugins; i++ {
a.StopAsync(handles[i], testReleaseAsyncBatch)
}
// test workload after already having started/stopped the same context
var wg sync.WaitGroup
for _, h := range handles {
wg.Add(1)
a.StartAsync(h, testAllocAsyncBatch)
go func(h cgo.Handle) {
counter := uint64(0)
field, freeField := allocSSPluginExtractField(1, sdk.FieldTypeUint64, "", "")
defer freeField()
for e := 0; e < 1000; e++ {
testSimulateAsyncRequest(t, &a, h, field)
value := **((**uint64)(unsafe.Pointer(&field.res[0])))
if value != counter {
panic(fmt.Sprintf("extracted %d but expected %d", value, counter))
}
counter++
} }
wg.Done() for i := 0; i < nPlugins; i++ {
}(h) a.StopAsync(handles[i], testReleaseAsyncBatch)
} }
wg.Wait()
for _, h := range handles { // test workload after already having started/stopped the same context
a.StopAsync(h, testReleaseAsyncBatch) var wg sync.WaitGroup
} for _, h := range handles {
}) wg.Add(1)
a.SetAsync(enabled)
a.StartAsync(h, testAllocAsyncBatch)
go func(h cgo.Handle, enabled bool) {
counter := uint64(0)
field, freeField := allocSSPluginExtractField(1, sdk.FieldTypeUint64, "", "")
defer freeField()
for e := 0; e < 1000; e++ {
if enabled {
testSimulateAsyncRequest(t, &a, h, field)
value := **((**uint64)(unsafe.Pointer(&field.res[0])))
if value != counter {
panic(fmt.Sprintf("extracted %d but expected %d", value, counter))
}
}
counter++
}
wg.Done()
}(h, enabled)
enabled = !enabled
}
wg.Wait()
for _, h := range handles {
a.StopAsync(h, testReleaseAsyncBatch)
}
})
})
}
} }

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.
@ -52,17 +53,17 @@ void async_deinit()
// Defined in extract.go // Defined in extract.go
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 *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
// calls the synchronous extractor function. // calls the synchronous extractor function.
FALCO_PLUGIN_SDK_PUBLIC int32_t plugin_extract_fields(ss_plugin_t *s, FALCO_PLUGIN_SDK_PUBLIC int32_t plugin_extract_fields(ss_plugin_t *s,
const ss_plugin_event *evt, const ss_plugin_event_input *evt,
uint32_t num_fields, const ss_plugin_field_extract_input* in)
ss_plugin_extract_field *fields)
{ {
// note: concurrent requests are supported on the context batch, but each // note: concurrent requests are supported on the context batch, but each
// slot with a different value of ss_plugin_t *s. As such, for each lock // slot with a different value of ss_plugin_t *s. As such, for each lock
@ -78,14 +79,15 @@ 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, num_fields, fields); return plugin_extract_fields_sync(s, evt, in->num_fields, in->fields, in->value_offsets);
} }
// Set input data // Set input data
s_async_ctx_batch[(size_t)s - 1].s = s; s_async_ctx_batch[(size_t)s - 1].s = 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 = num_fields; s_async_ctx_batch[(size_t)s - 1].num_fields = in->num_fields;
s_async_ctx_batch[(size_t)s - 1].fields = 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, 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.
@ -17,7 +18,7 @@ limitations under the License.
#pragma once #pragma once
#include <stdatomic.h> #include <stdatomic.h>
#include "../../plugin_types.h" #include "../../plugin_api.h"
typedef struct async_extractor_info typedef struct async_extractor_info
{ {
@ -26,9 +27,10 @@ typedef struct async_extractor_info
// input data // input data
ss_plugin_t *s; ss_plugin_t *s;
const ss_plugin_event *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,15 +77,24 @@ func allocSSPluginExtractField(fid, ftype uint32, fname, farg string) (*_Ctype_s
} }
} }
func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event, func()) { func allocSSPluginExtractValueOffsets(start *uint32, length *uint32) (*_Ctype_ss_plugin_extract_value_offsets) {
ret := &_Ctype_struct_ss_plugin_event{} ret := &_Ctype_ss_plugin_extract_value_offsets{}
ret.start = (*_Ctype_uint32_t)(start)
ret.length = (*_Ctype_uint32_t)(length)
return ret
}
func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event_input, func()) {
ret := &_Ctype_struct_ss_plugin_event_input{}
evts, _ := sdk.NewEventWriters(1, int64(len(data)))
evt := evts.Get(0)
evt.Writer().Write(data)
ret.evt = *(**_Ctype_struct_ss_plugin_event)(evts.ArrayPtr())
ret.evtnum = _Ctype_uint64_t(num) ret.evtnum = _Ctype_uint64_t(num)
ret.ts = _Ctype_uint64_t(ts)
ret.data = (*_Ctype_uint8_t)(&data[0])
ret.datalen = _Ctype_uint32_t(len(data))
return ret, func() { return ret, func() {
// nothing to deallocate here evts.Free()
} }
} }
@ -116,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 {
@ -129,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.
@ -53,4 +54,4 @@ int sync_benchmark(int n, int input)
int do_work_c(int i) int do_work_c(int i)
{ {
return i + 1; return i + 1;
} }

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.
@ -36,4 +37,4 @@ void data_request(atomic_int_least32_t *lock);
void async_benchmark(int32_t *lock, int n); void async_benchmark(int32_t *lock, int n);
int sync_benchmark(int n, int input); int sync_benchmark(int n, int input);
int do_work_c(int i); int do_work_c(int i);

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.
@ -21,4 +22,13 @@ limitations under the License.
const char* get_default_required_api_version() const char* get_default_required_api_version()
{ {
return PLUGIN_API_VERSION_STR; return PLUGIN_API_VERSION_STR;
} }
// todo(jasondellaluce,therealbobo): support this for real when we decide to
// deal with non-plugin events in the SDK Go
uint16_t* plugin_get_extract_event_types(uint32_t* num_types)
{
static uint16_t types[] = { 322 }; // PPME_PLUGINEVENT_E
*num_types = sizeof(types) / sizeof(uint16_t);
return &types[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.
@ -16,15 +17,16 @@ limitations under the License.
// This package exports a set of C functions that provide general // This package exports a set of C functions that provide general
// information about the plugin. The exported functions are: // information about the plugin. The exported functions are:
// uint32_t get_type(); //
// uint32_t get_id(); // uint32_t get_type();
// char* get_name(); // uint32_t get_id();
// char* get_description(); // char* get_name();
// char* get_contact(); // char* get_description();
// char* get_version(); // char* get_contact();
// char* get_required_api_version(); // char* get_version();
// char* get_event_source(); // char* get_required_api_version();
// char* get_extract_event_sources(); // char* get_event_source();
// char* get_extract_event_sources();
// //
// In almost all cases, your plugin should import this module, unless // In almost all cases, your plugin should import this module, unless
// your plugin exports those symbols by other means. // your plugin exports those symbols by other means.
@ -36,6 +38,7 @@ package info
import "C" import "C"
import ( import (
"encoding/json" "encoding/json"
"strings"
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr" "github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
) )
@ -105,7 +108,33 @@ func plugin_get_required_api_version() *C.char {
return (*C.char)(pRequiredAPIVersion.CharPtr()) return (*C.char)(pRequiredAPIVersion.CharPtr())
} }
func splitVersionString(version string) (string, string, string) {
nums := strings.Split(version, ".")
if len(nums) != 3 {
panic("Incorrect format. Expected: Semantic Versioning: X.Y.Z")
}
return nums[0], nums[1], nums[2]
}
func SetRequiredAPIVersion(apiVer string) { func SetRequiredAPIVersion(apiVer string) {
if apiVer != "" {
pluginRequiredMajor, pluginRequiredMinor, pluginRequiredPatch := splitVersionString(apiVer)
sdkRequiredMajor, sdkRequiredMinor, sdkRequiredPatch := splitVersionString(C.GoString(C.get_default_required_api_version()))
// The plugin should always require a version lower or equal to the one required by the SDK
// because the SDK couldn't support features coming from new framework versions.
// On the other side the plugin could require a lower version because maybe it doesn't
// need all features provided by the framework.
if sdkRequiredMajor != pluginRequiredMajor {
panic("Incompatible required Major version between SDK and the plugin. Major SDK version is equal to " + sdkRequiredMajor + " but the plugin uses " + pluginRequiredMajor + ". The 2 Major versions should be equal.")
}
if sdkRequiredMinor < pluginRequiredMinor {
panic("The plugin requires a Minor version greater than the SDK one. Minor SDK version is equal to " + sdkRequiredMinor + " but the plugin uses " + pluginRequiredMinor + ". The plugin should always require a Minor version lower or equal to the SDK one.")
}
if sdkRequiredMinor == pluginRequiredMinor && sdkRequiredPatch < pluginRequiredPatch {
panic("The plugin requires a Patch version greater than the SDK one. Patch SDK version is equal to " + sdkRequiredPatch + " but the plugin uses " + pluginRequiredPatch + ". The plugin should always require a Patch version lower or equal to the SDK one.")
}
}
pRequiredAPIVersion.Write(apiVer) pRequiredAPIVersion.Write(apiVer)
} }

View File

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

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/* /*
Copyright (C) 2021 The Falco Authors. Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -18,16 +19,22 @@ package info
import ( import (
"encoding/json" "encoding/json"
"fmt"
"testing" "testing"
"unsafe" "unsafe"
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr" "github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
"github.com/stretchr/testify/assert"
) )
var testStr = "test" var testStr = "test"
var testU32 = uint32(1) var testU32 = uint32(1)
var testStrSlice = []string{"hello", "world"} var testStrSlice = []string{"hello", "world"}
func testFormatVer(major, minor, patch int) string {
return fmt.Sprintf("%d.%d.%d", major, minor, patch)
}
func TestInfo(t *testing.T) { func TestInfo(t *testing.T) {
var resU32 uint32 var resU32 uint32
var resStr string var resStr string
@ -36,7 +43,7 @@ func TestInfo(t *testing.T) {
SetId(testU32) SetId(testU32)
resU32 = plugin_get_id() resU32 = plugin_get_id()
if resU32 != testU32 { if resU32 != testU32 {
t.Errorf("(id) expected %d, but found %d", testU32, resU32) t.Errorf("(plugin id) expected %d, but found %d", testU32, resU32)
} }
SetName(testStr) SetName(testStr)
@ -63,12 +70,6 @@ func TestInfo(t *testing.T) {
t.Errorf("(version) expected %s, but found %s", testStr, resStr) t.Errorf("(version) expected %s, but found %s", testStr, resStr)
} }
SetRequiredAPIVersion(testStr)
resStr = ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
if resStr != testStr {
t.Errorf("(requiredApiVersion) expected %s, but found %s", testStr, resStr)
}
SetEventSource(testStr) SetEventSource(testStr)
resStr = ptr.GoString(unsafe.Pointer(plugin_get_event_source())) resStr = ptr.GoString(unsafe.Pointer(plugin_get_event_source()))
if resStr != testStr { if resStr != testStr {
@ -102,3 +103,109 @@ func TestInfo(t *testing.T) {
t.Errorf("(extractEventSources) expected %s, but found %s", testStr, resStr) t.Errorf("(extractEventSources) expected %s, but found %s", testStr, resStr)
} }
} }
func TestSplitVersionString(t *testing.T) {
t.Run("invalid version string 1", func(t *testing.T) {
panicFunc := func() {
splitVersionString("2..1..2")
}
assert.Panics(t, panicFunc)
})
t.Run("invalid version string 2", func(t *testing.T) {
panicFunc := func() {
splitVersionString("2.2.3..32")
}
assert.Panics(t, panicFunc)
})
t.Run("invalid version string 3", func(t *testing.T) {
panicFunc := func() {
splitVersionString("2.2.3.")
}
assert.Panics(t, panicFunc)
})
t.Run("invalid version string 4", func(t *testing.T) {
panicFunc := func() {
splitVersionString("2..2.3")
}
assert.Panics(t, panicFunc)
})
t.Run("valid version string", func(t *testing.T) {
panicFunc := func() {
splitVersionString("2.2.3")
}
assert.NotPanics(t, panicFunc)
})
t.Run("check split version string", func(t *testing.T) {
major, minor, patch := splitVersionString("2.4.3")
if major != "2" {
t.Errorf("(Major) expected %s, but found %s", "2", major)
}
if minor != "4" {
t.Errorf("(Minor) expected %s, but found %s", "4", minor)
}
if patch != "3" {
t.Errorf("(Patch) expected %s, but found %s", "3", patch)
}
})
}
func TestSemver(t *testing.T) {
// Get the SDK required version
// we set an empty string to obtain the default SDK version
SetRequiredAPIVersion("")
versionSDK := ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
var majorSDK, minorSDK, patchSDK int
nums, err := fmt.Sscanf(versionSDK, "%d.%d.%d", &majorSDK, &minorSDK, &patchSDK)
if nums != 3 || err != nil {
t.Errorf("Unable to obtain the default SDK version")
}
// plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch == SDK Patch
t.Run("plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch == SDK Patch", func(t *testing.T) {
SetRequiredAPIVersion(testFormatVer(majorSDK, minorSDK, patchSDK))
requiredAPIVersion := ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
expectedRequiredAPIVersion := testFormatVer(majorSDK, minorSDK, patchSDK)
if expectedRequiredAPIVersion != requiredAPIVersion {
t.Errorf("(requiredApiVersion) expected %s, but found %s", expectedRequiredAPIVersion, requiredAPIVersion)
}
})
// plguin Major > SDK Major
t.Run("plguin Major > SDK Major", func(t *testing.T) {
panicFunc := func() {
SetRequiredAPIVersion(testFormatVer(majorSDK+1, minorSDK, patchSDK))
}
assert.PanicsWithValue(t, fmt.Sprintf("Incompatible required Major version between SDK and the plugin. Major SDK version is equal to %d but the plugin uses %d. The 2 Major versions should be equal.", majorSDK, majorSDK+1), panicFunc)
})
// plguin Major == SDK Major && plguin Minor > SDK Minor
t.Run("plguin Major == SDK Major && plguin Minor > SDK Minor", func(t *testing.T) {
panicFunc := func() {
SetRequiredAPIVersion(testFormatVer(majorSDK, minorSDK+1, patchSDK))
}
assert.PanicsWithValue(t, fmt.Sprintf("The plugin requires a Minor version greater than the SDK one. Minor SDK version is equal to %d but the plugin uses %d. The plugin should always require a Minor version lower or equal to the SDK one.", minorSDK, minorSDK+1), panicFunc)
})
// plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch > SDK Patch
t.Run("plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch > SDK Patch", func(t *testing.T) {
panicFunc := func() {
SetRequiredAPIVersion(testFormatVer(majorSDK, minorSDK, patchSDK+1))
}
assert.PanicsWithValue(t, fmt.Sprintf("The plugin requires a Patch version greater than the SDK one. Patch SDK version is equal to %d but the plugin uses %d. The plugin should always require a Patch version lower or equal to the SDK one.", patchSDK, patchSDK+1), panicFunc)
})
t.Run("empty plugin version", func(t *testing.T) {
// This should set as default the SDK required version since we don't provide the required plugin version
SetRequiredAPIVersion("")
requiredAPIVersion := ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
expectedRequiredAPIVersion := testFormatVer(majorSDK, minorSDK, patchSDK)
if expectedRequiredAPIVersion != requiredAPIVersion {
t.Errorf("(requiredApiVersion) expected %s, but found %s", expectedRequiredAPIVersion, requiredAPIVersion)
}
})
}

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.
@ -38,7 +39,7 @@ limitations under the License.
package initialize package initialize
/* /*
#include <stdint.h> #include "../../plugin_api.h"
*/ */
import "C" import "C"
import ( import (
@ -82,11 +83,12 @@ func SetOnInit(fn OnInitFn) {
} }
//export plugin_init //export plugin_init
func plugin_init(config *C.char, rc *int32) C.uintptr_t { func plugin_init(in *C.ss_plugin_init_input, rc *int32) C.uintptr_t {
var state sdk.PluginState var state sdk.PluginState
var err error var err error
state, err = onInitFn(C.GoString(config)) // todo(jasondellaluce,therealbobo): support table access and owner operations
state, err = onInitFn(C.GoString(in.config))
if err != nil { if err != nil {
state = &baseInit{} state = &baseInit{}
state.(sdk.LastError).SetLastError(err) state.(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.
@ -80,7 +81,16 @@ func TestInitialize(t *testing.T) {
SetOnInit(func(config string) (sdk.PluginState, error) { SetOnInit(func(config string) (sdk.PluginState, error) {
return nil, nil return nil, nil
}) })
handle = cgo.Handle(plugin_init((*_Ctype_char)(cStr.CharPtr()), &res))
// create an init input
var in _Ctype_struct_ss_plugin_init_input
in.config = nil
in.owner = nil
in.get_owner_last_error = nil
in.tables = nil
in.config = (*_Ctype_char)(cStr.CharPtr())
handle = cgo.Handle(plugin_init(&in, &res))
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 handle.Value() != nil { } else if handle.Value() != nil {
@ -92,7 +102,8 @@ func TestInitialize(t *testing.T) {
SetOnInit(func(config string) (sdk.PluginState, error) { SetOnInit(func(config string) (sdk.PluginState, error) {
return nil, errTest return nil, errTest
}) })
handle = cgo.Handle(plugin_init((*_Ctype_char)(cStr.CharPtr()), &res)) in.config = (*_Ctype_char)(cStr.CharPtr())
handle = cgo.Handle(plugin_init(&in, &res))
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)
} }
@ -109,7 +120,8 @@ func TestInitialize(t *testing.T) {
SetOnInit(func(config string) (sdk.PluginState, error) { SetOnInit(func(config string) (sdk.PluginState, error) {
return state, nil return state, nil
}) })
handle = cgo.Handle(plugin_init((*_Ctype_char)(cStr.CharPtr()), &res)) in.config = (*_Ctype_char)(cStr.CharPtr())
handle = cgo.Handle(plugin_init(&in, &res))
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 handle.Value() != state { } else if handle.Value() != state {

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.
@ -15,7 +16,7 @@ limitations under the License.
*/ */
// This package exports the following C function: // This package exports the following C function:
// - ss_plugin_rc plugin_next_batch(ss_plugin_t* s, ss_instance_t* h, uint32_t *nevts, ss_plugin_event **evts) // - ss_plugin_rc plugin_next_batch(ss_plugin_t* s, ss_instance_t* h, uint32_t *nevts, ss_plugin_event ***evts)
// //
// The exported plugin_next_batch requires s and h to be a handles // The exported plugin_next_batch requires s and h to be a handles
// of cgo.Handle from this SDK. The value of the s handle must implement // of cgo.Handle from this SDK. The value of the s handle must implement
@ -37,12 +38,12 @@ import (
) )
//export plugin_next_batch //export plugin_next_batch
func plugin_next_batch(pState C.uintptr_t, iState C.uintptr_t, nevts *uint32, retEvts **C.ss_plugin_event) int32 { func plugin_next_batch(pState C.uintptr_t, iState C.uintptr_t, nevts *uint32, retEvts ***C.ss_plugin_event) int32 {
events := cgo.Handle(iState).Value().(sdk.Events).Events() events := cgo.Handle(iState).Value().(sdk.Events).Events()
n, err := cgo.Handle(iState).Value().(sdk.NextBatcher).NextBatch(cgo.Handle(pState).Value().(sdk.PluginState), events) n, err := cgo.Handle(iState).Value().(sdk.NextBatcher).NextBatch(cgo.Handle(pState).Value().(sdk.PluginState), events)
*nevts = uint32(n) *nevts = uint32(n)
*retEvts = (*C.ss_plugin_event)(events.ArrayPtr()) *retEvts = (**C.ss_plugin_event)(events.ArrayPtr())
switch err { switch err {
case nil: case nil:
return sdk.SSPluginSuccess return sdk.SSPluginSuccess

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.
@ -68,7 +69,7 @@ func TestNextBatch(t *testing.T) {
// generic testing callback // generic testing callback
doTest := func(name string, res int32, num uint32, ptr unsafe.Pointer, err error) { doTest := func(name string, res int32, num uint32, ptr unsafe.Pointer, err error) {
var resNum uint32 var resNum uint32
var resPtr *_Ctype_ss_plugin_event var resPtr **_Ctype_ss_plugin_event
r := plugin_next_batch(_Ctype_uintptr_t(handle), _Ctype_uintptr_t(handle), &resNum, &resPtr) r := plugin_next_batch(_Ctype_uintptr_t(handle), _Ctype_uintptr_t(handle), &resNum, &resPtr)
if r != res { if r != res {
t.Errorf("(%s - res): expected %d, but found %d", name, res, r) t.Errorf("(%s - res): expected %d, but found %d", name, res, r)

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.