Skip to content
Open
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
27 changes: 27 additions & 0 deletions docs/cloud-workload-security/backend_linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,13 @@ Workload Protection events for Linux systems have the following JSON schema:
"trace_id": {
"type": "string",
"description": "Trace ID used for APM correlation"
},
"attributes": {
"additionalProperties": {
"type": "string"
},
"type": "object",
"description": "Attributes contains custom OTel thread-local attributes from the span context"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I recommend changing all instances of this to:

                    "description": "Custom OTel thread-local attributes from the span context"

This reads a bit cleaner and is consistent with the descriptions already in the doc.

}
},
"additionalProperties": false,
Expand Down Expand Up @@ -2279,6 +2286,12 @@ Workload Protection events for Linux systems have the following JSON schema:
},
"logs_collected": {
"type": "boolean"
},
"threadlocal_attribute_keys": {
"items": {
"type": "string"
},
"type": "array"
}
},
"additionalProperties": false,
Expand Down Expand Up @@ -3072,6 +3085,13 @@ Workload Protection events for Linux systems have the following JSON schema:
"trace_id": {
"type": "string",
"description": "Trace ID used for APM correlation"
},
"attributes": {
"additionalProperties": {
"type": "string"
},
"type": "object",
"description": "Attributes contains custom OTel thread-local attributes from the span context"
}
},
"additionalProperties": false,
Expand All @@ -3085,6 +3105,7 @@ Workload Protection events for Linux systems have the following JSON schema:
| ----- | ----------- |
| `span_id` | Span ID used for APM correlation |
| `trace_id` | Trace ID used for APM correlation |
| `attributes` | Attributes contains custom OTel thread-local attributes from the span context |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
| `attributes` | Attributes contains custom OTel thread-local attributes from the span context |
| `attributes` | Custom OTel thread-local attributes from the span context |



## `DNSEvent`
Expand Down Expand Up @@ -5892,6 +5913,12 @@ Workload Protection events for Linux systems have the following JSON schema:
},
"logs_collected": {
"type": "boolean"
},
"threadlocal_attribute_keys": {
"items": {
"type": "string"
},
"type": "array"
}
},
"additionalProperties": false,
Expand Down
13 changes: 13 additions & 0 deletions docs/cloud-workload-security/backend_linux.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,13 @@
"trace_id": {
"type": "string",
"description": "Trace ID used for APM correlation"
},
"attributes": {
"additionalProperties": {
"type": "string"
},
"type": "object",
"description": "Attributes contains custom OTel thread-local attributes from the span context"
}
},
"additionalProperties": false,
Expand Down Expand Up @@ -2268,6 +2275,12 @@
},
"logs_collected": {
"type": "boolean"
},
"threadlocal_attribute_keys": {
"items": {
"type": "string"
},
"type": "array"
}
},
"additionalProperties": false,
Expand Down
21 changes: 21 additions & 0 deletions pkg/discovery/tracermetadata/model/tracer_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@ type TracerMetadata struct {
ProcessTags string `json:"process_tags,omitempty"`
ContainerID string `json:"container_id,omitempty"`
LogsCollected bool `json:"logs_collected,omitempty"`
// ThreadlocalAttributeKeys is the ordered list of attribute key names for OTel
// Thread Local Context Records (per OTel spec PR #4947). Key indices in a thread's
// attrs_data section index into this list to resolve the full attribute name.
// The first entry is implicitly "datadog.local_root_span_id" (index 0).
ThreadlocalAttributeKeys []string `json:"threadlocal_attribute_keys,omitempty"`
}

// IsZero returns true if the TracerMetadata is empty (zero value).
func (t TracerMetadata) IsZero() bool {
return t.SchemaVersion == 0 &&
t.RuntimeID == "" &&
t.TracerLanguage == "" &&
t.TracerVersion == "" &&
t.Hostname == "" &&
t.ServiceName == "" &&
t.ServiceEnv == "" &&
t.ServiceVersion == "" &&
t.ProcessTags == "" &&
t.ContainerID == "" &&
!t.LogsCollected &&
len(t.ThreadlocalAttributeKeys) == 0
}

// ShouldSkipServiceTagKV checks if a tracer service tag key-value pair should be
Expand Down
86 changes: 81 additions & 5 deletions pkg/discovery/tracermetadata/model/tracer_metadata_gen.go

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

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
†®schema_version̯tracer_language£cpp®tracer_version¦v1.0.0¨hostname©test-host¬service_name±otel-test-serviceºthreadlocal_attribute_keys“«http.method«http.target©http.user
17 changes: 17 additions & 0 deletions pkg/discovery/tracermetadata/tracer_memfd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,23 @@ func TestGetTracerMetadata(t *testing.T) {
}, tags)
})

t.Run("cpp_with_threadlocal_attribute_keys", func(t *testing.T) {
loadTracerMetadata(t, "testdata/tracer_cpp_with_attrs.data")
trm, err := GetTracerMetadata(pid, procfs)
require.NoError(t, err)
require.Equal(t, "otel-test-service", trm.ServiceName)
require.Equal(t, "cpp", trm.TracerLanguage)
require.Equal(t, "v1.0.0", trm.TracerVersion)
require.Equal(t, "test-host", trm.Hostname)
require.Equal(t, uint8(2), trm.SchemaVersion)

// Verify threadlocal_attribute_keys are parsed
require.Len(t, trm.ThreadlocalAttributeKeys, 3, "should have 3 threadlocal attribute keys")
assert.Equal(t, "http.method", trm.ThreadlocalAttributeKeys[0])
assert.Equal(t, "http.target", trm.ThreadlocalAttributeKeys[1])
assert.Equal(t, "http.user", trm.ThreadlocalAttributeKeys[2])
})

t.Run("invalid data", func(t *testing.T) {
createTracerMemfd(t, []byte("invalid data"))
trm, err := GetTracerMetadata(pid, procfs)
Expand Down
2 changes: 1 addition & 1 deletion pkg/network/events/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (h *eventConsumerWrapper) Copy(ev *model.Event) any {
}
}

if tmeta := ev.GetProcessTracerMetadata(); (tmeta != tracermetadata.TracerMetadata{}) {
if tmeta := ev.GetProcessTracerMetadata(); !tmeta.IsZero() {
for key, value := range tmeta.Tags() {
if tracermetadata.ShouldSkipServiceTagKV(key, value,
tagsFound["DD_SERVICE"],
Expand Down
7 changes: 7 additions & 0 deletions pkg/security/ebpf/c/include/constants/enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ enum tls_format
DEFAULT_TLS_FORMAT
};

enum otel_runtime_language
{
OTEL_RUNTIME_NATIVE = 0,
OTEL_RUNTIME_GOLANG = 1,
};

enum bpf_cmd_def
{
BPF_MAP_CREATE_CMD,
Expand Down Expand Up @@ -232,6 +238,7 @@ enum erpc_op
PRCTL_DISCARDER,
AUID_DISCARDER,
NOP_EVENT_OP,
REGISTER_OTEL_TLS_OP_DEPRECATED, // DEPRECATED: replaced by dynsym-based discovery
};

enum selinux_source_event_t
Expand Down
28 changes: 28 additions & 0 deletions pkg/security/ebpf/c/include/constants/offsets/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,32 @@ u64 __attribute__((always_inline)) get_task_struct_pid_offset() {
return task_struct_pid_offset;
}

// OTel TLSDESC thread pointer access.
// Two offsets are summed to compute the address of the thread pointer within a task_struct:
// x86_64: fsbase_addr = (void *)task + thread_offset + fsbase_offset
// ARM64: tp_value_addr = (void *)task + thread_offset + uw_offset
// They are split because the BTF constant fetcher does not support dot-path
// traversal for named (non-anonymous) nested struct members.
u64 __attribute__((always_inline)) get_task_struct_thread_offset() {
u64 offset;
LOAD_CONSTANT("task_struct_thread_offset", offset);
return offset;
}

#if defined(__x86_64__)
u64 __attribute__((always_inline)) get_thread_struct_fsbase_offset() {
u64 offset;
LOAD_CONSTANT("thread_struct_fsbase_offset", offset);
return offset;
}
#elif defined(__aarch64__)
// thread_struct.uw.tp_value: tp_value is the first member of uw (offset 0),
// so the offset of uw within thread_struct gives us the tp_value address.
u64 __attribute__((always_inline)) get_thread_struct_uw_offset() {
u64 offset;
LOAD_CONSTANT("thread_struct_uw_offset", offset);
return offset;
}
#endif

#endif
Loading
Loading