-
Notifications
You must be signed in to change notification settings - Fork 94
137 lines (126 loc) · 5.46 KB
/
Copy pathfuzz.yml
File metadata and controls
137 lines (126 loc) · 5.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
name: Fuzz Testing
on:
schedule:
- cron: '0 4 * * *' # Nightly 4am UTC
workflow_dispatch: # Manual trigger
pull_request:
branches: [ '*' ]
types: [opened, reopened, ready_for_review]
push:
branches: [ master ]
jobs:
# The matrix context is not available in a job-level if:, so route by run
# type here instead: 600s full runs go to the nightly schedule / manual
# dispatch; 60s smoke runs go to non-draft PR open/reopen/ready and merges
# to master. Intermediate PR pushes (synchronize) are not a trigger.
select:
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.pick.outputs.matrix }}
steps:
- name: Pick fuzz matrix for ${{ github.event_name }}
id: pick
run: |
# schedule / dispatch -> full (600s); PR / push -> smoke (60s).
case "${{ github.event_name }}" in
schedule|workflow_dispatch) WANT=false ;;
*) WANT=true ;;
esac
PQC="--enable-dilithium --enable-mlkem --enable-experimental --enable-harden"
MATRIX=$(jq -nc --argjson want "$WANT" --arg pqc "$PQC" '{
include: [
{name:"fuzz-full", fuzz_time:600, smoke_only:false, wolfssl_extra_flags:"", wolftpm_extra_flags:"", max_len:4096},
{name:"fuzz-smoke", fuzz_time:60, smoke_only:true, wolfssl_extra_flags:"", wolftpm_extra_flags:"", max_len:4096},
{name:"fuzz-full-pqc", fuzz_time:600, smoke_only:false, wolfssl_extra_flags:$pqc, wolftpm_extra_flags:"--enable-v185", max_len:8192},
{name:"fuzz-smoke-pqc", fuzz_time:60, smoke_only:true, wolfssl_extra_flags:$pqc, wolftpm_extra_flags:"--enable-v185", max_len:8192}
] | map(select(.smoke_only == $want))
}')
echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"
fuzz:
needs: select
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.select.outputs.matrix) }}
steps:
- name: Checkout wolfTPM
uses: actions/checkout@v4
- name: ASLR workaround
run: sudo sysctl vm.mmap_rnd_bits=28
- name: Setup wolfSSL with fuzzer support
uses: ./.github/actions/setup-wolfssl
with:
cc: clang
configure-flags: --enable-wolftpm --enable-pkcallbacks --enable-keygen ${{ matrix.wolfssl_extra_flags }}
cflags: -fsanitize=fuzzer-no-link,address -fno-omit-frame-pointer -g -O1 -DWC_RSA_NO_PADDING
ldflags: -fsanitize=address
- name: Build fuzz target
run: |
./autogen.sh
CC=clang ./configure --enable-fwtpm --enable-fuzz \
${{ matrix.wolftpm_extra_flags }} \
CFLAGS="-fsanitize=fuzzer-no-link,address -fno-omit-frame-pointer -g -O1" \
LDFLAGS="-fsanitize=address"
make -j$(nproc)
- name: Generate seed corpus
run: python3 tests/fuzz/gen_corpus.py
- name: Verify v1.85 PQC opcode coverage in corpus
if: contains(matrix.name, 'pqc')
run: |
# Without this guard, fuzz-*-pqc could spend 10 minutes fuzzing
# classical paths with -DWOLFTPM_V185 set and never exercise an
# Encapsulate or SignSequenceComplete opcode. Fail fast if any of
# the 8 new v1.85 command codes is absent from the seed corpus.
# Seeds are binary; opcodes appear as raw 4-byte big-endian
# sequences. Hex-dump the concatenated corpus and grep the
# resulting hex stream for each opcode's bytes.
CORPUS_HEX=$(cat tests/fuzz/corpus/*.bin | xxd -p | tr -d '\n')
MISSING=()
for cc in 000001a3 000001a4 000001a5 000001a6 \
000001a7 000001a8 000001a9 000001aa; do
if ! echo "$CORPUS_HEX" | grep -q "$cc"; then
MISSING+=("0x${cc^^}")
fi
done
if [ ${#MISSING[@]} -gt 0 ]; then
echo "ERROR: PQC seed corpus missing the following command codes:"
printf ' %s\n' "${MISSING[@]}"
echo "Update tests/fuzz/gen_corpus.py to emit a seed for each."
exit 1
fi
echo "All 8 v1.85 PQC opcodes (0x1A3-0x1AA) present in seed corpus."
- name: Run fuzzer
env:
ASAN_OPTIONS: "detect_leaks=1:abort_on_error=1:symbolize=1"
run: |
echo "Fuzzing for ${{ matrix.fuzz_time }} seconds..."
timeout ${{ matrix.fuzz_time }} \
./tests/fuzz/fwtpm_fuzz \
tests/fuzz/corpus/ \
-dict=tests/fuzz/tpm2.dict \
-max_len=${{ matrix.max_len }} \
-timeout=30 \
-rss_limit_mb=2048 \
-print_final_stats=1 \
|| FUZZ_RC=$?
# timeout returns 124 on normal expiry, fuzzer returns 0 on no crash
if [ "${FUZZ_RC:-0}" -eq 124 ] || [ "${FUZZ_RC:-0}" -eq 0 ]; then
echo "Fuzzer completed without crashes"
else
echo "Fuzzer found crashes (exit code $FUZZ_RC)"
ls -la crash-* 2>/dev/null || true
exit 1
fi
- name: Upload crash artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: fuzz-crashes-${{ matrix.name }}
path: |
crash-*
oom-*
timeout-*
retention-days: 30
if-no-files-found: ignore