Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dynamic extraction of a parameter attribute #3143

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

ScriptSathi
Copy link
Contributor

@ScriptSathi ScriptSathi commented Nov 19, 2024

The discussion for this PR can be found here #3142

Take this PR in the today state as a proof of concept for dynamic parameter extraction. I will continue to work on this PR until the below checks are done.

At the current state, the PR is able to

  • Extract parameters from LSM programs
  • Extract parameters from kprobes programs
  • Handle exception for uprobes as it is not part of BTF
  • Have unit tests for all cases
  • - Validate CI for all kernel versions

Description

This PR introduce the dynamic extraction of a custom attribute

Test the PR

You can use the following config

apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: "lsm"
spec:
  lsmhooks:
  - hook: "bprm_check_security"
    args:
      - index: 0
        type: "string"
        resolve: "file.f_path.dentry.d_name.name"
    selectors:
      - matchArgs:
        - index: 0
          operator: "Postfix"
          values:
            - "ls"
            - "sh"
            - "bash"

Release-note

Add dynamic resolution of a parameter attribute

@ScriptSathi ScriptSathi requested a review from a team as a code owner November 19, 2024 16:27
@ScriptSathi ScriptSathi requested a review from jrfastab November 19, 2024 16:27
@ScriptSathi ScriptSathi marked this pull request as draft November 19, 2024 16:28
@ScriptSathi ScriptSathi force-pushed the pr/ScriptSathi/add-dynamic-paramter-extraction branch from 9a9d21f to ce33ec7 Compare November 20, 2024 10:48
Copy link

netlify bot commented Nov 20, 2024

Deploy Preview for tetragon ready!

Name Link
🔨 Latest commit 060882a
🔍 Latest deploy log https://app.netlify.com/sites/tetragon/deploys/6796bd1d040dad0008a9be98
😎 Deploy Preview https://deploy-preview-3143--tetragon.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@ScriptSathi ScriptSathi force-pushed the pr/ScriptSathi/add-dynamic-paramter-extraction branch from ce33ec7 to 5ebb3e0 Compare November 20, 2024 16:00
@mtardy mtardy linked an issue Nov 21, 2024 that may be closed by this pull request
2 tasks
@mtardy mtardy added the release-note/major This PR introduces major new functionality label Nov 21, 2024
@ScriptSathi ScriptSathi force-pushed the pr/ScriptSathi/add-dynamic-paramter-extraction branch 2 times, most recently from e3117d7 to ba048b3 Compare November 21, 2024 10:59
Copy link
Contributor

@olsajiri olsajiri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it, left some comments

thanks for splitting the code in multiple logical changes, it's rare ;-)

we were originally thinking of using C expression parsing (there's some go lib for that) but I think that can be done later if it's ever needed, the basic parsing you did should be fine

please add tests, would be great to have some framework where we could easily add various 'ExtractParam' expressions for testing

pkg/sensors/tracing/genericuprobe.go Show resolved Hide resolved
bpf/process/types/basic.h Outdated Show resolved Hide resolved
pkg/btf/btf.go Show resolved Hide resolved
pkg/btf/btf.go Outdated Show resolved Hide resolved
bpf/process/generic_calls.h Outdated Show resolved Hide resolved
bpf/process/types/basic.h Outdated Show resolved Hide resolved
bpf/process/generic_calls.h Outdated Show resolved Hide resolved
bpf/process/generic_calls.h Outdated Show resolved Hide resolved
pkg/sensors/tracing/generickprobe.go Show resolved Hide resolved
@ScriptSathi ScriptSathi force-pushed the pr/ScriptSathi/add-dynamic-paramter-extraction branch from ba048b3 to 1fb7dbc Compare November 23, 2024 17:54
@pchaigno pchaigno removed the request for review from jrfastab December 9, 2024 18:05
@ScriptSathi ScriptSathi force-pushed the pr/ScriptSathi/add-dynamic-paramter-extraction branch 2 times, most recently from 753fd10 to 2b1153f Compare January 10, 2025 14:12
@ScriptSathi ScriptSathi changed the title Add dynamic parameter extraction Add dynamic extraction of a parameter attribute Jan 10, 2025
@ScriptSathi ScriptSathi force-pushed the pr/ScriptSathi/add-dynamic-paramter-extraction branch from 2b1153f to a04e634 Compare January 10, 2025 16:36
@ScriptSathi ScriptSathi marked this pull request as ready for review January 10, 2025 16:38
@ScriptSathi ScriptSathi requested a review from mtardy as a code owner January 10, 2025 16:38
@ScriptSathi ScriptSathi force-pushed the pr/ScriptSathi/add-dynamic-paramter-extraction branch 2 times, most recently from 058c828 to 391c5a8 Compare January 10, 2025 18:32
@kkourt kkourt self-requested a review January 14, 2025 14:55
Copy link
Contributor

@olsajiri olsajiri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great, I left some comments, thanks

bpf/process/types/basic.h Outdated Show resolved Hide resolved
pkg/sensors/tracing/generic.go Outdated Show resolved Hide resolved
pkg/btf/btf.go Outdated Show resolved Hide resolved
pkg/btf/btf.go Outdated Show resolved Hide resolved
pkg/sensors/tracing/genericuprobe.go Outdated Show resolved Hide resolved
pkg/btf/btf_test.go Outdated Show resolved Hide resolved
pkg/btf/btf_test.go Outdated Show resolved Hide resolved
examples/tracingpolicy/lsm_track_grandparent.yml Outdated Show resolved Hide resolved
bpf/process/types/basic.h Outdated Show resolved Hide resolved
Copy link
Member

@mtardy mtardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been pulled-in for the docs change, here's a review. Thanks for adding docs!

pkg/sensors/tracing/generic.go Outdated Show resolved Hide resolved
docs/content/en/docs/concepts/tracing-policy/hooks.md Outdated Show resolved Hide resolved
docs/content/en/docs/concepts/tracing-policy/hooks.md Outdated Show resolved Hide resolved
docs/content/en/docs/concepts/tracing-policy/hooks.md Outdated Show resolved Hide resolved
examples/tracingpolicy/lsm_track_grandparent.yml Outdated Show resolved Hide resolved
docs/content/en/docs/concepts/tracing-policy/hooks.md Outdated Show resolved Hide resolved
docs/content/en/docs/concepts/tracing-policy/hooks.md Outdated Show resolved Hide resolved
docs/content/en/docs/concepts/tracing-policy/hooks.md Outdated Show resolved Hide resolved
docs/content/en/docs/concepts/tracing-policy/hooks.md Outdated Show resolved Hide resolved
@ScriptSathi ScriptSathi force-pushed the pr/ScriptSathi/add-dynamic-paramter-extraction branch from 391c5a8 to dac4d2e Compare January 23, 2025 13:51
@ScriptSathi
Copy link
Contributor Author

ScriptSathi commented Jan 23, 2025

@olsajiri The CI tests are still crashing on all kernel versions. I ran my tests on a 6.6 kernel, and everything worked fine. I'll investigate further to figure out the issue and update you soon.

EDIT : The tests were failing because btfFile was not set in the pipeline test, but it was in local. So I've added a new commit and the LoadBTF function to make sure this won’t happen again.

EDIT 2 : CI fails on pkg.watcher.TestFastK8s. It looks like it is related to this issue #2972

@ScriptSathi ScriptSathi force-pushed the pr/ScriptSathi/add-dynamic-paramter-extraction branch 4 times, most recently from e279770 to 3a85916 Compare January 26, 2025 17:00
@ScriptSathi ScriptSathi force-pushed the pr/ScriptSathi/add-dynamic-paramter-extraction branch 2 times, most recently from 060882a to 10e0ee3 Compare January 27, 2025 16:57
@ScriptSathi ScriptSathi requested a review from olsajiri January 27, 2025 18:02
pkg/sensors/tracing/generic_test.go Outdated Show resolved Hide resolved
Copy link
Contributor

@olsajiri olsajiri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good, one comment left, but could be fixed later if needed, thanks

pkg/sensors/tracing/genericlsm.go Show resolved Hide resolved
This commit introduces the `struct config_btf_arg_depth`. It appends
`btf_argN` to `struct event_config` as an array. This array stores the
path to the searched data.

Any `btf_argN` can have a list of elements as follow :
file->f_path is 152 bytes, so the array will look like
[{ offset: 152, is_pointer: 0, is_initialized: 1 }, ...].

The max value `MAX_BTF_ARG_DEPTH` as been set arbitrary as the verifier
need a fixed size.

In config_btf_arg, is_pointer and is_initialized are u16 because it must
match padding of 64 bits long structure

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
…_argN

This commit introduces the “extract_arg_depth” function and loops over it
to move into the “arg” buffer of config->btf_argN[i]->offset by iteration.
The goal is to reach the requiered data by overwriting over arg with
the new value.

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
This commit checks if btf.Type exists in Tetragon existing types.

For instance:

`struct file` with btf is called `file` and also exists in
`GenericStringToType` with the same alias.
However, the attribute `name` in `struct qstr` has a returned type
`unsigned char` wich does not exist yet in `GenericStringToType`.

The same thing happened with `linux_binprm->filename` as the type is
`char`

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
ResolveBtfPath function recursively searches in a btf structure in order
to find a specific path until it reaches the target or fails.

The function also searches in embedded anonymous structures or unions to
cover as much use cases as possible. For instance, mm_struct has 2
fields; anonymous struct and another type. But you are still able to look
into the anonymous struct by specifying a path like "mm.pgd.pgd".

For instance, if the search is in the linux_binprm structure and the
path is `file.f_path.dentry.d_name.name`, the following
actions will be done.

- Look for the variable name `file` inside `linux_binprm`.

- If it matches, it stores the offset from linux_binprm where the `file`
  variable could be found.

- Then it takes the btf type `file` and searches for a parameter named
  `f_path`.

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
In order to read the data properly on BPF side, integer/long values must
use `bpf_probe_read`. So now, every time the latest type retrieved is
defined as an integer, it will be safely read before accessing the data.

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
I've noticed that unit tests load differently the btf file than locally.
So when using `NewBTF()` locally it worked, but during the pipeline it
crashes. To avoid this behaviour, `LoadBTF` is added and ensure the btf
file path is set before trying to load it. Otherwise, it run the
`InitCachedBtf()`.

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
The function `FindBtfFuncParamFromHook` has been added to identify the
exact BTF type of the hook's parameters. This allows us to handle cases
where the hook has parameters that include multiple pointers to
structures. With those information, we will be able to dereference
correctly any parameters until we reach the data

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
This commit adds a new parameter to give the ability to the user to search
for a specific attribute following a "path" as follow:

```yml
...
  - hook: "bprm_check_security"
    args:
      - index: 0 # index 0 is struct linux_binprm
        type: "string"
        resolve: "file.f_path.dentry.d_name.name"
...
```

The above config can be used to extract a specific attribute from the
structure at index 0.

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
Searches if every user defined type with Resolve exists as a BTF
type and stores its corresponding offset in ConfigBtfArg.

This function does a basic split on `Resolve` to obtain the "path"
to the required data. Then, the array is given to `btf.ResolveBtfPath` to
find the offset of each element until we reach the required data.
The output is stored in EventConfig to keep the normal behaviour.

For example, if the arg 0 is `struct linux_binprm` and Resolve is
set to `file.f_path.dentry.d_name.name`, the output will give an array
of all the offsets from their parents as follows :
[{ offset: 96, is_pointer: 0 }, { offset: 152, is_pointer: 1 }, ...]

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
This commit updates `addLsm` function to use the new `arg.Resolve`
option in order to look for the attributes in BTF structure.

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
Since the Resolve attribute feature uses the hook name to retrieve the
hook parameters, if the LSM hook does not exist inside the BTF file, it
is not possible to resolve attributes correctly.

The feature that allows this was added to the kernel in v5.8 with the
patch below:
https://lore.kernel.org/bpf/20200329004356.27286-4-kpsingh@chromium.org/

After this patch, LSM hooks can be retrieved in the BTF file with this
format: `bpf_lsm_<hook_name>`

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
As BTF types are not defined for Uprobes, their offsets can't be found in
BTF file. Thus, if the user defines Resolve, an error is returned

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
Add very similar code as in `genericlsm.go` file to handle Resolve
feature.

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
…licy

`TestResolveBtfArgFromKprobePolicy` is introduced. It aims to test the
access to the requested attribute with no errors and assert that the very
last type corresponds to the requested policy type (string/int/etc).

3 different cases are handled:
- Test a classic hook
- Test resolve from double pointer parameter
- Assert an error is raised when the resolve path is too long

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
This test ensures 4 things :
- It can retrieve correctly the parameter of an kprobe hook.
- Is raises an error when btf.Type could not be found
- It raises an error when the type found is not a function.
- It raises an error when the requested parameter index is out of range
  for the FuncProto.Params array.

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
This commit adds 3 tests for ResolveBtfPath algorithm :
- `testAssertEqualBtfPath` to assert that a specific path has the exact
  same btfConfig as expected.
- `testAssertPathIsAccessible` tries to reach the path and asserts that
  no errors are raised.
- `testAssertErrorOnInvalidPath` asserts that the error   messages raised
  if the path is incorrect.

The chosen test cases have embed union/anonymous structs.

To Test locally :
```
go test -exec "sudo" ./pkg/btf/
```

Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
Signed-off-by: Tristan d'Audibert <tristan.daudibert@orange.com>
@ScriptSathi ScriptSathi force-pushed the pr/ScriptSathi/add-dynamic-paramter-extraction branch from 10e0ee3 to 3a883bb Compare January 29, 2025 13:05
@ScriptSathi ScriptSathi requested a review from kkourt January 29, 2025 13:55
@ScriptSathi ScriptSathi requested a review from mtardy January 31, 2025 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-note/major This PR introduces major new functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add dynamic parameter extration for specific use cases
4 participants