Skip to content

[codex] Simplify signal-safe crashtracker collector#2198

Draft
pawelchcki wants to merge 24 commits into
mainfrom
signal_safe_crashtracker
Draft

[codex] Simplify signal-safe crashtracker collector#2198
pawelchcki wants to merge 24 commits into
mainfrom
signal_safe_crashtracker

Conversation

@pawelchcki

Copy link
Copy Markdown
Contributor

Summary

Refactors the signal-safe crashtracker collector cleanup plan into code.

  • Trims the collector_signal_safe public surface and removes dead emitter/config paths.
  • Shares child reaping logic and simplifies handler/capability cleanup flows.
  • Moves signal and si_code naming into shared Rust code and removes the C shim.
  • Reworks syscall wrappers toward rustix while keeping raw syscalls only where needed.

Validation

Passed locally:

  • cargo check -p libdd-crashtracker --no-default-features --features collector_signal-safe
  • cargo check -p libdd-crashtracker
  • cross-target checks for x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu, and aarch64-apple-darwin
  • cargo +nightly-2026-02-08 fmt --all -- --check
  • cargo +stable clippy --workspace --all-targets --all-features -- -D warnings
  • cargo nextest run -p libdd-crashtracker --features collector_signal-safe,generate-unit-test-files --no-fail-fast
  • cargo test --doc -p libdd-crashtracker
  • ./tools/check_signal_safe_symbols.sh
  • ./scripts/update_license_3rdparty.sh
  • git diff --check

Known local validation caveats:

  • cargo deny check runs but fails on existing workspace-wide deny/advisory/license issues.
  • cargo nextest run --workspace --no-fail-fast ended with 2092 passed, 2 failed, 5 skipped; the FFE fixture test is blocked by an uninitialized datadog-ffe-test-suite/ffe-system-test-data submodule, and test_crash_tracking_bin_sigchld_sigstack passed when rerun in isolation.
  • The non-FP-walk Linux architecture cfg sweep was not run because no such Rust target is installed locally.

pawelchcki and others added 17 commits July 4, 2026 01:29
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Supersede signal_safe_collector_improvement_plan.md with a consolidated
signal_safe_crashtracker_plan.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Trim the collector_signal_safe public surface, remove dead emitter/config paths, reuse rustix/system helpers, and move signal/si-code names into shared Rust code.
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Clippy Allow Annotation Report

Comparing clippy allow annotations between branches:

  • Base Branch: origin/main
  • PR Branch: origin/signal_safe_crashtracker

Summary by Rule

Rule Base Branch PR Branch Change

Annotation Counts by File

File Base Branch PR Branch Change

Annotation Stats by Crate

Crate Base Branch PR Branch Change
clippy-annotation-reporter 5 5 No change (0%)
datadog-ffe-ffi 1 1 No change (0%)
datadog-ipc 22 22 No change (0%)
datadog-live-debugger 4 4 No change (0%)
datadog-live-debugger-ffi 10 10 No change (0%)
datadog-profiling-replayer 4 4 No change (0%)
datadog-sidecar 45 45 No change (0%)
libdd-common 13 13 No change (0%)
libdd-common-ffi 12 12 No change (0%)
libdd-data-pipeline 6 6 No change (0%)
libdd-ddsketch 2 2 No change (0%)
libdd-dogstatsd-client 1 1 No change (0%)
libdd-profiling 13 13 No change (0%)
libdd-remote-config 3 3 No change (0%)
libdd-telemetry 20 20 No change (0%)
libdd-tinybytes 4 4 No change (0%)
libdd-trace-normalization 2 2 No change (0%)
libdd-trace-obfuscation 3 3 No change (0%)
libdd-trace-stats 1 1 No change (0%)
libdd-trace-utils 11 11 No change (0%)
Total 182 182 No change (0%)

About This Report

This report tracks Clippy allow annotations for specific rules, showing how they've changed in this PR. Decreasing the number of these annotations generally improves code quality.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

📚 Documentation Check Results

⚠️ 3540 documentation warning(s) found

📦 builder - 239 warning(s)

📦 libdd-crashtracker-ffi - 1263 warning(s)

📦 libdd-crashtracker - 1092 warning(s)

📦 libdd-profiling-ffi - 773 warning(s)

📦 tools - 173 warning(s)


Updated: 2026-07-06 19:23:35 UTC | Commit: 4429aec | missing-docs job results

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

