Skip to content

Move appsec communication to sidecar - #3725

Draft
cataphract wants to merge 41 commits into
masterfrom
glopes/sidecar-comm
Draft

Move appsec communication to sidecar#3725
cataphract wants to merge 41 commits into
masterfrom
glopes/sidecar-comm

Conversation

@cataphract

@cataphract cataphract commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

Move AppSec communication to the sidecar

Summary

The AppSec helper already runs as a shared library loaded inside the sidecar
process
(the sidecar dlopens it via ddog_sidecar_enable_appsec). But until
now the extension did not talk to it through the sidecar: the helper opened its
own dedicated Unix domain socket, and the extension connected to that socket
directly, side-channeling past the sidecar's own transport. A lock file was used
to single-instance the helper. This PR removes that side-channel socket and lock
file.

The extension now reaches the helper by sending messages through the existing
sidecar transport
— the same channel already used for traces, telemetry, etc.
The AppSec request/response payloads (the dds-framed msgpack messages:
client_init, request_init, request_shutdown, …) are themselves unchanged,
but they are no longer exchanged over a raw socket: they are now wrapped as a
new message type inside the existing sidecar communication protocol
, and the
sidecar unwraps them and forwards them to the helper (and routes the reply
back).

As a consequence the standalone C++ helper is deleted in its entirety, along
with its build system and third-party dependencies (see "Secondary changes").

How communication works now

The broker API (libdatadog + components-rs)

The actual broker logic lives in libdatadog: this PR bumps the libdatadog
submodule, which adds the AppSec message-brokering API to the sidecar. To call
that API from this repo, components-rs/ carries the matching generated C
headers (sidecar.h, common.h) and the thin sidecar.rs wrapper, and the
new symbols are exported in datadog.sym. The new entry points are:

  • ddog_sidecar_send_appsec_message(transport, session_id, client_id, data)
    called by the extension side. It ships data to the sidecar, which
    routes it to the helper and returns the helper's reply as a
    ddog_AppsecCResponse { ptr, len, capacity, disconnect }. The disconnect
    flag tells the extension the session was torn down on the other end.
  • ddog_sidecar_appsec_response_drop(response) — frees the response buffer
    returned by send_appsec_message (a libdatadog-allocated Vec in the
    extension's own process, holding the bytes that came back over the sidecar
    transport). This is distinct from free_response below, which frees the
    helper's separate buffer on the sidecar side.
  • ddog_sidecar_appsec_register_message_handler(on_message, on_disconnect, free_response)
    — called by the helper when it is loaded into the sidecar, to register
    the three C callbacks the sidecar invokes.

Extension side

The socket transport in network.c/helper_process.c is gone (~600 lines
removed): no more connect()/retry loops, writev/recv framing,
SO_PEERCRED credential checks, send/recv timeouts, or socket/lock path
computation. dd_conn shrinks to { bool connected; uint64_t client_id; }.

Sending a command is now a single round-trip:

  • dd_conn_roundtripv() (replacing the old send + recv pair) serializes the
    outgoing msgpack into one buffer and hands it to a new
    dd_trace_send_appsec_message() wrapper in ddtrace.c.
  • That wrapper grabs the per-thread sidecar transport via the new
    ddtrace_get_sidecar_transport() export (added to datadog.sym and made
    ZTS-aware in ext/sidecar.c — it resolves the right thread's
    DATADOG_G(sidecar) from a passed-in TSRM cache) and calls
    ddog_sidecar_send_appsec_message(...).
  • The reply comes back as a ddog_AppsecCResponse, is parsed as msgpack, and
    freed with ddog_sidecar_appsec_response_drop().

Two new identifiers carry the routing:

  • session_id — the extension's formatted sidecar session id (the same one
    already used for the sidecar); it scopes a client to a PHP process tree.
  • client_id — a uint64 assigned by the helper. The extension's first
    message (client_init) is sent with client_id == 0, meaning "create a new
    client"; the helper allocates an id and returns it in the client_init
    response, and the extension stores it in conn->client_id for all
    subsequent messages.

New explicit teardown: commands/client_shutdown.{c,h} introduces a
client_shutdown message ({ clean: bool, error?: string }) sent from
GSHUTDOWN/request shutdown so the helper can drop the client promptly instead
of relying on a socket EOF. GSHUTDOWN was also made thread-safe (registers a
thread-local destructor and redirects TSRMLS_CACHE to the worker's cache).

test_mock_transport.{c,h} is new: in phpt tests there is no real sidecar, so
the mock transport intercepts dd_trace_send_appsec_message() and does raw
framed socket I/O against mock_helper over an fd handed in from PHP
(set_mock_helper_fd()).

Helper side

The helper no longer binds a UnixListener, no longer acquires a flock-based
single-instance lock (lock.rs, –178, deleted), and no longer polls the
sidecar for readiness. config.rs loses the socket and lock-path fields.

Instead, at startup it calls ddog_sidecar_appsec_register_message_handler and
serves traffic entirely through the three callbacks (new client/sidecar_msg.rs,
+718). Client tasks are still async Tokio tasks, but they are now fed by an
mpsc channel instead of a socket stream:

  • on_message(session_id, client_id, data, len) -> AppsecCResponse — the
    hot path. It looks up the client task for (session_id, client_id) in a
    CLIENTS map; if client_id == 0 it spawns a new client task and assigns a
    fresh id, writing it back through the *client_id out-parameter. It forwards
    the bytes to the task over an mpsc::Sender<HelperRequest> and block_ons
    the oneshot reply, then returns it as an AppsecCResponse. Errors/timeouts
    produce a FatalError reply with disconnect: true.
  • on_disconnect(session_id, client_id) — removes the client (or all
    clients of a session when client_id == 0) from the map; dropping the sender
    closes the task's channel and the task exits.
  • free_response(ptr, len, capacity) — reconstitutes and drops the Vec
    that backed a response.

The client message loop (client.rs) was reworked to decode Commands from
the mpsc stream (via the existing protocol::CommandCodec) and answer over a
oneshot sender rather than writing back to a socket; server.rs gains a
ClientTaskSet that owns the spawned tasks and drains them on shutdown.

So the end-to-end path for one command is:

extension: dd_conn_roundtripv → dd_trace_send_appsec_message
        → ddog_sidecar_send_appsec_message(session_id, client_id, data)
sidecar:  routes to helper → on_message(session_id, client_id, data)
helper:   mpsc → client task → oneshot reply → AppsecCResponse
sidecar:  returns bytes to extension; later free_response(...)
extension: parse msgpack; ddog_sidecar_appsec_response_drop

Secondary changes

  • C++ helper deleted: all of appsec/src/helper/** (client, engine, WAF
    glue, msgpack/network/proto layers) and its tests/benches/fuzzers.
  • Third-party deps dropped: appsec/third_party/{libddwaf,msgpack-c,cpp-base64}
    submodules and their .gitmodules/CMake wiring; cmake/helper.cmake,
    check_fslib.cpp and related clang-tidy/clang-format machinery.
  • Build/packaging: the separate helper build is gone —
    .gitlab/build-appsec-helper.sh deleted, the Rust helper now builds to the
    unified libddappsec-helper.so, generate-appsec.php/generate-package.php
    drop the C++ helper compile/asan/coverage jobs, and the final/SSI/debug
    artifact scripts stop shipping a second helper binary.
  • Config removed: DD_APPSEC_HELPER_RUNTIME_PATH and the
    helper_rust_redirection toggle (and their supported-configurations.json
    entries) — there is no socket/lock path to configure and no C++/Rust choice
    to make. client_init now only accepts the rust helper runtime.
  • Windows: config.w32 excludes the three new unix-only sidecar appsec
    symbols from the DLL exports (AppSec is not supported on Windows).
  • New integration tests: ConnectivityTests.groovy (clients exit promptly
    on sidecar disconnect, and clean shutdown via client_shutdown on GSHUTDOWN)
    and CrashDetectionTests.groovy (coredump on sidecar SIGSEGV; clean sidecar
    exit after Apache restart); TelemetryTests simplified now that the runtime
    is always Rust.

@cataphract
cataphract force-pushed the glopes/sidecar-comm branch 3 times, most recently from d9cd53f to 373c569 Compare March 24, 2026 20:29
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Mar 24, 2026

Copy link
Copy Markdown

Pipelines  Tests

Unblock PR with BitsAI

⚠️ Warnings

🚦 13 Pipeline jobs failed

DataDog/apm-reliability/dd-trace-php | ASAN test_c with multiple observers: [8.2]   View in Datadog   GitLab

DataDog/apm-reliability/dd-trace-php | test_extension_ci: [7.0]   View in Datadog   GitLab

DataDog/apm-reliability/dd-trace-php | test_extension_ci: [7.1]   View in Datadog   GitLab

View all 13 failed jobs.

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

🔄 Datadog auto-retried 1 job - 0 passed on retry View in Datadog

🎯 Code Coverage (details)
Patch Coverage: 54.49%
Overall Coverage: 16.71% (-43.97%)

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: ca267b0 | Docs | Datadog PR Page | Give us feedback!

@pr-commenter

pr-commenter Bot commented Mar 24, 2026

Copy link
Copy Markdown

Benchmarks [ tracer ]

Benchmark execution time: 2026-08-02 01:27:21

Comparing candidate commit ca267b0 in PR branch glopes/sidecar-comm with baseline commit af463f7 in branch master.

Found 4 performance improvements and 2 performance regressions! Performance is the same for 188 metrics, 0 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:HookBench/benchHookOverheadTraceFunction-opcache

  • 🟩 execution_time [-7.320µs; -3.731µs] or [-4.327%; -2.205%]

scenario:MessagePackSerializationBench/benchMessagePackSerialization

  • 🟩 execution_time [-4.971µs; -2.729µs] or [-4.432%; -2.433%]

scenario:MessagePackSerializationBench/benchMessagePackSerialization-opcache

  • 🟩 execution_time [-5.231µs; -3.509µs] or [-4.546%; -3.049%]

scenario:SamplingRuleMatchingBench/benchRegexMatching2-opcache

  • 🟩 execution_time [-10.850µs; -10.676µs] or [-86.774%; -85.382%]

scenario:SamplingRuleMatchingBench/benchRegexMatching3-opcache

  • 🟥 execution_time [+304.274ns; +609.326ns] or [+2.443%; +4.893%]

scenario:SamplingRuleMatchingBench/benchRegexMatching4-opcache

  • 🟥 execution_time [+472.051ns; +720.949ns] or [+3.804%; +5.810%]

@cataphract
cataphract force-pushed the glopes/sidecar-comm branch from 373c569 to 121733e Compare March 24, 2026 21:54
@codecov-commenter

codecov-commenter commented Mar 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 59.67213% with 492 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.84%. Comparing base (a1bb038) to head (366de49).

Files with missing lines Patch % Lines
appsec/helper-rust/src/client.rs 44.40% 144 Missing ⚠️
appsec/helper-rust/src/client/sidecar_msg.rs 81.47% 88 Missing ⚠️
appsec/helper-rust/src/server.rs 0.00% 77 Missing ⚠️
appsec/src/extension/test_mock_transport.c 58.76% 30 Missing and 10 partials ⚠️
appsec/src/extension/commands_helpers.c 66.96% 30 Missing and 7 partials ⚠️
appsec/src/extension/ddtrace.c 45.45% 30 Missing and 6 partials ⚠️
appsec/src/extension/network.c 58.82% 20 Missing and 8 partials ⚠️
appsec/helper-rust/src/lib.rs 0.00% 26 Missing ⚠️
appsec/src/extension/logging.h 0.00% 12 Missing ⚠️
appsec/src/extension/helper_process.c 66.66% 2 Missing ⚠️
... and 1 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3725      +/-   ##
==========================================
+ Coverage   68.81%   75.84%   +7.02%     
==========================================
  Files         166       66     -100     
  Lines       19030    13366    -5664     
  Branches     1797     1189     -608     
==========================================
- Hits        13095    10137    -2958     
+ Misses       5121     2662    -2459     
+ Partials      814      567     -247     
Flag Coverage Δ
helper-rust-unit 52.54% <60.16%> (+3.17%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
appsec/helper-rust/src/client/protocol.rs 95.07% <100.00%> (+0.01%) ⬆️
appsec/helper-rust/src/config.rs 97.77% <ø> (+0.21%) ⬆️
appsec/helper-rust/src/ffi.rs 74.48% <ø> (ø)
appsec/helper-rust/src/service/updateable_waf.rs 96.37% <100.00%> (+0.03%) ⬆️
appsec/helper-rust/src/service/waf_ruleset.rs 66.23% <ø> (ø)
appsec/helper-rust/src/telemetry.rs 74.07% <ø> (ø)
appsec/helper-rust/src/telemetry/sidecar.rs 82.60% <ø> (+3.50%) ⬆️
appsec/src/extension/commands/client_init.c 79.51% <100.00%> (+1.46%) ⬆️
appsec/src/extension/commands/request_exec.c 81.81% <100.00%> (ø)
appsec/src/extension/configuration.h 100.00% <ø> (ø)
... and 14 more

... and 34 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a1bb038...366de49. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cataphract
cataphract force-pushed the glopes/sidecar-comm branch 4 times, most recently from af7f0bc to 366de49 Compare March 25, 2026 02:04
@pr-commenter

pr-commenter Bot commented Mar 25, 2026

Copy link
Copy Markdown

Benchmarks [ appsec ]

Benchmark execution time: 2026-08-02 00:41:01

Comparing candidate commit ca267b0 in PR branch glopes/sidecar-comm with baseline commit af463f7 in branch master.

Found 3 performance improvements and 0 performance regressions! Performance is the same for 9 metrics, 0 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:LaravelBench/benchLaravelOverhead-appsec

  • 🟩 execution_time [-2.617ms; -2.441ms] or [-17.663%; -16.474%]

scenario:SymfonyBench/benchSymfonyOverhead-appsec

  • 🟩 execution_time [-2.859ms; -2.612ms] or [-25.026%; -22.864%]

scenario:WordPressBench/benchWordPressOverhead-appsec

  • 🟩 execution_time [-11.898ms; -11.770ms] or [-27.592%; -27.294%]

@estringana estringana assigned estringana and unassigned estringana Mar 25, 2026
Comment thread appsec/src/extension/commands_helpers.c Outdated
mlog(dd_log_debug, "Will exchange message with helper");

dd_result res = dd_conn_recv(conn, &imsg->_data, &imsg->_size);
// dd_result res = dd_conn_roundtripv(conn, iovecs, &imsg->_data,

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.

Should this comment go?

@cataphract
cataphract force-pushed the glopes/sidecar-comm branch 3 times, most recently from 8d09873 to 1238aea Compare May 13, 2026 12:53
@cataphract
cataphract force-pushed the glopes/sidecar-comm branch from 1238aea to 2b4a1c0 Compare May 20, 2026 13:24
cataphract and others added 2 commits May 20, 2026 14:26
The .gitmodules entry was removed in an earlier WIP commit but the
gitlink remained in the tree, causing CI checkout to fail.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@cataphract
cataphract force-pushed the glopes/sidecar-comm branch from 2698d89 to b4cf9f1 Compare May 27, 2026 15:54
@cataphract
cataphract force-pushed the glopes/sidecar-comm branch from 52e3c14 to d79dce4 Compare June 29, 2026 14:04
@cataphract
cataphract force-pushed the glopes/sidecar-comm branch from d79dce4 to 3c90bf0 Compare July 1, 2026 17:05
@cataphract
cataphract force-pushed the glopes/sidecar-comm branch from 1c54947 to 6c7685d Compare July 1, 2026 23:43
cataphract and others added 12 commits July 14, 2026 19:02
…hickory/reqwest

The root Cargo workspace includes appsec/helper-rust (since 3f893e2),
which depends on the appsec/third_party/libddwaf-rust submodule as a
path dependency. Any cargo invocation across the whole repo now needs
that submodule checked out, but GIT_SUBMODULE_PATHS for the tracer
pipeline (and the global default inherited by profiler/shared) never
included it, breaking nearly every job.

Also downgrade hickory-net/proto/resolver (via reqwest 0.13.4 -> 0.13.2)
back to the versions used on master, since 0.26.1 requires rustc 1.88
while the pinned toolchain is 1.87.0, breaking GitHub Actions profiling
jobs.
RUSTFLAGS didn't pick up -fsanitize=address, so build-script binaries
that link ASan-instrumented C objects (e.g. libddwaf-sys) failed with
undefined __asan_* symbols in debug-zts-asan compile jobs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…bers

Cargo.toml's members list was reformatted to one entry per line, so the
old `s/, "profiling"//` sed (expecting a single-line array) silently
no-oped, leaving profiling in the packaged Cargo.toml even though
profiling/ itself is never shipped in the pecl tarball.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
helper-rust is now a library dependency of the sidecar crate rather
than its own cdylib, so cargo no longer produces
target/release/libddappsec_helper.so, and datadog.appsec.helper_path
is no longer read anywhere.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@cataphract
cataphract force-pushed the glopes/sidecar-comm branch from 16330ba to 5861a71 Compare July 20, 2026 16:13
@cataphract
cataphract force-pushed the glopes/sidecar-comm branch from 5190d19 to 6e94b30 Compare July 30, 2026 09:37
@cataphract
cataphract force-pushed the glopes/sidecar-comm branch from a048b31 to 3eef763 Compare August 1, 2026 02:50
The portable (musl-built, glibc-compat) libdatadog_php.so has its libc
DT_NEEDED patched out and relies on the host's libc being in the global
scope. When the sidecar is direct-spawned, ld-linux execs the DSO itself,
so anything it needs beyond libc.so.6 (which ld-linux always brings in)
must be passed with --preload.

add_glibc_direct_preloads() only did that on glibc < 2.34, assuming 2.34
had merged all four DSOs into libc. It did not merge libm: exp/log/pow
(referenced by libdd-ddsketch, libdd-telemetry and datadog-ipc's shm
stats) still live in libm.so.6 on every glibc. On glibc >= 2.34 hosts the
spawned sidecar therefore died at load with

    libdatadog_php.so: symbol lookup error: undefined symbol: exp

which made every sidecar connection reset, so AppSec never started
("AppSec sidecar backend is unavailable"). This broke the FrankenPHP SSI
tests (dunglas/frankenphp:1.4-php8.4 is Debian 12, glibc 2.36): 27
FrankenphpClassicTests + 10 FrankenphpWorkerTests failures in the
"helper-rust integration coverage" job.

Preload libm.so.6 whenever the host is glibc, and keep libdl/libpthread/
librt for glibc < 2.34.

Verified with test8.4-release-zts-ssi (glibc 2.36, FrankenPHP): 27
failures before, 0 after; test8.3-release-ssi (glibc 2.31, the < 2.34
path) still green.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@cataphract
cataphract force-pushed the glopes/sidecar-comm branch from 2377925 to 3051f14 Compare August 1, 2026 11:37
cataphract and others added 5 commits August 1, 2026 14:33
The portable (glibc-compat) build is built against musl with
-C target-feature=-crt-static and then has its musl libc DT_NEEDED
patched out, so it binds to whatever libc the host process already has.
That left libgcc_s.so.1 as its one and only DT_NEEDED, which is wrong on
two counts: bare alpine images don't ship libgcc_s.so.1 (so the library
was unloadable there), and it was the only thing keeping ld.so from
treating the library as a static binary.

Drop it: rustc's unwind crate only emits -lgcc_s because crt-static is
off (library/unwind/src/lib.rs); point that -lgcc_s at libgcc_eh.a via a
linker script of our own so the unwinder is linked statically instead.
-static-libgcc does not help here -- it only affects the specs the GCC
driver expands for its own -lgcc, not an explicit -lgcc_s.

Then declare the dependencies the library actually has, using the glibc
names. musl's loader resolves libc.*/libm.*/libdl.*/libpthread.*/librt.*
DT_NEEDED entries to the implementation itself without touching the
filesystem, so a single artifact stays correct on both libcs, and the
references remain unversioned, so no .gnu.version_r entry is created.

This also avoids ending up with zero DT_NEEDED entries: since 2.33 glibc
re-execs an object with no DT_NEEDED and no PT_INTERP instead of loading
it (rtld_chain_load() in elf/rtld.c), which segfaults the sidecar's
direct spawn, where the library itself is the program handed to ld.so.

Verified on the real artifact: direct exec via ld.so and dlopen(RTLD_NOW)
both work with no preloads at all on bare debian bookworm-slim (glibc
2.36) and bare alpine 3.21, where the previous artifact failed outright.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
8a51d1b gave the portable DSO real DT_NEEDED entries (libc.so.6,
libm.so.6, libdl.so.2, libpthread.so.0, librt.so.1) instead of stripping
them all. That makes both the sidecar's direct-spawn and the SSI loader's
dlopen() resolve every dependency from the DSO's own dynamic section
before any preload/relocation step runs, so the libm.so.6 (and, on
glibc < 2.34, libdl/libpthread/librt) --preload injection is a strict
subset of what's now loaded anyway -- a no-op kept only as defense in
depth.

Verified on the real portable artifact (aarch64), direct-spawn and SSI
dlopen with zero preloads, on glibc 2.27/2.28/2.36 and musl 1.2.5: entry
point runs and symbols resolve. Negative control: removing libm.so.6 from
DT_NEEDED reproduces "undefined symbol: exp" on all of them, confirming
the DT_NEEDED entries (not the preloads) are what makes this work.

Also reverts the libdatadog submodule's spawn_worker --preload support
(2f9d3c1e8), which had no other caller, restoring
Config::spawn_without_trampoline and the argument-less
SpawnMethod::Direct. loader/dd_library_loader.c is now byte-identical to
origin/master.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(ci): isolate PHPTs from Fabric egress proxy

* fix(ci): isolate integration tests from Fabric proxy

* fix(appsec): unset proxy in test wrapper
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants