Skip to content

Commit 54bd9a9

Browse files
committed
Merge commit 'aa4767626d5893bb1e931482aa99f7b6307cc9c2'
2 parents 2dca3c1 + aa47676 commit 54bd9a9

47 files changed

Lines changed: 2618 additions & 169 deletions

Some content is hidden

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

.github/workflows/ci.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,68 @@ jobs:
342342
with:
343343
token: ${{ secrets.CODECOV_TOKEN }}
344344

345+
fuzz:
346+
name: Fuzz target smoke tests
347+
runs-on: ubuntu-latest
348+
steps:
349+
- name: Clone this repository
350+
uses: actions/checkout@v4
351+
352+
- name: Install latest Rust toolchain
353+
run: rustup toolchain install ${{ env.NIGHTLY_TOOLCHAIN }}
354+
355+
- name: Install cargo-fuzz
356+
run: cargo +stable install --locked cargo-fuzz
357+
358+
- name: Setup rust-cache
359+
uses: Swatinem/rust-cache@v2
360+
with:
361+
cache-bin: false
362+
workspaces: |
363+
. -> target
364+
commons/zenoh-codec/fuzz -> commons/zenoh-codec/fuzz/target
365+
commons/zenoh-protocol/fuzz -> commons/zenoh-protocol/fuzz/target
366+
367+
- name: Build zenoh-codec fuzz crate
368+
run: cargo build --manifest-path commons/zenoh-codec/fuzz/Cargo.toml --bins
369+
370+
- name: Generate zenoh-codec seed corpora
371+
run: cargo run --manifest-path commons/zenoh-codec/fuzz/Cargo.toml --bin gen_all_corpora
372+
373+
- name: Verify zenoh-codec seed corpora
374+
run: cargo run --manifest-path commons/zenoh-codec/fuzz/Cargo.toml --bin verify_all_corpora
375+
376+
- name: Smoke fuzz zenoh-codec targets
377+
working-directory: commons/zenoh-codec/fuzz
378+
run: |
379+
for target in transport_message network_message frame scouting_message; do
380+
cargo +${{ env.NIGHTLY_TOOLCHAIN }} fuzz run "$target" -- -max_total_time=60
381+
done
382+
383+
- name: Build endpoint_from_str fuzz target
384+
run: cargo build --manifest-path commons/zenoh-protocol/fuzz/Cargo.toml --bin endpoint_from_str
385+
386+
- name: Generate endpoint_from_str seed corpus
387+
run: cargo run --manifest-path commons/zenoh-protocol/fuzz/Cargo.toml --bin gen_endpoint_corpus
388+
389+
- name: Verify endpoint_from_str seed corpus
390+
run: cargo run --manifest-path commons/zenoh-protocol/fuzz/Cargo.toml --bin verify_endpoint_corpus
391+
392+
- name: Smoke fuzz endpoint_from_str
393+
working-directory: commons/zenoh-protocol/fuzz
394+
run: cargo +${{ env.NIGHTLY_TOOLCHAIN }} fuzz run endpoint_from_str -- -max_total_time=60
395+
396+
- name: Upload fuzz artifacts
397+
if: failure()
398+
uses: actions/upload-artifact@v4
399+
with:
400+
name: fuzz-artifacts-pr-smoke
401+
path: |
402+
commons/zenoh-codec/fuzz/artifacts
403+
commons/zenoh-protocol/fuzz/artifacts
404+
if-no-files-found: ignore
405+
retention-days: 14
406+
345407
valgrind:
346408
name: Memory leak checks
347409
runs-on: ubuntu-latest
@@ -491,6 +553,7 @@ jobs:
491553
test,
492554
test_unstable,
493555
test_shm,
556+
fuzz,
494557
valgrind,
495558
typos,
496559
markdown_lint,
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#
2+
# Copyright (c) 2026 ZettaScale Technology
3+
#
4+
# This program and the accompanying materials are made available under the
5+
# terms of the Eclipse Public License 2.0 which is available at
6+
# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
#
9+
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
#
11+
# Contributors:
12+
# ZettaScale Zenoh Team, <zenoh@zettascale.tech>
13+
#
14+
name: Scheduled Fuzzing
15+
16+
on:
17+
schedule:
18+
# Run the 1-hour campaign every day except Sunday.
19+
- cron: "0 0 * * 1-6"
20+
# Run the 5-hour campaign on Sunday instead of the daily run.
21+
- cron: "0 0 * * 0"
22+
workflow_dispatch:
23+
inputs:
24+
profile:
25+
type: choice
26+
description: Fuzzing duration profile
27+
required: true
28+
default: daily
29+
options:
30+
- daily
31+
- weekly
32+
33+
env:
34+
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
35+
NIGHTLY_TOOLCHAIN: nightly
36+
37+
jobs:
38+
determine-profile:
39+
name: Determine fuzzing profile
40+
runs-on: ubuntu-latest
41+
outputs:
42+
label: ${{ steps.profile.outputs.label }}
43+
max_total_time: ${{ steps.profile.outputs.max_total_time }}
44+
steps:
45+
- name: Select duration profile
46+
id: profile
47+
shell: bash
48+
run: |
49+
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
50+
profile="${{ inputs.profile }}"
51+
elif [[ "${{ github.event.schedule }}" == "0 0 * * 0" ]]; then
52+
profile="weekly"
53+
else
54+
profile="daily"
55+
fi
56+
57+
if [[ "$profile" == "weekly" ]]; then
58+
echo "label=weekly" >> "$GITHUB_OUTPUT"
59+
echo "max_total_time=18000" >> "$GITHUB_OUTPUT"
60+
else
61+
echo "label=daily" >> "$GITHUB_OUTPUT"
62+
echo "max_total_time=3600" >> "$GITHUB_OUTPUT"
63+
fi
64+
65+
fuzz-codec:
66+
name: Codec fuzz (${{ needs.determine-profile.outputs.label }}) - ${{ matrix.target }}
67+
needs: determine-profile
68+
runs-on: ubuntu-latest
69+
timeout-minutes: 330
70+
strategy:
71+
fail-fast: false
72+
matrix:
73+
target:
74+
- transport_message
75+
- network_message
76+
- frame
77+
- scouting_message
78+
steps:
79+
- name: Clone this repository
80+
uses: actions/checkout@v4
81+
82+
- name: Install latest Rust toolchain
83+
run: rustup toolchain install ${{ env.NIGHTLY_TOOLCHAIN }}
84+
85+
- name: Install cargo-fuzz
86+
run: cargo +stable install --locked cargo-fuzz
87+
88+
- name: Setup rust-cache
89+
uses: Swatinem/rust-cache@v2
90+
with:
91+
cache-bin: false
92+
workspaces: |
93+
. -> target
94+
commons/zenoh-codec/fuzz -> commons/zenoh-codec/fuzz/target
95+
96+
- name: Generate zenoh-codec seed corpora
97+
run: cargo run --bin gen_all_corpora
98+
working-directory: commons/zenoh-codec/fuzz
99+
100+
- name: Verify zenoh-codec seed corpora
101+
run: cargo run --bin verify_all_corpora
102+
working-directory: commons/zenoh-codec/fuzz
103+
104+
- name: Run codec fuzz target
105+
run: cargo +${{ env.NIGHTLY_TOOLCHAIN }} fuzz run ${{ matrix.target }} -- -max_total_time=${{ needs.determine-profile.outputs.max_total_time }}
106+
working-directory: commons/zenoh-codec/fuzz
107+
108+
- name: Upload codec fuzz artifacts
109+
if: failure()
110+
uses: actions/upload-artifact@v4
111+
with:
112+
name: fuzz-artifacts-codec-${{ needs.determine-profile.outputs.label }}-${{ matrix.target }}
113+
path: commons/zenoh-codec/fuzz/artifacts/${{ matrix.target }}
114+
if-no-files-found: ignore
115+
retention-days: 14
116+
117+
fuzz-protocol:
118+
name: Protocol fuzz (${{ needs.determine-profile.outputs.label }}) - endpoint_from_str
119+
needs: determine-profile
120+
runs-on: ubuntu-latest
121+
timeout-minutes: 330
122+
steps:
123+
- name: Clone this repository
124+
uses: actions/checkout@v4
125+
126+
- name: Install latest Rust toolchain
127+
run: rustup toolchain install ${{ env.NIGHTLY_TOOLCHAIN }}
128+
129+
- name: Install cargo-fuzz
130+
run: cargo +stable install --locked cargo-fuzz
131+
132+
- name: Setup rust-cache
133+
uses: Swatinem/rust-cache@v2
134+
with:
135+
cache-bin: false
136+
workspaces: |
137+
. -> target
138+
commons/zenoh-protocol/fuzz -> commons/zenoh-protocol/fuzz/target
139+
140+
- name: Generate endpoint_from_str seed corpus
141+
run: cargo run --bin gen_endpoint_corpus
142+
working-directory: commons/zenoh-protocol/fuzz
143+
144+
- name: Verify endpoint_from_str seed corpus
145+
run: cargo run --bin verify_endpoint_corpus
146+
working-directory: commons/zenoh-protocol/fuzz
147+
148+
- name: Run endpoint_from_str fuzz target
149+
run: cargo +${{ env.NIGHTLY_TOOLCHAIN }} fuzz run endpoint_from_str -- -max_total_time=${{ needs.determine-profile.outputs.max_total_time }}
150+
working-directory: commons/zenoh-protocol/fuzz
151+
152+
- name: Upload protocol fuzz artifacts
153+
if: failure()
154+
uses: actions/upload-artifact@v4
155+
with:
156+
name: fuzz-artifacts-protocol-${{ needs.determine-profile.outputs.label }}-endpoint_from_str
157+
path: commons/zenoh-protocol/fuzz/artifacts/endpoint_from_str
158+
if-no-files-found: ignore
159+
retention-days: 14

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,8 @@ ci/valgrind-check/*.log
2929

3030
# Code coverage reports
3131
*.profraw
32+
33+
# cargo-fuzz-related
34+
**/fuzz/artifacts
35+
**/fuzz/corpus
36+
**/fuzz/coverage

