Compare commits

...

76 Commits
v0.6.2 ... 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
98 changed files with 2807 additions and 595 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"
on:
push:
branches: [ main ]
branches:
- main
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
branches:
- main
schedule:
- cron: '45 5 * * 2'
@ -32,40 +22,21 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# 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
language:
- 'go'
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
with:
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
uses: github/codeql-action/autobuild@v1
# 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
uses: github/codeql-action/autobuild@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
- 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:
release:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v3
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: 1.17
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0
with:
distribution: goreleaser
version: v1.10.3
args: release --rm-dist --timeout 60m
args: release --clean --timeout 60m
env:
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
build:
skip: true
version: 2
builds:
- skip: true
release:
github:
github: {}
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
# the License. You may obtain a copy of the License at
@ -13,8 +14,9 @@
SHELL := /bin/bash
GO ?= $(shell which go)
CURL ?= $(shell which curl)
PATCH ?= $(shell which patch)
FALCOSECURITY_LIBS_REVISION ?= 000eb27573af74168510e4836330ff6958c3f355
FALCOSECURITY_LIBS_REVISION ?= 0.21.0
FALCOSECURITY_LIBS_REPO ?= falcosecurity/libs
PLUGINLIB_URL=https://raw.githubusercontent.com/${FALCOSECURITY_LIBS_REPO}/${FALCOSECURITY_LIBS_REVISION}/userspace/plugin
@ -30,13 +32,16 @@ clean: clean-pluginlib $(examples_clean)
.PHONY: pluginlib
pluginlib:
@$(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/loader/plugin_loader.h $(PLUGINLIB_URL)/plugin_loader.h
@$(CURL) -Lso pkg/loader/plugin_loader.c $(PLUGINLIB_URL)/plugin_loader.c
$(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/loader/plugin_loader.h $(PLUGINLIB_URL)/plugin_loader.h
$(CURL) -Lso pkg/loader/plugin_loader.c $(PLUGINLIB_URL)/plugin_loader.c
$(PATCH) -p1 < pkg/loader/plugin_api_include.patch
$(PATCH) -p1 < pkg/loader/strlcpy.patch
$(PATCH) -p1 < pkg/sdk/plugin_types_include.patch
clean-pluginlib:
@rm -f \
rm -f \
pkg/sdk/plugin_types.h \
pkg/sdk/plugin_api.h \
pkg/loader/plugin_loader.h \

1
OWNERS
View File

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

View File

@ -1,12 +1,10 @@
# 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)
[![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)
[![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

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
# the License. You may obtain a copy of the License at
@ -25,5 +26,5 @@ clean:
$(OUTPUT): bench.cpp bench.go
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)

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 the License.
@ -23,14 +24,14 @@ limitations under the License.
#include <vector>
#include <string>
#include "../../pkg/sdk/plugin_types.h"
#include "../../pkg/sdk/plugin_api.h"
// defined in Go and exported from bench.go
extern "C"
{
void plugin_destroy(ss_plugin_t*);
ss_plugin_t* plugin_init(const char*, ss_plugin_rc*);
ss_plugin_rc plugin_extract_fields(ss_plugin_t*, const ss_plugin_event*, uint32_t, ss_plugin_extract_field*);
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_input*, const ss_plugin_field_extract_input*);
}
// global benchmark options
@ -111,13 +112,16 @@ static void benchmark(ss_plugin_t *plugin) noexcept
e.arg_present = false;
e.ftype = FTYPE_UINT64;
e.flist = false;
ss_plugin_field_extract_input in;
in.fields = &e;
in.num_fields = 1;
// request multiple extractions and compute total execution time
auto start = std::chrono::high_resolution_clock::now();
ss_plugin_rc rc = SS_PLUGIN_FAILURE;
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)
{
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)
{
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)
{
fprintf(stderr, "can't initialize plugin");
@ -166,4 +172,4 @@ int main(int argc, char** argv)
}
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");
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.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/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.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-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
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=
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
# the License. You may obtain a copy of the License at
@ -23,4 +24,4 @@ clean:
@rm -f *.so *.h
$(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");
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.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/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.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-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
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=
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
# the License. You may obtain a copy of the License at
@ -23,4 +24,4 @@ clean:
@rm -f *.so *.h
$(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");
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.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/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.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-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
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=
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
# the License. You may obtain a copy of the License at
@ -23,4 +24,4 @@ clean:
@rm -f *.so *.h
$(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");
you may not use this file except in compliance with the License.
@ -28,6 +29,7 @@ import (
"encoding/gob"
"encoding/json"
"fmt"
"net"
"time"
"github.com/alecthomas/jsonschema"
@ -54,7 +56,8 @@ type MyPluginConfig struct {
// State variables to store in the plugin must be defined here.
type MyPlugin struct {
plugins.BasePlugin
config MyPluginConfig
config MyPluginConfig
initTime time.Time
}
// 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.
// This method is mandatory.
func (m *MyPlugin) Init(config string) error {
m.initTime = time.Now()
// Deserialize the config json. Ignoring the error
// and not validating the config values is possible
// due to the schema defined through InitSchema(),
@ -143,6 +147,13 @@ func (m *MyPlugin) Fields() []sdk.FieldEntry {
return []sdk.FieldEntry{
{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: "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
}
switch req.FieldID() {
case 0:
switch req.Field() {
case "example.count":
req.SetValue(value)
return nil
case 1:
case "example.countstr":
req.SetValue(fmt.Sprintf("%d", value))
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:
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
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
)

View File

@ -1,16 +1,27 @@
github.com/alecthomas/jsonschema v0.0.0-20211228220459-151e3c21f49d h1:4BQNwS4T13UU3Yee4GfzZH3Q9SNpKeJvLigfw8fDjX0=
github.com/alecthomas/jsonschema v0.0.0-20211228220459-151e3c21f49d/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b h1:doCpXjVwui6HUN+xgNsNS3SZ0/jUZ68Eb+mJRNOZfog=
github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
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/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
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/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.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.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-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
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=
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
# the License. You may obtain a copy of the License at
@ -23,5 +24,5 @@ clean:
@rm -f *.so *.h
$(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.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/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.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-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
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=
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");
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
go 1.15
go 1.17
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
)
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.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/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.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-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
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/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
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 the License.
@ -16,6 +17,12 @@ limitations under the License.
package cgo
import (
"fmt"
"sync/atomic"
"unsafe"
)
// Handle is an alternative implementation of cgo.Handle introduced by
// Go 1.17, see https://pkg.go.dev/runtime/cgo. This implementation
// optimizes performance in use cases related to plugins. It is intended
@ -42,12 +49,18 @@ package cgo
// The usage in other contexts is discuraged.
type Handle uintptr
// MaxHandle is the largest value that an Handle can hold
const MaxHandle = 256 - 1
const (
// 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 (
handles [MaxHandle + 1]interface{} // [int]interface{}
noHandle int = 0
handles [MaxHandle + 1]unsafe.Pointer // [int]*interface{}
noHandle unsafe.Pointer = nil
)
func init() {
@ -71,13 +84,30 @@ func init() {
//
// This function is not thread-safe.
func NewHandle(v interface{}) Handle {
for i := 1; i <= MaxHandle; i++ {
if handles[i] == &noHandle {
handles[i] = v
return Handle(i)
rounds := 0
for h := uintptr(1); ; h++ {
// we acquired ownership of an handle, return it
// 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.
@ -85,10 +115,10 @@ func NewHandle(v interface{}) Handle {
// The method panics if the handle is invalid.
// This function is not thread-safe.
func (h Handle) Value() interface{} {
if h > MaxHandle || handles[h] == &noHandle {
panic("plugin-sdk-go/cgo: misuse of an invalid Handle")
if h > MaxHandle || atomic.LoadPointer(&handles[h]) == noHandle {
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
@ -98,14 +128,14 @@ func (h Handle) Value() interface{} {
// The method panics if the handle is invalid.
// This function is not thread-safe.
func (h Handle) Delete() {
if h > MaxHandle || handles[h] == &noHandle {
panic("plugin-sdk-go/cgo: misuse of an invalid Handle")
if h > MaxHandle || atomic.LoadPointer(&handles[h]) == noHandle {
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() {
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");
you may not use this file except in compliance with the License.
@ -18,6 +19,7 @@ package cgo
import (
"reflect"
"sync/atomic"
"testing"
)
@ -60,7 +62,7 @@ func TestHandle(t *testing.T) {
siz := 0
for i := 0; i < MaxHandle; i++ {
if handles[i] != &noHandle {
if atomic.LoadPointer(&handles[i]) != noHandle {
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");
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);
}
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)
@ -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);
}
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);
}
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);
}
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"
)
// 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 (
errNotInitialized = errors.New("plugin is not initialized")
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
// dynamic library
type Plugin struct {
m sync.Mutex
handle *C.plugin_handle_t
state *C.ss_plugin_t
caps C.plugin_caps_t
info plugins.Info
initSchema *sdk.SchemaInfo
fields []sdk.FieldEntry
validated bool
validErr error
m sync.Mutex
handle *C.plugin_handle_t
state *C.ss_plugin_t
caps C.plugin_caps_t
info plugins.Info
initSchema *sdk.SchemaInfo
fields []sdk.FieldEntry
validated bool
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
@ -170,7 +188,10 @@ func NewPlugin(path string) (*Plugin, error) {
}
// 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)
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)),
Name: C.GoString(C.__get_info_str(p.handle.api.get_name)),
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)),
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{},
}
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)
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() {
// 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))
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
@ -234,9 +259,9 @@ func (p *Plugin) validate() error {
p.validErr = errors.New(C.GoString(errBuf))
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")
return p.validErr
return errAppend(p.validErr, p.capBrokenErr)
}
p.validated = true
}
@ -252,6 +277,16 @@ func (p *Plugin) Validate() error {
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
// field extraction capability.
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())
}
// 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)
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) {
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");
you may not use this file except in compliance with the License.
@ -16,117 +17,210 @@ limitations under the License.
*/
#ifdef _WIN32
#include <windows.h>
typedef HINSTANCE library_handle_t;
#include <windows.h>
typedef HINSTANCE library_handle_t;
#else
#include <dlfcn.h>
typedef void* library_handle_t;
#include <dlfcn.h>
typedef void* library_handle_t;
#endif
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "plugin_loader.h"
static inline void add_str_prefix(char* s, const char* prefix)
{
char tmp[PLUGIN_MAX_ERRLEN];
strncpy(tmp, prefix, PLUGIN_MAX_ERRLEN - 1);
strncat(tmp, s, PLUGIN_MAX_ERRLEN - 1);
strcpy(s, tmp);
// 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 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
return (void*) GetProcAddress(handle, name);
return (void*)GetProcAddress(handle, name);
#else
return (void*) dlsym(handle, name);
return (void*)dlsym(handle, name);
#endif
}
// little hack for simplifying the plugin_load function
#define SYM_RESOLVE(h, s) \
*(void **)(&(h->api.s)) = getsym(h->handle, "plugin_"#s)
#define SYM_RESOLVE(h, s) *(void**)(&(h->api.s)) = getsym(h->handle, "plugin_" #s)
plugin_handle_t* plugin_load(const char* path, char* err)
{
// alloc and init memory
strcpy(err, "");
plugin_handle_t* ret = (plugin_handle_t*) calloc (1, sizeof(plugin_handle_t));
plugin_handle_t* plugin_load(const char* path, char* err) {
// alloc and init memory
err[0] = '\0';
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
if(!ret) {
plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
return NULL;
}
// open dynamic library
// open dynamic library
#ifdef _WIN32
ret->handle = LoadLibrary(path);
if(ret->handle == NULL)
{
DWORD flg = FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS;
LPTSTR msg_buf = 0;
if (FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR) &msg_buf, 0, NULL) && msg_buf)
{
strncpy(err, msg_buf, PLUGIN_MAX_ERRLEN -1 );
LocalFree(msg_buf);
}
}
ret->handle = LoadLibrary(path);
if(ret->handle == NULL) {
DWORD flg = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS;
LPTSTR msg_buf = 0;
if(FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR)&msg_buf, 0, NULL) && msg_buf) {
plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
LocalFree(msg_buf);
}
}
#else
ret->handle = dlopen(path, RTLD_LAZY);
if (ret->handle == NULL)
{
strncpy(err, (const char*) dlerror(), PLUGIN_MAX_ERRLEN - 1);
}
ret->handle = dlopen(path, RTLD_LAZY);
if(ret->handle == NULL) {
plugin_loader_strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
}
#endif
// return NULL if library loading had errors
if (ret->handle == NULL)
{
add_str_prefix(err, "can't load plugin dynamic library: ");
free(ret);
return NULL;
}
// return NULL if library loading had errors
if(ret->handle == NULL) {
err_prepend(err, "can't load plugin dynamic library:", " ");
free(ret);
return NULL;
}
// load all library symbols
SYM_RESOLVE(ret, get_required_api_version);
SYM_RESOLVE(ret, get_version);
SYM_RESOLVE(ret, get_last_error);
SYM_RESOLVE(ret, get_name);
SYM_RESOLVE(ret, get_description);
SYM_RESOLVE(ret, get_contact);
SYM_RESOLVE(ret, get_init_schema);
SYM_RESOLVE(ret, init);
SYM_RESOLVE(ret, destroy);
SYM_RESOLVE(ret, get_id);
SYM_RESOLVE(ret, get_event_source);
SYM_RESOLVE(ret, open);
SYM_RESOLVE(ret, close);
SYM_RESOLVE(ret, next_batch);
SYM_RESOLVE(ret, get_progress);
SYM_RESOLVE(ret, list_open_params);
SYM_RESOLVE(ret, event_to_string);
SYM_RESOLVE(ret, get_fields);
SYM_RESOLVE(ret, extract_fields);
SYM_RESOLVE(ret, get_extract_event_sources);
return ret;
// load all library symbols
SYM_RESOLVE(ret, get_required_api_version);
SYM_RESOLVE(ret, get_version);
SYM_RESOLVE(ret, get_last_error);
SYM_RESOLVE(ret, get_name);
SYM_RESOLVE(ret, get_description);
SYM_RESOLVE(ret, get_contact);
SYM_RESOLVE(ret, get_init_schema);
SYM_RESOLVE(ret, init);
SYM_RESOLVE(ret, destroy);
SYM_RESOLVE(ret, get_id);
SYM_RESOLVE(ret, get_event_source);
SYM_RESOLVE(ret, open);
SYM_RESOLVE(ret, close);
SYM_RESOLVE(ret, next_batch);
SYM_RESOLVE(ret, get_progress);
SYM_RESOLVE(ret, list_open_params);
SYM_RESOLVE(ret, event_to_string);
SYM_RESOLVE(ret, get_fields);
SYM_RESOLVE(ret, extract_fields);
SYM_RESOLVE(ret, get_extract_event_sources);
SYM_RESOLVE(ret, get_extract_event_types);
SYM_RESOLVE(ret, get_parse_event_types);
SYM_RESOLVE(ret, get_parse_event_sources);
SYM_RESOLVE(ret, parse_event);
SYM_RESOLVE(ret, get_async_event_sources);
SYM_RESOLVE(ret, get_async_events);
SYM_RESOLVE(ret, set_async_event_handler);
SYM_RESOLVE(ret, dump_state);
SYM_RESOLVE(ret, set_config);
SYM_RESOLVE(ret, get_metrics);
SYM_RESOLVE(ret, capture_open);
SYM_RESOLVE(ret, capture_close);
return ret;
}
void plugin_unload(plugin_handle_t* h)
{
if (h)
{
if (h->handle)
{
plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
// alloc and init memory
err[0] = '\0';
if(!api) {
plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
return NULL;
}
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
if(!ret) {
plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
return NULL;
}
ret->api = *api;
// 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
FreeLibrary(h->handle);
FreeLibrary(h->handle);
#else
dlclose(h->handle);
dlclose(h->handle);
#endif
}
free(h);
}
}
free(h);
}
}
bool plugin_is_loaded(const char* path)
{
bool plugin_is_loaded(const char* path) {
#ifdef _WIN32
/*
* LoadLibrary maps the module into the address space of the calling process, if necessary,
@ -149,89 +243,125 @@ bool plugin_is_loaded(const char* path)
#endif
}
bool plugin_check_required_api_version(const plugin_handle_t* h, char* err)
{
uint32_t major, minor, patch;
const char *ver, *failmsg;
if (h->api.get_required_api_version == NULL)
{
strncpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN - 1);
return false;
}
bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) {
uint32_t major, minor, patch;
const char *ver, *failmsg;
if(h->api.get_required_api_version == NULL) {
plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
return false;
}
ver = h->api.get_required_api_version();
if (sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3)
{
snprintf(err, PLUGIN_MAX_ERRLEN, "plugin provided an invalid required API version: '%s'", ver);
return false;
}
ver = h->api.get_required_api_version();
if(sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3) {
snprintf(err,
PLUGIN_MAX_ERRLEN,
"plugin provided an invalid required API version: '%s'",
ver);
return false;
}
failmsg = NULL;
if(PLUGIN_API_VERSION_MAJOR != major)
{
failmsg = "major versions disagree";
}
else if(PLUGIN_API_VERSION_MINOR < minor)
{
failmsg = "framework's minor is less than the requested one";
}
else if(PLUGIN_API_VERSION_MINOR == minor && PLUGIN_API_VERSION_PATCH < patch)
{
failmsg = "framework's patch is less than the requested one";
}
failmsg = NULL;
/* The plugin requires a minimum framework version */
if(PLUGIN_API_VERSION_MAJOR != major) {
failmsg = "major versions disagree";
} else if(PLUGIN_API_VERSION_MINOR < minor) {
failmsg = "framework's minor is less than the requested one";
} else if(PLUGIN_API_VERSION_MINOR == minor && PLUGIN_API_VERSION_PATCH < patch) {
failmsg = "framework's patch is less than the requested one";
}
if (failmsg != NULL)
{
snprintf(err, PLUGIN_MAX_ERRLEN,
"plugin required API version '%s' not compatible with the framework's API version '%s': %s",
ver, PLUGIN_API_VERSION_STR, failmsg);
return false;
}
if(failmsg != NULL) {
snprintf(err,
PLUGIN_MAX_ERRLEN,
"plugin required API version '%s' not compatible with the framework's API version "
"'%s': %s",
ver,
PLUGIN_API_VERSION_STR,
failmsg);
return false;
}
return true;
return true;
}
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h)
{
plugin_caps_t caps = CAP_NONE;
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h, char* err) {
plugin_caps_t caps = CAP_NONE;
plugin_loader_strlcpy(err, "", PLUGIN_MAX_ERRLEN);
if (h->api.get_id != NULL
&& h->api.get_event_source != NULL
&& h->api.open != NULL
&& h->api.close != NULL
&& h->api.next_batch != NULL)
{
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_SOURCING);
}
if(h->api.open != NULL && h->api.close != NULL && h->api.next_batch != NULL) {
bool has_id = h->api.get_id != NULL && h->api.get_id() != 0;
bool has_source = h->api.get_event_source != NULL && strlen(h->api.get_event_source()) > 0;
if((has_id && has_source) || (!has_id && !has_source)) {
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_SOURCING);
} else {
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
err_append(err,
"must implement both 'plugin_get_id' and 'plugin_get_event_source' or "
"neither (event sourcing)",
", ");
}
} else if(h->api.open != NULL || h->api.close != NULL || h->api.next_batch != NULL) {
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
err_append(err,
"must implement all of 'plugin_open', 'plugin_close', and 'plugin_next_batch' "
"(event sourcing)",
", ");
}
if (h->api.get_fields != NULL
&& h->api.extract_fields != NULL)
{
caps = (plugin_caps_t)((uint32_t) caps | (uint32_t) CAP_EXTRACTION);
}
if(h->api.get_fields != NULL && h->api.extract_fields != NULL) {
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_EXTRACTION);
} else if(h->api.extract_fields != NULL) {
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
err_append(err,
"must implement both 'plugin_get_fields' and 'plugin_extract_fields' (field "
"extraction)",
", ");
}
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
#define SYM_REQCHECK(a, e, s) \
do { \
if(a->api.s == NULL) \
{ \
snprintf(e, PLUGIN_MAX_ERRLEN, "symbol not implemented: %s", #s); \
return false; \
} \
} while(0)
#define SYM_REQCHECK(a, e, s) \
do { \
if(a->api.s == NULL) { \
snprintf(e, PLUGIN_MAX_ERRLEN, "required symbol not implemented: '%s'", #s); \
return false; \
} \
} while(0)
bool plugin_check_required_symbols(const plugin_handle_t* h, char* err)
{
SYM_REQCHECK(h, err, get_required_api_version);
SYM_REQCHECK(h, err, get_version);
SYM_REQCHECK(h, err, get_name);
SYM_REQCHECK(h, err, get_description);
SYM_REQCHECK(h, err, get_contact);
SYM_REQCHECK(h, err, init);
SYM_REQCHECK(h, err, destroy);
SYM_REQCHECK(h, err, get_last_error);
return true;
bool plugin_check_required_symbols(const plugin_handle_t* h, char* err) {
SYM_REQCHECK(h, err, get_required_api_version);
SYM_REQCHECK(h, err, get_version);
SYM_REQCHECK(h, err, get_name);
SYM_REQCHECK(h, err, get_description);
SYM_REQCHECK(h, err, get_contact);
SYM_REQCHECK(h, err, init);
SYM_REQCHECK(h, err, destroy);
SYM_REQCHECK(h, err, get_last_error);
return true;
}

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 the License.
@ -19,16 +20,12 @@ limitations under the License.
#include "plugin_api.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#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.
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:
* ability to source events and provide them to the event loop
* 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
{
CAP_NONE = 0,
CAP_SOURCING = 1 << 0,
CAP_EXTRACTION = 1 << 1
typedef enum {
CAP_NONE = 0,
CAP_SOURCING = 1 << 0,
CAP_EXTRACTION = 1 << 1,
CAP_PARSING = 1 << 2,
CAP_ASYNC = 1 << 3,
CAP_CAPTURE_LISTENING = 1 << 4,
CAP_BROKEN = 1 << 31, // used to report inconsistencies
} plugin_caps_t;
/*!
@ -49,16 +52,22 @@ typedef enum
Pointers to this struct must be obtained through the plugin_load()
and released through plugin_unload().
*/
typedef struct plugin_handle_t
{
typedef struct plugin_handle_t {
#ifdef _WIN32
HINSTANCE handle; ///< Handle of the dynamic library
HINSTANCE handle; ///< Handle of the dynamic library
#else
void* handle; ///< Handle of the dynamic library
void* handle; ///< Handle of the dynamic library
#endif
plugin_api api; ///< The vtable method of the plugin that define its API
plugin_api api; ///< The vtable method of the plugin that define its API
} plugin_handle_t;
/*!
\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
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);
/*!
\brief Destroys a plugin_handle_t* previously allocated by
\brief Destroys a plugin_handle_t* previously allocated by
invoking plugin_load().
*/
void plugin_unload(plugin_handle_t* h);
@ -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);
/*!
\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
}

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");
you may not use this file except in compliance with the License.

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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");
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"
)
// 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.
// This interface is meant to be used in the next/next_batch.
//
@ -113,7 +128,8 @@ type EventWriters interface {
}
type eventWriters struct {
evts []*eventWriter
evts []*eventWriter
evtPtrs **C.ss_plugin_event
}
// NewEventWriters creates a new instance of sdk.EventWriters.
@ -129,16 +145,16 @@ func NewEventWriters(size, dataSize int64) (EventWriters, error) {
}
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
for i := range ret.evts {
// get i-th element of pluginEvtArray
evtPtr := unsafe.Pointer(uintptr(unsafe.Pointer(pluginEvtArray)) + uintptr(i*C.sizeof_ss_plugin_event))
if ret.evts[i], err = newEventWriter(evtPtr, dataSize); err != nil {
if ret.evts[i], err = newEventWriter(dataSize); err != nil {
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
}
@ -159,37 +175,52 @@ func (p *eventWriters) Free() {
}
func (p *eventWriters) ArrayPtr() unsafe.Pointer {
return p.evts[0].ssPluginEvt
return unsafe.Pointer(p.evtPtrs)
}
type eventWriter struct {
data ptr.BytesReadWriter
dataSize int64
ssPluginEvt unsafe.Pointer
ssPluginEvt *C.ss_plugin_event
}
func newEventWriter(evtPtr unsafe.Pointer, dataSize int64) (*eventWriter, error) {
evt := (*C.ss_plugin_event)(evtPtr)
func newEventWriter(dataSize int64) (*eventWriter, error) {
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.data = (*C.uint8_t)(C.malloc(C.size_t(dataSize)))
evt.datalen = 0
brw, err := ptr.NewBytesReadWriter(unsafe.Pointer(evt.data), int64(dataSize), int64(dataSize))
evt.tid = C.uint64_t(C.UINT64_MAX)
evt.len = (C.uint32_t)(PluginEventPayloadOffset)
// note(jasondellaluce): CGO fails to properly encode nparams for *reasons*,
// so we're forced to write their value manually with an offset
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + 22)) = 2
// 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 {
return nil, err
}
return &eventWriter{
ssPluginEvt: evtPtr,
ssPluginEvt: evt,
data: brw,
dataSize: dataSize,
}, 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 {
p.data.SetLen(p.dataSize)
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
}
@ -198,7 +229,8 @@ func (p *eventWriter) Write(data []byte) (n int, err error) {
if err != nil {
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
}
@ -207,26 +239,30 @@ func (p *eventWriter) SetTimestamp(value uint64) {
}
func (p *eventWriter) free() {
C.free(unsafe.Pointer((*C.ss_plugin_event)(p.ssPluginEvt).data))
C.free(unsafe.Pointer(p.ssPluginEvt))
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.
// Passing an invalid pointer may cause undefined behavior.
func NewEventReader(ssPluginEvt unsafe.Pointer) EventReader {
return (*eventReader)(ssPluginEvt)
func NewEventReader(ssPluginEvtInput unsafe.Pointer) EventReader {
return (*eventReader)(ssPluginEvtInput)
}
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
}
func (e *eventReader) Timestamp() uint64 {
return uint64(e.ts)
return uint64(e.evt.ts)
}
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");
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");
you may not use this file except in compliance with the License.
@ -28,11 +29,17 @@ package sdk
typedef union {
const char* str;
uint64_t u64;
uint32_t u32;
ss_plugin_bool boolean;
ss_plugin_byte_buffer buf;
} field_result_t;
*/
import "C"
import (
"net"
"reflect"
"time"
"unsafe"
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
@ -53,8 +60,14 @@ type ExtractRequest interface {
FieldID() uint64
//
// FieldType returns the type of the field for which the value extraction
// is requested. For now, only sdk.FieldTypeUint64 and
// sdk.FieldTypeCharBuf are supported.
// is requested. For now, the supported types are:
// - sdk.FieldTypeBool
// - sdk.FieldTypeUint64
// - sdk.FieldTypeCharBuf
// - sdk.FieldTypeRelTime
// - sdk.FieldTypeAbsTime
// - sdk.FieldTypeIPAddr
// - sdk.FieldTypeIPNet
FieldType() uint32
//
// 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
// associated to this extract request (as the returned by FieldType()),
// 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{})
//
// TODO SetValueOffsets sets the start offset and length of one or
// more fields. The start offset for each field must be from the
// beginning of the event to the start of the field data.
// sdk.PluginEventPayloadOffset should be used to get the event
// header size. {0,0} can be used to indicate that the field doesn't
// correspond to any bytes in the event or log data.
SetValueOffset(start, length uint32)
//
// SetPtr sets a pointer to a ss_plugin_extract_field C structure to
// be wrapped in this instance of ExtractRequest.
SetPtr(unsafe.Pointer)
//
// SetOffsetPtrs sets the pointers to the memory locations that will
// hold the values set by SetValueOffset.
SetOffsetPtrs(startPtr, lengthPtr unsafe.Pointer)
//
// WantOffset returns true if the caller is requesting the offset
// for the current field.
//
WantOffset() bool
}
// ExtractRequestPool represents a pool of reusable ExtractRequest objects.
@ -95,6 +136,18 @@ type ExtractRequestPool interface {
// position inside the pool. Indexes can be non-contiguous.
Get(requestIndex int) ExtractRequest
//
// MakeOffsetArrayPtrs allocates and initializes the start offset and length arrays,
// then assigns their pointers to the provided ss_plugin_extract_value_offsets structure.
// These arrays track field boundaries for extracted values.
//
// This function must be called before using any ExtractRequest returned by Get,
// as the arrays are uninitialized until this point.
//
// Parameters:
// - extractValueOffsets: pointer to ss_plugin_extract_value_offsets structure to populate
// - cap: required capacity for the offset arrays
MakeOffsetArrayPtrs(extractValueOffsets unsafe.Pointer, cap uint32)
//
// Free deallocates any memory used by the pool that can't be disposed
// through garbage collection. The behavior of Free after the first call
// is undefined.
@ -102,7 +155,9 @@ type ExtractRequestPool interface {
}
type extractRequestPool struct {
reqs map[uint]*extractRequest
reqs map[uint]*extractRequest
startArrayPtr, lengthArrayPtr unsafe.Pointer
arrayPtrCap uint32
}
func (e *extractRequestPool) Get(requestIndex int) ExtractRequest {
@ -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))),
resBufLen: minResultBufferLen,
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
}
return r
}
func (e *extractRequestPool) MakeOffsetArrayPtrs(extractValueOffsets unsafe.Pointer, cap uint32) {
// If we need more capacity, free old arrays and allocate new ones
if cap > e.arrayPtrCap {
// Free existing arrays if they exist
if e.arrayPtrCap > 0 {
C.free(e.startArrayPtr)
C.free(e.lengthArrayPtr)
}
// Allocate new arrays with required capacity - calloc zeros the memory
e.startArrayPtr = unsafe.Pointer(C.calloc(C.size_t(cap), C.sizeof_uint32_t))
e.lengthArrayPtr = unsafe.Pointer(C.calloc(C.size_t(cap), C.sizeof_uint32_t))
e.arrayPtrCap = cap
} else {
// Capacity is sufficient, just zero the arrays for fresh extraction request
size := C.size_t(cap) * C.sizeof_uint32_t
C.memset(e.startArrayPtr, 0, size)
C.memset(e.lengthArrayPtr, 0, size)
}
(*C.ss_plugin_extract_value_offsets)(extractValueOffsets).start = (*C.uint32_t)(e.startArrayPtr)
(*C.ss_plugin_extract_value_offsets)(extractValueOffsets).length = (*C.uint32_t)(e.lengthArrayPtr)
}
func (e *extractRequestPool) Free() {
for _, v := range e.reqs {
for _, b := range v.resStrBufs {
@ -125,6 +210,10 @@ func (e *extractRequestPool) Free() {
}
C.free(unsafe.Pointer(v.resBuf))
}
if e.arrayPtrCap > 0 {
C.free(e.startArrayPtr)
C.free(e.lengthArrayPtr)
}
}
// NewExtractRequestPool returns a new empty ExtractRequestPool.
@ -137,18 +226,31 @@ func NewExtractRequestPool() ExtractRequestPool {
type extractRequest struct {
req *C.ss_plugin_extract_field
// Pointer to the field's offset
resOffsetStart *C.uint32_t
// Pointer to the field's length
resOffsetLength *C.uint32_t
// Pointer to a C-allocated array of field_result_t
resBuf *C.field_result_t
// Length of the array pointed by resBuf
resBufLen uint32
// List of StringBuffer to return string results
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) {
e.req = (*C.ss_plugin_extract_field)(pef)
}
func (e *extractRequest) SetOffsetPtrs(startPtr, lengthPtr unsafe.Pointer) {
e.resOffsetStart = (*C.uint32_t)(startPtr)
e.resOffsetLength = (*C.uint32_t)(lengthPtr)
}
func (e *extractRequest) FieldID() uint64 {
return uint64(e.req.field_id)
}
@ -170,52 +272,175 @@ func (e *extractRequest) ArgIndex() uint64 {
}
func (e *extractRequest) ArgPresent() bool {
return bool(e.req.arg_present)
return e.req.arg_present != 0
}
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{}) {
switch e.FieldType() {
case FieldTypeUint64:
if e.req.flist {
if e.resBufLen < uint32(len(v.([]uint64))) {
C.free(unsafe.Pointer(e.resBuf))
e.resBufLen = uint32(len(v.([]uint64)))
e.resBuf = (*C.field_result_t)(C.malloc((C.size_t)(e.resBufLen * C.sizeof_field_result_t)))
case FieldTypeBool:
if e.IsList() {
for i, ptr := range e.resizeResValPtrs(len(v.([]bool)), C.sizeof_uint32_t) {
*((*C.uint32_t)(ptr)) = (C.uint32_t)(e.boolToU32((v.([]bool))[i]))
}
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 {
*((*C.uint64_t)(unsafe.Pointer(e.resBuf))) = (C.uint64_t)(v.(uint64))
e.req.res_len = (C.uint64_t)(1)
ptr := e.resizeResValPtrs(1, C.sizeof_uint32_t)[0]
*((*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:
if e.req.flist {
if e.resBufLen < uint32(len(v.([]string))) {
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 e.IsList() {
for i, out := range e.resizeResValPtrs(len(v.([]string)), C.sizeof_uintptr_t) {
if len(e.resStrBufs) <= i {
e.resStrBufs = append(e.resStrBufs, &ptr.StringBuffer{})
}
e.resStrBufs[i].Write(val)
*((**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(e.resBuf)) + uintptr(i*C.sizeof_field_result_t)))) = (*C.char)(e.resStrBufs[i].CharPtr())
e.resStrBufs[i].Write(v.([]string)[i])
*((**C.char)(out)) = (*C.char)(e.resStrBufs[i].CharPtr())
}
e.req.res_len = (C.uint64_t)(len(v.([]string)))
} else {
out := e.resizeResValPtrs(1, C.sizeof_uintptr_t)[0]
e.resStrBufs[0].Write(v.(string))
*((**C.char)(unsafe.Pointer(e.resBuf))) = (*C.char)(e.resStrBufs[0].CharPtr())
e.req.res_len = (C.uint64_t)(1)
*((**C.char)(out)) = (*C.char)(e.resStrBufs[0].CharPtr())
}
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:
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))
}
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");
you may not use this file except in compliance with the License.
@ -18,18 +19,26 @@ package sdk
import (
"fmt"
"net"
"testing"
"unsafe"
"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()) {
ret := &_Ctype_ss_plugin_extract_field{}
ret.field_id = _Ctype_uint32_t(fid)
ret.ftype = _Ctype_uint32_t(ftype)
ret.arg_present = _Ctype__Bool(farg_present)
ret.flist = _Ctype__Bool(list)
ret.arg_present = boolToUint32(farg_present)
ret.flist = boolToUint32(list)
ret.arg_index = _Ctype_uint64_t(farg_index)
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 {
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))
}
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 {
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))
}
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()) {
@ -93,27 +135,60 @@ func TestExtractRequestSetValue(t *testing.T) {
// init test data
testStr := "test str"
testU64 := uint64(99)
testU64Start := uint32(PluginEventPayloadOffset)
testU64Length := uint32(8)
testBool := true
testIPv6 := net.IPv6loopback
testStrList := make([]string, 0)
testU64List := make([]uint64, 0)
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))
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
pool := NewExtractRequestPool()
u64Ptr, freeU64Ptr := allocSSPluginExtractField(1, FieldTypeUint64, "test.u64", "", 0, true, false)
u64OffsetStartPtr := allocSSPluginExtractOffset()
u64OffsetLengthPtr := allocSSPluginExtractOffset()
u64ListPtr, freeU64ListPtr := allocSSPluginExtractField(2, FieldTypeUint64, "test.u64", "", 0, true, true)
u64ListOffsetStartPtr := allocSSPluginExtractOffset()
u64ListOffsetLengthPtr := allocSSPluginExtractOffset()
strPtr, freeStrPtr := allocSSPluginExtractField(3, FieldTypeCharBuf, "test.str", "", 0, true, false)
strListPtr, freeStrListPtr := allocSSPluginExtractField(4, FieldTypeCharBuf, "test.str", "", 0, true, true)
boolPtr, freeBoolPtr := allocSSPluginExtractField(5, FieldTypeBool, "test.bool", "", 0, true, false)
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)
u64ReqList := pool.Get(1)
strReq := pool.Get(2)
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.SetOffsetPtrs(unsafe.Pointer(u64OffsetStartPtr), unsafe.Pointer(u64OffsetLengthPtr))
u64ReqList.SetPtr(unsafe.Pointer(u64ListPtr))
u64ReqList.SetOffsetPtrs(unsafe.Pointer(u64ListOffsetStartPtr), unsafe.Pointer(u64ListOffsetLengthPtr))
strReq.SetPtr(unsafe.Pointer(strPtr))
strReqList.SetPtr(unsafe.Pointer(strListPtr))
boolReq.SetPtr(unsafe.Pointer(boolPtr))
boolReqList.SetPtr(unsafe.Pointer(boolListPtr))
binReq.SetPtr(unsafe.Pointer(binPtr))
binReqList.SetPtr(unsafe.Pointer(binListPtr))
// check that info is passed-through correctly
if u64Req.FieldID() != 1 {
@ -144,9 +219,23 @@ func TestExtractRequestSetValue(t *testing.T) {
// check panics
assertPanic(t, func() {
u64Req.SetValue("test")
u64Req.SetValue(bool(true))
boolReq.SetValue([]byte{0x41, 0x41, 0x41, 0x41})
})
assertPanic(t, func() {
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
@ -154,12 +243,26 @@ func TestExtractRequestSetValue(t *testing.T) {
if getU64ResSSPluingExtractField(t, u64Ptr, 0) != testU64 {
t.Errorf("expected value '%d', but found '%d'", testU64, getU64ResSSPluingExtractField(t, u64Ptr, 0))
}
u64Req.SetValueOffset(testU64Start, testU64Length)
if getResSSPluginExtractOffsetFromPtr(u64OffsetStartPtr) != testU64Start {
t.Errorf("expected start offset '%d', but found '%d'", testU64Start, getResSSPluginExtractOffsetFromPtr(u64OffsetStartPtr))
}
if getResSSPluginExtractOffsetFromPtr(u64OffsetLengthPtr) != testU64Length {
t.Errorf("expected length '%d', but found '%d'", testU64Length, getResSSPluginExtractOffsetFromPtr(u64OffsetLengthPtr))
}
u64ReqList.SetValue(testU64List)
u64ReqList.SetValueOffset(testU64ListStart, testU64ListLength)
for i, d := range testU64List {
if getU64ResSSPluingExtractField(t, u64ListPtr, i) != d {
t.Errorf("expected value '%d', but found '%d'", testU64, getU64ResSSPluingExtractField(t, u64Ptr, i))
}
}
if getResSSPluginExtractOffsetFromPtr(u64ListOffsetStartPtr) != testU64ListStart {
t.Errorf("expected start offset '%d', but found '%d'", testU64ListStart, getResSSPluginExtractOffsetFromPtr(u64ListOffsetStartPtr))
}
if getResSSPluginExtractOffsetFromPtr(u64ListOffsetLengthPtr) != testU64ListLength {
t.Errorf("expected length '%d', but found '%d'", testU64ListLength, getResSSPluginExtractOffsetFromPtr(u64ListOffsetLengthPtr))
}
strReq.SetValue(testStr)
if getStrResSSPluingExtractField(t, strPtr, 0) != testStr {
t.Errorf("expected value '%s', but found '%s'", testStr, getStrResSSPluingExtractField(t, strPtr, 0))
@ -170,10 +273,49 @@ func TestExtractRequestSetValue(t *testing.T) {
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()
freeU64Ptr()
freeU64ListPtr()
freeStrPtr()
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");
you may not use this file except in compliance with the License.

View File

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

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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");
you may not use this file except in compliance with the License.
@ -21,21 +22,36 @@ limitations under the License.
extern "C" {
#endif
#include <stdbool.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
// falcosecurity libs types.
typedef enum ss_plugin_field_type
{
typedef enum ss_plugin_field_type {
// A 64bit unsigned integer.
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;
// Values to return from init() / open() / next_batch() /
// extract_fields().
typedef enum ss_plugin_rc
{
typedef enum ss_plugin_rc {
SS_PLUGIN_SUCCESS = 0,
SS_PLUGIN_FAILURE = 1,
SS_PLUGIN_TIMEOUT = -1,
@ -44,8 +60,7 @@ typedef enum ss_plugin_rc
} ss_plugin_rc;
// The supported schema formats for the init configuration.
typedef enum ss_plugin_schema_type
{
typedef enum ss_plugin_schema_type {
// The schema is undefined and the init configuration
// is an opaque string.
SS_PLUGIN_SCHEMA_NONE = 0,
@ -57,26 +72,75 @@ typedef enum ss_plugin_schema_type
} ss_plugin_schema_type;
// This struct represents an event returned by the plugin, and is used
// below in next_batch().
// - evtnum: incremented for each event returned. Might not be contiguous.
// - data: pointer to a memory buffer pointer. The plugin will set it
// 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.
// below in next_batch(). It observes the event specifics of libscap.
// An event is represented as a contiguous region of memory composed by
// a header and a list of parameters appended, in the form of:
//
// Note: event numbers are assigned by the plugin
// framework. Therefore, there isn't any need to fill in evtnum when
// returning an event via plugin_next_batch. It will be ignored.
typedef struct ss_plugin_event
{
// | evt header | len param 1 (2B/4B) | ... | len param N (2B/4B) | data param 1 | ... | data param
// N |
//
// The event header is composed of:
// - ts: the event timestamp, in nanoseconds since the epoch.
// 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;
const uint8_t *data;
uint32_t datalen;
uint64_t ts;
} ss_plugin_event;
const char* evtsrc;
} ss_plugin_event_input;
typedef struct ss_plugin_byte_buffer {
uint32_t len;
const void* ptr;
} ss_plugin_byte_buffer;
// Used in extract_fields_and_offsets to receive field value offsets
// along with field data.
// Extraction functions that support offsets should be set these to an
// array of zero-indexed start offsets and lengths of each returned
// value in the event or log data. {0, 0} can be used to indicate that
// there are no valid offsets, e.g. if the value was generated or
// computed from other data.
// Extraction functions might not support offsets. In order to detect
// this, callers should initialize the start and length to nullptr.
typedef struct ss_plugin_extract_value_offsets {
uint32_t* start;
uint32_t* length;
} ss_plugin_extract_value_offsets;
// Used in extract_fields functions below to receive a field/arg
// pair and return an extracted value.
@ -86,16 +150,16 @@ typedef struct ss_plugin_event
// arg_key: the field argument, if a 'key' argument has been specified
// for the field (isKey=true), otherwise it's NULL.
// For example:
// * if the field specified by the user is foo.bar[pippo], arg_key
// * if the field specified by the user is foo.bar[pippo], arg_key
// will be the string "pippo"
// * if the field specified by the user is foo.bar, arg will be NULL
// arg_index: the field argument, if a 'index' argument has been specified
// for the field (isIndex=true), otherwise it's 0.
// For example:
// * if the field specified by the user is foo.bar[1], arg_index
// will be the uint64_t '1'.
// * if the field specified by the user is foo.bar[1], arg_index
// will be the uint64_t '1'.
// Please note the ambiguity with a 0
// argument which could be a real argument of just the default
// argument which could be a real argument of just the default
// value to point out the absence. The `arg_present` field resolves
// this ambiguity.
// arg_present: helps to understand if the arg is there since arg_index is
@ -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
// on how many values can be extracted from a given event.
// Setting res_len to 0 means that no value of this field can be extracted from a given event.
typedef struct ss_plugin_extract_field
{
typedef struct ss_plugin_extract_field {
// NOTE: For a given architecture, this has always the same size which
// is sizeof(uintptr_t). Adding new value types will not create breaking
// changes in the plugin API. However, we must make sure that each added
// type is always a pointer.
union
{
union {
const char** str;
uint64_t* u64;
uint32_t* u32;
ss_plugin_bool* boolean;
ss_plugin_byte_buffer* buf;
} res;
uint64_t res_len;
@ -136,16 +201,77 @@ typedef struct ss_plugin_extract_field
const char* field;
const char* arg_key;
uint64_t arg_index;
bool arg_present;
ss_plugin_bool arg_present;
uint32_t ftype;
bool flist;
ss_plugin_bool flist;
} ss_plugin_extract_field;
// Opaque a pointer to a state table. The falcosecurity libs define stateful
// components in the form of tables.
typedef void ss_plugin_table_t;
// Opaque a pointer to an entry of a state table.
typedef void ss_plugin_table_entry_t;
// Opaque accessor to a data field available in the entries of a state table.
typedef void ss_plugin_table_field_t;
// Types supported by entry fields of state tables.
// The noncontinguous numbers are to maintain equality with underlying
// falcosecurity libs types.
// todo(jasondellaluce): should we merge this with ss_plugin_field_type?
typedef enum ss_plugin_state_type {
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.
// It points to any data that might be needed plugin-wise. It is
// 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.
//
typedef void ss_plugin_t;
@ -155,11 +281,69 @@ typedef void ss_plugin_t;
// plugin.
// It points to any data that is needed while a capture is running. It is
// 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.
//
typedef void ss_instance_t;
//
// Severity available in the logging facility provided by the framework
typedef enum ss_plugin_log_severity {
SS_PLUGIN_LOG_SEV_FATAL = 1,
SS_PLUGIN_LOG_SEV_CRITICAL = 2,
SS_PLUGIN_LOG_SEV_ERROR = 3,
SS_PLUGIN_LOG_SEV_WARNING = 4,
SS_PLUGIN_LOG_SEV_NOTICE = 5,
SS_PLUGIN_LOG_SEV_INFO = 6,
SS_PLUGIN_LOG_SEV_DEBUG = 7,
SS_PLUGIN_LOG_SEV_TRACE = 8,
} ss_plugin_log_severity;
// Types supported by the by the metric values
typedef enum ss_plugin_metric_value_type {
SS_PLUGIN_METRIC_VALUE_TYPE_U32 = 0,
SS_PLUGIN_METRIC_VALUE_TYPE_S32 = 1,
SS_PLUGIN_METRIC_VALUE_TYPE_U64 = 2,
SS_PLUGIN_METRIC_VALUE_TYPE_S64 = 3,
SS_PLUGIN_METRIC_VALUE_TYPE_D = 4,
SS_PLUGIN_METRIC_VALUE_TYPE_F = 5,
SS_PLUGIN_METRIC_VALUE_TYPE_I = 6,
} ss_plugin_metric_value_type;
// Data representation of metric values
typedef union ss_plugin_metric_value {
uint32_t u32;
int32_t s32;
uint64_t u64;
int64_t s64;
double d;
float f;
int i;
} ss_plugin_metric_value;
// Metric types
typedef enum ss_plugin_metric_type {
SS_PLUGIN_METRIC_TYPE_MONOTONIC = 0,
SS_PLUGIN_METRIC_TYPE_NON_MONOTONIC = 1,
} ss_plugin_metric_type;
//
// Struct representing a metric to be provided to the plugin framework
typedef struct ss_plugin_metric {
//
// Opaque string representing the metric name
const char* name;
//
// Metric type
ss_plugin_metric_type type;
//
// Metric numeric value
ss_plugin_metric_value value;
//
// Metric value data type
ss_plugin_metric_value_type value_type;
} ss_plugin_metric;
#ifdef __cplusplus
}
#endif
#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");
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");
you may not use this file except in compliance with the License.

View File

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

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 the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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");
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");
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");
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");
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");
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
// 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 (
FieldTypeUint64 uint32 = 8
FieldTypeCharBuf uint32 = 9 // A printable buffer of bytes, NULL terminated
// A 64bit unsigned integer.
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

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 the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -38,7 +39,7 @@ import (
)
//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()
stringer, ok := cgo.Handle(pState).Value().(sdk.Stringer)
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");
you may not use this file except in compliance with the License.
@ -39,15 +40,16 @@ type sampleEvtStr struct {
expectedData []byte
}
func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event, func()) {
ret := &_Ctype_struct_ss_plugin_event{}
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.ts = _Ctype_uint64_t(ts)
ret.data = (*_Ctype_uint8_t)(&data[0])
ret.datalen = _Ctype_uint32_t(len(data))
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");
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
// in C memory, namely the total number of locks available
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 (
@ -185,7 +190,9 @@ func (a *asyncContext) acquireWorker(workerIdx int32) {
for _, i := range batchIdxs {
// reduce sync overhead by skipping unused batch slots
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
@ -199,6 +206,7 @@ func (a *asyncContext) acquireWorker(workerIdx int32) {
a.batch[i].evt,
uint32(a.batch[i].num_fields),
a.batch[i].fields,
a.batch[i].value_offsets,
),
)
// processing done, return back to waiting state
@ -243,13 +251,23 @@ func (a *asyncContext) releaseWorker(workerIdx int32) {
// side, we use the first visible slot and set an exit request. The worker
// will eventually synchronize with the used lock and stop.
idx := a.workerIdxToBatchIdxs(workerIdx)[0]
waitStartTime := time.Now()
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
waitStartTime = time.Now()
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

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 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");
you may not use this file except in compliance with the License.
@ -52,17 +53,17 @@ void async_deinit()
// Defined in extract.go
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,
ss_plugin_extract_field *fields);
ss_plugin_extract_field *fields,
ss_plugin_extract_value_offsets *offsets);
// This is the plugin API function. If s_async_ctx_batch is
// non-NULL, it calls the async extractor function. Otherwise, it
// calls the synchronous extractor function.
FALCO_PLUGIN_SDK_PUBLIC int32_t plugin_extract_fields(ss_plugin_t *s,
const ss_plugin_event *evt,
uint32_t num_fields,
ss_plugin_extract_field *fields)
const ss_plugin_event_input *evt,
const ss_plugin_field_extract_input* in)
{
// 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
@ -78,14 +79,15 @@ FALCO_PLUGIN_SDK_PUBLIC int32_t plugin_extract_fields(ss_plugin_t *s,
if (s_async_ctx_batch == NULL
|| atomic_load_explicit(&s_async_ctx_batch[(size_t)s - 1].lock, memory_order_seq_cst) != WAIT)
{
return plugin_extract_fields_sync(s, evt, num_fields, fields);
return plugin_extract_fields_sync(s, evt, in->num_fields, in->fields, in->value_offsets);
}
// Set input data
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].num_fields = num_fields;
s_async_ctx_batch[(size_t)s - 1].fields = fields;
s_async_ctx_batch[(size_t)s - 1].num_fields = in->num_fields;
s_async_ctx_batch[(size_t)s - 1].fields = in->fields;
s_async_ctx_batch[(size_t)s - 1].value_offsets = in->value_offsets;
// notify data request
atomic_store_explicit(&s_async_ctx_batch[(size_t)s - 1].lock, DATA_REQ, memory_order_seq_cst);

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 the License.
@ -27,6 +28,7 @@ limitations under the License.
package extract
/*
#include <stdlib.h>
#include "extract.h"
*/
import "C"
@ -38,20 +40,34 @@ import (
)
//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)
extract := pHandle.Value().(sdk.Extractor)
extrReqs := pHandle.Value().(sdk.ExtractRequests)
// https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices
// https://go.dev/wiki/cgo#turning-c-arrays-into-go-slices
flds := (*[1 << 28]C.struct_ss_plugin_extract_field)(unsafe.Pointer(fields))[:numFields:numFields]
var i uint32
var extrReq sdk.ExtractRequest
if offsets != nil {
extrReqs.ExtractRequests().MakeOffsetArrayPtrs(unsafe.Pointer(offsets), numFields)
}
for i = 0; i < numFields; i++ {
flds[i].res_len = (C.uint64_t)(0)
extrReq = extrReqs.ExtractRequests().Get(int(flds[i].field_id))
extrReq.SetPtr(unsafe.Pointer(&flds[i]))
if offsets == nil {
extrReq.SetOffsetPtrs(nil, nil)
} else {
extrReq.SetOffsetPtrs(
unsafe.Add(unsafe.Pointer(offsets.start), i*C.sizeof_uint32_t),
unsafe.Add(unsafe.Pointer(offsets.length), i*C.sizeof_uint32_t),
)
}
err := extract.Extract(extrReq, sdk.NewEventReader(unsafe.Pointer(evt)))
if err != nil {
pHandle.Value().(sdk.LastError).SetLastError(err)

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 the License.
@ -17,7 +18,7 @@ limitations under the License.
#pragma once
#include <stdatomic.h>
#include "../../plugin_types.h"
#include "../../plugin_api.h"
typedef struct async_extractor_info
{
@ -26,9 +27,10 @@ typedef struct async_extractor_info
// input data
ss_plugin_t *s;
const ss_plugin_event *evt;
const ss_plugin_event_input *evt;
uint32_t num_fields;
ss_plugin_extract_field *fields;
ss_plugin_extract_value_offsets *value_offsets;
// output data
int32_t rc;

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 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()) {
ret := &_Ctype_struct_ss_plugin_event{}
func allocSSPluginExtractValueOffsets(start *uint32, length *uint32) (*_Ctype_ss_plugin_extract_value_offsets) {
ret := &_Ctype_ss_plugin_extract_value_offsets{}
ret.start = (*_Ctype_uint32_t)(start)
ret.length = (*_Ctype_uint32_t)(length)
return ret
}
func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event_input, func()) {
ret := &_Ctype_struct_ss_plugin_event_input{}
evts, _ := sdk.NewEventWriters(1, int64(len(data)))
evt := evts.Get(0)
evt.Writer().Write(data)
ret.evt = *(**_Ctype_struct_ss_plugin_event)(evts.ArrayPtr())
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() {
// nothing to deallocate here
evts.Free()
}
}
@ -116,11 +126,22 @@ func TestExtract(t *testing.T) {
// panic
badHandle := cgo.NewHandle(1)
assertPanic(t, func() {
plugin_extract_fields_sync(_Ctype_uintptr_t(badHandle), event, 1, field)
plugin_extract_fields_sync(_Ctype_uintptr_t(badHandle), event, 1, field, nil)
})
// success
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field)
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field, nil)
if res != sdk.SSPluginSuccess {
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
} else if sample.lastErr != nil {
t.Errorf("(lastErr): should be nil")
}
// success + offsets
val_start := uint32(0)
val_length := uint32(8)
offsets := allocSSPluginExtractValueOffsets(&val_start, &val_length)
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field, offsets)
if res != sdk.SSPluginSuccess {
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
} else if sample.lastErr != nil {
@ -129,7 +150,7 @@ func TestExtract(t *testing.T) {
// error
sample.err = errTest
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field)
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field, nil)
if res != sdk.SSPluginFailure {
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginFailure, res)
} else if sample.lastErr != errTest {

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 the License.

View File

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

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -53,4 +54,4 @@ int sync_benchmark(int n, int input)
int do_work_c(int i)
{
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");
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);
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");
you may not use this file except in compliance with the License.

View File

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

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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");
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()
{
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");
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
// information about the plugin. The exported functions are:
// uint32_t get_type();
// uint32_t get_id();
// char* get_name();
// char* get_description();
// char* get_contact();
// char* get_version();
// char* get_required_api_version();
// char* get_event_source();
// char* get_extract_event_sources();
//
// uint32_t get_type();
// uint32_t get_id();
// char* get_name();
// char* get_description();
// char* get_contact();
// char* get_version();
// char* get_required_api_version();
// char* get_event_source();
// char* get_extract_event_sources();
//
// In almost all cases, your plugin should import this module, unless
// your plugin exports those symbols by other means.
@ -36,6 +38,7 @@ package info
import "C"
import (
"encoding/json"
"strings"
"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())
}
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) {
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)
}

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 the License.

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -18,16 +19,22 @@ package info
import (
"encoding/json"
"fmt"
"testing"
"unsafe"
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
"github.com/stretchr/testify/assert"
)
var testStr = "test"
var testU32 = uint32(1)
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) {
var resU32 uint32
var resStr string
@ -36,7 +43,7 @@ func TestInfo(t *testing.T) {
SetId(testU32)
resU32 = plugin_get_id()
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)
@ -63,12 +70,6 @@ func TestInfo(t *testing.T) {
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)
resStr = ptr.GoString(unsafe.Pointer(plugin_get_event_source()))
if resStr != testStr {
@ -102,3 +103,109 @@ func TestInfo(t *testing.T) {
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");
you may not use this file except in compliance with the License.
@ -38,7 +39,7 @@ limitations under the License.
package initialize
/*
#include <stdint.h>
#include "../../plugin_api.h"
*/
import "C"
import (
@ -82,11 +83,12 @@ func SetOnInit(fn OnInitFn) {
}
//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 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 {
state = &baseInit{}
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");
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) {
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 {
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
} else if handle.Value() != nil {
@ -92,7 +102,8 @@ func TestInitialize(t *testing.T) {
SetOnInit(func(config string) (sdk.PluginState, error) {
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 {
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) {
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 {
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
} 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");
you may not use this file except in compliance with the License.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2021 The Falco Authors.
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
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:
// - 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
// of cgo.Handle from this SDK. The value of the s handle must implement
@ -37,12 +38,12 @@ import (
)
//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()
n, err := cgo.Handle(iState).Value().(sdk.NextBatcher).NextBatch(cgo.Handle(pState).Value().(sdk.PluginState), events)
*nevts = uint32(n)
*retEvts = (*C.ss_plugin_event)(events.ArrayPtr())
*retEvts = (**C.ss_plugin_event)(events.ArrayPtr())
switch err {
case nil:
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");
you may not use this file except in compliance with the License.
@ -68,7 +69,7 @@ func TestNextBatch(t *testing.T) {
// generic testing callback
doTest := func(name string, res int32, num uint32, ptr unsafe.Pointer, err error) {
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)
if r != res {
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");
you may not use this file except in compliance with the License.

View File

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

View File

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

View File

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