🔒 Cargo Deny Results

⚠️ 11 issue(s) found, showing only errors (advisories, bans, sources)

📦 builder - 3 error(s)

Show output
error[vulnerability]: Quadratic run time when checking a start tag for duplicate attribute names
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:82:1
   │
82 │ quick-xml 0.37.5 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0194
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0194
   ├ `BytesStart::attributes()` returns an `Attributes` iterator which, by default
     (`with_checks(true)`), rejects a start tag that repeats an attribute name. For
     each attribute yielded, the iterator compared the new name against every name
     seen so far in the same tag using a linear scan, so a start tag with `N`
     distinct attribute names cost `O(N²)` byte comparisons. There was no bound on
     `N` other than the size of the buffered start tag.
     
     ## Impact
     
     Any code that parses untrusted XML and iterates a start tag's attributes with
     the default duplicate check enabled can be made to spend CPU time quadratic in
     the number of attributes on a single tag. Because the check is pure computation
     with no `.await`/I/O, an I/O-based timeout on the consumer (for example a read
     or request timeout) cannot interrupt it while it runs.
     
     Measured cost of a single start tag, release build:
     
     | Attributes on one tag | Time |
     |---|---|
     | 80,000  | ~6 s   |
     | 800,000 | ~10 min |
     
     The cost grows with the square of the attribute count, so a start tag of a few
     tens of megabytes can stall a parsing thread for hours. No memory is exhausted
     and the parser does not crash; the effect is CPU exhaustion on the thread doing
     the parsing: a single crafted start tag can pin a CPU core for minutes to hours,
     denying service to that worker. A deployment that places a wall-clock bound on
     parsing, or confines it to a non-critical thread, may consider the availability
     impact lower.
     
     ## Affected code paths
     
     * `BytesStart::attributes()` / `Attributes` iterated with checks enabled (the
       default), and `BytesStart::try_get_attribute`.
     * `NsReader`, which resolves namespaces by iterating a tag's attributes and so
       reaches the same check internally.
     
     Consumers that iterate attributes with `.attributes().with_checks(false)` and do
     not use `NsReader` are not affected.
     
     This was reported as reachable by a remote, unauthenticated attacker in a
     real-world RPKI relying party (NLnet Labs Routinator) via a crafted RRDP
     `snapshot.xml`.
     
     ## Remediation
     
     Upgrade to `quick-xml >= 0.41.0`, where the duplicate check keeps the linear
     scan for start tags with a small number of attributes and switches to an `O(1)`
     hash pre-filter above a threshold, making the whole tag `O(N)`. The reported
     `AttrError::Duplicated` positions are unchanged.
     
     If upgrading is not possible and duplicate-name detection is not required,
     disable it with `.attributes().with_checks(false)` (this does not help
     `NsReader` consumers, which have no equivalent opt-out before 0.41.0).
   ├ Announcement: https://github.com/tafia/quick-xml/issues/969
   ├ Solution: Upgrade to >=0.41.0 (try `cargo update -p quick-xml`)
   ├ quick-xml v0.37.5
     └── tools v37.0.0
         └── builder v37.0.0

error[vulnerability]: Unbounded namespace-declaration allocation in `NsReader` enables memory-exhaustion denial of service
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:82:1
   │