Cargo.lock

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

Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@
1212
# ZettaScale Zenoh Team, <zenoh@zettascale.tech>
1313
#
1414
[workspace]
15-
exclude = ["ci/nostd-check", "ci/valgrind-check", "ci/zenoh-1-75"]
15+
exclude = [
16+
"ci/nostd-check",
17+
"ci/valgrind-check",
18+
"ci/zenoh-1-75",
19+
"commons/zenoh-codec/fuzz",
20+
"commons/zenoh-protocol/fuzz",
21+
]
1622
members = [
1723
"commons/zenoh-buffers",
1824
"commons/zenoh-codec",

DEFAULT_CONFIG.json5

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@
4444
/// Accepts a single list (e.g. endpoints: ["tcp/10.10.10.10:7447", "tcp/11.11.11.11:7447"])
4545
/// or different lists for router, peer and client (e.g. endpoints: { router: ["tcp/10.10.10.10:7447"], peer: ["tcp/11.11.11.11:7447"] }).
4646
///
47+
/// Note that every element in the list can also be a list:
48+
/// E.g. endpoints: [{"strategy": "allOf", "locators": ["tcp/10.10.10.10:7447?rel=0", "tcp/10.10.10.10:7447?rel=1"]}, "tcp/11.11.11.11:7447"]
49+
/// This can be used in the client mode.
50+
/// Since the client mode only allows connecting to a single endpoint, this indicates that we want to build multiple links to the same endpoint.
51+
/// It doesn't make any difference for the peer or router mode.
52+
/// endpoints: [{"strategy": "allOf", "locators": ["tcp/10.10.10.10:7447?rel=0", "tcp/10.10.10.10:7447?rel=1"]}] is equivalent to endpoints: ["tcp/10.10.10.10:7447?rel=0", "tcp/10.10.10.10:7447?rel=1"].
53+
///
4754
/// See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html
4855
endpoints: [
4956
// "<proto>/<address>"

commons/zenoh-codec/README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,71 @@ It is highly recommended to depend solely on the zenoh and zenoh-ext crates and
66

77
- [Click here for Zenoh's main repository](https://github.com/eclipse-zenoh/zenoh)
88
- [Click here for Zenoh's documentation](https://zenoh.io)
9+
10+
## Fuzzing
11+
12+
The `zenoh-codec` crate includes `cargo-fuzz` targets for:
13+
14+
- `transport_message`
15+
- `network_message`
16+
- `frame`
17+
- `scouting_message`
18+
19+
From the `commons/zenoh-codec/fuzz` directory, run:
20+
21+
```sh
22+
# Generate the deterministic seed corpus
23+
cargo run --bin gen_all_corpora
24+
25+
# Optional: verify the generated corpus matches the current encoder
26+
cargo run --bin verify_all_corpora
27+
28+
# Run the fuzz targets
29+
cargo +nightly fuzz run transport_message
30+
cargo +nightly fuzz run network_message
31+
cargo +nightly fuzz run frame
32+
cargo +nightly fuzz run scouting_message
33+
34+
# Only rerun a certain input
35+
cargo +nightly fuzz run transport_message artifacts/transport_message/crash-xxxx
36+
cargo +nightly fuzz run network_message artifacts/network_message/crash-xxxx
37+
cargo +nightly fuzz run frame artifacts/frame/crash-xxxx
38+
cargo +nightly fuzz run scouting_message artifacts/scouting_message/crash-xxxx
39+
40+
# Analyze one input without running the fuzz loop
41+
cargo run --bin analyze_transport_message -- "[2, 220, 11, 13, 0]"
42+
cargo run --bin analyze_network_message -- "[29, 0, 1, 2]"
43+
cargo run --bin analyze_frame -- "[37, 1]"
44+
cargo run --bin analyze_scouting_message -- "[1, 1, 10]"
45+
```
46+
47+
To inspect corpus coverage for the fuzz target, run:
48+
49+
```sh
50+
# Collect coverage data from the corpus
51+
# Use `-s none` to disable sanitizers during coverage collection.
52+
cargo +nightly fuzz coverage -s none transport_message corpus/transport_message
53+
54+
# Resolve the LLVM tools shipped with the nightly toolchain
55+
LLVM_BIN="$(dirname "$(rustc +nightly --print target-libdir)")/bin"
56+
57+
# Hide Rust stdlib and cargo-registry dependencies from the report.
58+
# Print a text summary
59+
"$LLVM_BIN/llvm-cov" report \
60+
target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release/transport_message \
61+
-instr-profile=coverage/transport_message/coverage.profdata \
62+
--ignore-filename-regex='^/rustc/|^.*/.cargo/registry'
63+
64+
# Hide Rust stdlib and cargo-registry dependencies from the report.
65+
# Only render HTML for the Zenoh source trees we want to inspect.
66+
# Generate an HTML report focused on Zenoh sources
67+
"$LLVM_BIN/llvm-cov" show \
68+
target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release/transport_message \
69+
-instr-profile=coverage/transport_message/coverage.profdata \
70+
--format=html \
71+
--output-dir=coverage/transport_message/html \
72+
--ignore-filename-regex='^/rustc/|^.*/.cargo/registry' \
73+
../src \
74+
../../zenoh-protocol/src \
75+
../../zenoh-buffers/src
76+
```

0 commit comments

Comments
 (0)