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

[CWS] Add 'cgroup' variable scope #32378

Merged
merged 4 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions cmd/security-agent/subcommands/runtime/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,13 @@ func eventDataFromJSON(file string) (eval.Event, error) {
return nil, errors.New("unknown event type")
}

m := &model.Model{}
event := m.NewDefaultEventWithType(kind)
event := &model.Event{
BaseEvent: model.BaseEvent{
Type: uint32(kind),
FieldHandlers: &model.FakeFieldHandlers{},
ContainerContext: &model.ContainerContext{},
},
}
event.Init()

for k, v := range eventData.Values {
Expand Down
9 changes: 7 additions & 2 deletions cmd/system-probe/subcommands/runtime/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,8 +533,13 @@ func eventDataFromJSON(file string) (eval.Event, error) {
return nil, errors.New("unknown event type")
}

m := &model.Model{}
event := m.NewDefaultEventWithType(kind)
event := &model.Event{
BaseEvent: model.BaseEvent{
Type: uint32(kind),
FieldHandlers: &model.FakeFieldHandlers{},
ContainerContext: &model.ContainerContext{},
},
}
event.Init()

for k, v := range eventData.Values {
Expand Down
4 changes: 2 additions & 2 deletions pkg/network/events/monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestEventConsumerWrapperCopy(t *testing.T) {
},
FieldHandlers: &model.FakeFieldHandlers{},
},
CGroupContext: model.CGroupContext{
CGroupContext: &model.CGroupContext{
CGroupID: "cid_exec",
},
}
Expand Down Expand Up @@ -87,7 +87,7 @@ func TestEventConsumerWrapperCopy(t *testing.T) {
},
FieldHandlers: &model.FakeFieldHandlers{},
},
CGroupContext: model.CGroupContext{
CGroupContext: &model.CGroupContext{
CGroupID: "cid_fork",
},
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/security/probe/field_handlers_ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,8 @@ func (fh *EBPFFieldHandlers) ResolveCGroupID(ev *model.Event, e *model.CGroupCon
return string(entry.CGroup.CGroupID)
}

if cgroupContext, err := fh.resolvers.ResolveCGroupContext(e.CGroupFile, e.CGroupFlags); err == nil {
*e = *cgroupContext
if cgroupContext, _, err := fh.resolvers.ResolveCGroupContext(e.CGroupFile, e.CGroupFlags); err == nil {
ev.CGroupContext = cgroupContext
}
}
}
Expand Down
18 changes: 12 additions & 6 deletions pkg/security/probe/probe_ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ func (p *EBPFProbe) EventMarshallerCtor(event *model.Event) func() events.EventM
}