82 │ quick-xml 0.37.5 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0195
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0195
   ├ `NsReader` resolves namespaces by calling `NamespaceResolver::push` for every
     `Start`/`Empty` event *before* the event is returned to the caller. `push`
     iterated all `xmlns` / `xmlns:*` attributes on the start tag and, for each one,
     appended the prefix bytes to an internal buffer and pushed a `NamespaceBinding`
     (32 bytes on 64-bit) to an internal `Vec`, with no upper bound on the number of
     declarations.
     
     ## Impact
     
     A start tag with `N` namespace declarations drove roughly `3×` the tag's byte
     size in `NamespaceResolver` heap, allocated *inside* `quick-xml` before the
     `NsReader` consumer ever received the event and could inspect or reject it. A
     consumer that bounds its *input* size therefore still cannot bound this
     allocation: an `M`-byte start tag yields on the order of `3 × M` bytes of
     resolver heap the caller never sees.
     
     On untrusted XML this lets a remote, unauthenticated attacker force large heap
     allocations with a single start tag. With several `NsReader`s running
     concurrently on independent inputs (a common server pattern), the allocations
     stack and can exhaust process memory, causing the operating system to kill the
     process (OOM). This was confirmed against a real-world RPKI relying party (NLnet
     Labs Routinator), where concurrent RRDP validation workers parsing a crafted
     `snapshot.xml` exceeded the memory limit and the process was OOM-killed.
     
     ## Affected code paths
     
     Consumers using `NsReader` (which always calls `NamespaceResolver::push` before
     yielding `Start`/`Empty`), or calling `NamespaceResolver::push` directly. A plain
     `Reader` that does not perform namespace resolution is not affected.
     
     ## Remediation
     
     Upgrade to `quick-xml >= 0.41.0`. `NamespaceResolver::push` now rejects a start
     tag that declares more than `DEFAULT_MAX_DECLARATIONS_PER_ELEMENT` (256)
     namespace bindings, returning the new `NamespaceError::TooManyDeclarations`
     instead of allocating without limit. The limit is configurable via
     `NamespaceResolver::set_max_declarations_per_element` (use `usize::MAX` to
     restore the previous unbounded behavior), and `NsReader::resolver_mut()` is
     provided to reach it.
     
     There is no clean workaround for `NsReader` consumers before 0.41.0, as the
     allocation happens inside the reader with no configuration knob to cap it.
   ├ Announcement: https://github.com/tafia/quick-xml/issues/970
   ├ Solution: Upgrade to >=0.41.0 (try `cargo update -p quick-xml`)
   ├ quick-xml v0.37.5
     └── tools v37.0.0
         └── builder v37.0.0

error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:85:1
   │
85 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
   │
   ├ ID: RUSTSEC-2026-0097
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
   ├ It has been reported (by @lopopolo) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
     
     - The `log` and `thread_rng` features are enabled
     - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
     - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
     - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
     - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
     
     `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
   ├ Announcement: https://github.com/rust-random/rand/pull/1763
   ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 OR <0.9.0, >=0.8.6 (try `cargo update -p rand`)
   ├ rand v0.8.5
     └── (dev) libdd-common v5.0.0
         ├── builder v37.0.0
         └── tools v37.0.0
             └── builder v37.0.0 (*)

advisories FAILED, bans ok, sources ok

📦 libdd-crashtracker-ffi - 1 error(s)

Show output
error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:228:1
    │
228 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
    │
    ├ ID: RUSTSEC-2026-0097
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
    ├ It has been reported (by @lopopolo) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
      
      - The `log` and `thread_rng` features are enabled
      - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
      - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
      - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
      - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
      
      `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
    ├ Announcement: https://github.com/rust-random/rand/pull/1763
    ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 OR <0.9.0, >=0.8.6 (try `cargo update -p rand`)
    ├ rand v0.8.5
      ├── libdd-common v5.0.0
      │   ├── libdd-capabilities-impl v2.0.0
      │   │   └── libdd-shared-runtime v1.0.0
      │   │       └── libdd-telemetry v5.0.1
      │   │           └── libdd-crashtracker v1.0.0
      │   │               └── libdd-crashtracker-ffi v37.0.0
      │   ├── libdd-common-ffi v37.0.0
      │   │   └── libdd-crashtracker-ffi v37.0.0 (*)
      │   ├── (build) libdd-crashtracker v1.0.0 (*)
      │   ├── libdd-crashtracker-ffi v37.0.0 (*)
      │   ├── libdd-shared-runtime v1.0.0 (*)
      │   └── libdd-telemetry v5.0.1 (*)
      ├── libdd-crashtracker v1.0.0 (*)
      └── (dev) libdd-ddsketch v1.0.1
          └── libdd-telemetry v5.0.1 (*)

advisories FAILED, bans ok, sources ok

📦 libdd-crashtracker - 1 error(s)

Show output
error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:203:1
    │
203 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
    │
    ├ ID: RUSTSEC-2026-0097
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
    ├ It has been reported (by @lopopolo) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
      
      - The `log` and `thread_rng` features are enabled
      - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
      - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
      - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
      - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
      
      `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
    ├ Announcement: https://github.com/rust-random/rand/pull/1763
    ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 OR <0.9.0, >=0.8.6 (try `cargo update -p rand`)
    ├ rand v0.8.5
      ├── libdd-common v5.0.0
      │   ├── libdd-capabilities-impl v2.0.0
      │   │   └── libdd-shared-runtime v1.0.0
      │   │       └── libdd-telemetry v5.0.1
      │   │           └── libdd-crashtracker v1.0.0
      │   ├── (build) libdd-crashtracker v1.0.0 (*)
      │   ├── libdd-shared-runtime v1.0.0 (*)
      │   └── libdd-telemetry v5.0.1 (*)
      ├── libdd-crashtracker v1.0.0 (*)
      └── (dev) libdd-ddsketch v1.0.1
          └── libdd-telemetry v5.0.1 (*)

advisories FAILED, bans ok, sources ok

📦 libdd-profiling-ffi - 3 error(s)

Show output
error[vulnerability]: NSEC3 closest-encloser proof validation enters unbounded loop on cross-zone responses
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:90:1
   │
90 │ hickory-proto 0.25.2 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0118
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0118
   ├ The NSEC3 closest-encloser proof validation in `hickory-proto`'s
     `DnssecDnsHandle` walks from the QNAME up to the SOA owner name, building a
     list of candidate encloser names. The iterator used assumes the
     QNAME is a descendant of the SOA owner, terminating only when the current
     candidate equals the SOA name. When the SOA in a response's authority section
     is not an ancestor of the QNAME, the loop stalls at the DNS root and never
     terminates, repeatedly calling `Name::base_name()` and pushing newly allocated
     `Name` and hashed-name entries into the candidate `Vec`.
     
     The bug is reachable by any caller of `DnssecDnsHandle` — including the
     resolver, recursor, and client — when built with the `dnssec-ring` or
     `dnssec-aws-lc-rs` feature and configured to perform DNSSEC validation. It is
     triggered while validating a NoData or NXDomain response whose authority
     section contains an SOA record from a zone other than an ancestor of the
     QNAME, on a code path that requires NSEC3 closest-encloser proof. In practice
     this can be reached through an insecure CNAME chain that crosses zone
     boundaries into a DNSSEC-signed zone returning NoData, but the minimum
     condition is just a mismatched SOA owner on a response requiring NSEC3
     validation.
     
     A `debug_assert_ne!(name, Name::root())` guards the loop body, so debug builds
     abort with a panic on the first iteration past the root. Release builds
     compile the assertion out and run the loop unbounded, allocating until the
     process exhausts available memory (OOM). A reachable upstream attacker who
     can return such a response can therefore crash a debug-built validator or
     exhaust memory on a release-built one.
     
     The affected code was migrated from `hickory-proto` to `hickory-net` as part of
     the 0.26.0 release. The `hickory-proto` 0.26.x release no longer offers
     `DnssecDnsHandle` and so we recommend all affected users update to `hickory-net`
     0.26.1 when the implementation of that type is required.
   ├ Announcement: https://github.com/hickory-dns/hickory-dns/security/advisories/GHSA-3v94-mw7p-v465
   ├ Solution: No safe upgrade is available!
   ├ hickory-proto v0.25.2
     └── hickory-resolver v0.25.2
         └── reqwest v0.13.2
             ├── libdd-common v5.0.0
             │   ├── libdd-common-ffi v37.0.0
             │   │   └── libdd-profiling-ffi v1.0.0
             │   ├── libdd-profiling v1.0.0
             │   │   ├── (dev) libdd-profiling v1.0.0 (*)
             │   │   └── libdd-profiling-ffi v1.0.0 (*)
             │   └── libdd-profiling-ffi v1.0.0 (*)
             └── libdd-profiling v1.0.0 (*)

error[vulnerability]: CPU exhaustion during message encoding due to O(n²) name compression
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:90:1
   │
90 │ hickory-proto 0.25.2 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0119
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0119
   ├ During message encoding, `hickory-proto`'s `BinEncoder` stores pointers to
     labels that are candidates for name compression in a `Vec<(usize, Vec<u8>)>`.
     The name compression logic then searches for matches with a linear scan.
     
     A malicious message with many records can both introduce many candidate labels,
     and invoke this linear scan many times. This can amplify CPU exhaustion in DoS
     attacks.
     
     This is similar to
     [CVE-2024-8508](https://www.nlnetlabs.nl/downloads/unbound/CVE-2024-8508.txt).
     
     We recommend all affected users update to `hickory-proto` 0.26.1 for the fix.
   ├ Announcement: https://github.com/hickory-dns/hickory-dns/security/advisories/GHSA-q2qq-hmj6-3wpp
   ├ Solution: Upgrade to >=0.26.1 (try `cargo update -p hickory-proto`)
   ├ hickory-proto v0.25.2
     └── hickory-resolver v0.25.2
         └── reqwest v0.13.2
             ├── libdd-common v5.0.0
             │   ├── libdd-common-ffi v37.0.0
             │   │   └── libdd-profiling-ffi v1.0.0
             │   ├── libdd-profiling v1.0.0
             │   │   ├── (dev) libdd-profiling v1.0.0 (*)
             │   │   └── libdd-profiling-ffi v1.0.0 (*)
             │   └── libdd-profiling-ffi v1.0.0 (*)
             └── libdd-profiling v1.0.0 (*)

error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:171:1
    │
171 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
    │
    ├ ID: RUSTSEC-2026-0097
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
    ├ It has been reported (by @lopopolo) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
      
      - The `log` and `thread_rng` features are enabled
      - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
      - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
      - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
      - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
      
      `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
    ├ Announcement: https://github.com/rust-random/rand/pull/1763
    ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 OR <0.9.0, >=0.8.6 (try `cargo update -p rand`)
    ├ rand v0.8.5
      ├── libdd-common v5.0.0
      │   ├── libdd-common-ffi v37.0.0
      │   │   └── libdd-profiling-ffi v1.0.0
      │   ├── libdd-profiling v1.0.0
      │   │   ├── (dev) libdd-profiling v1.0.0 (*)
      │   │   └── libdd-profiling-ffi v1.0.0 (*)
      │   └── libdd-profiling-ffi v1.0.0 (*)
      ├── libdd-profiling v1.0.0 (*)
      └── proptest v1.5.0
          └── (dev) libdd-profiling v1.0.0 (*)

advisories FAILED, bans ok, sources ok

📦 tools - 3 error(s)

Show output
error[vulnerability]: Quadratic run time when checking a start tag for duplicate attribute names
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:73:1
   │
73 │ quick-xml 0.37.5 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0194
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0194
   ├ `BytesStart::attributes()` returns an `Attributes` iterator which, by default
     (`with_checks(true)`), rejects a start tag that repeats an attribute name. For
     each attribute yielded, the iterator compared the new name against every name
     seen so far in the same tag using a linear scan, so a start tag with `N`
     distinct attribute names cost `O(N²)` byte comparisons. There was no bound on
     `N` other than the size of the buffered start tag.
     
     ## Impact
     
     Any code that parses untrusted XML and iterates a start tag's attributes with
     the default duplicate check enabled can be made to spend CPU time quadratic in
     the number of attributes on a single tag. Because the check is pure computation
     with no `.await`/I/O, an I/O-based timeout on the consumer (for example a read
     or request timeout) cannot interrupt it while it runs.
     
     Measured cost of a single start tag, release build:
     
     | Attributes on one tag | Time |
     |---|---|
     | 80,000  | ~6 s   |
     | 800,000 | ~10 min |
     
     The cost grows with the square of the attribute count, so a start tag of a few
     tens of megabytes can stall a parsing thread for hours. No memory is exhausted
     and the parser does not crash; the effect is CPU exhaustion on the thread doing
     the parsing: a single crafted start tag can pin a CPU core for minutes to hours,
     denying service to that worker. A deployment that places a wall-clock bound on
     parsing, or confines it to a non-critical thread, may consider the availability
     impact lower.
     
     ## Affected code paths
     
     * `BytesStart::attributes()` / `Attributes` iterated with checks enabled (the
       default), and `BytesStart::try_get_attribute`.
     * `NsReader`, which resolves namespaces by iterating a tag's attributes and so
       reaches the same check internally.
     
     Consumers that iterate attributes with `.attributes().with_checks(false)` and do
     not use `NsReader` are not affected.
     
     This was reported as reachable by a remote, unauthenticated attacker in a
     real-world RPKI relying party (NLnet Labs Routinator) via a crafted RRDP
     `snapshot.xml`.
     
     ## Remediation
     
     Upgrade to `quick-xml >= 0.41.0`, where the duplicate check keeps the linear
     scan for start tags with a small number of attributes and switches to an `O(1)`
     hash pre-filter above a threshold, making the whole tag `O(N)`. The reported
     `AttrError::Duplicated` positions are unchanged.
     
     If upgrading is not possible and duplicate-name detection is not required,
     disable it with `.attributes().with_checks(false)` (this does not help
     `NsReader` consumers, which have no equivalent opt-out before 0.41.0).
   ├ Announcement: https://github.com/tafia/quick-xml/issues/969
   ├ Solution: Upgrade to >=0.41.0 (try `cargo update -p quick-xml`)
   ├ quick-xml v0.37.5
     └── tools v37.0.0

error[vulnerability]: Unbounded namespace-declaration allocation in `NsReader` enables memory-exhaustion denial of service
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:73:1
   │
73 │ quick-xml 0.37.5 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0195
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0195
   ├ `NsReader` resolves namespaces by calling `NamespaceResolver::push` for every
     `Start`/`Empty` event *before* the event is returned to the caller. `push`
     iterated all `xmlns` / `xmlns:*` attributes on the start tag and, for each one,
     appended the prefix bytes to an internal buffer and pushed a `NamespaceBinding`
     (32 bytes on 64-bit) to an internal `Vec`, with no upper bound on the number of
     declarations.
     
     ## Impact
     
     A start tag with `N` namespace declarations drove roughly `3×` the tag's byte
     size in `NamespaceResolver` heap, allocated *inside* `quick-xml` before the
     `NsReader` consumer ever received the event and could inspect or reject it. A
     consumer that bounds its *input* size therefore still cannot bound this
     allocation: an `M`-byte start tag yields on the order of `3 × M` bytes of
     resolver heap the caller never sees.
     
     On untrusted XML this lets a remote, unauthenticated attacker force large heap
     allocations with a single start tag. With several `NsReader`s running
     concurrently on independent inputs (a common server pattern), the allocations
     stack and can exhaust process memory, causing the operating system to kill the
     process (OOM). This was confirmed against a real-world RPKI relying party (NLnet
     Labs Routinator), where concurrent RRDP validation workers parsing a crafted
     `snapshot.xml` exceeded the memory limit and the process was OOM-killed.
     
     ## Affected code paths
     
     Consumers using `NsReader` (which always calls `NamespaceResolver::push` before
     yielding `Start`/`Empty`), or calling `NamespaceResolver::push` directly. A plain
     `Reader` that does not perform namespace resolution is not affected.
     
     ## Remediation
     
     Upgrade to `quick-xml >= 0.41.0`. `NamespaceResolver::push` now rejects a start
     tag that declares more than `DEFAULT_MAX_DECLARATIONS_PER_ELEMENT` (256)
     namespace bindings, returning the new `NamespaceError::TooManyDeclarations`
     instead of allocating without limit. The limit is configurable via
     `NamespaceResolver::set_max_declarations_per_element` (use `usize::MAX` to
     restore the previous unbounded behavior), and `NsReader::resolver_mut()` is
     provided to reach it.
     
     There is no clean workaround for `NsReader` consumers before 0.41.0, as the
     allocation happens inside the reader with no configuration knob to cap it.
   ├ Announcement: https://github.com/tafia/quick-xml/issues/970
   ├ Solution: Upgrade to >=0.41.0 (try `cargo update -p quick-xml`)
   ├ quick-xml v0.37.5
     └── tools v37.0.0

error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:76:1
   │
76 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
   │
   ├ ID: RUSTSEC-2026-0097
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
   ├ It has been reported (by @lopopolo) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
     
     - The `log` and `thread_rng` features are enabled
     - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
     - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
     - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
     - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
     
     `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
   ├ Announcement: https://github.com/rust-random/rand/pull/1763
   ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 OR <0.9.0, >=0.8.6 (try `cargo update -p rand`)
   ├ rand v0.8.5
     └── (dev) libdd-common v5.0.0
         └── tools v37.0.0

advisories FAILED, bans ok, sources ok

Updated: 2026-07-06 19:24:03 UTC | Commit: 4429aec | dependency-check job results

@datadog-official

datadog-official Bot commented Jul 6, 2026

Copy link
Copy Markdown

Pipelines  Tests

Fix all issues with BitsAI

⚠️ Warnings

🚦 12 Pipeline jobs failed

Lint | clippy #ubuntu-latest msrv   View in Datadog   GitHub Actions

Lint | clippy #ubuntu-latest nightly   View in Datadog   GitHub Actions

Lint | clippy #ubuntu-latest stable   View in Datadog   GitHub Actions

View all 12 failed jobs.

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 56.54%
Overall Coverage: 73.96% (-0.41%)

Useful? React with 👍 / 👎

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant