-
Notifications
You must be signed in to change notification settings - Fork 474
wip: feat(sensors): support 38+ override on lsm funcs #4244
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
base: main
Are you sure you want to change the base?
Conversation
|
@olsajiri may I have your feedback on this one? Thanks a lot. |
c0067a5 to
23c75cf
Compare
olsajiri
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good, left few comments, thanks
| if fmodret, ok = fmodretMap[attachFunc]; !ok { | ||
|
|
||
| fmodret = program.Builder( | ||
| path.Join(option.Config.HubbleLib, loadProgName), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since we already add new program for this, could we move override programs into separated object?
that might speed up the load
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I think it makes a lot of sense to do this. Thanks!
| "github.com/cilium/tetragon/pkg/sensors/program" | ||
| ) | ||
|
|
||
| var fmodretMap map[string]*program.Program |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about something similar but bit more generic to cover also standard kprobe override programs.. there's no limitation for attached kprobe programs, but it would at least benefit from having just single copy of the program and reduce the footprint
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a good idea. Let me look into this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One issue I noticed is that, if I'm not mistaken, for kprobe override programs, when multi-kprobe is enabled, each kprobe attach points actually share the same override_maps. Do you think we should change that and use per-hookpoint map instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hum not sure what you mean..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I wasn't aware that the creation and loading of maps and programs in multi kprobe flows are based on the data type of load.LoaderData. That makes sense now. Thanks a lot!
| fmodret.PinPath = "fmod_ret/" + attachFunc | ||
|
|
||
| fmodretmap := program.MapBuilder("override_tasks", fmodret) | ||
| fmodretmap.PinPath = path.Join("fmod_ret/", attachFunc, "override_tasks") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'd rather place it in some visibly special place like we do for base sensor, perhaps something like:
__override__/fmodret/security_xxx
__override__/fmodret/security_yyy
...
__override__/kprobe/ksys_read
__override__/kprobe/ksys_write
...
__override__/override_tasks
| // setup sensor based program pin path | ||
| p.PinPath = filepath.Join(s.policyDir(), s.Name, p.PinName) | ||
| // setup sensor based program pin path if it's not specified | ||
| if p.PinPath == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this needed, or it's just a leftover? PinPath should be always defined even with your change no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah there might be a better way to implement this, but the code here is basically a lazy initialization. When the PinPath is already given, it uses the existing one. For override program, we prefill the PinPath so it falls under this category.
For other programs, the default PinPath under s.policyDir() will be used in Ln70.
pkg/sensors/tracing/generickprobe.go
Outdated
| logger.GetLogger().Info("loading generic fmod ret program", "prog", load) | ||
|
|
||
| unload := func() { | ||
| deleteFmodRetProg(load.Attach) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we use program.Program.unloaderOverride or add something in there so it gets removed during program's unload?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I didn't notice this function exists when I wrote the code. From its name it's definitely more suitable. Let me look into this.
23c75cf to
acfea29
Compare
✅ Deploy Preview for tetragon ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Changes since v1:
|
|
I still keep this as draft because of an item that I'd like to discuss first. Say we have a scenario is like the below (keep in mind that in v2 we use a shared override_tasks map):
I can think of a few directions:
@olsajiri do you think this is a real issue that we should address? I'd love to know your thoughts on this. |
yea, that seems like a problem.. so at the moment override_task is program's map, so each override program has its own copy, I'd suggest to have some state of this change doing the same, and adding a change to single map on top of that perhaps we could have policy id as part of the override_task value and have sensor unload to cleanup its records before it unloads the override program.. something like you suggest in 2) but not sure what's benefit of inner map I'll check on your change in more detail but on first glance please try to split the change into more logical changes/commits, it's easier to review, thanks |
Move bpf functions regarding overrides into bpf_generic_override.o Signed-off-by: Sam Wang (holyspectral) <[email protected]>
Provide a custom CustomUnloader, so custom actions can be performed when a ebpf program is unloaded and unloaderOverride is called. Signed-off-by: Sam Wang (holyspectral) <[email protected]>
1. Allow policies to share override programs as long as they share the same attached functions. This includes both programs based on kprobe and fmod_ret. 2. The pinned path of ebpf programs and maps are moved to below locations: /bpffs/tetragon/__override__ /bpffs/tetragon/__override__/kprobe /bpffs/tetragon/__override__/kprobe/__x64_sys_symlinkat /bpffs/tetragon/__override__/kprobe/__x64_sys_symlinkat/link_override /bpffs/tetragon/__override__/kprobe/__x64_sys_symlinkat/prog_override /bpffs/tetragon/__override__/kprobe/__x64_sys_execve /bpffs/tetragon/__override__/kprobe/__x64_sys_execve/link_override /bpffs/tetragon/__override__/kprobe/__x64_sys_execve/prog_override /bpffs/tetragon/__override__/override_tasks /bpffs/tetragon/__override__/fmod_ret /bpffs/tetragon/__override__/fmod_ret/security_bprm_creds_for_exec /bpffs/tetragon/__override__/fmod_ret/security_bprm_creds_for_exec/prog Signed-off-by: Sam Wang (holyspectral) <[email protected]>
Signed-off-by: Sam Wang (holyspectral) <[email protected]>
acfea29 to
99bf162
Compare
Thanks. I think that makes sense. Let me see if I can add an extra field to the key or value of override_tasks map.
I've split them into multiple commits. Please feel free to let me know if anything is not clear! |
olsajiri
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, left few comments, please split the change into more commits in next version
| spec *ebpf.ProgramSpec, | ||
| ) (unloader.Unloader, error) { | ||
|
|
||
| pinPath := filepath.Join(bpfDir, load.PinPath, "prog_override") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps no need for the override suffix now? also for link
| func LoadFmodRetProgram(bpfDir string, load *Program, maps []*Map, progName string, verbose int) error { | ||
| func LoadKProbeOverrideProgram(bpfDir string, load *Program, maps []*Map, progName string, verbose int, unloadFunc func(bool) error) error { | ||
| opts := &LoadOpts{ | ||
| Attach: func( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we tend to put callbacks code in functions, please add override attach and open fnuctions
| if !ok { | ||
| return fmt.Errorf("progName %s not in collecition spec programs: %+v", progName, coll.Programs) | ||
| } | ||
| progSpec.AttachTo = load.Attach |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this needed for kprobe?
| "fmod_ret/"+attachFunc, | ||
| "generic_fmod_ret") | ||
|
|
||
| overrideProg.PinPath = path.Join("__override__", "fmod_ret", attachFunc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's probably ok, but could you please check tetrag debug progs/maps works properly with this?
| } | ||
|
|
||
| func createFmodRetOverrideProgramFromEntry(load *program.Program, attachFunc string, progs []*program.Program, maps []*program.Map) ([]*program.Program, []*program.Map) { | ||
| // setup fmodret program and its input |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like this function and the above createKProbeOverrideProgramFromEntry could be unified in just one function with load.OverrideFmodRet as bool argument
| } | ||
| if unloadFunc != nil { | ||
| load.unloaderOverride = &unloader.CustomUnloader{ | ||
| UnloadFunc: unloadFunc, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we just set load.unloaderOverride in getOverrideProg ? then we could leave LoadFmodRetProgram as is
| } | ||
|
|
||
| func LoadFmodRetProgram(bpfDir string, load *Program, maps []*Map, progName string, verbose int) error { | ||
| func LoadKProbeOverrideProgram(bpfDir string, load *Program, maps []*Map, progName string, verbose int, unloadFunc func(bool) error) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm why do we need special override function for kprobe and not for fmodret? can't we just use LoadKprobeProgram?
|
|
||
| func (k *observerKprobeSensor) LoadProbe(args sensors.LoadProbeArgs) error { | ||
| return loadGenericKprobeSensor(args.BPFDir, args.Load, args.Maps, args.Verbose) | ||
| func (k *kprobeOverrideProgram) LoadProbe(args sensors.LoadProbeArgs) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so the kprobe override program depends on being loaded 'before' the actual program so it gets in the kprobe list behind the actual program, which is laded after.. tricky ;-) I guess if tests are passing we're doing it somehow, but I wonder we specifically ensure this
Fixes #4204
Description
This draft PR is to get early feedback about the potential fix for #4204. Any comments will be appreciated.
As mentioned in #4204, this PR makes multiple kprobe sensors to share their
fmod_retprograms, as long as they attach to the same function.The changes include:
A new probe type
generic_fmod_retis created, so we can manage the lifecycle of shared fmod_ret separately from the original kprobe sensors.program.Programandprogram.Map's LoadState fields are used to track the reference count of these data, so they can be automatically cleaned up.The pinPath of these programs/maps are moved to a global path under
/tetragon/fmod_ret/<func>/. For example,/.../tetragon/fmod_ret/security_bprm_creds_for_exec/prog/.../tetragon/fmod_ret/security_bprm_creds_for_exec/override_tasksA
unload()function is injected intounloader.UnloadProg(), so we can clean upfmodretMap.There might be a better way to implement these, so any comments will be appreciated.
Changelog