func (p *EBPFProbe) unmarshalContexts(data []byte, event *model.Event) (int, error) {
read, err := model.UnmarshalBinary(data, &event.PIDContext, &event.SpanContext, event.ContainerContext, &event.CGroupContext)
read, err := model.UnmarshalBinary(data, &event.PIDContext, &event.SpanContext, event.ContainerContext, event.CGroupContext)
if err != nil {
return 0, err
}
Expand Down Expand Up @@ -750,8 +750,8 @@ func (p *EBPFProbe) unmarshalProcessCacheEntry(ev *model.Event, data []byte) (in
entry.Process.ContainerID = ev.ContainerContext.ContainerID
entry.ContainerID = ev.ContainerContext.ContainerID

entry.Process.CGroup.Merge(&ev.CGroupContext)
entry.CGroup.Merge(&ev.CGroupContext)
entry.Process.CGroup.Merge(ev.CGroupContext)
entry.CGroup.Merge(ev.CGroupContext)

entry.Source = model.ProcessCacheEntryFromEvent

Expand Down Expand Up @@ -780,7 +780,7 @@ func (p *EBPFProbe) setProcessContext(eventType model.EventType, event *model.Ev
}

// do the same with cgroup context
event.CGroupContext = event.ProcessCacheEntry.CGroup
event.CGroupContext = &event.ProcessCacheEntry.CGroup

if process.IsKThread(event.ProcessContext.PPid, event.ProcessContext.Pid) {
return false
Expand Down Expand Up @@ -809,9 +809,9 @@ func (p *EBPFProbe) zeroEvent() *model.Event {
}

func (p *EBPFProbe) resolveCGroup(pid uint32, cgroupPathKey model.PathKey, cgroupFlags containerutils.CGroupFlags, newEntryCb func(entry *model.ProcessCacheEntry, err error)) (*model.CGroupContext, error) {
cgroupContext, err := p.Resolvers.ResolveCGroupContext(cgroupPathKey, cgroupFlags)
cgroupContext, _, err := p.Resolvers.ResolveCGroupContext(cgroupPathKey, cgroupFlags)
if err != nil {
return nil, fmt.Errorf("failed to resorve cgroup for pid %d: %w", pid, err)
return nil, fmt.Errorf("failed to resolve cgroup for pid %d: %w", pid, err)
}
updated := p.Resolvers.ProcessResolver.UpdateProcessCGroupContext(pid, cgroupContext, newEntryCb)
if !updated {
Expand Down Expand Up @@ -908,6 +908,12 @@ func (p *EBPFProbe) handleEvent(CPU int, data []byte) {
seclog.Debugf("Failed to resolve cgroup: %s", err.Error())
} else {
event.CgroupTracing.CGroupContext = *cgroupContext
if cgroupContext.CGroupFlags.IsContainer() {
containerID, _ := containerutils.FindContainerID(cgroupContext.CGroupID)
event.CgroupTracing.ContainerContext.ContainerID = containerID
}

event.CGroupContext = cgroupContext
p.profileManagers.activityDumpManager.HandleCGroupTracingEvent(&event.CgroupTracing)
}
return
Expand Down
5 changes: 4 additions & 1 deletion pkg/security/resolvers/cgroup/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ func NewResolver(statsdClient statsd.ClientInterface) (*Resolver, error) {
}

cleanup := func(value *cgroupModel.CacheEntry) {
value.CallReleaseCallback()
if value.CGroupContext.IsContainer() {
value.ContainerContext.CallReleaseCallback()
}
value.CGroupContext.CallReleaseCallback()
value.Deleted.Store(true)

cr.NotifyListeners(CGroupDeleted, value)
Expand Down
8 changes: 4 additions & 4 deletions pkg/security/resolvers/resolvers_ebpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,14 @@ func (r *EBPFResolvers) Start(ctx context.Context) error {
}

// ResolveCGroupContext resolves the cgroup context from a cgroup path key
func (r *EBPFResolvers) ResolveCGroupContext(pathKey model.PathKey, cgroupFlags containerutils.CGroupFlags) (*model.CGroupContext, error) {
func (r *EBPFResolvers) ResolveCGroupContext(pathKey model.PathKey, cgroupFlags containerutils.CGroupFlags) (*model.CGroupContext, bool, error) {
if cgroupContext, found := r.CGroupResolver.GetCGroupContext(pathKey); found {
return cgroupContext, nil
return cgroupContext, true, nil
}

cgroup, err := r.DentryResolver.Resolve(pathKey, true)
if err != nil {
return nil, fmt.Errorf("failed to resolve cgroup file %v: %w", pathKey, err)
return nil, false, fmt.Errorf("failed to resolve cgroup file %v: %w", pathKey, err)
}

cgroupContext := &model.CGroupContext{
Expand All @@ -235,7 +235,7 @@ func (r *EBPFResolvers) ResolveCGroupContext(pathKey model.PathKey, cgroupFlags
CGroupManager: containerutils.CGroupManager(cgroupFlags & containerutils.CGroupManagerMask).String(),
}

return cgroupContext, nil
return cgroupContext, false, nil
}

// Snapshot collects data on the current state of the system to populate user space and kernel space caches.
Expand Down
28 changes: 28 additions & 0 deletions pkg/security/rules/engine_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,34 @@ func (e *RuleEngine) GetSECLVariables() map[string]*api.SECLVariableState {
continue
}

scopedValue := fmt.Sprintf("%v", value)
seclVariables[scopedName] = &api.SECLVariableState{
Name: scopedName,
Value: scopedValue,
}
}
} else if strings.HasPrefix(name, "cgroup.") {
scopedVariable := value.(eval.ScopedVariable)

cgr := e.probe.PlatformProbe.(*probe.EBPFProbe).Resolvers.CGroupResolver
containerWorkloads := cgr.GetContainerWorkloads()
if containerWorkloads == nil {
continue
}

for _, cgce := range containerWorkloads.Values() {
cgce.RLock()
defer cgce.RUnlock()

event := e.probe.PlatformProbe.NewEvent()
event.CGroupContext = &cgce.CGroupContext
ctx := eval.NewContext(event)
scopedName := fmt.Sprintf("%s.%s", name, cgce.CGroupID)
value, found := scopedVariable.GetValue(ctx)
if !found {
continue
}

scopedValue := fmt.Sprintf("%v", value)
seclVariables[scopedName] = &api.SECLVariableState{
Name: scopedName,
Expand Down
18 changes: 11 additions & 7 deletions pkg/security/secl/compiler/eval/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ func NewIntArrayVariable(size int, ttl time.Duration) *IntArrayVariable {
// VariableScope is the interface to be implemented by scoped variable in order to be released
type VariableScope interface {
AppendReleaseCallback(callback func())
Hash() string
}

// Scoper maps a variable to the entity its scoped to
Expand Down Expand Up @@ -566,7 +567,7 @@ type MutableSECLVariable interface {
// ScopedVariables holds a set of scoped variables
type ScopedVariables struct {
scoper Scoper
vars map[VariableScope]map[string]MutableSECLVariable
vars map[string]map[string]MutableSECLVariable
}

// Len returns the length of the variable map
Expand All @@ -577,19 +578,22 @@ func (v *ScopedVariables) Len() int {
// NewSECLVariable returns new variable of the type of the specified value
func (v *ScopedVariables) NewSECLVariable(name string, value interface{}, opts VariableOpts) (SECLVariable, error) {
getVariable := func(ctx *Context) MutableSECLVariable {
v := v.vars[v.scoper(ctx)]
scope := v.scoper(ctx)
key := scope.Hash()
v := v.vars[key]
return v[name]
}

setVariable := func(ctx *Context, value interface{}) error {
key := v.scoper(ctx)
if key == nil {
scope := v.scoper(ctx)
if scope == nil {
return fmt.Errorf("failed to scope variable '%s'", name)
}

key := scope.Hash()
vars := v.vars[key]
if vars == nil {
key.AppendReleaseCallback(func() {
scope.AppendReleaseCallback(func() {
v.ReleaseVariable(key)
})

Expand Down Expand Up @@ -655,14 +659,14 @@ func (v *ScopedVariables) NewSECLVariable(name string, value interface{}, opts V
}

// ReleaseVariable releases a scoped variable
func (v *ScopedVariables) ReleaseVariable(key VariableScope) {
func (v *ScopedVariables) ReleaseVariable(key string) {
delete(v.vars, key)
}

// NewScopedVariables returns a new set of scope variables
func NewScopedVariables(scoper Scoper) *ScopedVariables {
return &ScopedVariables{
scoper: scoper,
vars: make(map[VariableScope]map[string]MutableSECLVariable),
vars: make(map[string]map[string]MutableSECLVariable),
}
}
21 changes: 18 additions & 3 deletions pkg/security/secl/model/accessors_unix.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions pkg/security/secl/model/field_handlers_unix.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading