-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
resolver_linux.go
131 lines (107 loc) · 3.19 KB
/
resolver_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.
//go:build linux
// Package usersessions holds model related to the user sessions resolver
package usersessions
import (
"encoding/json"
"fmt"
"sync"
"github.com/cilium/ebpf"
"github.com/hashicorp/golang-lru/v2/simplelru"
manager "github.com/DataDog/ebpf-manager"
"github.com/DataDog/datadog-agent/pkg/security/probe/managerhelper"
"github.com/DataDog/datadog-agent/pkg/security/secl/model"
"github.com/DataDog/datadog-agent/pkg/security/secl/model/usersession"
"github.com/DataDog/datadog-agent/pkg/security/seclog"
)
// UserSessionKey describes the key to a user session
type UserSessionKey struct {
ID uint64
Cursor byte
Padding [7]byte
}
// UserSessionData stores user session context data retrieved from the kernel
type UserSessionData struct {
SessionType usersession.Type
RawData string
}
// UnmarshalBinary unmarshalls a binary representation of itself
func (e *UserSessionData) UnmarshalBinary(data []byte) error {
if len(data) < 256 {
return model.ErrNotEnoughSpace
}
e.SessionType = usersession.Type(data[0])
e.RawData += model.NullTerminatedString(data[1:])
return nil
}
// Resolver is used to resolve the user sessions context
type Resolver struct {
sync.RWMutex
userSessions *simplelru.LRU[uint64, *model.UserSessionContext]
userSessionsMap *ebpf.Map
}
// NewResolver returns a new instance of Resolver
func NewResolver(cacheSize int) (*Resolver, error) {
lru, err := simplelru.NewLRU[uint64, *model.UserSessionContext](cacheSize, nil)
if err != nil {
return nil, fmt.Errorf("couldn't create User Session resolver cache: %w", err)
}
return &Resolver{
userSessions: lru,
}, nil
}
// Start initializes the eBPF map of the resolver
func (r *Resolver) Start(manager *manager.Manager) error {
r.Lock()
defer r.Unlock()
m, err := managerhelper.Map(manager, "user_sessions")
if err != nil {
return fmt.Errorf("couldn't start user session resolver: %w", err)
}
r.userSessionsMap = m
return nil
}
// ResolveUserSession returns the user session associated to the provided ID
func (r *Resolver) ResolveUserSession(id uint64) *model.UserSessionContext {
r.Lock()
defer r.Unlock()
if id == 0 {
return nil
}
// is this session already in cache ?
if session, ok := r.userSessions.Get(id); ok {
return session
}
// lookup the session in kernel space
key := UserSessionKey{
ID: id,
Cursor: 1,
}
value := UserSessionData{}
err := r.userSessionsMap.Lookup(&key, &value)
for err == nil {
key.Cursor++
err = r.userSessionsMap.Lookup(&key, &value)
}
if key.Cursor == 1 && err != nil {
// the session doesn't exist, leave now
return nil
}
ctx := &model.UserSessionContext{
ID: id,
SessionType: value.SessionType,
}
// parse the content of the user session context
err = json.Unmarshal([]byte(value.RawData), ctx)
if err != nil {
seclog.Debugf("failed to parse user session data: %v", err)
return nil
}
ctx.Resolved = true
// cache resolved context
r.userSessions.Add(id, ctx)
return ctx
}