Skip to content

Commit 4253aeb

Browse files
authored
nspr: fix bytecode loading and complete eBPF probe implementation (#1017)
Fix #1016: The NSPR probe failed to load eBPF bytecode because: 1. bytecode filename was hardcoded as 'bytecode/nspr_kern.o' but embedded assets use _core.o / _noncore.o suffixes 2. eBPF manager setup was never implemented (placeholder only) 3. TLSDataEvent struct layout did not match the C ssl_data_event_t Changes: - event.go: Rewrite TLSDataEvent to match C struct exactly (DataType absorbs u32+padding as int64, fields reordered) - nspr_probe.go: Implement full eBPF manager with uprobe/uretprobe for PR_Write/PR_Read, correct bytecode loading via GetBPFName() - nspr_probe_test.go: Update tests for new struct layout - All 12 nspr tests pass, full make test-race passes
1 parent 5ccbc23 commit 4253aeb

3 files changed

Lines changed: 257 additions & 119 deletions

File tree

internal/probe/nspr/event.go

Lines changed: 71 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -25,35 +25,55 @@ import (
2525
)
2626

2727
const (
28+
// DataType constants matching C enum ssl_data_event_type
29+
DataTypeRead = 0
30+
DataTypeWrite = 1
31+
2832
// MaxDataSize is the maximum size of TLS data payload
29-
MaxDataSize = 4096
33+
// Must match MAX_DATA_SIZE_OPENSSL in kern/common.h
34+
MaxDataSize = 1024 * 16 // 16384
35+
36+
// TaskCommLen is the maximum length of the process command name
37+
// Must match TASK_COMM_LEN in kern/common.h
38+
TaskCommLen = 16
3039
)
3140

32-
// TLSDataEvent represents a TLS data event from NSPR/NSS
41+
// TLSDataEvent represents a TLS data event from NSPR/NSS eBPF probe.
42+
// The struct layout must exactly match the C struct ssl_data_event_t in kern/nspr_kern.c:
43+
//
44+
// struct ssl_data_event_t {
45+
// enum ssl_data_event_type type; // u32 at offset 0 (0=read, 1=write)
46+
// // implicit 4-byte alignment padding
47+
// u64 timestamp_ns; // u64 at offset 8
48+
// u32 pid; // u32 at offset 16
49+
// u32 tid; // u32 at offset 20
50+
// char data[MAX_DATA_SIZE_OPENSSL]; // [16384]byte at offset 24
51+
// s32 data_len; // s32 at offset 16408
52+
// char comm[TASK_COMM_LEN]; // [16]byte at offset 16412
53+
// };
54+
// // Total: 16428 bytes
3355
type TLSDataEvent struct {
56+
// DataType encodes the event type (0=read, 1=write).
57+
// Uses int64 to absorb the C struct's u32 type + 4-byte alignment padding.
58+
DataType int64 `json:"dataType"`
59+
3460
// Timestamp is the event timestamp in nanoseconds
35-
Timestamp uint64
61+
Timestamp uint64 `json:"timestamp"`
3662

3763
// PID is the process ID
38-
PID uint32
64+
PID uint32 `json:"pid"`
3965

4066
// TID is the thread ID
41-
TID uint32
67+
TID uint32 `json:"tid"`
4268

43-
// Comm is the process command name
44-
Comm [16]byte
45-
46-
// FD is the file descriptor
47-
FD int32
69+
// Data is the TLS data payload
70+
Data [MaxDataSize]byte `json:"data"`
4871

4972
// DataLen is the length of actual data
50-
DataLen uint32
73+
DataLen int32 `json:"dataLen"`
5174

52-
// Direction: 0 = read, 1 = write
53-
Direction uint32
54-
55-
// Data is the TLS data payload
56-
Data [MaxDataSize]byte
75+
// Comm is the process command name
76+
Comm [TaskCommLen]byte `json:"comm"`
5777
}
5878

5979
// GetTimestamp returns the event timestamp as time.Time
@@ -82,42 +102,41 @@ func (e *TLSDataEvent) GetComm() string {
82102
return string(e.Comm[:])
83103
}
84104

85-
// GetFD returns the file descriptor
86-
func (e *TLSDataEvent) GetFD() int32 {
87-
return e.FD
88-
}
89-
90105
// GetDataLen returns the length of actual data
91106
func (e *TLSDataEvent) GetDataLen() uint32 {
92-
return e.DataLen
93-
}
94-
95-
// GetDirection returns the data direction (0 = read, 1 = write)
96-
func (e *TLSDataEvent) GetDirection() uint32 {
97-
return e.Direction
107+
return uint32(e.DataLen)
98108
}
99109

100110
// GetData returns the TLS data payload (up to DataLen bytes)
101111
func (e *TLSDataEvent) GetData() []byte {
102112
if e.DataLen > MaxDataSize {
103113
return e.Data[:MaxDataSize]
104114
}
115+
if e.DataLen < 0 {
116+
return nil
117+
}
105118
return e.Data[:e.DataLen]
106119
}
107120

108121
// IsRead returns true if this is a read event
109122
func (e *TLSDataEvent) IsRead() bool {
110-
return e.Direction == 0
123+
return e.DataType == DataTypeRead
111124
}
112125

113126
// IsWrite returns true if this is a write event
114127
func (e *TLSDataEvent) IsWrite() bool {
115-
return e.Direction == 1
128+
return e.DataType == DataTypeWrite
116129
}
117130

118-
// DecodeFromBytes implements domain.Event interface
131+
// DecodeFromBytes implements domain.Event interface.
132+
// Reads fields in exact order matching the C struct layout.
119133
func (e *TLSDataEvent) DecodeFromBytes(data []byte) error {
120-
buf := bytes.NewReader(data)
134+
buf := bytes.NewBuffer(data)
135+
136+
// Read DataType (int64 absorbs C's u32 type + 4-byte padding)
137+
if err := binary.Read(buf, binary.LittleEndian, &e.DataType); err != nil {
138+
return errors.NewEventDecodeError("nspr.DataType", err)
139+
}
121140

122141
// Read Timestamp
123142
if err := binary.Read(buf, binary.LittleEndian, &e.Timestamp); err != nil {
@@ -134,29 +153,19 @@ func (e *TLSDataEvent) DecodeFromBytes(data []byte) error {
134153
return errors.NewEventDecodeError("nspr.TID", err)
135154
}
136155

137-
// Read Comm
138-
if err := binary.Read(buf, binary.LittleEndian, &e.Comm); err != nil {
139-
return errors.NewEventDecodeError("nspr.Comm", err)
140-
}
141-
142-
// Read FD
143-
if err := binary.Read(buf, binary.LittleEndian, &e.FD); err != nil {
144-
return errors.NewEventDecodeError("nspr.FD", err)
156+
// Read Data
157+
if err := binary.Read(buf, binary.LittleEndian, &e.Data); err != nil {
158+
return errors.NewEventDecodeError("nspr.Data", err)
145159
}
146160

147161
// Read DataLen
148162
if err := binary.Read(buf, binary.LittleEndian, &e.DataLen); err != nil {
149163
return errors.NewEventDecodeError("nspr.DataLen", err)
150164
}
151165

152-
// Read Direction
153-
if err := binary.Read(buf, binary.LittleEndian, &e.Direction); err != nil {
154-
return errors.NewEventDecodeError("nspr.Direction", err)
155-
}
156-
157-
// Read Data
158-
if err := binary.Read(buf, binary.LittleEndian, &e.Data); err != nil {
159-
return errors.NewEventDecodeError("nspr.Data", err)
166+
// Read Comm
167+
if err := binary.Read(buf, binary.LittleEndian, &e.Comm); err != nil {
168+
return errors.NewEventDecodeError("nspr.Comm", err)
160169
}
161170

162171
return nil
@@ -169,8 +178,8 @@ func (e *TLSDataEvent) String() string {
169178
direction = "write"
170179
}
171180

172-
return fmt.Sprintf("TLSDataEvent{Timestamp: %v, PID: %d, TID: %d, Comm: %s, FD: %d, Direction: %s, DataLen: %d}",
173-
e.GetTimestamp(), e.PID, e.TID, e.GetComm(), e.FD, direction, e.DataLen)
181+
return fmt.Sprintf("TLSDataEvent{Timestamp: %v, PID: %d, TID: %d, Comm: %s, Direction: %s, DataLen: %d}",
182+
e.GetTimestamp(), e.PID, e.TID, e.GetComm(), direction, e.DataLen)
174183
}
175184

176185
// StringHex implements domain.Event interface - returns a hexadecimal representation
@@ -180,8 +189,8 @@ func (e *TLSDataEvent) StringHex() string {
180189
direction = "write"
181190
}
182191

183-
return fmt.Sprintf("TLSDataEvent{Timestamp: %v, PID: %d, TID: %d, Comm: %s, FD: %d, Direction: %s, DataLen: %d, Data(hex): %x}",
184-
e.GetTimestamp(), e.PID, e.TID, e.GetComm(), e.FD, direction, e.DataLen, e.GetData())
192+
return fmt.Sprintf("TLSDataEvent{Timestamp: %v, PID: %d, TID: %d, Comm: %s, Direction: %s, DataLen: %d, Data(hex): %x}",
193+
e.GetTimestamp(), e.PID, e.TID, e.GetComm(), direction, e.DataLen, e.GetData())
185194
}
186195

187196
// Clone implements domain.Event interface
@@ -216,6 +225,11 @@ func (e *TLSDataEvent) Decode(data []byte) error {
216225
func (e *TLSDataEvent) Encode() ([]byte, error) {
217226
buf := new(bytes.Buffer)
218227

228+
// Write DataType
229+
if err := binary.Write(buf, binary.LittleEndian, e.DataType); err != nil {
230+
return nil, fmt.Errorf("failed to write data type: %w", err)
231+
}
232+
219233
// Write Timestamp
220234
if err := binary.Write(buf, binary.LittleEndian, e.Timestamp); err != nil {
221235
return nil, fmt.Errorf("failed to write timestamp: %w", err)
@@ -231,29 +245,19 @@ func (e *TLSDataEvent) Encode() ([]byte, error) {
231245
return nil, fmt.Errorf("failed to write TID: %w", err)
232246
}
233247

234-
// Write Comm
235-
if err := binary.Write(buf, binary.LittleEndian, e.Comm); err != nil {
236-
return nil, fmt.Errorf("failed to write comm: %w", err)
237-
}
238-
239-
// Write FD
240-
if err := binary.Write(buf, binary.LittleEndian, e.FD); err != nil {
241-
return nil, fmt.Errorf("failed to write FD: %w", err)
248+
// Write Data
249+
if err := binary.Write(buf, binary.LittleEndian, e.Data); err != nil {
250+
return nil, fmt.Errorf("failed to write data: %w", err)
242251
}
243252

244253
// Write DataLen
245254
if err := binary.Write(buf, binary.LittleEndian, e.DataLen); err != nil {
246255
return nil, fmt.Errorf("failed to write data length: %w", err)
247256
}
248257

249-
// Write Direction
250-
if err := binary.Write(buf, binary.LittleEndian, e.Direction); err != nil {
251-
return nil, fmt.Errorf("failed to write direction: %w", err)
252-
}
253-
254-
// Write Data
255-
if err := binary.Write(buf, binary.LittleEndian, e.Data); err != nil {
256-
return nil, fmt.Errorf("failed to write data: %w", err)
258+
// Write Comm
259+
if err := binary.Write(buf, binary.LittleEndian, e.Comm); err != nil {
260+
return nil, fmt.Errorf("failed to write comm: %w", err)
257261
}
258262

259263
return buf.Bytes(), nil

0 commit comments

Comments
 (0)