Skip to content

Commit fa521b6

Browse files
committed
Merge remote-tracking branch 'origin/main' into ralph/alp-log-querying-benchmark
# Conflicts: # comp/core/agenttelemetry/fx/go.sum # comp/core/agenttelemetry/impl/go.sum # comp/logs-library/go.sum # comp/otelcol/collector-contrib/impl/go.sum # comp/otelcol/ddflareextension/impl/go.sum # comp/otelcol/logsagentpipeline/go.sum # comp/otelcol/logsagentpipeline/logsagentpipelineimpl/go.sum # comp/otelcol/otlp/components/exporter/datadogexporter/go.sum # comp/otelcol/otlp/components/exporter/logsagentexporter/go.sum # comp/otelcol/otlp/components/exporter/serializerexporter/go.sum # go.sum # internal/qbranch/anomalydetection-testbench/go.sum # test/otel/go.mod # test/otel/go.sum
2 parents 8a57d29 + f43a236 commit fa521b6

139 files changed

Lines changed: 1148 additions & 399 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.bazelrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,11 @@ common:linux --credential_helper=buildbarn-frontend-datadog-agent.us1.ddbuild.io
5959
common:linux --strategy=sandboxed
6060

6161
# macOS config ---------------------------------------------------------------------------------------------------------
62+
common:macos --copt=-mmacosx-version-min=12.0 # https://docs.datadoghq.com/agent/supported_platforms/?tab=macos
6263
common:macos --credential_helper=buildbarn-edge-cache.buildbarn.local-cluster.local-dc.fabric.dog=%workspace%/bazel/tools/credential-helper
6364
common:macos --credential_helper=buildbarn-frontend-datadog-agent.us1.ddbuild.io=%workspace%/bazel/tools/credential-helper
6465
common:macos --features=-macos_default_link_flags # https://github.com/bazelbuild/bazel/issues/23312
65-
common:macos --macos_minimum_os=12.0 # Keep in sync with https://docs.datadoghq.com/agent/supported_platforms/?tab=macos
66+
common:macos --linkopt=-mmacosx-version-min=12.0 # https://docs.datadoghq.com/agent/supported_platforms/?tab=macos
6667
common:macos --strategy=sandboxed
6768

6869
# Windows config -------------------------------------------------------------------------------------------------------
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
name: cws-iouring-coverage
3+
description: Audit CWS (runtime-security) io_uring functional-test coverage and add a functional test for any io_uring opcode whose operation CWS observes but that is not exercised through io_uring. Test-driven — coverage is judged by tests, never by reading eBPF/hook internals. Use when auditing io_uring test coverage or after new IORING_OP_ opcodes appear.
4+
---
5+
6+
# CWS io_uring test coverage audit
7+
8+
For every io_uring operation CWS observes, there must be a functional test that issues the
9+
operation *through io_uring* and asserts the event fires. This skill finds the gaps and fills
10+
them.
11+
12+
## Principle: tests are the only arbiter
13+
14+
Coverage is decided by tests, nothing else. **Do not read eBPF programs or C hooks** (anything
15+
under `pkg/security/ebpf/`) to judge coverage — implementation is out of scope and misleads.
16+
The only question is: *does an io_uring test exist for this operation, and does it pass?*
17+
18+
The one io_uring-specific fact (it's a test assertion, not implementation): io_uring completes
19+
asynchronously, so **every io_uring test must assert `event.async == true`**.
20+
21+
## The audit: build three lists, then intersect
22+
23+
**List A — io_uring opcodes.** `WebFetch https://man7.org/linux/man-pages/man2/io_uring_enter.2.html`
24+
and list every `IORING_OP_*` with the syscall it performs (e.g. `IORING_OP_SOCKET``socket(2)`).
25+
Offline fallback: the iouring-go fork is `replace`d in `go.mod` — import path stays
26+
`github.com/iceber/iouring-go`, but source on disk is under
27+
`$(go env GOMODCACHE)/github.com/lebauce/iouring-go@*/syscall/types.go`.
28+
29+
**List B — tested syscalls.** Read `pkg/security/tests/`. A syscall is *tested* when a test
30+
issues it **as the triggering action** (inside the `func() error {…}` passed to
31+
`WaitSignal`/`runSyscallTester`) **and asserts an event** — not when it only appears as setup.
32+
Build the list from test bodies, not event names: the asserted event may be named differently.
33+
34+
**List C — tested io_uring opcodes.** `grep -rn 'iouring\.\|io_uring' pkg/security/tests/*.go`.
35+
Mostly `t.Run("io_uring", …)` subtests plus a few standalone funcs.
36+
37+
**Conclude, per opcode in A:**
38+
- syscall ∉ B → **out of scope** (CWS doesn't observe it; no io_uring test expected).
39+
- syscall ∈ B → **in scope**; then opcode ∈ C → **tested**, else → **gap**.
40+
41+
Write a test for every gap.
42+
43+
## Writing the io_uring test
44+
45+
Model on an existing subtest (`open_test.go``t.Run("io_uring", …)`). For each gap:
46+
47+
1. **Rule scope.** The test process is `testsuite`. Many rules are scoped to
48+
`process.file.name == "syscall_tester"`; reuse the parent rule only if it already admits
49+
`testsuite` (e.g. `in [ "syscall_tester", "testsuite" ]`), otherwise add a new rule scoped to
50+
`process.file.name == "testsuite"`. Check the parent's `ruleDefs` first.
51+
2. **Submit.** `iour, err := iouring.New(1)`; submit the op; read the result; in the validation
52+
callback assert event type, key fields, and `event.async == true`.
53+
3. **Kernel gate, not errno skip.** Gate "kernel too old for this opcode" deterministically at
54+
the top of the subtest:
55+
`checkKernelCompatibility(t, "io_uring <op> needs Linux X.Y", func(kv *kernel.Version) bool { return kv.Code < kernel.VersionCode(X, Y, 0) })`.
56+
Don't skip on a negative errno — a malformed raw SQE returns one too, so skipping would hide
57+
the gap behind a green test. On a supported kernel, treat an unexpected negative result as a
58+
**failure** (`return fmt.Errorf(...)`). (A library prep helper can't be malformed, so an
59+
errno skip there is harmless.)
60+
4. **ebpfless.** Only matters if the parent test is in the `available` list (`~`-prefixed
61+
entries) in `pkg/security/tests/main_linux.go` — those prefix-match subtests and pull yours
62+
into the ebpfless run, where io_uring is unsupported. If so, add an `exclude` entry. The
63+
match is exact on the full `t.Name()`, so prefer a flat sibling name
64+
(`TestOpen/io_uring_ftruncate`, not a nested `TestOpen/io_uring/ftruncate`).
65+
66+
**No prep helper in the fork?** The fork wraps only a subset. For other opcodes build a raw SQE
67+
with a custom `iouring.PrepRequest` using the helpers in `pkg/security/tests/iouring_test.go`
68+
(extend them as needed). This is the one place you may touch an opcode's low-level shape.
69+
70+
## Verify
71+
72+
- `gofmt -l <your files>` (no output = OK).
73+
- Run the test via the harness:
74+
`dda inv security-agent.functional-tests --skip-linters --testflags="-test.run <YourTest>"`.
75+
Green = covered, red = the gap is real.
76+
77+
## Report
78+
79+
Report the per-opcode classification (out of scope / tested / gap) and the test files
80+
added or changed.

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
/.claude/skills/create-runtime-setting/ @DataDog/agent-runtimes @DataDog/agent-configuration
3434
/.claude/skills/create-status-provider/ @DataDog/agent-configuration
3535
/.claude/skills/create-subcommand/ @DataDog/agent-configuration
36+
/.claude/skills/cws-iouring-coverage/ @DataDog/agent-security
3637
/.claude/skills/explain-lading-config @DataDog/single-machine-performance
3738
/.claude/skills/quality-gate-size-analysis/ @DataDog/agent-build
3839
/.claude/skills/review-pr-comments/ @DataDog/agent-devx

MODULE.bazel

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ bazel_dep(name = "package_metadata", version = "0.0.13")
5656
bazel_dep(name = "platforms", version = "1.1.0")
5757
bazel_dep(name = "protobuf", version = "35.1")
5858
bazel_dep(name = "re.bzl", version = "0.3.1")
59-
bazel_dep(name = "rules_cc", version = "0.2.20")
59+
bazel_dep(name = "rules_cc", version = "0.2.21")
6060
bazel_dep(name = "rules_flex", version = "0.4.1")
6161
bazel_dep(name = "rules_go", version = "0.61.1")
6262
bazel_dep(name = "rules_m4", version = "0.3.bcr.1")
@@ -108,6 +108,14 @@ single_version_override(
108108
],
109109
)
110110

111+
# Temporary until https://github.com/bazel-contrib/toolchains_llvm/pull/790 lands in a release
112+
archive_override(
113+
module_name = "toolchains_llvm",
114+
sha256 = "addeebfa8fdcf9fbc1c339e451cbb285e1c0d4c078c3718e42bd1791d0d96d4e",
115+
strip_prefix = "toolchains_llvm-ffe407ca2423f4d171b7a0f3897c23bbb7e40310",
116+
urls = ["https://github.com/bazel-contrib/toolchains_llvm/archive/ffe407ca2423f4d171b7a0f3897c23bbb7e40310.tar.gz"],
117+
)
118+
111119
#########################
112120
## Prebuilt binaries ##
113121
#########################

MODULE.bazel.lock

Lines changed: 4 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bazel/rules/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@ sh_binary(
99
"--patchelf",
1010
"$(location @patchelf)",
1111
],
12+
"@platforms//os:macos": [
13+
"--install-name-tool",
14+
"$(location @llvm_toolchain_llvm//:install-name-tool)",
15+
],
1216
"//conditions:default": [],
1317
}),
1418
data = select({
1519
"@platforms//os:linux": ["@patchelf"],
20+
"@platforms//os:macos": ["@llvm_toolchain_llvm//:install-name-tool"],
1621
"//conditions:default": [],
1722
}),
1823
tags = ["manual"],

bazel/rules/dd_packaging/dd_cc_packaged.bzl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ _dd_packaged_files_rule = rule(
7070
allow_single_file = True,
7171
cfg = "exec",
7272
),
73+
"_install_name_tool": attr.label(
74+
default = "@@//bazel/tools:install_name_tool",
75+
executable = True,
76+
cfg = "exec",
77+
),
7378
"_install_dir": attr.label(default = "@@//:install_dir"),
7479
},
7580
toolchains = [

bazel/rules/foreign_cc_runnable/foreign_cc_runnable.bzl

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,20 @@ def _foreign_cc_runnable_impl(ctx):
9797
if not is_linux and not is_macos:
9898
fail("{}: unsupported platform (Linux and macOS only)".format(ctx.label))
9999

100-
patchelf_path = ""
101-
patchelf_tools = []
100+
args = ctx.actions.args()
101+
102+
tools = []
102103
if is_linux:
103104
patchelf_toolchain = ctx.toolchains["@@//bazel/toolchains/patchelf:patchelf_toolchain_type"].patchelf
104105
patchelf = patchelf_toolchain.label[DefaultInfo].files_to_run
105-
patchelf_path = patchelf.executable.path
106-
patchelf_tools = [patchelf]
106+
args.add("--patchelf", patchelf.executable.path)
107+
tools.append(patchelf)
108+
else:
109+
install_name_tool = ctx.executable._install_name_tool
110+
args.add("--install-name-tool", install_name_tool.path)
111+
tools.append(install_name_tool)
107112

108-
args = ctx.actions.args()
109113
args.add("linux" if is_linux else "darwin")
110-
args.add(patchelf_path)
111114
args.add(input_tree.path)
112115
args.add(output_tree.path)
113116
args.add(manifest.path)
@@ -117,7 +120,7 @@ def _foreign_cc_runnable_impl(ctx):
117120
executable = ctx.file._script,
118121
arguments = [args],
119122
inputs = [input_tree, manifest],
120-
tools = patchelf_tools,
123+
tools = tools,
121124
outputs = [output_tree],
122125
mnemonic = "ForeignCcRunnable",
123126
progress_message = "Rewriting rpaths for %{label}",
@@ -168,6 +171,11 @@ foreign_cc_runnable = rule(
168171
cfg = "exec",
169172
executable = True,
170173
),
174+
"_install_name_tool": attr.label(
175+
default = "@@//bazel/tools:install_name_tool",
176+
executable = True,
177+
cfg = "exec",
178+
),
171179
"_linux_constraint": attr.label(
172180
default = "@platforms//os:linux",
173181
),

bazel/rules/foreign_cc_runnable/patch_rpaths.sh

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,36 @@
1010
# A FILE must exist; a GLOB must match at least one file.
1111
set -euo pipefail
1212

13+
PATCHELF=""
14+
INSTALL_NAME_TOOL=""
15+
16+
while [ "$#" -gt 0 ]; do
17+
case "$1" in
18+
--patchelf)
19+
shift
20+
PATCHELF="$1"
21+
;;
22+
--install-name-tool)
23+
shift
24+
INSTALL_NAME_TOOL="$1"
25+
;;
26+
*)
27+
break
28+
;;
29+
esac
30+
shift
31+
done
32+
33+
if [ "$#" -lt 4 ]; then
34+
echo "Usage: patch_rpaths.sh [--patchelf <path>|--install-name-tool <path>] <platform> <input> <output> <manifest> [rpath dirs...]" >&2
35+
exit 1
36+
fi
37+
1338
PLATFORM="$1"
14-
PATCHELF="$2"
15-
INPUT="$3"
16-
OUTPUT="$4"
17-
MANIFEST="$5"
18-
shift 5
39+
INPUT="$2"
40+
OUTPUT="$3"
41+
MANIFEST="$4"
42+
shift 4
1943
RPATH_DIRS=("$@")
2044

2145
# `cp -rL` materializes a real copy and dereferences any symlinks that
@@ -36,8 +60,9 @@ patch_file() {
3660
done
3761

3862
if [[ "$PLATFORM" == "darwin" ]]; then
63+
"$INSTALL_NAME_TOOL" -delete_all_rpaths "$f"
3964
for dir in "${RPATH_DIRS[@]}"; do
40-
install_name_tool -add_rpath "@loader_path/${ups}${dir}" "$f"
65+
"$INSTALL_NAME_TOOL" -add_rpath "@loader_path/${ups}${dir}" "$f"
4166
done
4267
# Re-sign with an ad-hoc signature; install_name_tool invalidates any existing code signature.
4368
codesign --sign - --force "$f" 2>/dev/null

bazel/rules/replace_prefix.sh

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
set -euo pipefail
44

5+
INSTALL_NAME_TOOL=""
6+
57
while [ "$#" -gt 0 ]; do
68
case "$1" in
79
--prefix | -p)
@@ -12,6 +14,10 @@ while [ "$#" -gt 0 ]; do
1214
shift
1315
PATCHELF="$1"
1416
;;
17+
--install-name-tool)
18+
shift
19+
INSTALL_NAME_TOOL="$1"
20+
;;
1521
*)
1622
break
1723
esac
@@ -47,31 +53,29 @@ for f in "$@"; do
4753
if file "$f" | grep -q ELF; then
4854
${PATCHELF} --force-rpath --set-rpath "$PREFIX"/lib "$f"
4955
elif file "$f" | grep -q "Mach-O"; then
56+
if [ -z "$INSTALL_NAME_TOOL" ]; then
57+
echo "replace_prefix.sh: --install-name-tool is required for Mach-O files" >&2
58+
exit 1
59+
fi
60+
5061
# Handle macOS binaries (executables and other Mach-O files)
5162
# Match the Linux patchelf --set-rpath behavior: replace existing paths
5263
# instead of just appending them.
5364
new_rpath="$PREFIX/lib"
54-
otool -l "$f" | awk '
55-
$1 == "cmd" && $2 == "LC_RPATH" { in_rpath = 1; next }
56-
in_rpath && $1 == "path" { print $2; in_rpath = 0 }
57-
' | while read -r rpath; do
58-
install_name_tool -delete_rpath "$rpath" "$f" 2>/dev/null || true
59-
done
60-
install_name_tool -add_rpath "$new_rpath" "$f" 2>/dev/null || true
65+
"$INSTALL_NAME_TOOL" -delete_all_rpaths -add_rpath "$new_rpath" "$f"
6166
# Get the old install name/ID
6267
dylib_name=$(basename "$f")
6368
new_id="$PREFIX/lib/$dylib_name"
6469

6570
# Change the dylib's own ID
66-
install_name_tool -id "$new_id" "$f"
71+
"$INSTALL_NAME_TOOL" -id "$new_id" "$f"
6772

6873
# Update all dependency paths that point to sandbox locations
6974
otool -L "$f" | tail -n +2 | awk '{print $1}' | while read -r dep; do
7075
if [[ "$dep" == *"sandbox"* ]] || [[ "$dep" == *"bazel-out"* ]]; then
7176
dep_name=$(basename "$dep")
7277
new_dep="$PREFIX/lib/$dep_name"
73-
install_name_tool -change "$dep" "$new_dep" "$f" 2>/dev/null || true
74-
install_name_tool -add_rpath "$PREFIX/lib" "$dep" 2>/dev/null || true
78+
"$INSTALL_NAME_TOOL" -change "$dep" "$new_dep" "$f" 2>/dev/null || true
7579
fi
7680
done
7781
# Re-sign with an ad-hoc signature after modification as install_name_tool invalidates

0 commit comments

Comments
 (0)