From c16337834bbd4a5538d7aad3ab13cb36e0bc3019 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 9 Oct 2026 19:46:02 -0700 Subject: [PATCH 1/8] Expand continuous integration coverage --- .dockerignore | 1 + .github/docker/wolfsentry-ci/Dockerfile | 14 + .github/semgrep-rules.yml | 40 +++ .github/workflows/codeql.yml | 52 ++++ .github/workflows/coverage.yml | 53 ++++ .github/workflows/examples.yml | 252 ++++++++++++++++++ .github/workflows/macos-check.yml | 26 +- .github/workflows/multi-compiler.yml | 44 +++ .github/workflows/nightly.yml | 232 ++++++++++++++++ .github/workflows/options-matrix.yml | 76 ++++++ .github/workflows/sanitizers.yml | 58 ++++ .github/workflows/semgrep.yml | 41 +++ .github/workflows/static-analysis.yml | 81 ++++++ .github/workflows/ubuntu-check.yml | 34 ++- .github/workflows/wolfssl-versions.yml | 123 +++++++++ Makefile | 8 +- Makefile.analyzers | 16 +- examples/Linux-LWIP/Dockerfile | 27 +- examples/Linux-LWIP/docker-compose.yml | 10 +- .../Linux-LWIP/lwip-include/arch/sys_arch.h | 1 + examples/Linux-LWIP/main.c | 28 ++ examples/Linux-LWIP/sentry.c | 16 +- examples/Linux-LWIP/sentry.h | 6 +- examples/Linux-wolfIP/Makefile | 7 +- examples/Linux-wolfIP/main.c | 8 +- examples/Linux-wolfIP/wolfip/config.h | 1 + examples/STM32-LWIP-WOLFSSL/Inc/echo.h | 4 +- examples/STM32-LWIP-WOLFSSL/Inc/sentry.h | 3 +- examples/STM32-LWIP-WOLFSSL/Src/echo.c | 16 +- examples/STM32-LWIP-WOLFSSL/Src/sentry.c | 45 ++-- examples/STM32-LWIP/Inc/sentry.h | 3 +- examples/STM32-LWIP/Src/echo.c | 6 +- examples/STM32-LWIP/Src/sentry.c | 59 ++-- .../udp_to_dbus/udp_to_dbus.c | 1 + lwip/LWIP_PACKET_FILTER_API.patch | 14 +- ports/FreeRTOS-lwIP/include/lwipopts.h | 2 +- tests/filter-clang-analyzer.py | 60 +++++ tests/notification-dbus-service.py | 63 +++++ tests/run-notification-demo-ci.sh | 36 +++ tests/stm32-compat/cmsis_os.h | 22 ++ tests/stm32-compat/user_settings.h | 15 ++ tests/unittests.c | 8 +- tests/wolfssl-allow-all.json | 6 + 43 files changed, 1492 insertions(+), 126 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/docker/wolfsentry-ci/Dockerfile create mode 100644 .github/semgrep-rules.yml create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/coverage.yml create mode 100644 .github/workflows/examples.yml create mode 100644 .github/workflows/multi-compiler.yml create mode 100644 .github/workflows/nightly.yml create mode 100644 .github/workflows/options-matrix.yml create mode 100644 .github/workflows/sanitizers.yml create mode 100644 .github/workflows/semgrep.yml create mode 100644 .github/workflows/static-analysis.yml create mode 100644 .github/workflows/wolfssl-versions.yml create mode 100644 tests/filter-clang-analyzer.py create mode 100644 tests/notification-dbus-service.py create mode 100644 tests/run-notification-demo-ci.sh create mode 100644 tests/stm32-compat/cmsis_os.h create mode 100644 tests/stm32-compat/user_settings.h create mode 100644 tests/wolfssl-allow-all.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6b8710a --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.git diff --git a/.github/docker/wolfsentry-ci/Dockerfile b/.github/docker/wolfsentry-ci/Dockerfile new file mode 100644 index 0000000..d864936 --- /dev/null +++ b/.github/docker/wolfsentry-ci/Dockerfile @@ -0,0 +1,14 @@ +FROM ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + bubblewrap \ + dbus \ + gcc-arm-none-eabi \ + iproute2 \ + iputils-ping \ + libnewlib-arm-none-eabi \ + libnotify-dev \ + python3-dbus \ + python3-gi \ + && rm -rf /var/lib/apt/lists/* diff --git a/.github/semgrep-rules.yml b/.github/semgrep-rules.yml new file mode 100644 index 0000000..bf71ff4 --- /dev/null +++ b/.github/semgrep-rules.yml @@ -0,0 +1,40 @@ +# Deterministic wolfSentry security rules. Style and maintainability checks +# belong to cppcheck and clang-tidy; these rules cover unsafe primitives. + +rules: + - id: wolfsentry-unsafe-libc + languages: [c] + severity: ERROR + message: Use a length-bounded alternative to this unsafe C library call. + paths: + include: + - src/ + - wolfsentry/ + pattern-either: + - pattern: gets(...) + - pattern: strcpy(...) + - pattern: strcat(...) + - pattern: sprintf(...) + - pattern: vsprintf(...) + + - id: wolfsentry-shell-execution + languages: [c] + severity: ERROR + message: Core library code must not invoke a command shell. + paths: + include: + - src/ + - wolfsentry/ + pattern-either: + - pattern: system(...) + - pattern: popen(...) + + - id: wolfsentry-insecure-temporary-name + languages: [c] + severity: ERROR + message: mktemp is race-prone; use mkstemp or an equivalent safe primitive. + paths: + include: + - src/ + - wolfsentry/ + pattern: mktemp(...) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..0749794 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,52 @@ +name: CodeQL + +run-name: ${{ inputs.nightly_run_id || github.workflow }} + +on: + push: + branches: [ 'master', 'release/**' ] + pull_request: + branches: [ '**' ] + workflow_dispatch: + inputs: + nightly_run_id: + description: Nightly coordinator run ID + required: false + type: string + +permissions: + contents: read + security-events: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -e {0} + +jobs: + analyze: + name: CodeQL (C/C++) + runs-on: ubuntu-latest + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: c-cpp + build-mode: manual + queries: security-extended + - name: Build all default unit-test paths + run: make -j2 UNITTEST_LIST_JSON_DOM_EXTRAS=test_json_corpus test + - name: Perform CodeQL analysis + uses: github/codeql-action/analyze@v3 + with: + category: /language:c-cpp diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..dd93824 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,53 @@ +name: Code Coverage + +run-name: ${{ inputs.nightly_run_id || github.workflow }} + +on: + push: + branches: [ 'master', 'release/**' ] + pull_request: + branches: [ '**' ] + workflow_dispatch: + inputs: + nightly_run_id: + description: Nightly coordinator run ID + required: false + type: string + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -e {0} + +jobs: + coverage: + name: Line coverage + runs-on: ubuntu-latest + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + + steps: + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Run instrumented unit tests + run: make coverage + - name: Capture coverage + run: | + lcov --capture --directory coverage-build --output-file coverage.info + lcov --remove coverage.info '/usr/*' '*/tests/*' \ + '*/src/json/centijson_sax.c' --ignore-errors unused \ + --output-file coverage.info + lcov --summary coverage.info + lcov --summary --fail-under-lines 65 coverage.info + - name: Upload coverage data + uses: actions/upload-artifact@v4 + with: + name: wolfsentry-coverage + path: coverage.info diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml new file mode 100644 index 0000000..e8c1fb1 --- /dev/null +++ b/.github/workflows/examples.yml @@ -0,0 +1,252 @@ +name: Examples + +run-name: ${{ inputs.nightly_run_id || github.workflow }} + +on: + push: + pull_request: + branches: [ '**' ] + workflow_dispatch: + inputs: + nightly_run_id: + description: Nightly coordinator run ID + required: false + type: string + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -e {0} + +jobs: + linux-lwip: + name: Linux lwIP runtime + runs-on: ubuntu-latest + timeout-minutes: 20 + env: + COMPOSE_FILE: examples/Linux-LWIP/docker-compose.yml + COMPOSE_PROJECT_NAME: wolfsentry-lwip-${{ github.run_id }} + + steps: + - uses: actions/checkout@v4 + - name: Build and start the lwIP network + run: docker compose up --build --detach + - name: Exercise allowed and rejected traffic + run: | + for attempt in $(seq 1 30); do + if docker compose ps --status running --services | grep -qx echoserver; then + break + fi + if [ "$attempt" -eq 30 ]; then + docker compose logs echoserver + exit 1 + fi + sleep 1 + done + + docker compose exec -T tester1 ping -c 2 -W 2 172.20.20.5 + if docker compose exec -T tester2 ping -c 2 -W 2 172.20.20.5; then + echo 'tester2 ICMP traffic was expected to be rejected' >&2 + exit 1 + fi + if docker compose exec -T tester3 ping -c 2 -W 2 172.20.20.5; then + echo 'tester3 traffic was expected to be rejected by MAC address' >&2 + exit 1 + fi + + printf 'nightly-wolfsentry\n' \ + | docker compose exec -T tester2 nc -w 3 172.20.20.5 11111 || true + printf 'blocked-tcp\n' \ + | docker compose exec -T tester1 nc -w 3 172.20.20.5 11111 || true + sleep 2 + + docker compose logs --no-color echoserver > lwip-example.log + grep -F 'Ping accepted from 172.20.20.10' lwip-example.log + grep -F 'Ping rejected from 172.20.20.20' lwip-example.log + grep -F 'Sentry rejected MAC address DE:C0:DE:03:03:01' lwip-example.log + grep -F 'Got: nightly-wolfsentry' lwip-example.log + grep -F 'Sentry rejected connection from: 172.20.20.10' lwip-example.log + - name: Show lwIP logs + if: always() + run: docker compose logs --no-color + - name: Stop the lwIP network + if: always() + run: docker compose down --volumes --remove-orphans + + linux-wolfip: + name: Linux wolfIP TAP runtime + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - uses: actions/checkout@v4 + with: + path: wolfsentry + - uses: actions/checkout@v4 + with: + repository: wolfSSL/wolfip + path: wolfip + - name: Build the wolfSentry CI image + run: | + docker build \ + --file wolfsentry/.github/docker/wolfsentry-ci/Dockerfile \ + --tag wolfsentry-ci:local wolfsentry + - name: Build and run the wolfIP example + run: | + docker run --rm \ + --cap-drop=ALL \ + --cap-add=NET_ADMIN \ + --cap-add=NET_RAW \ + --device=/dev/net/tun \ + --security-opt=no-new-privileges \ + --volume "$GITHUB_WORKSPACE/wolfsentry:/workspace/wolfsentry:ro" \ + --volume "$GITHUB_WORKSPACE/wolfip:/workspace/wolfip:ro" \ + --workdir /tmp \ + wolfsentry-ci:local bash -euc ' + cp -R /workspace/wolfsentry /tmp/wolfsentry-build + ln -s /workspace/wolfip /tmp/wolfip + cd /tmp/wolfsentry-build/examples/Linux-wolfIP + make clean + make -j2 \ + WOLFSENTRY_PATH=/tmp/wolfsentry-build \ + WOLFIP_PATH=/tmp/wolfip + set +e + timeout --signal=TERM --kill-after=5s 30s \ + stdbuf -oL -eL ./wolfip-wolfsentry-demo \ + > wolfip-example.log 2>&1 + status=$? + set -e + cat wolfip-example.log + if [ "$status" -ne 0 ] && [ "$status" -ne 124 ]; then + exit "$status" + fi + grep -F "wolfIP ready on wolfip0" wolfip-example.log + grep -F "drop-icmp-mod7" wolfip-example.log + grep -F "Exiting." wolfip-example.log + ' + + notification-demo: + name: Notification demo TLS runtime + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v4 + with: + path: wolfsentry + - uses: actions/checkout@v4 + with: + repository: wolfSSL/wolfssl + path: wolfssl + - name: Build the wolfSentry CI image + run: | + docker build \ + --file wolfsentry/.github/docker/wolfsentry-ci/Dockerfile \ + --tag wolfsentry-ci:local wolfsentry + - name: Build and exercise the notification demo + run: | + docker run --rm \ + --cap-drop=ALL \ + --security-opt=no-new-privileges \ + --env TMPDIR=/tmp \ + --volume "$GITHUB_WORKSPACE/wolfsentry:/workspace/wolfsentry:ro" \ + --volume "$GITHUB_WORKSPACE/wolfssl:/workspace/wolfssl:ro" \ + --workdir /workspace/wolfsentry \ + wolfsentry-ci:local bash -euc ' + git config --global --add safe.directory /workspace/wolfssl + git config --global --add safe.directory /workspace/wolfssl/.git + git config --global --add safe.directory /workspace/wolfsentry/../wolfssl/.git + dbus-run-session -- bash tests/run-notification-demo-ci.sh + ' + + stm32-fragments: + name: STM32 fragments and Cortex-M build + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v4 + with: + path: wolfsentry + - uses: actions/checkout@v4 + with: + repository: wolfSSL/wolfssl + path: wolfssl + - uses: actions/checkout@v4 + with: + repository: lwip-tcpip/lwip + ref: STABLE-2_1_3_RELEASE + path: lwip + - uses: actions/checkout@v4 + with: + repository: lwip-tcpip/lwip-contrib + ref: STABLE-2_1_0_RELEASE + path: lwip/contrib + - uses: actions/checkout@v4 + with: + repository: FreeRTOS/FreeRTOS-Kernel + ref: V10.5.1 + path: freertos/FreeRTOS/Source + - name: Apply the wolfSentry lwIP packet filter API + run: patch --directory lwip --strip 1 < wolfsentry/lwip/LWIP_PACKET_FILTER_API.patch + - name: Build the wolfSentry CI image + run: | + docker build \ + --file wolfsentry/.github/docker/wolfsentry-ci/Dockerfile \ + --tag wolfsentry-ci:local wolfsentry + - name: Compile STM32 fragments and Cortex-M integration + run: | + docker run --rm \ + --env TMPDIR=/tmp \ + --volume "$GITHUB_WORKSPACE/wolfsentry:/workspace/wolfsentry:ro" \ + --volume "$GITHUB_WORKSPACE/wolfssl:/workspace/wolfssl:ro" \ + --volume "$GITHUB_WORKSPACE/lwip:/workspace/lwip:ro" \ + --volume "$GITHUB_WORKSPACE/freertos:/workspace/freertos:ro" \ + --workdir /workspace/wolfsentry \ + wolfsentry-ci:local bash -euc ' + make BUILD_TOP=/tmp/wolfsentry-host-build \ + /tmp/wolfsentry-host-build/wolfsentry/wolfsentry_options.h + + common_flags=( + -std=gnu99 + -fsyntax-only + -Wall + -Wextra + -Werror=format + -Werror=implicit-function-declaration + -Werror=incompatible-pointer-types + -Werror=strict-prototypes + -Wno-unused-parameter + -DLWIP_IPV6=0 + -Iports/Linux-lwIP/include + -I/workspace/lwip/contrib/ports/unix/port/include + -I/workspace/lwip/src/include + -I/tmp/wolfsentry-host-build + -I. + ) + + gcc "${common_flags[@]}" \ + -Iexamples/STM32-LWIP/Inc \ + examples/STM32-LWIP/Src/sentry.c \ + examples/STM32-LWIP/Src/echo.c \ + examples/STM32-LWIP/Src/ping.c + + gcc "${common_flags[@]}" \ + -DWOLFSSL_USER_SETTINGS \ + -Itests/stm32-compat \ + -Iexamples/STM32-LWIP-WOLFSSL/Inc \ + -I/workspace/wolfssl \ + examples/STM32-LWIP-WOLFSSL/Src/sentry.c \ + examples/STM32-LWIP-WOLFSSL/Src/echo.c + + make -j2 \ + FREERTOS_TOP=/workspace/freertos \ + LWIP_TOP=/workspace/lwip \ + freertos-arm32-thumb-build-test + ' diff --git a/.github/workflows/macos-check.yml b/.github/workflows/macos-check.yml index 0461fd3..60d9785 100644 --- a/.github/workflows/macos-check.yml +++ b/.github/workflows/macos-check.yml @@ -1,17 +1,31 @@ name: macOS Build Test +run-name: ${{ inputs.nightly_run_id || github.workflow }} + on: push: - branches: [ '*' ] + branches: [ 'master', 'release/**' ] pull_request: - branches: [ '*' ] + branches: [ '**' ] + workflow_dispatch: + inputs: + nightly_run_id: + description: Nightly coordinator run ID + required: false + type: string + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build: - runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - name: make test - run: make -j test + - uses: actions/checkout@v4 + - name: Build, sanitize, and run primary configuration suite + run: make -j2 check-macosx diff --git a/.github/workflows/multi-compiler.yml b/.github/workflows/multi-compiler.yml new file mode 100644 index 0000000..eb4cfb9 --- /dev/null +++ b/.github/workflows/multi-compiler.yml @@ -0,0 +1,44 @@ +name: Multi-Compiler + +run-name: ${{ inputs.nightly_run_id || github.workflow }} + +on: + push: + branches: [ 'master', 'release/**' ] + pull_request: + branches: [ '**' ] + workflow_dispatch: + inputs: + nightly_run_id: + description: Nightly coordinator run ID + required: false + type: string + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -e {0} + +jobs: + compilers: + name: ${{ matrix.cc }} + runs-on: ubuntu-latest + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + strategy: + fail-fast: false + matrix: + cc: [gcc-11, gcc-12, gcc-13, clang-14, clang-15, clang-17] + + steps: + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Build and test + run: make -j2 CC=${{ matrix.cc }} test diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 0000000..9ef5f4f --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,232 @@ +name: Nightly CI + +on: + schedule: + # 09:00 UTC is overnight in Pacific time. + - cron: '0 9 * * *' + workflow_dispatch: + +permissions: + actions: write + contents: read + issues: write + +concurrency: + group: nightly-ci + cancel-in-progress: false + +jobs: + trigger: + name: Run all CI and report failures + runs-on: ubuntu-latest + timeout-minutes: 150 + if: github.repository == 'wolfSSL/wolfsentry' + + steps: + - name: Dispatch workflows, wait, and report results + uses: actions/github-script@v7 + with: + script: | + const FAILURE_LABEL = 'nightly-failure'; + const ISSUE_MARKER = ''; + const POLL_INTERVAL_MS = 60 * 1000; + const POLL_TIMEOUT_MS = 120 * 60 * 1000; + const dispatchToken = `nightly-${context.runId}-${context.runAttempt}`; + const workflows = [ + 'codeql.yml', + 'coverage.yml', + 'examples.yml', + 'macos-check.yml', + 'multi-compiler.yml', + 'options-matrix.yml', + 'sanitizers.yml', + 'semgrep.yml', + 'static-analysis.yml', + 'ubuntu-check.yml', + 'wolfssl-versions.yml', + ]; + const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + const basename = (path) => (path || '').split('/').pop(); + const since = new Date(Date.now() - 60 * 1000).toISOString(); + const dispatchErrors = new Map(); + const dispatched = new Set(); + + for (const workflow of workflows) { + try { + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: workflow, + ref: 'master', + inputs: { nightly_run_id: dispatchToken }, + }); + dispatched.add(workflow); + core.info(`Triggered ${workflow}`); + } catch (error) { + dispatchErrors.set(workflow, error.message); + core.warning(`Failed to trigger ${workflow}: ${error.message}`); + } + } + + async function collectRuns() { + const runs = await github.paginate( + github.rest.actions.listWorkflowRunsForRepo, + { + owner: context.repo.owner, + repo: context.repo.repo, + event: 'workflow_dispatch', + created: `>=${since}`, + per_page: 100, + } + ); + const latest = new Map(); + for (const run of runs) { + const workflow = basename(run.path); + if (!dispatched.has(workflow) || run.display_title !== dispatchToken) { + continue; + } + const previous = latest.get(workflow); + if (previous === undefined || run.run_number > previous.run_number) { + latest.set(workflow, run); + } + } + return latest; + } + + await sleep(30 * 1000); + + const deadline = Date.now() + POLL_TIMEOUT_MS; + let latest = new Map(); + while (true) { + latest = await collectRuns(); + const pending = [...latest.values()] + .filter((run) => run.status !== 'completed'); + core.info( + `Tracking ${latest.size}/${workflows.length} runs, ` + + `${pending.length} still running` + ); + if (latest.size >= dispatched.size && pending.length === 0) { + break; + } + if (Date.now() >= deadline) { + core.warning('Timed out waiting for nightly runs to complete'); + break; + } + await sleep(POLL_INTERVAL_MS); + } + + const states = new Map(); + let allPassed = dispatchErrors.size === 0; + for (const workflow of workflows) { + const run = latest.get(workflow); + let state; + if (dispatchErrors.has(workflow)) { + state = 'dispatch failed'; + } else if (run === undefined) { + state = 'run not found'; + } else if (run.status !== 'completed') { + state = run.status; + } else { + state = run.conclusion || 'unknown'; + } + states.set(workflow, state); + if (state !== 'success') { + allPassed = false; + } + } + + let summary = '## Nightly CI Results\n\n'; + summary += '| Workflow | Result | Run |\n|---|---|---|\n'; + for (const workflow of workflows) { + const run = latest.get(workflow); + const link = run ? `[run #${run.run_number}](${run.html_url})` : '-'; + summary += `| ${workflow} | ${states.get(workflow)} | ${link} |\n`; + } + await core.summary.addRaw(summary).write(); + + const openIssues = await github.paginate( + github.rest.issues.listForRepo, + { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + labels: FAILURE_LABEL, + per_page: 100, + } + ); + const nightlyIssues = openIssues.filter( + (issue) => !issue.pull_request && issue.body?.includes(ISSUE_MARKER) + ); + const runUrl = + `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}` + + `/actions/runs/${context.runId}`; + + if (allPassed) { + for (const issue of nightlyIssues) { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: `Nightly CI recovered in [run #${context.runNumber}](${runUrl}). Closing this issue.`, + }); + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + state: 'closed', + state_reason: 'completed', + }); + core.info(`Closed recovered nightly failure issue #${issue.number}`); + } + core.info('All nightly workflows passed'); + return; + } + + try { + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: FAILURE_LABEL, + color: 'b60205', + description: 'Automated nightly CI failure report', + }); + } catch (error) { + if (error.status !== 422) { + throw error; + } + } + + const today = new Date().toISOString().slice(0, 10); + let body = `${ISSUE_MARKER}\nNightly CI reported failures on ${today}.\n\n`; + body += '| Workflow | Result | Run |\n|---|---|---|\n'; + for (const workflow of workflows) { + const run = latest.get(workflow); + const link = run ? `[run #${run.run_number}](${run.html_url})` : '-'; + body += `| ${workflow} | ${states.get(workflow)} | ${link} |\n`; + } + for (const [workflow, message] of dispatchErrors) { + body += `\nDispatch error for ${workflow}: \`${message}\`\n`; + } + body += `\nTriggered by nightly run [#${context.runNumber}](${runUrl}).\n`; + + if (nightlyIssues.length > 0) { + const issue = nightlyIssues[0]; + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body, + }); + core.info(`Updated existing issue #${issue.number}`); + } else { + const created = await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: 'Nightly CI failure', + body, + labels: [FAILURE_LABEL], + }); + core.info(`Opened issue #${created.data.number}`); + } + + core.setFailed('One or more nightly workflows failed'); diff --git a/.github/workflows/options-matrix.yml b/.github/workflows/options-matrix.yml new file mode 100644 index 0000000..c712bb2 --- /dev/null +++ b/.github/workflows/options-matrix.yml @@ -0,0 +1,76 @@ +name: Build Options + +run-name: ${{ inputs.nightly_run_id || github.workflow }} + +on: + push: + branches: [ 'master', 'release/**' ] + pull_request: + branches: [ '**' ] + workflow_dispatch: + inputs: + nightly_run_id: + description: Nightly coordinator run ID + required: false + type: string + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -e {0} + +jobs: + options: + name: ${{ matrix.name }} + runs-on: ubuntu-latest + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + strategy: + fail-fast: false + matrix: + include: + - name: Dynamic library + target: dynamic-build-test + - name: C99 + target: c99-test + - name: No alloca + target: no-alloca-test + - name: Single-threaded + target: singlethreaded-test + - name: No JSON + target: no-json-test + - name: No JSON DOM + target: no-json-dom-test + - name: No error strings + target: no-error-strings-test + - name: No protocol names + target: no-protocol-names-test + - name: No getprotoby + target: no-getprotoby-test + - name: No stdio streams + target: no-stdio-streams-build-test + - name: Minimal + target: minimal-build-test + - name: Minimal threaded + target: minimal-threaded-build-test + - name: User settings + target: user-settings-build-test + - name: Short enums + target: short-enums-test + - name: Prefix-only address matching + target: no-addr-bitmask-matching-test + - name: No IPv6 + target: no-ipv6-test + + steps: + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Test configuration + run: make -j2 ${{ matrix.target }} diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml new file mode 100644 index 0000000..f2ad0bd --- /dev/null +++ b/.github/workflows/sanitizers.yml @@ -0,0 +1,58 @@ +name: Sanitizers + +run-name: ${{ inputs.nightly_run_id || github.workflow }} + +on: + push: + branches: [ 'master', 'release/**' ] + pull_request: + branches: [ '**' ] + workflow_dispatch: + inputs: + nightly_run_id: + description: Nightly coordinator run ID + required: false + type: string + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -e {0} + +jobs: + sanitizer: + name: ${{ matrix.name }} + runs-on: ubuntu-latest + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + options: ${{ matrix.container_options }} + strategy: + fail-fast: false + matrix: + include: + - name: Address and undefined behavior + target: sanitize + cc: gcc + extra_cflags: -fno-sanitize-recover=all + container_options: '' + - name: Thread + target: sanitize-thread + cc: clang + extra_cflags: -fno-sanitize-recover=all -D__SANITIZE_THREAD__ + container_options: --security-opt seccomp=unconfined + + steps: + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Run sanitizer + run: | + make -j2 BUILD_TOP=/tmp/wolfsentry-sanitizer \ + CC=${{ matrix.cc }} \ + EXTRA_CFLAGS="${{ matrix.extra_cflags }}" ${{ matrix.target }} diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml new file mode 100644 index 0000000..6dc88fd --- /dev/null +++ b/.github/workflows/semgrep.yml @@ -0,0 +1,41 @@ +name: Semgrep + +run-name: ${{ inputs.nightly_run_id || github.workflow }} + +on: + push: + branches: [ 'master', 'release/**' ] + pull_request: + branches: [ '**' ] + workflow_dispatch: + inputs: + nightly_run_id: + description: Nightly coordinator run ID + required: false + type: string + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -e {0} + +jobs: + semgrep: + name: Semgrep security rules + runs-on: ubuntu-latest + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Run wolfSentry security rules + run: semgrep scan --config .github/semgrep-rules.yml --error --quiet . diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..e0dacd8 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,81 @@ +name: Static Analysis + +run-name: ${{ inputs.nightly_run_id || github.workflow }} + +on: + push: + branches: [ 'master', 'release/**' ] + pull_request: + branches: [ '**' ] + workflow_dispatch: + inputs: + nightly_run_id: + description: Nightly coordinator run ID + required: false + type: string + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -e {0} + +jobs: + cppcheck: + name: cppcheck + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + steps: + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Run cppcheck + run: | + cppcheck -j2 --enable=warning,performance,portability \ + --error-exitcode=1 --inline-suppr --suppress=missingIncludeSystem \ + --suppress=constParameterPointer --suppress=constParameter \ + --suppress=knownConditionTrueFalse --suppress=unusedStructMember \ + --suppress=allocaCalled -DSIZE_T_64 -D__GNUC__=13 \ + -I. -Iwolfsentry src tests/unittests.c + + clang-analyzer: + name: Clang Static Analyzer + runs-on: ubuntu-latest + timeout-minutes: 20 + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + steps: + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Run scan-build + run: | + scan-build -sarif --keep-empty \ + -o scan-results make -j2 CC=clang test + python3 tests/filter-clang-analyzer.py scan-results + - name: Upload analyzer reports + if: failure() + uses: actions/upload-artifact@v4 + with: + name: clang-static-analyzer + path: scan-results/ + + gcc-analyzer: + name: GCC -fanalyzer + runs-on: ubuntu-latest + timeout-minutes: 20 + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + steps: + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Build and test with GCC analyzer + run: make -j2 CC=gcc EXTRA_CFLAGS=-fanalyzer test diff --git a/.github/workflows/ubuntu-check.yml b/.github/workflows/ubuntu-check.yml index e721474..55b01a4 100644 --- a/.github/workflows/ubuntu-check.yml +++ b/.github/workflows/ubuntu-check.yml @@ -1,17 +1,39 @@ name: Ubuntu Build Test +run-name: ${{ inputs.nightly_run_id || github.workflow }} + on: push: - branches: [ '*' ] + branches: [ 'master', 'release/**' ] pull_request: - branches: [ '*' ] + branches: [ '**' ] + workflow_dispatch: + inputs: + nightly_run_id: + description: Nightly coordinator run ID + required: false + type: string + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -e {0} jobs: build: - runs-on: ubuntu-latest + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc steps: - - uses: actions/checkout@v2 - - name: make test - run: make -j test + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Build and run primary configuration suite + run: make -j2 check diff --git a/.github/workflows/wolfssl-versions.yml b/.github/workflows/wolfssl-versions.yml new file mode 100644 index 0000000..a23b63f --- /dev/null +++ b/.github/workflows/wolfssl-versions.yml @@ -0,0 +1,123 @@ +name: wolfSSL Version Matrix + +run-name: ${{ inputs.nightly_run_id || github.workflow }} + +on: + push: + branches: [ 'master', 'release/**' ] + pull_request: + branches: [ '**' ] + workflow_dispatch: + inputs: + nightly_run_id: + description: Nightly coordinator run ID + required: false + type: string + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -e {0} + +jobs: + discover: + name: Resolve wolfSSL versions + runs-on: ubuntu-latest + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + outputs: + matrix: ${{ steps.versions.outputs.matrix }} + steps: + - name: Build matrix + id: versions + run: | + LATEST=$(git ls-remote --tags --refs \ + https://github.com/wolfSSL/wolfssl.git 'v*-stable' \ + | awk -F/ '{print $NF}' | sort -V | tail -n 1) + test -n "$LATEST" + if [[ ! "$LATEST" =~ ^v[0-9]+(\.[0-9]+)+-stable$ ]]; then + echo "Unexpected wolfSSL stable tag: $LATEST" >&2 + exit 1 + fi + # v4.8.0 introduced --enable-wolfsentry. Keep it as a non-blocking + # customer-era probe because current wolfSentry APIs may not compile + # against that first integration. + MATRIX=$(jq -nc --arg latest "$LATEST" '{ + include: [ + {"name":"historical v4.8 integration probe","ref":"v4.8.0-stable","allow_failure":true}, + {"name":"legacy compatibility","ref":"v5.8.0-stable","allow_failure":false}, + {"name":"latest stable","ref":$latest,"allow_failure":false}, + {"name":"master","ref":"master","allow_failure":false} + ] + }') + echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT" + + integration: + name: ${{ matrix.name }} (${{ matrix.ref }}) + needs: discover + continue-on-error: ${{ matrix.allow_failure }} + runs-on: ubuntu-latest + container: + image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.discover.outputs.matrix) }} + + steps: + - uses: actions/checkout@v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Build and install wolfSentry + run: | + make -j2 test + make INSTALL_DIR="$HOME/wolfsentry-install" install + - name: Build wolfSSL with wolfSentry hooks + env: + WOLFSSL_REF: ${{ matrix.ref }} + run: | + git clone --depth 1 --branch "$WOLFSSL_REF" \ + https://github.com/wolfSSL/wolfssl.git "$HOME/wolfssl" + cd "$HOME/wolfssl" + ./autogen.sh + ./configure --enable-wolfsentry \ + --with-wolfsentry="$HOME/wolfsentry-install" \ + --enable-opensslextra --disable-shared + make -j2 examples/server/server examples/client/client + - name: Run wolfSSL client/server with wolfSentry filtering + run: | + cd "$HOME/wolfssl" + runtime_dir=$(mktemp -d) + policy="$GITHUB_WORKSPACE/tests/wolfssl-allow-all.json" + ./examples/server/server -p 12345 -d \ + -R "$runtime_dir/server.ready" \ + --wolfsentry-config "$policy" \ + > "$runtime_dir/server.log" 2>&1 & + server_pid=$! + trap 'test -z "${server_pid:-}" || kill "$server_pid" 2>/dev/null || true' EXIT + for attempt in $(seq 1 30); do + test -f "$runtime_dir/server.ready" && break + if [ "$attempt" -eq 30 ]; then + cat "$runtime_dir/server.log" + exit 1 + fi + sleep 1 + done + ./examples/client/client -h 127.0.0.1 -p 12345 \ + --wolfsentry-config "$policy" \ + > "$runtime_dir/client.log" 2>&1 + if ! wait "$server_pid"; then + cat "$runtime_dir/server.log" + exit 1 + fi + server_pid= + cat "$runtime_dir/client.log" + cat "$runtime_dir/server.log" + grep -F 'decision=1 (ACCEPT)' "$runtime_dir/client.log" + grep -F 'decision=1 (ACCEPT)' "$runtime_dir/server.log" diff --git a/Makefile b/Makefile index ff042fe..a83b2c0 100644 --- a/Makefile +++ b/Makefile @@ -204,12 +204,8 @@ endif # JSON settings need to be extracted from $(USER_SETTINGS_FILE) to determine if JSON sources should be built. ifdef USER_SETTINGS_FILE - ifeq "$(shell grep -q -E -e '^#define WOLFSENTRY_NO_JSON$$' '$(USER_SETTINGS_FILE)' && echo 1 || echo 0)" "1" - USER_SETTINGS_NO_JSON := 1 - endif - ifeq "$(shell grep -q -E -e '^#define WOLFSENTRY_NO_JSON_DOM$$' '$(USER_SETTINGS_FILE)' && echo 1 || echo 0)" "1" - USER_SETTINGS_NO_JSON_DOM := 1 - endif + USER_SETTINGS_NO_JSON := $(shell grep -q -x '\#define WOLFSENTRY_NO_JSON' '$(USER_SETTINGS_FILE)' && echo 1) + USER_SETTINGS_NO_JSON_DOM := $(shell grep -q -x '\#define WOLFSENTRY_NO_JSON_DOM' '$(USER_SETTINGS_FILE)' && echo 1) endif ifdef NO_JSON diff --git a/Makefile.analyzers b/Makefile.analyzers index 0faa2db..edc57fb 100644 --- a/Makefile.analyzers +++ b/Makefile.analyzers @@ -579,7 +579,7 @@ freertos-arm32-thumb-build-test: @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-freertos-arm32-thumb-test-builds" HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP FREERTOS_TOP=$(FREERTOS_TOP_FOR_TEST) LWIP_TOP=$(LWIP_TOP_FOR_TEST) EXTRA_CFLAGS+='-mthumb -mcpu=cortex-m7' UNITTEST_LIST=test_lwip clean # now rebuild with FUNCTION_SECTIONS=1, to test expected text size on a parsimonious link. @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-freertos-arm32-thumb-test-builds" HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP FREERTOS_TOP=$(FREERTOS_TOP_FOR_TEST) LWIP_TOP=$(LWIP_TOP_FOR_TEST) EXTRA_CFLAGS+='-mthumb -mcpu=cortex-m7 -specs=nano.specs -Wno-inline' NO_STDIO_STREAMS=1 '$(BUILD_PARENT)/wolfsentry-freertos-arm32-thumb-test-builds/tests/test_lwip' UNITTEST_LIST=test_lwip OPTIM='-Os' STRIPPED=1 FUNCTION_SECTIONS=1 - @TEST_LWIP_SZ=$$(stat --format='%s' '$(BUILD_PARENT)/wolfsentry-freertos-arm32-thumb-test-builds/tests/test_lwip'); if [[ "$$TEST_LWIP_SZ" -gt 100000 ]]; then echo "$(BUILD_PARENT)/wolfsentry-freertos-arm32-thumb-test-builds/tests/test_lwip is unexpectedly large ($$TEST_LWIP_SZ bytes)."; exit 1; fi + @TEST_LWIP_SZ=$$(stat --format='%s' '$(BUILD_PARENT)/wolfsentry-freertos-arm32-thumb-test-builds/tests/test_lwip'); if [[ "$$TEST_LWIP_SZ" -gt 110000 ]]; then echo "$(BUILD_PARENT)/wolfsentry-freertos-arm32-thumb-test-builds/tests/test_lwip is unexpectedly large ($$TEST_LWIP_SZ bytes)."; exit 1; fi @rm -rf '$(BUILD_PARENT)/'wolfsentry-freertos-arm32-thumb-test-builds/tests/{freertos,lwip} @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-freertos-arm32-thumb-test-builds" HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP FREERTOS_TOP=$(FREERTOS_TOP_FOR_TEST) LWIP_TOP=$(LWIP_TOP_FOR_TEST) EXTRA_CFLAGS+='-mthumb -mcpu=cortex-m7' UNITTEST_LIST=test_lwip clean @echo "passed: freertos-arm32-thumb-build test." @@ -748,6 +748,8 @@ linux-lwip-sanitize-all-gcc: @echo "passed: no defects from linux-lwip-sanitize-all-gcc for thread sanitizer" @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) VERY_QUIET=1 -f $(THIS_MAKEFILE) BUILD_TOP="$(BUILD_PARENT)/linux-lwip-sanitizer-builds" RUNTIME=Linux-lwIP LWIP_TOP=$(LWIP_TOP_FOR_TEST) UNITTEST_LIST_EXTRAS=test_lwip clean +NOTIFICATION_SANDBOX ?= bwrap --setenv TMPDIR "$(BUILD_PARENT)" --ro-bind / / --dev-bind /dev /dev --ro-bind /dev/shm /dev/shm --dev-bind /proc /proc --dev-bind "$(BUILD_PARENT)" "$(BUILD_PARENT)" + .PHONY: notification-demo-build-test notification-demo-build-test: @rm -rf "$(BUILD_PARENT)/wolfsentry-notification-demo-build" "$(BUILD_PARENT)/wolfssl-notification-demo-build" @@ -759,7 +761,7 @@ notification-demo-build-test: @echo 'building libwolfssl with --enable-wolfsentry' @cd "$(BUILD_PARENT)/wolfssl-notification-demo-build" && \ git checkout -q master && \ - bwrap --setenv TMPDIR "$(BUILD_PARENT)" --ro-bind / / --dev-bind /dev /dev --ro-bind /dev/shm /dev/shm --dev-bind /proc /proc --dev-bind "$(BUILD_PARENT)" "$(BUILD_PARENT)" /bin/bash -c './autogen.sh >/dev/null 2>&1 && ./configure --quiet --disable-jobserver --enable-opensslextra --enable-wolfsentry CPPFLAGS="-pedantic -DNO_WOLFSSL_CIPHER_SUITE_TEST -DWOLFSSL_OLD_PRIME_CHECK -Wno-restrict" --with-wolfsentry="$(BUILD_PARENT)/wolfsentry-notification-demo-build/installed" --enable-intelasm --prefix "$(BUILD_PARENT)/wolfssl-notification-demo-build/installed" && $(MAKE) V=1 >/dev/null && echo "checking libwolfssl" && $(MAKE) V=1 check >/dev/null && echo "installing libwolfssl at $(BUILD_PARENT)/wolfssl-notification-demo-build/installed" && $(MAKE) $(QUIET_FLAG) install >/dev/null' + $(NOTIFICATION_SANDBOX) /bin/bash -c './autogen.sh >/dev/null 2>&1 && ./configure --quiet --disable-jobserver --enable-opensslextra --enable-wolfsentry CPPFLAGS="-pedantic -DNO_WOLFSSL_CIPHER_SUITE_TEST -DWOLFSSL_OLD_PRIME_CHECK -Wno-restrict" --with-wolfsentry="$(BUILD_PARENT)/wolfsentry-notification-demo-build/installed" --enable-intelasm --prefix "$(BUILD_PARENT)/wolfssl-notification-demo-build/installed" && $(MAKE) V=1 >/dev/null && echo "checking libwolfssl" && AM_BWRAPPED=yes $(MAKE) V=1 check >/dev/null && echo "installing libwolfssl at $(BUILD_PARENT)/wolfssl-notification-demo-build/installed" && $(MAKE) $(QUIET_FLAG) install >/dev/null' @cd '$(BUILD_PARENT)/wolfsentry-notification-demo-build/notification-demo/log_server' && \ $(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) WOLFSENTRY_ROOT='$(BUILD_PARENT)/wolfsentry-notification-demo-build/installed' WOLFSSL_ROOT='$(BUILD_PARENT)/wolfssl-notification-demo-build/installed' clean && \ $(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) WOLFSENTRY_ROOT='$(BUILD_PARENT)/wolfsentry-notification-demo-build/installed' WOLFSSL_ROOT='$(BUILD_PARENT)/wolfssl-notification-demo-build/installed' OPTFLAGS='$(OPTIM)' DIAGFLAGS='$(DEBUG) $(C_WARNFLAGS)' EXTRA_CFLAGS='-DDEBUG_WOLFSENTRY' @@ -768,7 +770,7 @@ notification-demo-build-test: { ./udp_to_dbus > '$(BUILD_PARENT)/wolfsentry-notification-demo-build/udp_to_dbus.out' 2>&1 & } && \ UDP_TO_DBUS_PID=$$! && \ sleep 1 && \ - kill -0 $$UDP_TO_DBUS_PID && \ + { kill -0 $$UDP_TO_DBUS_PID || { cat '$(BUILD_PARENT)/wolfsentry-notification-demo-build/udp_to_dbus.out'; false; }; } && \ UDP_TO_DBUS_OK=1; \ else \ UDP_TO_DBUS_PID=; \ @@ -781,7 +783,11 @@ notification-demo-build-test: sleep 1 && \ kill -0 $$LOG_SERVER_PID || { cat '$(BUILD_PARENT)/wolfsentry-notification-demo-build/log_server.out' && false; } && \ cd '$(BUILD_PARENT)/wolfssl-notification-demo-build' && \ - curl --max-time 2 --no-progress-meter --cert ./certs/client-ecc384-cert.pem --key ./certs/client-ecc384-key.pem --cacert ./certs/ca-ecc-cert.pem --resolve 'www.wolfssl.com:10443:127.0.0.1' 'https://www.wolfssl.com:10443/show-log' > '$(BUILD_PARENT)/wolfsentry-notification-demo-build/curl.out' && \ + curl --max-time 2 --no-progress-meter \ + --cert '$(BUILD_PARENT)/wolfsentry-notification-demo-build/notification-demo/log_server/certs/client-ecc384-cert.pem' \ + --key '$(BUILD_PARENT)/wolfsentry-notification-demo-build/notification-demo/log_server/certs/client-ecc384-key.pem' \ + --cacert '$(BUILD_PARENT)/wolfsentry-notification-demo-build/notification-demo/log_server/certs/ca-ecc-cert.pem' \ + --resolve 'www.wolfssl.com:10443:127.0.0.1' 'https://www.wolfssl.com:10443/show-log' > '$(BUILD_PARENT)/wolfsentry-notification-demo-build/curl.out' && \ kill $$UDP_TO_DBUS_PID $$LOG_SERVER_PID && \ sleep 1 && \ { grep -q -E '"action" : "notify-on-decision", "trigger" : "event-on-connect", "parent" : "event-on-connect", "rule-id" : [0-9]{2,}, "rule-hitcount" : [0-9]+, "af" : "INET", "proto" : 6, "remote" : { "address" : "127\.0\.0\.1", "port" : [0-9]+ }, "local" : { "address" : "127\.0\.0\.1", "port" : 10443 }, "decision" : \["accept"\]' '$(BUILD_PARENT)/wolfsentry-notification-demo-build/curl.out' || { echo 'unexpected contents in $(BUILD_PARENT)/wolfsentry-notification-demo-build/curl.out' 1>&2; exit 1; }; } && \ @@ -874,7 +880,7 @@ ifneq "$(NO_JSON)" "1" $(BUILD_TOP)/tests/coverage-unittest.o: override CFLAGS+=-DTEST_JSON_CORPUS endif $(BUILD_TOP)/tests/coverage-unittest.o: override CFLAGS+=$(TEST_JSON_CFLAGS) -$(BUILD_TOP)/tests/coverage-unittest.o: $(SRC_TOP)/tests/unittests.c +$(BUILD_TOP)/tests/coverage-unittest.o: $(SRC_TOP)/tests/unittests.c $(OPTIONS_FILE) @[ -d $(dir $@) ] || mkdir -p $(dir $@) @rm -f $(@:.o=.gcda) ifeq "$(V)" "1" diff --git a/examples/Linux-LWIP/Dockerfile b/examples/Linux-LWIP/Dockerfile index f1ef25a..372da55 100644 --- a/examples/Linux-LWIP/Dockerfile +++ b/examples/Linux-LWIP/Dockerfile @@ -1,27 +1,34 @@ -FROM debian:10 AS builder +FROM debian:12 AS builder -RUN apt-get update && apt-get install -y unzip libpcap-dev build-essential git cmake libpcap0.8 +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential ca-certificates cmake git libpcap-dev netbase patch \ + && rm -rf /var/lib/apt/lists/* WORKDIR /src -RUN git clone https://github.com/lwip-tcpip/lwip -RUN git clone https://github.com/wolfSSL/wolfsentry +COPY . wolfsentry -WORKDIR wolfsentry +RUN git clone --depth 1 --branch STABLE-2_1_3_RELEASE \ + https://github.com/lwip-tcpip/lwip.git \ + && git clone --depth 1 --branch STABLE-2_1_0_RELEASE \ + https://git.savannah.nongnu.org/git/lwip/lwip-contrib.git \ + lwip/contrib \ + && cd lwip \ + && patch -p1 < ../wolfsentry/lwip/LWIP_PACKET_FILTER_API.patch -RUN CFLAGS="-g -O0" make -j && make install +WORKDIR /src/wolfsentry -WORKDIR /src +RUN make -j"$(nproc)" test && make install -COPY . lwip-echo +RUN cp -a examples/Linux-LWIP /src/lwip-echo WORKDIR /build -RUN cmake /src/lwip-echo/ && make -j +RUN cmake /src/lwip-echo/ && make -j"$(nproc)" WORKDIR /app RUN cp /build/lwip-runner . -COPY echo-config.json . +COPY examples/Linux-LWIP/echo-config.json . CMD /app/lwip-runner diff --git a/examples/Linux-LWIP/docker-compose.yml b/examples/Linux-LWIP/docker-compose.yml index 051795f..d605591 100644 --- a/examples/Linux-LWIP/docker-compose.yml +++ b/examples/Linux-LWIP/docker-compose.yml @@ -1,7 +1,9 @@ version: "3.9" services: echoserver: - build: . + build: + context: ../.. + dockerfile: examples/Linux-LWIP/Dockerfile ports: - "11111:11111" mac_address: de:c0:de:01:02:03 @@ -9,7 +11,7 @@ services: echo: ipv4_address: 172.20.20.3 tester1: - image: alpine + image: alpine:3.21 stdin_open: true tty: true mac_address: de:c0:de:03:02:01 @@ -17,7 +19,7 @@ services: echo: ipv4_address: 172.20.20.10 tester2: - image: alpine + image: alpine:3.21 stdin_open: true tty: true mac_address: de:c0:de:03:02:02 @@ -25,7 +27,7 @@ services: echo: ipv4_address: 172.20.20.20 tester3: - image: alpine + image: alpine:3.21 stdin_open: true tty: true mac_address: de:c0:de:03:03:01 diff --git a/examples/Linux-LWIP/lwip-include/arch/sys_arch.h b/examples/Linux-LWIP/lwip-include/arch/sys_arch.h index 422104a..f7e6be0 100644 --- a/examples/Linux-LWIP/lwip-include/arch/sys_arch.h +++ b/examples/Linux-LWIP/lwip-include/arch/sys_arch.h @@ -69,6 +69,7 @@ int lwip_unix_keypressed(void); */ void sys_mark_tcpip_thread(void); +#undef LWIP_MARK_TCPIP_THREAD #define LWIP_MARK_TCPIP_THREAD() sys_mark_tcpip_thread() #if LWIP_TCPIP_CORE_LOCKING diff --git a/examples/Linux-LWIP/main.c b/examples/Linux-LWIP/main.c index 27cc873..8682fbb 100644 --- a/examples/Linux-LWIP/main.c +++ b/examples/Linux-LWIP/main.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include #include +#include #include +#include #include @@ -19,6 +22,31 @@ #include "ping.h" #include "sentry.h" +unsigned int lwip_port_rand(void) +{ + unsigned int value; + unsigned char *output = (unsigned char *)&value; + size_t remaining = sizeof value; + + while (remaining > 0) { + ssize_t bytes_read = getrandom(output, remaining, 0); + + if (bytes_read > 0) { + output += (size_t)bytes_read; + remaining -= (size_t)bytes_read; + } + else if ((bytes_read < 0) && (errno == EINTR)) { + continue; + } + else { + perror("getrandom"); + abort(); + } + } + + return value; +} + /* Callback to send a raw lwIP packet via PCAP */ static err_t pcap_output(struct netif *netif, struct pbuf *p) { diff --git a/examples/Linux-LWIP/sentry.c b/examples/Linux-LWIP/sentry.c index 2063c71..acc24c7 100644 --- a/examples/Linux-LWIP/sentry.c +++ b/examples/Linux-LWIP/sentry.c @@ -3,8 +3,8 @@ #include #include #include -#include "lwip/sockets.h" #include "lwip/etharp.h" +#include "lwip/prot/ip.h" #include "lwip/tcp.h" #include "sentry.h" @@ -14,7 +14,7 @@ static struct wolfsentry_context *wolfsentry = NULL; /* Callback that is fired when an action is taken, this can be used for * debugging for now */ static wolfsentry_errcode_t test_action( - struct wolfsentry_context *wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_IN, const struct wolfsentry_action *action, void *handler_arg, void *caller_arg, @@ -22,11 +22,11 @@ static wolfsentry_errcode_t test_action( wolfsentry_action_type_t action_type, const struct wolfsentry_route *target_route, struct wolfsentry_route_table *route_table, - const struct wolfsentry_route *rule_route, + struct wolfsentry_route *rule_route, wolfsentry_action_res_t *action_results) { const struct wolfsentry_event *parent_event = wolfsentry_route_parent_event(rule_route); - (void)wolfsentry; + WOLFSENTRY_CONTEXT_ARGS_NOT_USED; (void)handler_arg; (void)route_table; (void)action_results; @@ -159,7 +159,7 @@ int sentry_init() /* Check a TCP connection with wolfSentry. This is called for connect and * disconnect so wolfSentry can count the simultaneous connections */ -int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_port, in_port_t remote_port, sentry_action_type action) +int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, uint16_t local_port, uint16_t remote_port, sentry_action_type action) { wolfsentry_errcode_t ret; wolfsentry_action_res_t action_results; @@ -187,7 +187,7 @@ int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_por /* Setup sockaddr information to send to wolfSentry */ remote.sa.sa_family = WOLFSENTRY_AF_INET; - remote.sa.sa_proto = IPPROTO_TCP; + remote.sa.sa_proto = IP_PROTO_TCP; remote.sa.sa_port = remote_port; /* Essentially a prefix size, wolfSentry uses the lesser of this and the * rule in JSON as to how much of the IP address to compare */ @@ -196,7 +196,7 @@ int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_por memcpy(remote.sa.addr, &remoteip, 4); local.sa.sa_family = WOLFSENTRY_AF_INET; - local.sa.sa_proto = IPPROTO_TCP; + local.sa.sa_proto = IP_PROTO_TCP; local.sa.sa_port = local_port; local.sa.addr_len = 32; local.sa.interface = 0; @@ -242,7 +242,7 @@ int sentry_action_ping(const ip_addr_t *addr, u8_t type) /* ICMP protocol check. The ICMP packet type is the port number for this * check */ remote.sa.sa_family = WOLFSENTRY_AF_INET; - remote.sa.sa_proto = IPPROTO_ICMP; + remote.sa.sa_proto = IP_PROTO_ICMP; remote.sa.sa_port = type; remote.sa.addr_len = 32; remote.sa.interface = 0; diff --git a/examples/Linux-LWIP/sentry.h b/examples/Linux-LWIP/sentry.h index 6f2b9d9..5545cb9 100644 --- a/examples/Linux-LWIP/sentry.h +++ b/examples/Linux-LWIP/sentry.h @@ -2,10 +2,10 @@ #ifndef __SENTRY_H__ #define __SENTRY_H__ -#include "lwip/tcp.h" -#include "lwip/sockets.h" +#include "lwip/ip_addr.h" #include #include +#include typedef enum { SENTRY_ACTION_NONE, @@ -14,7 +14,7 @@ typedef enum { } sentry_action_type; int sentry_init(void); -int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_port, in_port_t remote_port, sentry_action_type action); +int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, uint16_t local_port, uint16_t remote_port, sentry_action_type action); int sentry_action_ping(const ip_addr_t *addr, u8_t type); int sentry_action_mac(struct eth_addr *addr); #endif diff --git a/examples/Linux-wolfIP/Makefile b/examples/Linux-wolfIP/Makefile index 9b2b191..7ecec7d 100644 --- a/examples/Linux-wolfIP/Makefile +++ b/examples/Linux-wolfIP/Makefile @@ -9,11 +9,10 @@ CFLAGS ?= -O2 -g CFLAGS += -D_GNU_SOURCE CFLAGS += -DCONFIG_IPFILTER=1 CFLAGS += -Wall -Wextra -Wpedantic -std=c99 -CFLAGS += -std=c99 CFLAGS += -I. CFLAGS += -I./wolfip -CFLAGS += -I../../../wolfsentry/wolfsentry -CFLAGS += -I../../../wolfsentry +CFLAGS += -I$(WOLFSENTRY_PATH)/wolfsentry +CFLAGS += -I$(WOLFSENTRY_PATH) CFLAGS += -I$(WOLFIP_PATH) CFLAGS += -I$(WOLFIP_PATH)/src CFLAGS += -I$(WOLFIP_PATH)/src/port/posix @@ -40,6 +39,8 @@ all: $(TARGET) $(TARGET): $(APP_OBJS) $(TAP_OBJ) $(WOLFIP_LIB) $(WOLFSENTRY_LIB) $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ +$(APP_OBJS): $(WOLFSENTRY_LIB) + $(APP_OBJS): %.o : %.c $(CC) $(CFLAGS) -c $< -o $@ diff --git a/examples/Linux-wolfIP/main.c b/examples/Linux-wolfIP/main.c index 0d9a455..bce9587 100644 --- a/examples/Linux-wolfIP/main.c +++ b/examples/Linux-wolfIP/main.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -#define _GNU_SOURCE #include #include #include @@ -355,7 +354,12 @@ int main(void) stop_ping_process(); wolfsentry_cleanup_wolfip_filter_callbacks(WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(sentry, NULL), NULL); - wolfsentry_shutdown(WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(&sentry, NULL)); + ret = wolfsentry_shutdown(WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(&sentry, NULL)); + if (ret < 0) { + fprintf(stderr, "wolfsentry_shutdown failed: " + WOLFSENTRY_ERROR_FMT "\n", WOLFSENTRY_ERROR_FMT_ARGS(ret)); + return EXIT_FAILURE; + } printf("Exiting.\n"); return 0; diff --git a/examples/Linux-wolfIP/wolfip/config.h b/examples/Linux-wolfIP/wolfip/config.h index 9019f83..6884578 100644 --- a/examples/Linux-wolfIP/wolfip/config.h +++ b/examples/Linux-wolfIP/wolfip/config.h @@ -8,6 +8,7 @@ #define MAX_TCPSOCKETS 4 #define MAX_UDPSOCKETS 2 +#define MAX_ICMPSOCKETS 2 #define RXBUF_SIZE (LINK_MTU * 16) #define TXBUF_SIZE (LINK_MTU * 16) diff --git a/examples/STM32-LWIP-WOLFSSL/Inc/echo.h b/examples/STM32-LWIP-WOLFSSL/Inc/echo.h index 7651aff..b616146 100644 --- a/examples/STM32-LWIP-WOLFSSL/Inc/echo.h +++ b/examples/STM32-LWIP-WOLFSSL/Inc/echo.h @@ -12,9 +12,9 @@ struct tcp_pcb; struct tcp_hdr; -void echo_init(); +void echo_init(void); int sentry_tcp_inpkt(struct tcp_pcb *pcb, struct tcp_hdr *hdr, uint16_t optlen, uint16_t opt1len, uint8_t *opt2, struct pbuf *p); -int echo_ssl(); +int echo_ssl(void); void echo_msgclose(struct tcp_pcb *pcb); #endif diff --git a/examples/STM32-LWIP-WOLFSSL/Inc/sentry.h b/examples/STM32-LWIP-WOLFSSL/Inc/sentry.h index 6f2b9d9..e78586a 100644 --- a/examples/STM32-LWIP-WOLFSSL/Inc/sentry.h +++ b/examples/STM32-LWIP-WOLFSSL/Inc/sentry.h @@ -3,7 +3,6 @@ #ifndef __SENTRY_H__ #define __SENTRY_H__ #include "lwip/tcp.h" -#include "lwip/sockets.h" #include #include @@ -14,7 +13,7 @@ typedef enum { } sentry_action_type; int sentry_init(void); -int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_port, in_port_t remote_port, sentry_action_type action); +int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, uint16_t local_port, uint16_t remote_port, sentry_action_type action); int sentry_action_ping(const ip_addr_t *addr, u8_t type); int sentry_action_mac(struct eth_addr *addr); #endif diff --git a/examples/STM32-LWIP-WOLFSSL/Src/echo.c b/examples/STM32-LWIP-WOLFSSL/Src/echo.c index 2d8df3b..2872cec 100644 --- a/examples/STM32-LWIP-WOLFSSL/Src/echo.c +++ b/examples/STM32-LWIP-WOLFSSL/Src/echo.c @@ -28,7 +28,7 @@ struct thread_data { struct tcp_pcb *pcb; }; -const char cert[] = "-----BEGIN CERTIFICATE-----" +const unsigned char cert[] = "-----BEGIN CERTIFICATE-----" "MIIB2TCCAX+gAwIBAgIUclisQ2ZFuLig1QRSSpfRgt7F3jswCgYIKoZIzj0EAwIw" "QjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwT" "RGVmYXVsdCBDb21wYW55IEx0ZDAeFw0yMjAzMjgxNjE5MjFaFw0yMzAzMjgxNjE5" @@ -41,7 +41,7 @@ const char cert[] = "-----BEGIN CERTIFICATE-----" "lVmbi+AeY3ZjiYQCIAy/eYMMhFGMnIukdTMIP/Qf3KqfcBvlpLqiI3OaBZw4" "-----END CERTIFICATE-----"; -const char key[] = "-----BEGIN EC PARAMETERS-----" +const unsigned char key[] = "-----BEGIN EC PARAMETERS-----" "BggqhkjOPQMBBw==" "-----END EC PARAMETERS-----" "-----BEGIN EC PRIVATE KEY-----" @@ -117,7 +117,7 @@ static err_t echo_msgaccept(void *arg, struct tcp_pcb *pcb, err_t err) } /* Init the TCP listener */ -int echo_ssl() +int echo_ssl(void) { int ret; @@ -131,7 +131,7 @@ int echo_ssl() /* Load server certificates into WOLFSSL_CTX */ if ((ret = wolfSSL_CTX_use_certificate_buffer(wolf_ctx, cert, - strlen(cert), WOLFSSL_FILETYPE_PEM)) + sizeof cert - 1, WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) { fprintf(stderr, "ERROR: failed to load certificate buffer.\n"); return -1; @@ -139,26 +139,26 @@ int echo_ssl() /* Load server key into WOLFSSL_CTX */ if ((ret = wolfSSL_CTX_use_PrivateKey_buffer(wolf_ctx, key, - strlen(key), WOLFSSL_FILETYPE_PEM)) + sizeof key - 1, WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) { fprintf(stderr, "ERROR: failed to load key buffer.\n"); return -1; } return 0; } -void echo_init() +void echo_init(void) { struct tcp_pcb *pcb; /* Create lwIP TCP instance */ pcb = tcp_new(); - LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: pcb: %x\n", pcb)); + LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: pcb: %p\n", (void *)pcb)); /* Bind port 11111 */ int r = tcp_bind(pcb, IP_ADDR_ANY, 8080); LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: tcp_bind: %d\n", r)); /* Enable listening */ tcp_arg(pcb, NULL); pcb = tcp_listen(pcb); - LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: listen-pcb: %x\n", pcb)); + LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: listen-pcb: %p\n", (void *)pcb)); /* Set accept connection callback */ tcp_accept(pcb, echo_msgaccept); fprintf(stderr, "Accept ready!\n"); diff --git a/examples/STM32-LWIP-WOLFSSL/Src/sentry.c b/examples/STM32-LWIP-WOLFSSL/Src/sentry.c index 952cab6..cceb7b1 100644 --- a/examples/STM32-LWIP-WOLFSSL/Src/sentry.c +++ b/examples/STM32-LWIP-WOLFSSL/Src/sentry.c @@ -3,7 +3,6 @@ #include #include #include -#include "lwip/sockets.h" #include "lwip/etharp.h" #include "lwip/tcp.h" #include "sentry.h" @@ -104,7 +103,7 @@ static const char *wolfsentry_config_data = "{\n" /* Callback that is fired when an action is taken, this can be used for * debugging for now */ static wolfsentry_errcode_t test_action( - struct wolfsentry_context *wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_IN, const struct wolfsentry_action *action, void *handler_arg, void *caller_arg, @@ -112,12 +111,13 @@ static wolfsentry_errcode_t test_action( wolfsentry_action_type_t action_type, const struct wolfsentry_route *target_route, struct wolfsentry_route_table *route_table, - const struct wolfsentry_route *rule_route, + struct wolfsentry_route *rule_route, wolfsentry_action_res_t *action_results) { const struct wolfsentry_event *parent_event = wolfsentry_route_parent_event(rule_route); - (void)wolfsentry; + WOLFSENTRY_CONTEXT_ARGS_NOT_USED; (void)handler_arg; + (void)parent_event; (void)route_table; (void)action_results; @@ -132,13 +132,14 @@ static wolfsentry_errcode_t test_action( } /* Initialize wolfSentry with a config file */ -int sentry_init() +int sentry_init(void) { wolfsentry_errcode_t ret; wolfsentry_ent_id_t id; struct wolfsentry_eventconfig config = { .route_private_data_size = 32, .route_private_data_alignment = 16 }; - ret = wolfsentry_init(wolfsentry_build_settings, NULL /* hpi */, &config, + ret = wolfsentry_init(wolfsentry_build_settings, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(NULL /* hpi */, NULL /* thread */), &config, &wolfsentry); if (ret < 0) @@ -147,7 +148,7 @@ int sentry_init() } /* Insert the possible actions into wolfSentry */ - wolfsentry_action_insert( wolfsentry, + wolfsentry_action_insert( WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "handle-insert", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -156,7 +157,7 @@ int sentry_init() &id); wolfsentry_action_insert( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "handle-delete", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -165,7 +166,7 @@ int sentry_init() &id); wolfsentry_action_insert( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "handle-match", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -174,7 +175,7 @@ int sentry_init() &id); wolfsentry_action_insert( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "notify-on-match", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -183,7 +184,7 @@ int sentry_init() &id); wolfsentry_action_insert( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "handle-connect", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -192,7 +193,7 @@ int sentry_init() &id); wolfsentry_action_insert( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "handle-connect2", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -206,7 +207,7 @@ int sentry_init() /* Initalize the wolfSentry JSON parser */ if ((ret = wolfsentry_config_json_init( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), WOLFSENTRY_CONFIG_LOAD_FLAG_NONE, &jps)) < 0) { @@ -215,7 +216,9 @@ int sentry_init() /* wolfSentry uses a streaming reader/parser for the config file */ /* Send the read data into the JSON parser */ - ret = wolfsentry_config_json_feed(jps, wolfsentry_config_data, strlen(wolfsentry_config_data), err_buf, sizeof err_buf); + ret = wolfsentry_config_json_feed(jps, + (const unsigned char *)wolfsentry_config_data, + strlen(wolfsentry_config_data), err_buf, sizeof err_buf); if (ret < 0) { @@ -234,7 +237,7 @@ int sentry_init() /* Check a TCP connection with wolfSentry. This is called for connect and * disconnect so wolfSentry can count the simultaneous connections */ -int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_port, in_port_t remote_port, sentry_action_type action) +int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, uint16_t local_port, uint16_t remote_port, sentry_action_type action) { wolfsentry_errcode_t ret; wolfsentry_action_res_t action_results; @@ -262,7 +265,7 @@ int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_por /* Setup sockaddr information to send to wolfSentry */ remote.sa.sa_family = WOLFSENTRY_AF_INET; - remote.sa.sa_proto = IPPROTO_TCP; + remote.sa.sa_proto = IP_PROTO_TCP; remote.sa.sa_port = remote_port; /* Essentially a prefix size, wolfSentry uses the lesser of this and the * rule in JSON as to how much of the IP address to compare */ @@ -271,7 +274,7 @@ int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_por memcpy(remote.sa.addr, &remoteip, 4); local.sa.sa_family = WOLFSENTRY_AF_INET; - local.sa.sa_proto = IPPROTO_TCP; + local.sa.sa_proto = IP_PROTO_TCP; local.sa.sa_port = local_port; local.sa.addr_len = 32; local.sa.interface = 0; @@ -279,7 +282,7 @@ int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_por /* Send the details of this to wolfSentry and get the result */ ret = wolfsentry_route_event_dispatch_with_inited_result( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), &remote.sa, &local.sa, WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, @@ -318,14 +321,14 @@ int sentry_action_ping(const ip_addr_t *addr, u8_t type) /* ICMP protocol check. The ICMP packet type is the port number for this * check */ remote.sa.sa_family = WOLFSENTRY_AF_INET; - remote.sa.sa_proto = IPPROTO_ICMP; + remote.sa.sa_proto = IP_PROTO_ICMP; remote.sa.sa_port = type; remote.sa.addr_len = 32; remote.sa.interface = 0; memcpy(remote.sa.addr, &addr->addr, 4); ret = wolfsentry_route_event_dispatch( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), &remote.sa, &remote.sa, // Reuse for now WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, @@ -366,7 +369,7 @@ int sentry_action_mac(struct eth_addr *addr) memcpy(remote.sa.addr, &addr->addr, 6); ret = wolfsentry_route_event_dispatch( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), &remote.sa, &remote.sa, // Reuse for now WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, diff --git a/examples/STM32-LWIP/Inc/sentry.h b/examples/STM32-LWIP/Inc/sentry.h index 6f2b9d9..e78586a 100644 --- a/examples/STM32-LWIP/Inc/sentry.h +++ b/examples/STM32-LWIP/Inc/sentry.h @@ -3,7 +3,6 @@ #ifndef __SENTRY_H__ #define __SENTRY_H__ #include "lwip/tcp.h" -#include "lwip/sockets.h" #include #include @@ -14,7 +13,7 @@ typedef enum { } sentry_action_type; int sentry_init(void); -int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_port, in_port_t remote_port, sentry_action_type action); +int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, uint16_t local_port, uint16_t remote_port, sentry_action_type action); int sentry_action_ping(const ip_addr_t *addr, u8_t type); int sentry_action_mac(struct eth_addr *addr); #endif diff --git a/examples/STM32-LWIP/Src/echo.c b/examples/STM32-LWIP/Src/echo.c index bbc88ca..5a07f4f 100644 --- a/examples/STM32-LWIP/Src/echo.c +++ b/examples/STM32-LWIP/Src/echo.c @@ -41,7 +41,7 @@ static err_t echo_msgrecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, for (q = p; q != NULL; q = q->next) { - printf("Got: %.*s\n", q->len, q->payload); + printf("Got: %.*s\n", q->len, (const char *)q->payload); } } else if (err == ERR_OK && p == NULL) @@ -98,13 +98,13 @@ int echo_init(void) /* Create lwIP TCP instance */ pcb = tcp_new(); - LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: pcb: %x\n", pcb)); + LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: pcb: %p\n", (void *)pcb)); /* Bind port 11111 */ int r = tcp_bind(pcb, IP_ADDR_ANY, 11111); LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: tcp_bind: %d\n", r)); /* Enable listening */ pcb = tcp_listen(pcb); - LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: listen-pcb: %x\n", pcb)); + LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: listen-pcb: %p\n", (void *)pcb)); /* Set accept connection callback */ tcp_accept(pcb, echo_msgaccept); diff --git a/examples/STM32-LWIP/Src/sentry.c b/examples/STM32-LWIP/Src/sentry.c index 9452856..8c7c2c9 100644 --- a/examples/STM32-LWIP/Src/sentry.c +++ b/examples/STM32-LWIP/Src/sentry.c @@ -3,7 +3,6 @@ #include #include #include -#include "lwip/sockets.h" #include "lwip/etharp.h" #include "lwip/tcp.h" #include "sentry.h" @@ -104,7 +103,7 @@ static const char *wolfsentry_config_data = "{\n" /* Callback that is fired when an action is taken, this can be used for * debugging for now */ static wolfsentry_errcode_t test_action( - struct wolfsentry_context *wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_IN, const struct wolfsentry_action *action, void *handler_arg, void *caller_arg, @@ -112,12 +111,13 @@ static wolfsentry_errcode_t test_action( wolfsentry_action_type_t action_type, const struct wolfsentry_route *target_route, struct wolfsentry_route_table *route_table, - const struct wolfsentry_route *rule_route, + struct wolfsentry_route *rule_route, wolfsentry_action_res_t *action_results) { const struct wolfsentry_event *parent_event = wolfsentry_route_parent_event(rule_route); - (void)wolfsentry; + WOLFSENTRY_CONTEXT_ARGS_NOT_USED; (void)handler_arg; + (void)parent_event; (void)route_table; (void)action_results; @@ -132,22 +132,24 @@ static wolfsentry_errcode_t test_action( } /* Initialize wolfSentry with a config file */ -int sentry_init() +int sentry_init(void) { wolfsentry_errcode_t ret; wolfsentry_ent_id_t id; struct wolfsentry_eventconfig config = { .route_private_data_size = 32, .route_private_data_alignment = 16 }; - ret = wolfsentry_init(wolfsentry_build_settings, NULL /* hpi */, &config, + ret = wolfsentry_init(wolfsentry_build_settings, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(NULL /* hpi */, NULL /* thread */), &config, &wolfsentry); if (ret < 0) { - printf("unable to initialize wolfSentry, code: %ld\n", WOLFSENTRY_ERROR_DECODE_ERROR_CODE(ret)); + printf("unable to initialize wolfSentry, " WOLFSENTRY_ERROR_FMT "\n", + WOLFSENTRY_ERROR_FMT_ARGS(ret)); } /* Insert the possible actions into wolfSentry */ - wolfsentry_action_insert( wolfsentry, + wolfsentry_action_insert( WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "handle-insert", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -156,7 +158,7 @@ int sentry_init() &id); wolfsentry_action_insert( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "handle-delete", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -165,7 +167,7 @@ int sentry_init() &id); wolfsentry_action_insert( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "handle-match", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -174,7 +176,7 @@ int sentry_init() &id); wolfsentry_action_insert( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "notify-on-match", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -183,7 +185,7 @@ int sentry_init() &id); wolfsentry_action_insert( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "handle-connect", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -192,7 +194,7 @@ int sentry_init() &id); wolfsentry_action_insert( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), "handle-connect2", WOLFSENTRY_LENGTH_NULL_TERMINATED, WOLFSENTRY_ACTION_FLAG_NONE, @@ -206,26 +208,33 @@ int sentry_init() /* Initalize the wolfSentry JSON parser */ if ((ret = wolfsentry_config_json_init( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), WOLFSENTRY_CONFIG_LOAD_FLAG_NONE, &jps)) < 0) { - printf("error while initializing wolfSentry config parser, code: %ld\n", WOLFSENTRY_ERROR_DECODE_ERROR_CODE(ret)); + printf("error while initializing wolfSentry config parser, " + WOLFSENTRY_ERROR_FMT "\n", WOLFSENTRY_ERROR_FMT_ARGS(ret)); } /* wolfSentry uses a streaming reader/parser for the config file */ /* Send the read data into the JSON parser */ - ret = wolfsentry_config_json_feed(jps, wolfsentry_config_data, strlen(wolfsentry_config_data), err_buf, sizeof err_buf); + ret = wolfsentry_config_json_feed(jps, + (const unsigned char *)wolfsentry_config_data, + strlen(wolfsentry_config_data), err_buf, sizeof err_buf); if (ret < 0) { - printf("error while loading wolfSentry config data, code: %ld, msg: %s\n", WOLFSENTRY_ERROR_DECODE_ERROR_CODE(ret), err_buf); + printf("error while loading wolfSentry config data, " + WOLFSENTRY_ERROR_FMT ", msg: %s\n", + WOLFSENTRY_ERROR_FMT_ARGS(ret), err_buf); } /* Clean up the JSON parser */ if ((ret = wolfsentry_config_json_fini(&jps, err_buf, sizeof err_buf)) < 0) { - printf("error while loading wolfSentry config data, code: %ld, msg: %s\n", WOLFSENTRY_ERROR_DECODE_ERROR_CODE(ret), err_buf); + printf("error while loading wolfSentry config data, " + WOLFSENTRY_ERROR_FMT ", msg: %s\n", + WOLFSENTRY_ERROR_FMT_ARGS(ret), err_buf); } return 0; @@ -234,7 +243,7 @@ int sentry_init() /* Check a TCP connection with wolfSentry. This is called for connect and * disconnect so wolfSentry can count the simultaneous connections */ -int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_port, in_port_t remote_port, sentry_action_type action) +int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, uint16_t local_port, uint16_t remote_port, sentry_action_type action) { wolfsentry_errcode_t ret; wolfsentry_action_res_t action_results; @@ -262,7 +271,7 @@ int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_por /* Setup sockaddr information to send to wolfSentry */ remote.sa.sa_family = WOLFSENTRY_AF_INET; - remote.sa.sa_proto = IPPROTO_TCP; + remote.sa.sa_proto = IP_PROTO_TCP; remote.sa.sa_port = remote_port; /* Essentially a prefix size, wolfSentry uses the lesser of this and the * rule in JSON as to how much of the IP address to compare */ @@ -271,7 +280,7 @@ int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_por memcpy(remote.sa.addr, &remoteip, 4); local.sa.sa_family = WOLFSENTRY_AF_INET; - local.sa.sa_proto = IPPROTO_TCP; + local.sa.sa_proto = IP_PROTO_TCP; local.sa.sa_port = local_port; local.sa.addr_len = 32; local.sa.interface = 0; @@ -279,7 +288,7 @@ int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, in_port_t local_por /* Send the details of this to wolfSentry and get the result */ ret = wolfsentry_route_event_dispatch_with_inited_result( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), &remote.sa, &local.sa, WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, @@ -318,14 +327,14 @@ int sentry_action_ping(const ip_addr_t *addr, u8_t type) /* ICMP protocol check. The ICMP packet type is the port number for this * check */ remote.sa.sa_family = WOLFSENTRY_AF_INET; - remote.sa.sa_proto = IPPROTO_ICMP; + remote.sa.sa_proto = IP_PROTO_ICMP; remote.sa.sa_port = type; remote.sa.addr_len = 32; remote.sa.interface = 0; memcpy(remote.sa.addr, &addr->addr, 4); ret = wolfsentry_route_event_dispatch( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), &remote.sa, &remote.sa, // Reuse for now WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, @@ -366,7 +375,7 @@ int sentry_action_mac(struct eth_addr *addr) memcpy(remote.sa.addr, &addr->addr, 6); ret = wolfsentry_route_event_dispatch( - wolfsentry, + WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), &remote.sa, &remote.sa, // Reuse for now WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, diff --git a/examples/notification-demo/udp_to_dbus/udp_to_dbus.c b/examples/notification-demo/udp_to_dbus/udp_to_dbus.c index 6c98df7..ec7f9c9 100644 --- a/examples/notification-demo/udp_to_dbus/udp_to_dbus.c +++ b/examples/notification-demo/udp_to_dbus/udp_to_dbus.c @@ -54,6 +54,7 @@ static int notnormal = 0; break; \ } \ (ptr) += _len; \ + (ptr_len_left) -= _len; \ } #define WARN_ON_JSON_FAILURE(x) do { int _x = (x); if (_x < 0) { fprintf(stderr, "ERROR: %s L %d: JSON call (%s) failed with code %d (%s)\n", __FILE__, __LINE__, #x, _x, json_error_str(_x)); } } while (0) diff --git a/lwip/LWIP_PACKET_FILTER_API.patch b/lwip/LWIP_PACKET_FILTER_API.patch index 8cf32d4..5651863 100644 --- a/lwip/LWIP_PACKET_FILTER_API.patch +++ b/lwip/LWIP_PACKET_FILTER_API.patch @@ -44,7 +44,7 @@ index f35ff4b5..ae368bee 100644 + * we're turning around. + */ + if (netif != NULL) { -+ if (icmp_filter_dispatch_outgoing(FILT_SENDING, netif, &iphdr->dest, &iphdr->src, type, icmphdr) != ERR_OK) { ++ if (icmp_filter_dispatch_outgoing(FILT_SENDING, netif, &iphdr->dest, &iphdr->src, type, (const struct icmp_hdr *)icmphdr) != ERR_OK) { + LWIP_DEBUGF(IP_DEBUG, ("icmp_send_response: icmp_filter_dispatch_outgoing rejected packet.\n")); + netif = NULL; + } @@ -54,7 +54,7 @@ index f35ff4b5..ae368bee 100644 if (netif != NULL) { /* calculate checksum */ icmphdr->chksum = 0; -@@ -405,4 +436,84 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code) +@@ -405,4 +436,85 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code) pbuf_free(q); } @@ -101,7 +101,8 @@ index f35ff4b5..ae368bee 100644 + event.netif = netif; + event.packet_hdr.icmp_hdr = hdr; + ret = filter_cb(filter_arg, &event, -+ ip4_current_dest_addr(), ip4_current_src_addr(), hdr->type); ++ ip4_current_dest_addr(), ip4_current_src_addr(), ++ ((const struct icmp_echo_hdr *)hdr)->type); + + packet_filter_lock = 0; + @@ -801,7 +802,7 @@ index 1b17e40f..bd243a70 100644 tcp_pcb_remove(&tcp_active_pcbs, pcb); tcp_free(pcb); return 1; -@@ -640,6 +665,21 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) +@@ -640,6 +665,22 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) LWIP_ASSERT("tcp_listen_input: invalid pcb", pcb != NULL); @@ -811,8 +812,9 @@ index 1b17e40f..bd243a70 100644 + if (err != ERR_OK) { + if (err == ERR_RST) { + LWIP_DEBUGF(IP_DEBUG, ("tcp_listen_input: tcp_filter_dispatch_incoming rejected connect, sending reset.\n")); -+ tcp_rst_netif(ip_data.current_input_netif, ackno, seqno + tcplen, ip_current_dest_addr(), -+ ip_current_src_addr(), tcphdr->dest, tcphdr->src); ++ tcp_rst((const struct tcp_pcb *)pcb, ackno, seqno + tcplen, ++ ip_current_dest_addr(), ip_current_src_addr(), ++ tcphdr->dest, tcphdr->src); + } else + LWIP_DEBUGF(IP_DEBUG, ("tcp_listen_input: tcp_filter_dispatch_incoming rejected connect.\n")); + return; diff --git a/ports/FreeRTOS-lwIP/include/lwipopts.h b/ports/FreeRTOS-lwIP/include/lwipopts.h index b25a852..cbfacf8 100644 --- a/ports/FreeRTOS-lwIP/include/lwipopts.h +++ b/ports/FreeRTOS-lwIP/include/lwipopts.h @@ -101,7 +101,7 @@ #define IP_OPTIONS 1 #define ICMP_TTL 255 #define LWIP_DHCP 0 -#define DHCP_DOES_ARP_CHECK 1 +#define DHCP_DOES_ARP_CHECK 0 #define UDP_TTL 255 /* #define STATS */ diff --git a/tests/filter-clang-analyzer.py b/tests/filter-clang-analyzer.py new file mode 100644 index 0000000..f4e199f --- /dev/null +++ b/tests/filter-clang-analyzer.py @@ -0,0 +1,60 @@ +#!/usr/bin/python3 + +"""Reject Clang analyzer results except documented file-local false positives.""" + +import json +import pathlib +import sys + + +ALLOWED_RESULTS = { + ("core.uninitialized.Assign", "src/json/centijson_value.c", 1285), + ("core.NullDereference", "src/json/centijson_value.c", 1483), + ("core.NullDereference", "src/json/centijson_value.c", 1520), +} + + +def normalized_rule(rule_id): + return rule_id.removeprefix("clang-analyzer-") + + +def result_location(result): + locations = result.get("locations", []) + if not locations: + return "", 0 + physical = locations[0].get("physicalLocation", {}) + location = physical.get("artifactLocation", {}).get("uri", "") + line = physical.get("region", {}).get("startLine", 0) + return location, line + + +def main(): + report_dir = pathlib.Path(sys.argv[1]) + unexpected = [] + suppressed = 0 + + for report_path in sorted(report_dir.rglob("*.sarif")): + report = json.loads(report_path.read_text(encoding="utf-8")) + for run in report.get("runs", []): + for result in run.get("results", []): + rule = normalized_rule(result.get("ruleId", "")) + location, line = result_location(result) + allowed = any( + rule == allowed_rule + and location.endswith(allowed_path) + and line == allowed_line + for allowed_rule, allowed_path, allowed_line in ALLOWED_RESULTS + ) + if allowed: + suppressed += 1 + else: + unexpected.append((rule, location, line)) + + for rule, location, line in unexpected: + print(f"unexpected Clang analyzer result: {rule} at {location}:{line}") + print(f"suppressed {suppressed} documented analyzer result(s)") + return 1 if unexpected else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/notification-dbus-service.py b/tests/notification-dbus-service.py new file mode 100644 index 0000000..bf1075d --- /dev/null +++ b/tests/notification-dbus-service.py @@ -0,0 +1,63 @@ +#!/usr/bin/python3 + +"""Minimal org.freedesktop.Notifications service for headless CI.""" + +import dbus +import dbus.service +from dbus.mainloop.glib import DBusGMainLoop +from gi.repository import GLib + + +INTERFACE = "org.freedesktop.Notifications" +OBJECT_PATH = "/org/freedesktop/Notifications" + + +class NotificationService(dbus.service.Object): + """Accept desktop notifications without requiring a graphical session.""" + + @dbus.service.method(INTERFACE, in_signature="", out_signature="as") + def GetCapabilities(self): + return ["body"] + + @dbus.service.method(INTERFACE, in_signature="", out_signature="ssss") + def GetServerInformation(self): + return ("wolfSentry CI", "wolfSSL", "1.0", "1.2") + + @dbus.service.method( + INTERFACE, + in_signature="susssasa{sv}i", + out_signature="u", + ) + def Notify( + self, + app_name, + replaces_id, + app_icon, + summary, + body, + actions, + hints, + expire_timeout, + ): + del app_name, replaces_id, app_icon, body, actions, hints, expire_timeout + print(f"notification received: {summary}", flush=True) + return dbus.UInt32(1) + + @dbus.service.method(INTERFACE, in_signature="u", out_signature="") + def CloseNotification(self, notification_id): + del notification_id + + +def main(): + DBusGMainLoop(set_as_default=True) + bus = dbus.SessionBus() + bus_name = dbus.service.BusName(INTERFACE, bus) + service = NotificationService(bus_name, OBJECT_PATH) + print("notification service ready", flush=True) + main_loop = GLib.MainLoop() + main_loop.run() + del service + + +if __name__ == "__main__": + main() diff --git a/tests/run-notification-demo-ci.sh b/tests/run-notification-demo-ci.sh new file mode 100644 index 0000000..21f9c63 --- /dev/null +++ b/tests/run-notification-demo-ci.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +set -euo pipefail + +service_log=$(mktemp) +service_pid= + +cleanup() { + if [[ -n "$service_pid" ]]; then + kill "$service_pid" 2>/dev/null || true + wait "$service_pid" 2>/dev/null || true + fi + rm -f "$service_log" +} +trap cleanup EXIT + +/usr/bin/python3 tests/notification-dbus-service.py >"$service_log" 2>&1 & +service_pid=$! + +for attempt in $(seq 1 30); do + if grep -q -F 'notification service ready' "$service_log"; then + break + fi + if ! kill -0 "$service_pid" 2>/dev/null; then + cat "$service_log" + exit 1 + fi + if [[ "$attempt" -eq 30 ]]; then + cat "$service_log" + exit 1 + fi + sleep 1 +done + +make -j2 NOTIFICATION_SANDBOX= notification-demo-build-test +grep -q -F 'notification received:' "$service_log" diff --git a/tests/stm32-compat/cmsis_os.h b/tests/stm32-compat/cmsis_os.h new file mode 100644 index 0000000..31f062c --- /dev/null +++ b/tests/stm32-compat/cmsis_os.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef WOLFSENTRY_TEST_CMSIS_OS_H +#define WOLFSENTRY_TEST_CMSIS_OS_H + +#include + +typedef void *QueueHandle_t; +typedef int BaseType_t; +typedef uint32_t TickType_t; + +typedef enum { + osOK = 0 +} osStatus; + +#define pdPASS 1 + +BaseType_t xQueueSendFromISR(QueueHandle_t queue, const void *item, + BaseType_t *higher_priority_task_woken); +osStatus osDelay(uint32_t millisec); + +#endif /* WOLFSENTRY_TEST_CMSIS_OS_H */ diff --git a/tests/stm32-compat/user_settings.h b/tests/stm32-compat/user_settings.h new file mode 100644 index 0000000..fcba1da --- /dev/null +++ b/tests/stm32-compat/user_settings.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef WOLFSENTRY_TEST_WOLFSSL_USER_SETTINGS_H +#define WOLFSENTRY_TEST_WOLFSSL_USER_SETTINGS_H + +#define WOLFSSL_LWIP_NATIVE +#define WOLFSSL_TLS13 +#define WOLFSSL_CMSIS_RTOS +#define SINGLE_THREADED +#define NO_WRITEV +#define WOLFSSL_NO_SOCK +#define ECC_TIMING_RESISTANT +#define WC_RSA_BLINDING + +#endif /* WOLFSENTRY_TEST_WOLFSSL_USER_SETTINGS_H */ diff --git a/tests/unittests.c b/tests/unittests.c index 8f346ad..7a75686 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -460,7 +460,8 @@ static __attribute_maybe_unused__ wolfsentry_errcode_t load_test_action_handlers static __attribute_maybe_unused__ wolfsentry_errcode_t json_feed_file(WOLFSENTRY_CONTEXT_ARGS_IN, const char *fname, wolfsentry_config_load_flags_t flags, int verbose) { wolfsentry_errcode_t ret; struct wolfsentry_json_process_state *jps; - FILE *f = NULL; + FILE *f = stdin; + int close_f = 0; unsigned char buf[512]; char err_buf[512]; int fini_ret; @@ -471,6 +472,7 @@ static __attribute_maybe_unused__ wolfsentry_errcode_t json_feed_file(WOLFSENTRY (void)fprintf(stderr, "fopen(%s): %s\n",fname,strerror(errno)); WOLFSENTRY_ERROR_RETURN(UNIT_TEST_FAILURE); } + close_f = 1; } ret = wolfsentry_config_json_init(WOLFSENTRY_CONTEXT_ARGS_OUT, flags, &jps); @@ -478,7 +480,7 @@ static __attribute_maybe_unused__ wolfsentry_errcode_t json_feed_file(WOLFSENTRY goto out; for (;;) { - size_t n = fread(buf, 1, sizeof buf, f ? f : stdin); + size_t n = fread(buf, 1, sizeof buf, f); if ((n < sizeof buf) && ferror(f)) { (void)fprintf(stderr,"fread(%s): %s\n",fname, strerror(errno)); ret = WOLFSENTRY_ERROR_ENCODE(UNIT_TEST_FAILURE); @@ -507,7 +509,7 @@ static __attribute_maybe_unused__ wolfsentry_errcode_t json_feed_file(WOLFSENTRY if (WOLFSENTRY_ERROR_CODE_IS(ret, OK)) ret = WOLFSENTRY_ERROR_ENCODE(OK); - if (f) + if (close_f) fclose(f); if ((ret < 0) && verbose) diff --git a/tests/wolfssl-allow-all.json b/tests/wolfssl-allow-all.json new file mode 100644 index 0000000..3f69812 --- /dev/null +++ b/tests/wolfssl-allow-all.json @@ -0,0 +1,6 @@ +{ + "wolfsentry-config-version": 1, + "default-policies": { + "default-policy": "accept" + } +} From 801c787a9b1218e3a4e7f9f48374c21f4a28cb1f Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 9 Oct 2026 20:20:38 -0700 Subject: [PATCH 2/8] Publish CI image and enforce C89 builds --- .github/workflows/examples.yml | 10 +-- .github/workflows/options-matrix.yml | 6 +- .github/workflows/publish-ci-image.yml | 83 ++++++++++++++++++++++++ Makefile.analyzers | 2 +- examples/Linux-wolfIP/Makefile | 6 +- examples/Linux-wolfIP/main.c | 5 +- examples/STM32-LWIP-WOLFSSL/Inc/echo.h | 2 +- examples/STM32-LWIP-WOLFSSL/Inc/sentry.h | 2 +- examples/STM32-LWIP-WOLFSSL/Src/echo.c | 16 +++-- examples/STM32-LWIP-WOLFSSL/Src/sentry.c | 19 +++--- examples/STM32-LWIP/Inc/echo.h | 2 +- examples/STM32-LWIP/Inc/ping.h | 2 +- examples/STM32-LWIP/Inc/sentry.h | 2 +- examples/STM32-LWIP/Src/echo.c | 7 +- examples/STM32-LWIP/Src/ping.c | 5 +- examples/STM32-LWIP/Src/sentry.c | 19 +++--- src/wolfip/packet_filter_glue.c | 32 ++++----- tests/stm32-compat/user_settings.h | 1 + 18 files changed, 156 insertions(+), 65 deletions(-) create mode 100644 .github/workflows/publish-ci-image.yml diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index e8c1fb1..da7f049 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -214,7 +214,9 @@ jobs: /tmp/wolfsentry-host-build/wolfsentry/wolfsentry_options.h common_flags=( - -std=gnu99 + -DWOLFSENTRY_C89 + -Wno-variadic-macros + -Wno-overlength-strings -fsyntax-only -Wall -Wextra @@ -231,13 +233,13 @@ jobs: -I. ) - gcc "${common_flags[@]}" \ + gcc -std=c89 -pedantic "${common_flags[@]}" \ -Iexamples/STM32-LWIP/Inc \ examples/STM32-LWIP/Src/sentry.c \ examples/STM32-LWIP/Src/echo.c \ examples/STM32-LWIP/Src/ping.c - gcc "${common_flags[@]}" \ + gcc -std=c99 "${common_flags[@]}" \ -DWOLFSSL_USER_SETTINGS \ -Itests/stm32-compat \ -Iexamples/STM32-LWIP-WOLFSSL/Inc \ @@ -248,5 +250,5 @@ jobs: make -j2 \ FREERTOS_TOP=/workspace/freertos \ LWIP_TOP=/workspace/lwip \ - freertos-arm32-thumb-build-test + freertos-arm32-c89-build-test ' diff --git a/.github/workflows/options-matrix.yml b/.github/workflows/options-matrix.yml index c712bb2..bfa10e6 100644 --- a/.github/workflows/options-matrix.yml +++ b/.github/workflows/options-matrix.yml @@ -37,10 +37,8 @@ jobs: include: - name: Dynamic library target: dynamic-build-test - - name: C99 - target: c99-test - - name: No alloca - target: no-alloca-test + - name: C89 + target: c89-test - name: Single-threaded target: singlethreaded-test - name: No JSON diff --git a/.github/workflows/publish-ci-image.yml b/.github/workflows/publish-ci-image.yml new file mode 100644 index 0000000..1089d9a --- /dev/null +++ b/.github/workflows/publish-ci-image.yml @@ -0,0 +1,83 @@ +name: Publish CI image + +on: + push: + branches: [ '**' ] + paths: + - '.github/docker/wolfsentry-ci/**' + - '.github/workflows/publish-ci-image.yml' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: publish-ci-image-${{ github.ref }} + cancel-in-progress: false + +jobs: + publish: + name: Publish CI image + if: github.repository == 'wolfSSL/wolfsentry' + runs-on: ubuntu-latest + timeout-minutes: 45 + permissions: + contents: read + packages: write + outputs: + digest: ${{ steps.build.outputs.digest }} + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push image + id: build + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + with: + context: . + file: .github/docker/wolfsentry-ci/Dockerfile + platforms: linux/amd64 + pull: true + push: true + tags: | + ghcr.io/wolfssl/wolfsentry-ci:sha-${{ github.sha }} + ghcr.io/wolfssl/wolfsentry-ci:${{ github.ref == 'refs/heads/master' && 'latest' || 'edge' }} + labels: | + org.opencontainers.image.source=https://github.com/${{ github.repository }} + org.opencontainers.image.revision=${{ github.sha }} + cache-from: type=registry,ref=ghcr.io/wolfssl/wolfsentry-ci:latest + cache-to: type=inline + + smoke: + name: Test published CI image + needs: publish + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + packages: read + container: + image: ghcr.io/wolfssl/wolfsentry-ci@${{ needs.publish.outputs.digest }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + defaults: + run: + shell: bash -e {0} + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - name: Trust workspace + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Exercise image + run: | + gcc --version + clang --version + arm-none-eabi-gcc --version + scan-build --version + shellcheck --version + /usr/bin/python3 -c 'import dbus, gi' + make -j2 test diff --git a/Makefile.analyzers b/Makefile.analyzers index edc57fb..fb91cb1 100644 --- a/Makefile.analyzers +++ b/Makefile.analyzers @@ -618,7 +618,7 @@ freertos-arm32-c89-build-test: @[ -d $(LWIP_TOP_FOR_TEST)/. ] || ( echo '$@: $(LWIP_TOP_FOR_TEST) not found.' >&2; exit 1) @command -v arm-none-eabi-gcc >/dev/null || ( echo '$@: arm-none-eabi-gcc not found.' >&2; exit 1) @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-freertos-arm32-c89-test-builds" HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP FREERTOS_TOP=$(FREERTOS_TOP_FOR_TEST) LWIP_TOP=$(LWIP_TOP_FOR_TEST) EXTRA_CFLAGS+='-mthumb -mcpu=cortex-m7 -DWOLFSENTRY_DEBUG_LWIP' clean - @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-freertos-arm32-c89-test-builds" HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP FREERTOS_TOP=$(FREERTOS_TOP_FOR_TEST) LWIP_TOP=$(LWIP_TOP_FOR_TEST) EXTRA_CFLAGS+='-DWOLFSENTRY_DEBUG_LWIP -std=c89 -pedantic -DWOLFSENTRY_C89 -DWOLFSENTRY_USE_NONPOSIX_SEMAPHORES -Wno-variadic-macros -Wno-overlength-strings -mthumb -mcpu=cortex-m7 -DWOLFSENTRY_DEBUG_LWIP -Wno-attributes' + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-freertos-arm32-c89-test-builds" HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP FREERTOS_TOP=$(FREERTOS_TOP_FOR_TEST) LWIP_TOP=$(LWIP_TOP_FOR_TEST) EXTRA_CFLAGS+='-std=c89 -pedantic -DWOLFSENTRY_C89 -D_ISOC99_SOURCE -DWOLFSENTRY_USE_NONPOSIX_SEMAPHORES -Wno-variadic-macros -Wno-overlength-strings -mthumb -mcpu=cortex-m7 -DWOLFSENTRY_DEBUG_LWIP -Wno-attributes' @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-freertos-arm32-c89-test-builds" HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP FREERTOS_TOP=$(FREERTOS_TOP_FOR_TEST) LWIP_TOP=$(LWIP_TOP_FOR_TEST) EXTRA_CFLAGS+='-mthumb -mcpu=cortex-m7 -DWOLFSENTRY_DEBUG_LWIP' clean @echo "passed: freertos-arm32-c89-build test." diff --git a/examples/Linux-wolfIP/Makefile b/examples/Linux-wolfIP/Makefile index 7ecec7d..9940a23 100644 --- a/examples/Linux-wolfIP/Makefile +++ b/examples/Linux-wolfIP/Makefile @@ -3,12 +3,13 @@ AR ?= ar WOLFSENTRY_PATH ?= ../../../wolfsentry WOLFSENTRY_LIB ?= $(WOLFSENTRY_PATH)/libwolfsentry.a +WOLFSENTRY_CFLAGS ?= -std=c89 -pedantic -DWOLFSENTRY_C89 -Wno-variadic-macros -Wno-overlength-strings WOLFIP_PATH ?= ../../../wolfip CFLAGS ?= -O2 -g CFLAGS += -D_GNU_SOURCE CFLAGS += -DCONFIG_IPFILTER=1 -CFLAGS += -Wall -Wextra -Wpedantic -std=c99 +CFLAGS += -Wall -Wextra -Wpedantic -std=c99 -DWOLFSENTRY_C89 CFLAGS += -I. CFLAGS += -I./wolfip CFLAGS += -I$(WOLFSENTRY_PATH)/wolfsentry @@ -57,7 +58,8 @@ $(WOLFSENTRY_LIB): $(MAKE) -C $(WOLFSENTRY_PATH) libwolfsentry.a \ WOLFIP=1 \ WOLFIP_TOP=$(abspath $(WOLFIP_PATH)) \ - WOLFIP_CONFIG_DIR=$(abspath $(CURDIR)/wolfip) + WOLFIP_CONFIG_DIR=$(abspath $(CURDIR)/wolfip) \ + EXTRA_CFLAGS+='$(WOLFSENTRY_CFLAGS)' clean: $(RM) $(APP_OBJS) $(TAP_OBJ) $(WOLFIP_OBJ) $(WOLFIP_LIB) $(TARGET) diff --git a/examples/Linux-wolfIP/main.c b/examples/Linux-wolfIP/main.c index bce9587..553a378 100644 --- a/examples/Linux-wolfIP/main.c +++ b/examples/Linux-wolfIP/main.c @@ -110,8 +110,7 @@ static void log_event(const struct wolfIP_filter_event *event, const char *tag) } static wolfsentry_errcode_t icmp_mod7_action( - struct wolfsentry_context *wolfsentry, - struct wolfsentry_thread_context *thread, + WOLFSENTRY_CONTEXT_ARGS_IN, const struct wolfsentry_action *action, void *handler_arg, void *caller_arg, @@ -125,7 +124,7 @@ static wolfsentry_errcode_t icmp_mod7_action( struct icmp_filter_state *state = (struct icmp_filter_state *)handler_arg; const struct wolfIP_filter_event *event = (const struct wolfIP_filter_event *)caller_arg; (void)wolfsentry; - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; (void)action; (void)trigger_event; (void)action_type; diff --git a/examples/STM32-LWIP-WOLFSSL/Inc/echo.h b/examples/STM32-LWIP-WOLFSSL/Inc/echo.h index b616146..5bc67dc 100644 --- a/examples/STM32-LWIP-WOLFSSL/Inc/echo.h +++ b/examples/STM32-LWIP-WOLFSSL/Inc/echo.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __ECHO_H__ #define __ECHO_H__ diff --git a/examples/STM32-LWIP-WOLFSSL/Inc/sentry.h b/examples/STM32-LWIP-WOLFSSL/Inc/sentry.h index e78586a..d963300 100644 --- a/examples/STM32-LWIP-WOLFSSL/Inc/sentry.h +++ b/examples/STM32-LWIP-WOLFSSL/Inc/sentry.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __SENTRY_H__ #define __SENTRY_H__ diff --git a/examples/STM32-LWIP-WOLFSSL/Src/echo.c b/examples/STM32-LWIP-WOLFSSL/Src/echo.c index 2872cec..ac18bfb 100644 --- a/examples/STM32-LWIP-WOLFSSL/Src/echo.c +++ b/examples/STM32-LWIP-WOLFSSL/Src/echo.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "cmsis_os.h" #include "lwip/debug.h" @@ -56,7 +56,8 @@ void echo_msgclose(struct tcp_pcb *pcb) printf("Closing connection from: %s\n", ipaddr_ntoa(&(pcb->remote_ip))); /* Tell sentry_action() that this is a disconnect event which decrements * the connection count */ - //sentry_action(&pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port, SENTRY_ACTION_DISCONNECT); + /* sentry_action(&pcb->local_ip, &pcb->remote_ip, pcb->local_port, + * pcb->remote_port, SENTRY_ACTION_DISCONNECT); */ /* Remove all the callbacks and shutdown the connection */ tcp_arg(pcb, NULL); @@ -76,6 +77,7 @@ static void echo_msgerr(void *arg, err_t err) static err_t echo_msgaccept(void *arg, struct tcp_pcb *pcb, err_t err) { WOLFSSL *ssl; + struct thread_data tdata; /* Accepted new connection */ LWIP_PLATFORM_DIAG(("echo_msgaccept called\n")); @@ -94,9 +96,8 @@ static err_t echo_msgaccept(void *arg, struct tcp_pcb *pcb, err_t err) */ /* Set an arbitrary pointer for callbacks. We don't use this right now */ - //tcp_arg(pcb, esm); + /* tcp_arg(pcb, esm); */ - struct thread_data tdata; tdata.pcb = pcb; /* Create a WOLFSSL object */ if ((ssl = wolfSSL_new(wolf_ctx)) == NULL) { @@ -149,11 +150,12 @@ int echo_ssl(void) void echo_init(void) { struct tcp_pcb *pcb; + int r; /* Create lwIP TCP instance */ pcb = tcp_new(); LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: pcb: %p\n", (void *)pcb)); /* Bind port 11111 */ - int r = tcp_bind(pcb, IP_ADDR_ANY, 8080); + r = tcp_bind(pcb, IP_ADDR_ANY, 8080); LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: tcp_bind: %d\n", r)); /* Enable listening */ tcp_arg(pcb, NULL); @@ -177,8 +179,8 @@ int sentry_tcp_inpkt(struct tcp_pcb *pcb, struct tcp_hdr *hdr, uint16_t optlen, * yet, that happens immediately after this callback, so we get these * details from other sources. The same sources that are about to fill * in the details into the sruct */ - //fprintf(stderr, "Incomming connection from: %s\n", - // ipaddr_ntoa(ip_current_src_addr())); + /* fprintf(stderr, "Incomming connection from: %s\n", + * ipaddr_ntoa(ip_current_src_addr())); */ if (sentry_action(ip_current_dest_addr(), ip_current_src_addr(), pcb->local_port, hdr->src , SENTRY_ACTION_CONNECT) != 0) diff --git a/examples/STM32-LWIP-WOLFSSL/Src/sentry.c b/examples/STM32-LWIP-WOLFSSL/Src/sentry.c index cceb7b1..aad1cb4 100644 --- a/examples/STM32-LWIP-WOLFSSL/Src/sentry.c +++ b/examples/STM32-LWIP-WOLFSSL/Src/sentry.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ #include #include @@ -136,8 +136,12 @@ int sentry_init(void) { wolfsentry_errcode_t ret; wolfsentry_ent_id_t id; + struct wolfsentry_eventconfig config = { 0 }; + char err_buf[512]; + struct wolfsentry_json_process_state *jps; - struct wolfsentry_eventconfig config = { .route_private_data_size = 32, .route_private_data_alignment = 16 }; + config.route_private_data_size = 32; + config.route_private_data_alignment = 16; ret = wolfsentry_init(wolfsentry_build_settings, WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(NULL /* hpi */, NULL /* thread */), &config, &wolfsentry); @@ -202,9 +206,6 @@ int sentry_init(void) &id); - char err_buf[512]; - struct wolfsentry_json_process_state *jps; - /* Initalize the wolfSentry JSON parser */ if ((ret = wolfsentry_config_json_init( WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), @@ -269,7 +270,7 @@ int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, uint16_t local_port remote.sa.sa_port = remote_port; /* Essentially a prefix size, wolfSentry uses the lesser of this and the * rule in JSON as to how much of the IP address to compare */ - remote.sa.addr_len = 32; // prefix size + remote.sa.addr_len = 32; /* prefix size */ remote.sa.interface = 0; memcpy(remote.sa.addr, &remoteip, 4); @@ -330,7 +331,7 @@ int sentry_action_ping(const ip_addr_t *addr, u8_t type) ret = wolfsentry_route_event_dispatch( WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), &remote.sa, - &remote.sa, // Reuse for now + &remote.sa, /* Reuse for now */ WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, "call-in-from-echo", strlen("call-in-from-echo"), @@ -365,13 +366,13 @@ int sentry_action_mac(struct eth_addr *addr) remote.sa.sa_family = WOLFSENTRY_AF_LINK; remote.sa.addr_len = 48; remote.sa.interface = 0; - // MAC addresses are 6 bytes (48 bits) + /* MAC addresses are 6 bytes (48 bits) */ memcpy(remote.sa.addr, &addr->addr, 6); ret = wolfsentry_route_event_dispatch( WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), &remote.sa, - &remote.sa, // Reuse for now + &remote.sa, /* Reuse for now */ WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, "call-in-from-echo", strlen("call-in-from-echo"), diff --git a/examples/STM32-LWIP/Inc/echo.h b/examples/STM32-LWIP/Inc/echo.h index 6601a92..49010b1 100644 --- a/examples/STM32-LWIP/Inc/echo.h +++ b/examples/STM32-LWIP/Inc/echo.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __ECHO_H__ #define __ECHO_H__ diff --git a/examples/STM32-LWIP/Inc/ping.h b/examples/STM32-LWIP/Inc/ping.h index 66e3d3d..29ef3d8 100644 --- a/examples/STM32-LWIP/Inc/ping.h +++ b/examples/STM32-LWIP/Inc/ping.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __PING_H__ #define __PING_H__ diff --git a/examples/STM32-LWIP/Inc/sentry.h b/examples/STM32-LWIP/Inc/sentry.h index e78586a..d963300 100644 --- a/examples/STM32-LWIP/Inc/sentry.h +++ b/examples/STM32-LWIP/Inc/sentry.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef __SENTRY_H__ #define __SENTRY_H__ diff --git a/examples/STM32-LWIP/Src/echo.c b/examples/STM32-LWIP/Src/echo.c index 5a07f4f..aa84568 100644 --- a/examples/STM32-LWIP/Src/echo.c +++ b/examples/STM32-LWIP/Src/echo.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "lwip/debug.h" @@ -80,7 +80,7 @@ static err_t echo_msgaccept(void *arg, struct tcp_pcb *pcb, err_t err) */ /* Set an arbitrary pointer for callbacks. We don't use this right now */ - //tcp_arg(pcb, esm); + /* tcp_arg(pcb, esm); */ /* Set TCP receive packet callback. */ tcp_recv(pcb, echo_msgrecv); @@ -95,12 +95,13 @@ static err_t echo_msgaccept(void *arg, struct tcp_pcb *pcb, err_t err) int echo_init(void) { struct tcp_pcb *pcb; + int r; /* Create lwIP TCP instance */ pcb = tcp_new(); LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: pcb: %p\n", (void *)pcb)); /* Bind port 11111 */ - int r = tcp_bind(pcb, IP_ADDR_ANY, 11111); + r = tcp_bind(pcb, IP_ADDR_ANY, 11111); LWIP_DEBUGF(ECHO_DEBUG, ("echo_init: tcp_bind: %d\n", r)); /* Enable listening */ pcb = tcp_listen(pcb); diff --git a/examples/STM32-LWIP/Src/ping.c b/examples/STM32-LWIP/Src/ping.c index 95a3c4a..3f76acc 100644 --- a/examples/STM32-LWIP/Src/ping.c +++ b/examples/STM32-LWIP/Src/ping.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "lwip/debug.h" @@ -18,7 +18,8 @@ static u8_t ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_a /* If the message is long enough, get the header */ if (p->tot_len >= (PBUF_IP_HLEN + sizeof(struct icmp_echo_hdr))) { - iecho = (struct icmp_echo_hdr *)(p->payload + PBUF_IP_HLEN); + iecho = (struct icmp_echo_hdr *)((unsigned char *)p->payload + + PBUF_IP_HLEN); /* Extract the ICMP message type (8 is a PING received), wolfSentry * will accept or reject the ICMP message */ if (sentry_action_ping(addr, iecho->type) != 0) diff --git a/examples/STM32-LWIP/Src/sentry.c b/examples/STM32-LWIP/Src/sentry.c index 8c7c2c9..68d7c1f 100644 --- a/examples/STM32-LWIP/Src/sentry.c +++ b/examples/STM32-LWIP/Src/sentry.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ #include #include @@ -136,8 +136,12 @@ int sentry_init(void) { wolfsentry_errcode_t ret; wolfsentry_ent_id_t id; + struct wolfsentry_eventconfig config = { 0 }; + char err_buf[512]; + struct wolfsentry_json_process_state *jps; - struct wolfsentry_eventconfig config = { .route_private_data_size = 32, .route_private_data_alignment = 16 }; + config.route_private_data_size = 32; + config.route_private_data_alignment = 16; ret = wolfsentry_init(wolfsentry_build_settings, WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(NULL /* hpi */, NULL /* thread */), &config, &wolfsentry); @@ -203,9 +207,6 @@ int sentry_init(void) &id); - char err_buf[512]; - struct wolfsentry_json_process_state *jps; - /* Initalize the wolfSentry JSON parser */ if ((ret = wolfsentry_config_json_init( WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), @@ -275,7 +276,7 @@ int sentry_action(ip_addr_t *local_ip, ip_addr_t *remote_ip, uint16_t local_port remote.sa.sa_port = remote_port; /* Essentially a prefix size, wolfSentry uses the lesser of this and the * rule in JSON as to how much of the IP address to compare */ - remote.sa.addr_len = 32; // prefix size + remote.sa.addr_len = 32; /* prefix size */ remote.sa.interface = 0; memcpy(remote.sa.addr, &remoteip, 4); @@ -336,7 +337,7 @@ int sentry_action_ping(const ip_addr_t *addr, u8_t type) ret = wolfsentry_route_event_dispatch( WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), &remote.sa, - &remote.sa, // Reuse for now + &remote.sa, /* Reuse for now */ WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, "call-in-from-echo", strlen("call-in-from-echo"), @@ -371,13 +372,13 @@ int sentry_action_mac(struct eth_addr *addr) remote.sa.sa_family = WOLFSENTRY_AF_LINK; remote.sa.addr_len = 48; remote.sa.interface = 0; - // MAC addresses are 6 bytes (48 bits) + /* MAC addresses are 6 bytes (48 bits) */ memcpy(remote.sa.addr, &addr->addr, 6); ret = wolfsentry_route_event_dispatch( WOLFSENTRY_CONTEXT_ARGS_OUT_EX4(wolfsentry, NULL), &remote.sa, - &remote.sa, // Reuse for now + &remote.sa, /* Reuse for now */ WOLFSENTRY_ROUTE_FLAG_DIRECTION_IN, "call-in-from-echo", strlen("call-in-from-echo"), diff --git a/src/wolfip/packet_filter_glue.c b/src/wolfip/packet_filter_glue.c index 2dcaec6..d3411ab 100644 --- a/src/wolfip/packet_filter_glue.c +++ b/src/wolfip/packet_filter_glue.c @@ -571,7 +571,7 @@ static wolfsentry_errcode_t wolfip_apply_masks(WOLFSENTRY_CONTEXT_ARGS_IN) WOLFSENTRY_API_VOID wolfsentry_cleanup_wolfip_filter_callbacks(WOLFSENTRY_CONTEXT_ARGS_IN, void *cleanup_arg) { (void)wolfsentry; - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; (void)cleanup_arg; wolfip_mask_eth = wolfip_mask_ip = wolfip_mask_icmp = wolfip_mask_tcp = wolfip_mask_udp = 0; wolfip_cleanup_registered = 0; @@ -591,7 +591,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_ethernet_ca wolfsentry_errcode_t ret; WOLFSENTRY_MUTEX_OR_RETURN(); - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; wolfip_mask_eth = ethernet_mask; ret = wolfip_apply_masks(WOLFSENTRY_CONTEXT_ARGS_OUT); WOLFSENTRY_ERROR_UNLOCK_AND_RERETURN(ret); @@ -604,7 +604,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_ip4_callbac wolfsentry_errcode_t ret; WOLFSENTRY_MUTEX_OR_RETURN(); - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; wolfip_mask_ip = ip_mask; ret = wolfip_apply_masks(WOLFSENTRY_CONTEXT_ARGS_OUT); WOLFSENTRY_ERROR_UNLOCK_AND_RERETURN(ret); @@ -617,7 +617,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_icmp_callba wolfsentry_errcode_t ret; WOLFSENTRY_MUTEX_OR_RETURN(); - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; wolfip_mask_icmp = icmp_mask; ret = wolfip_apply_masks(WOLFSENTRY_CONTEXT_ARGS_OUT); WOLFSENTRY_ERROR_UNLOCK_AND_RERETURN(ret); @@ -630,7 +630,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_tcp_callbac wolfsentry_errcode_t ret; WOLFSENTRY_MUTEX_OR_RETURN(); - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; if (tcp_mask & (WOLFIP_FILT_MASK(WOLFIP_FILT_ACCEPTING) | WOLFIP_FILT_MASK(WOLFIP_FILT_CLOSED) | WOLFIP_FILT_MASK(WOLFIP_FILT_REMOTE_RESET))) @@ -649,7 +649,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_udp_callbac wolfsentry_errcode_t ret; WOLFSENTRY_MUTEX_OR_RETURN(); - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; wolfip_mask_udp = udp_mask; ret = wolfip_apply_masks(WOLFSENTRY_CONTEXT_ARGS_OUT); WOLFSENTRY_ERROR_UNLOCK_AND_RERETURN(ret); @@ -666,7 +666,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_callbacks( wolfsentry_errcode_t ret; WOLFSENTRY_MUTEX_OR_RETURN(); - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; wolfip_mask_eth = ethernet_mask; wolfip_mask_ip = ip_mask; wolfip_mask_icmp = icmp_mask; @@ -680,7 +680,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_callbacks( WOLFSENTRY_API_VOID wolfsentry_cleanup_wolfip_filter_callbacks(WOLFSENTRY_CONTEXT_ARGS_IN, void *cleanup_arg) { - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; (void)cleanup_arg; (void)wolfsentry; } @@ -689,7 +689,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_ethernet_ca WOLFSENTRY_CONTEXT_ARGS_IN, uint32_t ethernet_mask) { - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; (void)wolfsentry; if (ethernet_mask) WOLFSENTRY_ERROR_RETURN(IMPLEMENTATION_MISSING); @@ -700,7 +700,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_ip4_callbac WOLFSENTRY_CONTEXT_ARGS_IN, uint32_t ip_mask) { - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; (void)wolfsentry; if (ip_mask) WOLFSENTRY_ERROR_RETURN(IMPLEMENTATION_MISSING); @@ -711,7 +711,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_icmp_callba WOLFSENTRY_CONTEXT_ARGS_IN, uint32_t icmp_mask) { - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; (void)wolfsentry; if (icmp_mask) WOLFSENTRY_ERROR_RETURN(IMPLEMENTATION_MISSING); @@ -722,7 +722,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_tcp_callbac WOLFSENTRY_CONTEXT_ARGS_IN, uint32_t tcp_mask) { - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; (void)wolfsentry; if (tcp_mask) WOLFSENTRY_ERROR_RETURN(IMPLEMENTATION_MISSING); @@ -733,7 +733,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_udp_callbac WOLFSENTRY_CONTEXT_ARGS_IN, uint32_t udp_mask) { - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; (void)wolfsentry; if (udp_mask) WOLFSENTRY_ERROR_RETURN(IMPLEMENTATION_MISSING); @@ -748,7 +748,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_callbacks( uint32_t tcp_mask, uint32_t udp_mask) { - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; (void)wolfsentry; if (ethernet_mask || ip_mask || icmp_mask || tcp_mask || udp_mask) WOLFSENTRY_ERROR_RETURN(IMPLEMENTATION_MISSING); @@ -761,7 +761,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_ip6_callbac WOLFSENTRY_CONTEXT_ARGS_IN, uint32_t ip_mask) { - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; (void)wolfsentry; if (ip_mask) WOLFSENTRY_ERROR_RETURN(IMPLEMENTATION_MISSING); @@ -772,7 +772,7 @@ WOLFSENTRY_API wolfsentry_errcode_t wolfsentry_install_wolfip_filter_icmp6_callb WOLFSENTRY_CONTEXT_ARGS_IN, uint32_t icmp_mask) { - (void)thread; + WOLFSENTRY_CONTEXT_ARGS_THREAD_NOT_USED; (void)wolfsentry; if (icmp_mask) WOLFSENTRY_ERROR_RETURN(IMPLEMENTATION_MISSING); diff --git a/tests/stm32-compat/user_settings.h b/tests/stm32-compat/user_settings.h index fcba1da..2f68113 100644 --- a/tests/stm32-compat/user_settings.h +++ b/tests/stm32-compat/user_settings.h @@ -7,6 +7,7 @@ #define WOLFSSL_TLS13 #define WOLFSSL_CMSIS_RTOS #define SINGLE_THREADED +#define NO_FILESYSTEM #define NO_WRITEV #define WOLFSSL_NO_SOCK #define ECC_TIMING_RESISTANT From b5015406495fa43d21b3653a8ecb63e0e43b64b7 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 9 Oct 2026 20:24:23 -0700 Subject: [PATCH 3/8] Fix CI image smoke check --- .github/workflows/publish-ci-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-ci-image.yml b/.github/workflows/publish-ci-image.yml index 1089d9a..1d01a20 100644 --- a/.github/workflows/publish-ci-image.yml +++ b/.github/workflows/publish-ci-image.yml @@ -77,7 +77,7 @@ jobs: gcc --version clang --version arm-none-eabi-gcc --version - scan-build --version + scan-build --help > /dev/null shellcheck --version /usr/bin/python3 -c 'import dbus, gi' make -j2 test From 70b4b131348156272fc4b410cd0a52ef7ac1dad2 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 9 Oct 2026 20:28:01 -0700 Subject: [PATCH 4/8] Align CI image smoke test with toolchain --- .github/workflows/publish-ci-image.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/publish-ci-image.yml b/.github/workflows/publish-ci-image.yml index 1d01a20..0ea0986 100644 --- a/.github/workflows/publish-ci-image.yml +++ b/.github/workflows/publish-ci-image.yml @@ -78,6 +78,5 @@ jobs: clang --version arm-none-eabi-gcc --version scan-build --help > /dev/null - shellcheck --version /usr/bin/python3 -c 'import dbus, gi' make -j2 test From 01bf1e90599130ce398adcda0994de6b9e364f65 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 9 Oct 2026 20:38:27 -0700 Subject: [PATCH 5/8] Fix CI runner compatibility --- .github/workflows/coverage.yml | 2 +- .github/workflows/examples.yml | 12 +++++++----- .github/workflows/macos-check.yml | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index dd93824..4038582 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -45,7 +45,7 @@ jobs: '*/src/json/centijson_sax.c' --ignore-errors unused \ --output-file coverage.info lcov --summary coverage.info - lcov --summary --fail-under-lines 65 coverage.info + lcov --fail-under-lines 65 --summary coverage.info - name: Upload coverage data uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index da7f049..108a987 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -183,11 +183,13 @@ jobs: repository: lwip-tcpip/lwip ref: STABLE-2_1_3_RELEASE path: lwip - - uses: actions/checkout@v4 - with: - repository: lwip-tcpip/lwip-contrib - ref: STABLE-2_1_0_RELEASE - path: lwip/contrib + - name: Check out lwIP contrib + run: | + git clone --branch STABLE-2_1_0_RELEASE --depth 1 \ + https://git.savannah.nongnu.org/git/lwip/lwip-contrib.git \ + lwip/contrib + test "$(git -C lwip/contrib rev-parse HEAD)" = \ + 35b011d4cf4c4b480f8859c456587a884ec9d287 - uses: actions/checkout@v4 with: repository: FreeRTOS/FreeRTOS-Kernel diff --git a/.github/workflows/macos-check.yml b/.github/workflows/macos-check.yml index 60d9785..2933582 100644 --- a/.github/workflows/macos-check.yml +++ b/.github/workflows/macos-check.yml @@ -28,4 +28,4 @@ jobs: steps: - uses: actions/checkout@v4 - name: Build, sanitize, and run primary configuration suite - run: make -j2 check-macosx + run: make -j2 CLANG_PATH=/usr/bin check-macosx From 144040dab7e83faf6060edcea0c796878dc01541 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 9 Oct 2026 20:43:56 -0700 Subject: [PATCH 6/8] Keep historical wolfSSL probe non-blocking --- .github/workflows/wolfssl-versions.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wolfssl-versions.yml b/.github/workflows/wolfssl-versions.yml index a23b63f..3d9f878 100644 --- a/.github/workflows/wolfssl-versions.yml +++ b/.github/workflows/wolfssl-versions.yml @@ -61,7 +61,6 @@ jobs: integration: name: ${{ matrix.name }} (${{ matrix.ref }}) needs: discover - continue-on-error: ${{ matrix.allow_failure }} runs-on: ubuntu-latest container: image: ghcr.io/wolfssl/wolfcose-ci@sha256:c073c7afb4cd3f296b8c1a305db2f718530b7a8aca899482629aee3a5cf8bfbc @@ -79,6 +78,8 @@ jobs: make -j2 test make INSTALL_DIR="$HOME/wolfsentry-install" install - name: Build wolfSSL with wolfSentry hooks + id: wolfssl_build + continue-on-error: ${{ matrix.allow_failure }} env: WOLFSSL_REF: ${{ matrix.ref }} run: | @@ -91,6 +92,9 @@ jobs: --enable-opensslextra --disable-shared make -j2 examples/server/server examples/client/client - name: Run wolfSSL client/server with wolfSentry filtering + id: wolfssl_runtime + if: steps.wolfssl_build.outcome == 'success' + continue-on-error: ${{ matrix.allow_failure }} run: | cd "$HOME/wolfssl" runtime_dir=$(mktemp -d) @@ -121,3 +125,11 @@ jobs: cat "$runtime_dir/server.log" grep -F 'decision=1 (ACCEPT)' "$runtime_dir/client.log" grep -F 'decision=1 (ACCEPT)' "$runtime_dir/server.log" + - name: Report historical incompatibility + if: >- + matrix.allow_failure && + (steps.wolfssl_build.outcome == 'failure' || + steps.wolfssl_runtime.outcome == 'failure') + run: >- + echo "::warning::${{ matrix.ref }} is an informational compatibility + probe and is not the minimum supported wolfSSL version" From d676ac1a25cf73bce0462b8a5f981f11e141e087 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Mon, 12 Oct 2026 10:13:00 -0700 Subject: [PATCH 7/8] Run STM32 examples on M33MU in CI --- .github/workflows/examples.yml | 84 +++---- Makefile | 6 +- examples/STM32-LWIP-WOLFSSL/Src/sentry.c | 4 +- examples/STM32-LWIP/Src/sentry.c | 4 +- src/lwip/packet_filter_glue.c | 20 +- tests/stm32h563-m33mu/Makefile | 194 ++++++++++++++++ tests/stm32h563-m33mu/README.md | 17 ++ .../stm32h563-m33mu/include/FreeRTOSConfig.h | 58 +++++ tests/stm32h563-m33mu/include/arch/cc.h | 27 +++ tests/stm32h563-m33mu/include/cmsis_os.h | 20 ++ tests/stm32h563-m33mu/include/lwipopts.h | 59 +++++ tests/stm32h563-m33mu/include/user_settings.h | 38 ++++ tests/stm32h563-m33mu/linker.ld | 64 ++++++ tests/stm32h563-m33mu/main.c | 207 ++++++++++++++++++ tests/stm32h563-m33mu/run.sh | 33 +++ tests/stm32h563-m33mu/startup.c | 184 ++++++++++++++++ 16 files changed, 947 insertions(+), 72 deletions(-) create mode 100644 tests/stm32h563-m33mu/Makefile create mode 100644 tests/stm32h563-m33mu/README.md create mode 100644 tests/stm32h563-m33mu/include/FreeRTOSConfig.h create mode 100644 tests/stm32h563-m33mu/include/arch/cc.h create mode 100644 tests/stm32h563-m33mu/include/cmsis_os.h create mode 100644 tests/stm32h563-m33mu/include/lwipopts.h create mode 100644 tests/stm32h563-m33mu/include/user_settings.h create mode 100644 tests/stm32h563-m33mu/linker.ld create mode 100644 tests/stm32h563-m33mu/main.c create mode 100755 tests/stm32h563-m33mu/run.sh create mode 100644 tests/stm32h563-m33mu/startup.c diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 108a987..5020f7f 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -165,18 +165,28 @@ jobs: dbus-run-session -- bash tests/run-notification-demo-ci.sh ' - stm32-fragments: - name: STM32 fragments and Cortex-M build + stm32-m33mu: + name: M33MU ${{ matrix.example }} runtime runs-on: ubuntu-latest timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + example: + - stm32-lwip + - stm32-lwip-wolfssl + container: + image: ghcr.io/wolfssl/wolfboot-ci-m33mu@sha256:f6b66c9240ecd94f99400565196f956d1b067059b659a66dbbe83581cc7bf4c7 steps: - uses: actions/checkout@v4 with: path: wolfsentry - uses: actions/checkout@v4 + if: matrix.example == 'stm32-lwip-wolfssl' with: repository: wolfSSL/wolfssl + ref: f99453320ff306fe5bfb10788117f18c9bfeaf6b path: wolfssl - uses: actions/checkout@v4 with: @@ -197,60 +207,18 @@ jobs: path: freertos/FreeRTOS/Source - name: Apply the wolfSentry lwIP packet filter API run: patch --directory lwip --strip 1 < wolfsentry/lwip/LWIP_PACKET_FILTER_API.patch - - name: Build the wolfSentry CI image - run: | - docker build \ - --file wolfsentry/.github/docker/wolfsentry-ci/Dockerfile \ - --tag wolfsentry-ci:local wolfsentry - - name: Compile STM32 fragments and Cortex-M integration + - name: Build ${{ matrix.example }} firmware run: | - docker run --rm \ - --env TMPDIR=/tmp \ - --volume "$GITHUB_WORKSPACE/wolfsentry:/workspace/wolfsentry:ro" \ - --volume "$GITHUB_WORKSPACE/wolfssl:/workspace/wolfssl:ro" \ - --volume "$GITHUB_WORKSPACE/lwip:/workspace/lwip:ro" \ - --volume "$GITHUB_WORKSPACE/freertos:/workspace/freertos:ro" \ - --workdir /workspace/wolfsentry \ - wolfsentry-ci:local bash -euc ' - make BUILD_TOP=/tmp/wolfsentry-host-build \ - /tmp/wolfsentry-host-build/wolfsentry/wolfsentry_options.h - - common_flags=( - -DWOLFSENTRY_C89 - -Wno-variadic-macros - -Wno-overlength-strings - -fsyntax-only - -Wall - -Wextra - -Werror=format - -Werror=implicit-function-declaration - -Werror=incompatible-pointer-types - -Werror=strict-prototypes - -Wno-unused-parameter - -DLWIP_IPV6=0 - -Iports/Linux-lwIP/include - -I/workspace/lwip/contrib/ports/unix/port/include - -I/workspace/lwip/src/include - -I/tmp/wolfsentry-host-build - -I. - ) - - gcc -std=c89 -pedantic "${common_flags[@]}" \ - -Iexamples/STM32-LWIP/Inc \ - examples/STM32-LWIP/Src/sentry.c \ - examples/STM32-LWIP/Src/echo.c \ - examples/STM32-LWIP/Src/ping.c - - gcc -std=c99 "${common_flags[@]}" \ - -DWOLFSSL_USER_SETTINGS \ - -Itests/stm32-compat \ - -Iexamples/STM32-LWIP-WOLFSSL/Inc \ - -I/workspace/wolfssl \ - examples/STM32-LWIP-WOLFSSL/Src/sentry.c \ - examples/STM32-LWIP-WOLFSSL/Src/echo.c - - make -j2 \ - FREERTOS_TOP=/workspace/freertos \ - LWIP_TOP=/workspace/lwip \ - freertos-arm32-c89-build-test - ' + make -C wolfsentry/tests/stm32h563-m33mu -j2 \ + "build/${{ matrix.example }}.bin" \ + FREERTOS_TOP="$GITHUB_WORKSPACE/freertos" \ + LWIP_TOP="$GITHUB_WORKSPACE/lwip" \ + WOLFSSL_TOP="$GITHUB_WORKSPACE/wolfssl" + - name: Boot ${{ matrix.example }} on STM32H563 M33MU + working-directory: wolfsentry/tests/stm32h563-m33mu + env: + EXPECTED_MARKER: >- + ${{ matrix.example == 'stm32-lwip-wolfssl' + && 'PASS: STM32-LWIP-WOLFSSL on FreeRTOS/lwIP under M33MU' + || 'PASS: STM32-LWIP on FreeRTOS/lwIP under M33MU' }} + run: ./run.sh "build/${{ matrix.example }}.bin" "$EXPECTED_MARKER" diff --git a/Makefile b/Makefile index a83b2c0..23c98a4 100644 --- a/Makefile +++ b/Makefile @@ -93,10 +93,11 @@ ifdef RUNTIME ifndef FREERTOS_TOP $(error FREERTOS_TOP not supplied with RUNTIME=$(RUNTIME)) endif + FREERTOS_PORT ?= ARM_CM3 ifndef LWIP LWIP := 1 endif - RUNTIME_CFLAGS += -DFREERTOS -DWOLFSENTRY_NO_GETPROTOBY -DWOLFSENTRY_NO_POSIX_MEMALIGN -ffreestanding -I$(FREERTOS_TOP)/FreeRTOS/Source/include -I$(FREERTOS_TOP)/FreeRTOS/Source/portable/GCC/ARM_CM3 + RUNTIME_CFLAGS += -DFREERTOS -DWOLFSENTRY_NO_GETPROTOBY -DWOLFSENTRY_NO_POSIX_MEMALIGN -ffreestanding -I$(FREERTOS_TOP)/FreeRTOS/Source/include -I$(FREERTOS_TOP)/FreeRTOS/Source/portable/GCC/$(FREERTOS_PORT) else ifeq "$(RUNTIME)" "Linux-lwIP" ifndef LWIP LWIP := 1 @@ -119,7 +120,8 @@ else RUNTIME := $(shell uname -s) endif -RUNTIME_CFLAGS += $(shell [ -d "$(SRC_TOP)/ports/$(RUNTIME)/include/" ] && echo -I$(SRC_TOP)/ports/$(RUNTIME)/include) +RUNTIME_INCLUDE_DIR ?= $(SRC_TOP)/ports/$(RUNTIME)/include +RUNTIME_CFLAGS += $(shell [ -d "$(RUNTIME_INCLUDE_DIR)/" ] && echo -I$(RUNTIME_INCLUDE_DIR)) ifdef LWIP ifndef LWIP_TOP diff --git a/examples/STM32-LWIP-WOLFSSL/Src/sentry.c b/examples/STM32-LWIP-WOLFSSL/Src/sentry.c index aad1cb4..ec26cbd 100644 --- a/examples/STM32-LWIP-WOLFSSL/Src/sentry.c +++ b/examples/STM32-LWIP-WOLFSSL/Src/sentry.c @@ -45,8 +45,8 @@ static const char *wolfsentry_config_data = "{\n" " }\n" " ],\n" " \"default-policies\" : {\n" -" \"default-policy-static\" : \"reject\",\n" -" \"default-event-static\" : \"static-route-parent\"\n" +" \"default-policy\" : \"reject\",\n" +" \"default-event\" : \"static-route-parent\"\n" " },\n" " \"static-routes-insert\" : [\n" "{\n" diff --git a/examples/STM32-LWIP/Src/sentry.c b/examples/STM32-LWIP/Src/sentry.c index 68d7c1f..69b7f6a 100644 --- a/examples/STM32-LWIP/Src/sentry.c +++ b/examples/STM32-LWIP/Src/sentry.c @@ -45,8 +45,8 @@ static const char *wolfsentry_config_data = "{\n" " }\n" " ],\n" " \"default-policies\" : {\n" -" \"default-policy-static\" : \"reject\",\n" -" \"default-event-static\" : \"static-route-parent\"\n" +" \"default-policy\" : \"reject\",\n" +" \"default-event\" : \"static-route-parent\"\n" " },\n" " \"static-routes-insert\" : [\n" "{\n" diff --git a/src/lwip/packet_filter_glue.c b/src/lwip/packet_filter_glue.c index 1311aec..f8d3b60 100644 --- a/src/lwip/packet_filter_glue.c +++ b/src/lwip/packet_filter_glue.c @@ -23,6 +23,10 @@ #include #include #include "lwip/sockets.h" +#include "lwip/prot/ip.h" +#if LWIP_IPV6 +#include "lwip/prot/ip6.h" +#endif #define WOLFSENTRY_SOURCE_ID WOLFSENTRY_SOURCE_ID_LWIP_PACKET_FILTER_GLUE_C @@ -625,10 +629,10 @@ static err_t tcp_filter_with_wolfsentry( memset(&local.local.addr, 0, sizeof *ip_2_ip4(laddr)); } - remote.remote.sa_proto = IPPROTO_TCP; + remote.remote.sa_proto = IP_PROTO_TCP; remote.remote.sa_port = rport; - local.local.sa_proto = IPPROTO_TCP; + local.local.sa_proto = IP_PROTO_TCP; local.local.sa_port = lport; if (event->netif) @@ -814,10 +818,10 @@ static err_t udp_filter_with_wolfsentry( memset(&local.local.addr, 0, sizeof *ip_2_ip4(laddr)); } - remote.remote.sa_proto = IPPROTO_UDP; + remote.remote.sa_proto = IP_PROTO_UDP; remote.remote.sa_port = rport; - local.local.sa_proto = IPPROTO_UDP; + local.local.sa_proto = IP_PROTO_UDP; local.local.sa_port = lport; if (event->netif) @@ -962,10 +966,10 @@ static err_t icmp4_filter_with_wolfsentry( else memset(&local.local.addr, 0, sizeof *laddr); - remote.remote.sa_proto = IPPROTO_ICMP; + remote.remote.sa_proto = IP_PROTO_ICMP; remote.remote.sa_port = 0; - local.local.sa_proto = IPPROTO_ICMP; + local.local.sa_proto = IP_PROTO_ICMP; local.local.sa_port = icmp4_type; if (event->netif) @@ -1098,10 +1102,10 @@ static err_t icmp6_filter_with_wolfsentry( else memset(&local.local.addr, 0, sizeof *laddr); - remote.remote.sa_proto = IPPROTO_ICMPV6; + remote.remote.sa_proto = IP6_NEXTH_ICMP6; remote.remote.sa_port = 0; - local.local.sa_proto = IPPROTO_ICMPV6; + local.local.sa_proto = IP6_NEXTH_ICMP6; local.local.sa_port = icmp6_type; if (event->netif) diff --git a/tests/stm32h563-m33mu/Makefile b/tests/stm32h563-m33mu/Makefile new file mode 100644 index 0000000..e3eb1d8 --- /dev/null +++ b/tests/stm32h563-m33mu/Makefile @@ -0,0 +1,194 @@ +TOOLPREFIX ?= arm-none-eabi- +CC := $(TOOLPREFIX)gcc +AR := $(TOOLPREFIX)ar +RANLIB := $(TOOLPREFIX)ranlib +OBJCOPY := $(TOOLPREFIX)objcopy +SIZE := $(TOOLPREFIX)size + +ROOT := ../.. +BUILD_DIR ?= build +FREERTOS_TOP ?= $(ROOT)/../freertos +FREERTOS_KERNEL := $(FREERTOS_TOP)/FreeRTOS/Source +LWIP_TOP ?= $(ROOT)/../lwip +WOLFSSL_TOP ?= $(ROOT)/../wolfssl +M33MU ?= m33mu + +FREERTOS_PORT := portable/GCC/ARM_CM33_NTZ/non_secure +INCLUDE_DIR := $(CURDIR)/include +WOLFSENTRY_BUILD := $(abspath $(BUILD_DIR)/wolfsentry) +CPU_FLAGS := -mcpu=cortex-m33 -mthumb -mno-unaligned-access +COMMON_FLAGS := $(CPU_FLAGS) -Os -g -ffunction-sections -fdata-sections \ + -fno-common -Wall -Wextra -Werror=format \ + -DFREERTOS -DWOLFSENTRY_LWIP -DWOLFSENTRY_NO_GETPROTOBY \ + -DWOLFSENTRY_NO_POSIX_MEMALIGN \ + -I$(INCLUDE_DIR) -I$(ROOT) -I$(WOLFSENTRY_BUILD) \ + -I$(FREERTOS_KERNEL)/include -I$(FREERTOS_KERNEL)/$(FREERTOS_PORT) \ + -I$(LWIP_TOP)/src/include \ + -I$(LWIP_TOP)/contrib/ports/freertos/include +C89_FLAGS := -std=c89 -pedantic -DWOLFSENTRY_C89 -D_ISOC99_SOURCE \ + -Wno-long-long -Wno-overlength-strings -Wno-variadic-macros +TLS_C89_FLAGS := -std=gnu89 -DWOLFSENTRY_C89 -D_ISOC99_SOURCE \ + -Wno-long-long -Wno-overlength-strings -Wno-variadic-macros +THIRD_PARTY_FLAGS := -std=gnu11 -Wno-unused-parameter -Wno-sign-conversion \ + -Wno-conversion -Wno-cast-align +WOLFSSL_CFLAGS := $(CPU_FLAGS) -Os -ffunction-sections -fdata-sections \ + -I$(INCLUDE_DIR) -I$(FREERTOS_KERNEL)/include \ + -I$(FREERTOS_KERNEL)/$(FREERTOS_PORT) -I$(LWIP_TOP)/src/include +LINK_FLAGS = $(CPU_FLAGS) -specs=nano.specs -specs=nosys.specs \ + -Wl,-T,linker.ld -Wl,--gc-sections -Wl,-Map,$@.map + +FREERTOS_SRCS := \ + $(FREERTOS_KERNEL)/tasks.c \ + $(FREERTOS_KERNEL)/list.c \ + $(FREERTOS_KERNEL)/queue.c \ + $(FREERTOS_KERNEL)/portable/MemMang/heap_4.c \ + $(FREERTOS_KERNEL)/$(FREERTOS_PORT)/port.c \ + $(FREERTOS_KERNEL)/$(FREERTOS_PORT)/portasm.c + +LWIP_SRCS := \ + $(LWIP_TOP)/src/core/def.c \ + $(LWIP_TOP)/src/core/init.c \ + $(LWIP_TOP)/src/core/inet_chksum.c \ + $(LWIP_TOP)/src/core/ip.c \ + $(LWIP_TOP)/src/core/mem.c \ + $(LWIP_TOP)/src/core/memp.c \ + $(LWIP_TOP)/src/core/netif.c \ + $(LWIP_TOP)/src/core/pbuf.c \ + $(LWIP_TOP)/src/core/raw.c \ + $(LWIP_TOP)/src/core/stats.c \ + $(LWIP_TOP)/src/core/sys.c \ + $(LWIP_TOP)/src/core/tcp.c \ + $(LWIP_TOP)/src/core/tcp_in.c \ + $(LWIP_TOP)/src/core/tcp_out.c \ + $(LWIP_TOP)/src/core/timeouts.c \ + $(LWIP_TOP)/src/core/udp.c \ + $(LWIP_TOP)/src/core/ipv4/etharp.c \ + $(LWIP_TOP)/src/core/ipv4/icmp.c \ + $(LWIP_TOP)/src/core/ipv4/ip4.c \ + $(LWIP_TOP)/src/core/ipv4/ip4_addr.c \ + $(LWIP_TOP)/src/core/ipv4/ip4_frag.c \ + $(LWIP_TOP)/src/api/api_lib.c \ + $(LWIP_TOP)/src/api/api_msg.c \ + $(LWIP_TOP)/src/api/err.c \ + $(LWIP_TOP)/src/api/netbuf.c \ + $(LWIP_TOP)/src/api/sockets.c \ + $(LWIP_TOP)/src/api/tcpip.c \ + $(LWIP_TOP)/src/netif/ethernet.c \ + $(LWIP_TOP)/contrib/ports/freertos/sys_arch.c + +PLATFORM_SRCS := startup.c +BASIC_SRCS := $(ROOT)/examples/STM32-LWIP/Src/sentry.c \ + $(ROOT)/examples/STM32-LWIP/Src/echo.c \ + $(ROOT)/examples/STM32-LWIP/Src/ping.c +TLS_SRCS := $(ROOT)/examples/STM32-LWIP-WOLFSSL/Src/sentry.c \ + $(ROOT)/examples/STM32-LWIP-WOLFSSL/Src/echo.c + +PLATFORM_OBJS := $(patsubst %.c,$(BUILD_DIR)/common/%.o,$(PLATFORM_SRCS)) +FREERTOS_OBJS := $(patsubst $(FREERTOS_KERNEL)/%.c,$(BUILD_DIR)/freertos/%.o,$(FREERTOS_SRCS)) +LWIP_OBJS := $(patsubst $(LWIP_TOP)/%.c,$(BUILD_DIR)/lwip/%.o,$(LWIP_SRCS)) +COMMON_OBJS := $(PLATFORM_OBJS) $(FREERTOS_OBJS) $(LWIP_OBJS) +BASIC_OBJS := $(patsubst %.c,$(BUILD_DIR)/basic/%.o,$(notdir $(BASIC_SRCS))) +TLS_OBJS := $(patsubst %.c,$(BUILD_DIR)/tls/%.o,$(notdir $(TLS_SRCS))) + +.PHONY: all clean run check-paths wolfsentry wolfssl + +all: $(BUILD_DIR)/stm32-lwip.bin $(BUILD_DIR)/stm32-lwip-wolfssl.bin + +check-paths: + @test -f $(FREERTOS_KERNEL)/tasks.c || { echo "FREERTOS_TOP is invalid" >&2; exit 1; } + @test -f $(LWIP_TOP)/src/core/init.c || { echo "LWIP_TOP is invalid" >&2; exit 1; } + @test -f $(LWIP_TOP)/contrib/ports/freertos/sys_arch.c || { echo "lwIP contrib is required" >&2; exit 1; } + +wolfsentry: check-paths + $(MAKE) -C $(ROOT) -j2 \ + BUILD_TOP=$(WOLFSENTRY_BUILD) \ + HOST=arm-none-eabi RUNTIME=FreeRTOS-lwIP \ + FREERTOS_TOP=$(abspath $(FREERTOS_TOP)) \ + FREERTOS_PORT=ARM_CM33_NTZ/non_secure \ + RUNTIME_INCLUDE_DIR=$(INCLUDE_DIR) \ + LWIP_TOP=$(abspath $(LWIP_TOP)) \ + EXTRA_CFLAGS='$(CPU_FLAGS) $(C89_FLAGS) -I$(abspath $(LWIP_TOP))/contrib/ports/freertos/include' \ + FUNCTION_SECTIONS=1 + +$(WOLFSENTRY_BUILD)/libwolfsentry.a: wolfsentry + @test -f $@ + +wolfssl: $(WOLFSSL_TOP)/src/.libs/libwolfssl.a + +$(WOLFSSL_TOP)/src/.libs/libwolfssl.a: + @test -x $(WOLFSSL_TOP)/autogen.sh || { echo "WOLFSSL_TOP is invalid" >&2; exit 1; } + @test -f $(FREERTOS_KERNEL)/tasks.c || { echo "FREERTOS_TOP is invalid" >&2; exit 1; } + @test -f $(LWIP_TOP)/src/core/init.c || { echo "LWIP_TOP is invalid" >&2; exit 1; } + cd $(WOLFSSL_TOP) && ./autogen.sh + cd $(WOLFSSL_TOP) && \ + CC=$(CC) AR=$(AR) RANLIB=$(RANLIB) \ + CFLAGS='$(WOLFSSL_CFLAGS)' \ + LDFLAGS='$(CPU_FLAGS) -specs=nosys.specs' \ + ./configure --host=arm-none-eabi --enable-usersettings \ + --enable-static --disable-shared --disable-examples \ + --disable-crypttests --disable-benchmark --disable-filesystem + $(MAKE) -C $(WOLFSSL_TOP) -j2 \ + EXTRA_CFLAGS='-Wno-error=unused-parameter -Wno-error=bad-function-cast' \ + src/libwolfssl.la + +$(BUILD_DIR)/common/%.o: %.c | check-paths + @mkdir -p $(@D) + $(CC) $(COMMON_FLAGS) $(C89_FLAGS) -c $< -o $@ + +$(BUILD_DIR)/freertos/%.o: $(FREERTOS_KERNEL)/%.c | check-paths + @mkdir -p $(@D) + $(CC) $(COMMON_FLAGS) $(THIRD_PARTY_FLAGS) -c $< -o $@ + +$(BUILD_DIR)/lwip/%.o: $(LWIP_TOP)/%.c | check-paths + @mkdir -p $(@D) + $(CC) $(COMMON_FLAGS) $(THIRD_PARTY_FLAGS) -c $< -o $@ + +$(BUILD_DIR)/basic/main.o: main.c | check-paths + @mkdir -p $(@D) + $(CC) $(COMMON_FLAGS) $(C89_FLAGS) -DECHO_DEBUG=LWIP_DBG_OFF \ + -I$(ROOT)/examples/STM32-LWIP/Inc \ + -c $< -o $@ + +$(BUILD_DIR)/tls/main.o: main.c | check-paths + @mkdir -p $(@D) + $(CC) $(COMMON_FLAGS) $(TLS_C89_FLAGS) -DM33MU_EXAMPLE_TLS \ + -DWOLFSSL_USER_SETTINGS -I$(ROOT)/examples/STM32-LWIP-WOLFSSL/Inc \ + -I$(WOLFSSL_TOP) -c $< -o $@ + +$(BUILD_DIR)/basic/%.o: $(ROOT)/examples/STM32-LWIP/Src/%.c | check-paths + @mkdir -p $(@D) + $(CC) $(COMMON_FLAGS) $(C89_FLAGS) -DECHO_DEBUG=LWIP_DBG_OFF \ + -I$(ROOT)/examples/STM32-LWIP/Inc \ + -c $< -o $@ + +$(BUILD_DIR)/tls/%.o: $(ROOT)/examples/STM32-LWIP-WOLFSSL/Src/%.c | check-paths + @mkdir -p $(@D) + $(CC) $(COMMON_FLAGS) $(TLS_C89_FLAGS) -DM33MU_EXAMPLE_TLS \ + -DWOLFSSL_USER_SETTINGS -I$(ROOT)/examples/STM32-LWIP-WOLFSSL/Inc \ + -I$(WOLFSSL_TOP) -c $< -o $@ + +$(BUILD_DIR)/stm32-lwip.elf: $(COMMON_OBJS) $(BUILD_DIR)/basic/main.o $(BASIC_OBJS) \ + $(WOLFSENTRY_BUILD)/libwolfsentry.a linker.ld + $(CC) $(LINK_FLAGS) -o $@ $(COMMON_OBJS) $(BUILD_DIR)/basic/main.o $(BASIC_OBJS) \ + $(WOLFSENTRY_BUILD)/libwolfsentry.a -lc -lm -lgcc + $(SIZE) $@ + +$(BUILD_DIR)/stm32-lwip-wolfssl.elf: $(COMMON_OBJS) $(BUILD_DIR)/tls/main.o $(TLS_OBJS) \ + $(WOLFSENTRY_BUILD)/libwolfsentry.a $(WOLFSSL_TOP)/src/.libs/libwolfssl.a \ + linker.ld + $(CC) $(LINK_FLAGS) -o $@ $(COMMON_OBJS) $(BUILD_DIR)/tls/main.o $(TLS_OBJS) \ + $(WOLFSENTRY_BUILD)/libwolfsentry.a \ + $(WOLFSSL_TOP)/src/.libs/libwolfssl.a -lc -lm -lgcc + $(SIZE) $@ + +$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf + $(OBJCOPY) -O binary $< $@ + +run: all + M33MU=$(M33MU) ./run.sh $(BUILD_DIR)/stm32-lwip.bin \ + 'PASS: STM32-LWIP on FreeRTOS/lwIP under M33MU' + M33MU=$(M33MU) ./run.sh $(BUILD_DIR)/stm32-lwip-wolfssl.bin \ + 'PASS: STM32-LWIP-WOLFSSL on FreeRTOS/lwIP under M33MU' + +clean: + rm -rf $(BUILD_DIR) diff --git a/tests/stm32h563-m33mu/README.md b/tests/stm32h563-m33mu/README.md new file mode 100644 index 0000000..405ab36 --- /dev/null +++ b/tests/stm32h563-m33mu/README.md @@ -0,0 +1,17 @@ +# STM32H563 M33MU example runtime + +This fixture boots the STM32 lwIP examples on an emulated Cortex-M33. Each +firmware image starts the FreeRTOS scheduler and lwIP TCP/IP task before it +runs the example initialization and wolfSentry allow/deny policy checks. + +The test requires the M33MU emulator, the Arm GNU toolchain, FreeRTOS V10.5.1, +patched lwIP 2.1.3 with lwIP contrib, and wolfSSL for the TLS variant. Run both +images with: + +```sh +make run FREERTOS_TOP=/workspace/freertos LWIP_TOP=/workspace/lwip \ + WOLFSSL_TOP=/workspace/wolfssl +``` + +M33MU is emulator evidence. This fixture does not replace testing on an +STM32H563 board. diff --git a/tests/stm32h563-m33mu/include/FreeRTOSConfig.h b/tests/stm32h563-m33mu/include/FreeRTOSConfig.h new file mode 100644 index 0000000..c800aa6 --- /dev/null +++ b/tests/stm32h563-m33mu/include/FreeRTOSConfig.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef WOLFSENTRY_M33MU_FREERTOS_CONFIG_H +#define WOLFSENTRY_M33MU_FREERTOS_CONFIG_H + +#define configUSE_PREEMPTION 1 +#define configUSE_TICKLESS_IDLE 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configCPU_CLOCK_HZ 64000000UL +#define configTICK_RATE_HZ 1000 +#define configMAX_PRIORITIES 5 +#define configMINIMAL_STACK_SIZE 256 +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_QUEUE_SETS 0 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_TASK_NOTIFICATIONS 1 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1 +#define configUSE_TIMERS 0 +#define configUSE_TRACE_FACILITY 0 +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configTOTAL_HEAP_SIZE (256UL * 1024UL) +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configENABLE_FPU 0 +#define configENABLE_MPU 0 +#define configENABLE_TRUSTZONE 0 + +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskGetSchedulerState 1 + +#define configPRIO_BITS 4 +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 +#define configKERNEL_INTERRUPT_PRIORITY \ + (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) +#define configMAX_SYSCALL_INTERRUPT_PRIORITY \ + (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) + +void m33mu_assert(const char *file, unsigned long line); +#define configASSERT(condition) do { \ + if ((condition) == 0) \ + m33mu_assert(__FILE__, (unsigned long)__LINE__); \ +} while (0) + +#endif /* WOLFSENTRY_M33MU_FREERTOS_CONFIG_H */ diff --git a/tests/stm32h563-m33mu/include/arch/cc.h b/tests/stm32h563-m33mu/include/arch/cc.h new file mode 100644 index 0000000..b1994b4 --- /dev/null +++ b/tests/stm32h563-m33mu/include/arch/cc.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef WOLFSENTRY_M33MU_LWIP_ARCH_CC_H +#define WOLFSENTRY_M33MU_LWIP_ARCH_CC_H + +#include +#include +#include + +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif +#ifndef inet_ntop +#define inet_ntop lwip_inet_ntop +#endif +#ifndef inet_pton +#define inet_pton lwip_inet_pton +#endif +#define LWIP_PLATFORM_DIAG(message) do { printf message; } while (0) +#define LWIP_PLATFORM_ASSERT(message) do { \ + printf("lwIP assertion: %s\n", message); \ + m33mu_fail(); \ +} while (0) + +void m33mu_fail(void); + +#endif /* WOLFSENTRY_M33MU_LWIP_ARCH_CC_H */ diff --git a/tests/stm32h563-m33mu/include/cmsis_os.h b/tests/stm32h563-m33mu/include/cmsis_os.h new file mode 100644 index 0000000..75f755b --- /dev/null +++ b/tests/stm32h563-m33mu/include/cmsis_os.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef WOLFSENTRY_M33MU_CMSIS_OS_H +#define WOLFSENTRY_M33MU_CMSIS_OS_H + +#include "FreeRTOS.h" +#include "queue.h" +#include "task.h" + +typedef int osStatus; + +#define osOK 0 + +static __inline__ osStatus osDelay(uint32_t millisec) +{ + vTaskDelay(pdMS_TO_TICKS(millisec)); + return osOK; +} + +#endif /* WOLFSENTRY_M33MU_CMSIS_OS_H */ diff --git a/tests/stm32h563-m33mu/include/lwipopts.h b/tests/stm32h563-m33mu/include/lwipopts.h new file mode 100644 index 0000000..110b982 --- /dev/null +++ b/tests/stm32h563-m33mu/include/lwipopts.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef WOLFSENTRY_M33MU_LWIPOPTS_H +#define WOLFSENTRY_M33MU_LWIPOPTS_H + +#define NO_SYS 0 +#define SYS_LIGHTWEIGHT_PROT 1 +#define MEM_ALIGNMENT 4 +#define MEM_SIZE (48 * 1024) +#define MEM_LIBC_MALLOC 0 +#define MEMP_MEM_MALLOC 0 +#define MEMP_NUM_PBUF 16 +#define MEMP_NUM_RAW_PCB 4 +#define MEMP_NUM_TCP_PCB 8 +#define MEMP_NUM_TCP_PCB_LISTEN 4 +#define MEMP_NUM_TCP_SEG 16 +#define MEMP_NUM_SYS_TIMEOUT 8 +#define MEMP_NUM_TCPIP_MSG_API 8 +#define MEMP_NUM_TCPIP_MSG_INPKT 8 +#define MEMP_NUM_NETBUF 4 +#define MEMP_NUM_NETCONN 4 +#define MEMP_NUM_API_MSG 8 +#define PBUF_POOL_SIZE 8 +#define PBUF_POOL_BUFSIZE 1536 + +#define LWIP_IPV4 1 +#define LWIP_IPV6 0 +#define LWIP_ETHERNET 1 +#define LWIP_ARP 1 +#define LWIP_ICMP 1 +#define LWIP_RAW 1 +#define LWIP_TCP 1 +#define LWIP_UDP 1 +#define LWIP_DHCP 0 +#define LWIP_SOCKET 1 +#define LWIP_NETCONN 1 +#define LWIP_STATS 0 +#define LWIP_CHECKSUM_CTRL_PER_NETIF 1 +#define LWIP_PACKET_FILTER_API 1 +#define LWIP_COMPAT_SOCKETS 0 +#define LWIP_ERRNO_STDINCLUDE 1 +#define LWIP_TIMEVAL_PRIVATE 0 +#define TCPIP_THREAD_NAME "tcpip" +#define TCPIP_THREAD_STACKSIZE 2048 +#define TCPIP_THREAD_PRIO 3 +#define TCPIP_MBOX_SIZE 16 +#define TCP_MSS 1460 +#define TCP_WND (4 * TCP_MSS) +#define TCP_SND_BUF (4 * TCP_MSS) +#define TCP_SND_QUEUELEN 16 +#define TCP_QUEUE_OOSEQ 1 +#define TCP_TTL 255 +#define ICMP_TTL 255 +#define ARP_TABLE_SIZE 8 +#define ARP_QUEUEING 1 +unsigned int lwip_port_rand(void); +#define LWIP_RAND() lwip_port_rand() + +#endif /* WOLFSENTRY_M33MU_LWIPOPTS_H */ diff --git a/tests/stm32h563-m33mu/include/user_settings.h b/tests/stm32h563-m33mu/include/user_settings.h new file mode 100644 index 0000000..e4deb8a --- /dev/null +++ b/tests/stm32h563-m33mu/include/user_settings.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef WOLFSENTRY_M33MU_WOLFSSL_USER_SETTINGS_H +#define WOLFSENTRY_M33MU_WOLFSSL_USER_SETTINGS_H + +#define WOLFSSL_LWIP_NATIVE +#define WOLFSSL_TLS13 +#define WOLFSSL_NO_TLS12 +#define NO_OLD_TLS +#define HAVE_TLS_EXTENSIONS +#define HAVE_SUPPORTED_CURVES +#define HAVE_HKDF +#define HAVE_ECC +#define ECC_USER_CURVES +#define HAVE_AESGCM +#define WOLFSSL_SP_MATH_ALL +#define WOLFSSL_SP_SMALL +#if !defined(__ASSEMBLER__) + #ifndef FREERTOS + #define FREERTOS + #endif +#endif +#define SINGLE_THREADED +#define NO_FILESYSTEM +#define NO_WRITEV +#define WOLFSSL_NO_SOCK +#define NO_DEV_RANDOM +#define WOLFSSL_NO_GETPID +#define NO_DH +#define NO_RSA +#define CUSTOM_RAND_GENERATE_BLOCK m33mu_random_block +#define ECC_TIMING_RESISTANT + +#if !defined(__ASSEMBLER__) +int m33mu_random_block(unsigned char *output, unsigned int size); +#endif + +#endif /* WOLFSENTRY_M33MU_WOLFSSL_USER_SETTINGS_H */ diff --git a/tests/stm32h563-m33mu/linker.ld b/tests/stm32h563-m33mu/linker.ld new file mode 100644 index 0000000..df99fb2 --- /dev/null +++ b/tests/stm32h563-m33mu/linker.ld @@ -0,0 +1,64 @@ +ENTRY(Reset_Handler) + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2M + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 512K +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +PHDRS +{ + text PT_LOAD FLAGS(5); + data PT_LOAD FLAGS(6); +} + +SECTIONS +{ + .vectors ORIGIN(FLASH) : + { + KEEP(*(.vectors)) + } > FLASH :text + + .text : + { + *(.text*) + *(.rodata*) + KEEP(*(.init)) + KEEP(*(.fini)) + *(.ARM.extab*) + *(.ARM.exidx*) + } > FLASH :text + + .data : + { + . = ALIGN(8); + _sdata = .; + *(.data*) + . = ALIGN(8); + _edata = .; + } > RAM AT > FLASH :data + + .bss (NOLOAD) : + { + . = ALIGN(8); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(8); + _ebss = .; + _end = .; + } > RAM :NONE + + .heap (NOLOAD) : + { + . = ALIGN(8); + _heap_start = .; + . += 96K; + _heap_end = .; + } > RAM :NONE + + ASSERT(_heap_end < (_estack - 16K), "STM32H563 RAM overflow") +} diff --git a/tests/stm32h563-m33mu/main.c b/tests/stm32h563-m33mu/main.c new file mode 100644 index 0000000..d23acd3 --- /dev/null +++ b/tests/stm32h563-m33mu/main.c @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include +#include +#include + +#include "FreeRTOS.h" +#include "task.h" +#include "lwip/ip_addr.h" +#include "lwip/tcpip.h" +#include "lwip/etharp.h" + +#include "sentry.h" +#include "echo.h" +#if !defined(M33MU_EXAMPLE_TLS) + #include "ping.h" +#endif + +#if defined(M33MU_EXAMPLE_TLS) + #define EXAMPLE_REMOTE_A 192 + #define EXAMPLE_REMOTE_B 168 + #define EXAMPLE_REMOTE_C 4 + #define EXAMPLE_REMOTE_D 85 +#else + #define EXAMPLE_REMOTE_A 192 + #define EXAMPLE_REMOTE_B 168 + #define EXAMPLE_REMOTE_C 103 + #define EXAMPLE_REMOTE_D 2 +#endif + +static volatile int tcpip_ready; +static volatile int example_network_ready; +static volatile int example_network_status; +static uint32_t random_state = 0x6d33336dUL; + +static void tcpip_initialized(void *argument) +{ + (void)argument; + tcpip_ready = 1; +} + +static void example_network_init(void *argument) +{ + (void)argument; +#if defined(M33MU_EXAMPLE_TLS) + echo_init(); + example_network_status = 0; +#else + example_network_status = echo_init(); + if (example_network_status == 0) + example_network_status = ping_init(); +#endif + example_network_ready = 1; +} + +unsigned int lwip_port_rand(void) +{ + random_state ^= random_state << 13; + random_state ^= random_state >> 17; + random_state ^= random_state << 5; + return random_state; +} + +int m33mu_random_block(unsigned char *output, unsigned int size) +{ + unsigned int i; + + if (output == NULL) + return -1; + for (i = 0; i < size; ++i) + output[i] = (unsigned char)lwip_port_rand(); + return 0; +} + +void m33mu_fail(void) +{ + printf("FAIL: STM32H563 M33MU example\n"); + __asm volatile("bkpt 0x01"); + for (;;) { + } +} + +void m33mu_assert(const char *file, unsigned long line) +{ + printf("FreeRTOS assertion: %s:%lu\n", file, line); + __asm volatile("bkpt 0x02"); + for (;;) { + } +} + +void vApplicationMallocFailedHook(void) +{ + printf("FreeRTOS allocation failed\n"); + __asm volatile("bkpt 0x03"); + for (;;) { + } +} + +void vApplicationStackOverflowHook(TaskHandle_t task, char *name) +{ + (void)task; + printf("FreeRTOS stack overflow: %s\n", name); + __asm volatile("bkpt 0x04"); + for (;;) { + } +} + +static void require_result(int condition, const char *message) +{ + if (!condition) { + printf("failed: %s\n", message); + __asm volatile("bkpt 0x07"); + for (;;) { + } + } +} + +static void run_policy_checks(void) +{ + ip_addr_t local; + ip_addr_t allowed; + ip_addr_t rejected; + struct eth_addr allowed_mac; + struct eth_addr rejected_mac; + + IP4_ADDR(ip_2_ip4(&local), 192, 168, 0, 10); + IP4_ADDR(ip_2_ip4(&allowed), EXAMPLE_REMOTE_A, EXAMPLE_REMOTE_B, + EXAMPLE_REMOTE_C, EXAMPLE_REMOTE_D); + IP4_ADDR(ip_2_ip4(&rejected), EXAMPLE_REMOTE_A, EXAMPLE_REMOTE_B, + EXAMPLE_REMOTE_C, EXAMPLE_REMOTE_D + 1); + + allowed_mac.addr[0] = 0xde; + allowed_mac.addr[1] = 0xc0; + allowed_mac.addr[2] = 0xde; + allowed_mac.addr[3] = 0x03; + allowed_mac.addr[4] = 0x02; + allowed_mac.addr[5] = 0x7f; + rejected_mac.addr[0] = 0xde; + rejected_mac.addr[1] = 0xc0; + rejected_mac.addr[2] = 0xde; + rejected_mac.addr[3] = 0x03; + rejected_mac.addr[4] = 0x03; + rejected_mac.addr[5] = 0x01; + + require_result(sentry_action(&local, &allowed, 11111, 49152, + SENTRY_ACTION_CONNECT) == 0, "allowed TCP route"); + require_result(sentry_action(&local, &rejected, 11111, 49152, + SENTRY_ACTION_CONNECT) != 0, "rejected TCP route"); + require_result(sentry_action_ping(&allowed, 8) == 0, + "allowed ICMP route"); + require_result(sentry_action_ping(&rejected, 8) != 0, + "rejected ICMP route"); + require_result(sentry_action_mac(&allowed_mac) == 0, + "allowed Ethernet route"); + require_result(sentry_action_mac(&rejected_mac) != 0, + "rejected Ethernet route"); +} + +static void example_task(void *argument) +{ + (void)argument; + printf("M33MU: FreeRTOS task started\n"); + + tcpip_init(tcpip_initialized, NULL); + while (!tcpip_ready) + vTaskDelay(pdMS_TO_TICKS(1)); + printf("M33MU: lwIP TCP/IP task started\n"); + + require_result(sentry_init() == 0, "wolfSentry initialization"); +#if defined(M33MU_EXAMPLE_TLS) + require_result(echo_ssl() == 0, "wolfSSL TLS initialization"); +#endif + require_result(tcpip_callback(example_network_init, NULL) == ERR_OK, + "lwIP example callback"); + while (!example_network_ready) + vTaskDelay(pdMS_TO_TICKS(1)); + require_result(example_network_status == 0, "lwIP example initialization"); + run_policy_checks(); + +#if defined(M33MU_EXAMPLE_TLS) + printf("PASS: STM32-LWIP-WOLFSSL on FreeRTOS/lwIP under M33MU\n"); +#else + printf("PASS: STM32-LWIP on FreeRTOS/lwIP under M33MU\n"); +#endif + __asm volatile("bkpt 0x7f"); + for (;;) { + } +} + +int main(void) +{ + BaseType_t status; + + setvbuf(stdout, NULL, _IONBF, 0); + printf("M33MU: STM32H563 booted\n"); + status = xTaskCreate(example_task, "example", 8192, NULL, 2, NULL); + if (status != pdPASS) { + __asm volatile("bkpt 0x05"); + for (;;) { + } + } + vTaskStartScheduler(); + __asm volatile("bkpt 0x06"); + for (;;) { + } + return 1; +} diff --git a/tests/stm32h563-m33mu/run.sh b/tests/stm32h563-m33mu/run.sh new file mode 100755 index 0000000..99dd75c --- /dev/null +++ b/tests/stm32h563-m33mu/run.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +set -eu + +image=${1:?usage: run.sh image.bin expected-marker} +marker=${2:?usage: run.sh image.bin expected-marker} +emulator=${M33MU:-m33mu} +timeout_seconds=${M33MU_TIMEOUT:-30} +log=$(mktemp) +status_file=$(mktemp) +trap 'rm -f "$log" "$status_file"' EXIT INT TERM + +( + set +e + "$emulator" --cpu stm32h563 --no-tz --uart-stdout \ + --expect-bkpt 0x7f --quit-on-faults --timeout "$timeout_seconds" \ + "$image" 2>&1 + printf '%s\n' "$?" > "$status_file" +) | tee "$log" +status=$(cat "$status_file") + +grep -F 'M33MU: STM32H563 booted' "$log" +grep -F 'M33MU: FreeRTOS task started' "$log" +grep -F 'M33MU: lwIP TCP/IP task started' "$log" +grep -F "$marker" "$log" +grep -F '[EXPECT BKPT] Success' "$log" + +if grep -Eq '^\[(MEMFAULT|BUSFAULT|USAGEFLT|HARDFLT)\]|HardFault|SecureFault' "$log"; then + echo 'M33MU reported a processor fault' >&2 + exit 1 +fi + +exit "$status" diff --git a/tests/stm32h563-m33mu/startup.c b/tests/stm32h563-m33mu/startup.c new file mode 100644 index 0000000..0011893 --- /dev/null +++ b/tests/stm32h563-m33mu/startup.c @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include +#include +#include +#include + +extern uint32_t _sidata; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; +extern uint32_t _estack; +extern unsigned char _heap_start; +extern unsigned char _heap_end; + +extern int main(void); +extern void SVC_Handler(void); +extern void PendSV_Handler(void); +extern void SysTick_Handler(void); + +void Reset_Handler(void); + +void Default_Handler(void) +{ + for (;;) { + } +} + +void NMI_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void HardFault_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void MemManage_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void BusFault_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void UsageFault_Handler(void) __attribute__((weak, alias("Default_Handler"))); +void DebugMon_Handler(void) __attribute__((weak, alias("Default_Handler"))); + +__attribute__((section(".vectors"), used)) +const void *m33mu_vectors[] = { + (void *)&_estack, + (void *)Reset_Handler, + (void *)NMI_Handler, + (void *)HardFault_Handler, + (void *)MemManage_Handler, + (void *)BusFault_Handler, + (void *)UsageFault_Handler, + NULL, NULL, NULL, NULL, + (void *)SVC_Handler, + (void *)DebugMon_Handler, + NULL, + (void *)PendSV_Handler, + (void *)SysTick_Handler +}; + +#define REG32(address) (*(volatile uint32_t *)(address)) +#define RCC_AHB2ENR REG32(0x44020C8CUL) +#define RCC_APB1LENR REG32(0x44020C9CUL) +#define GPIOD_MODER REG32(0x42020C00UL) +#define GPIOD_AFRH REG32(0x42020C24UL) +#define USART3_CR1 REG32(0x40004800UL) +#define USART3_CR2 REG32(0x40004804UL) +#define USART3_CR3 REG32(0x40004808UL) +#define USART3_BRR REG32(0x4000480CUL) +#define USART3_ISR REG32(0x4000481CUL) +#define USART3_TDR REG32(0x40004828UL) + +static void uart_init(void) +{ + RCC_AHB2ENR |= (1UL << 3); + RCC_APB1LENR |= (1UL << 18); + GPIOD_MODER = (GPIOD_MODER & ~(3UL << 16)) | (2UL << 16); + GPIOD_AFRH = (GPIOD_AFRH & ~15UL) | 7UL; + USART3_CR1 = 0UL; + USART3_CR2 = 0UL; + USART3_CR3 = 0UL; + USART3_BRR = 278UL; + USART3_CR1 = (1UL << 3) | (1UL << 2) | 1UL; +} + +static void uart_putc(char c) +{ + while ((USART3_ISR & (1UL << 7)) == 0UL) { + } + USART3_TDR = (uint32_t)(unsigned char)c; +} + +void Reset_Handler(void) +{ + uint32_t *source; + uint32_t *dest; + + source = &_sidata; + dest = &_sdata; + while (dest < &_edata) + *dest++ = *source++; + dest = &_sbss; + while (dest < &_ebss) + *dest++ = 0UL; + + uart_init(); + (void)main(); + for (;;) { + } +} + +ssize_t _write(int fd, const void *buffer, size_t count) +{ + const unsigned char *bytes; + size_t i; + + (void)fd; + bytes = (const unsigned char *)buffer; + for (i = 0; i < count; ++i) { + if (bytes[i] == (unsigned char)'\n') + uart_putc('\r'); + uart_putc((char)bytes[i]); + } + return (ssize_t)count; +} + +void *_sbrk(ptrdiff_t increment) +{ + static unsigned char *current = &_heap_start; + unsigned char *previous; + + previous = current; + if ((increment < 0) || ((size_t)increment > (size_t)(&_heap_end - current))) + return (void *)-1; + current += increment; + return previous; +} + +int _close(int fd) +{ + (void)fd; + return -1; +} + +int _fstat(int fd, struct stat *state) +{ + (void)fd; + state->st_mode = S_IFCHR; + return 0; +} + +int _isatty(int fd) +{ + (void)fd; + return 1; +} + +off_t _lseek(int fd, off_t offset, int whence) +{ + (void)fd; + (void)offset; + (void)whence; + return (off_t)-1; +} + +ssize_t _read(int fd, void *buffer, size_t count) +{ + (void)fd; + (void)buffer; + (void)count; + return -1; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int signal) +{ + (void)pid; + (void)signal; + return -1; +} + +void _exit(int status) +{ + (void)status; + for (;;) { + } +} From 74806cf42dac1389cf95b077397d5fe4428da15e Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Mon, 12 Oct 2026 10:18:48 -0700 Subject: [PATCH 8/8] Ensure M33 example options are generated --- tests/stm32h563-m33mu/Makefile | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/stm32h563-m33mu/Makefile b/tests/stm32h563-m33mu/Makefile index e3eb1d8..019b830 100644 --- a/tests/stm32h563-m33mu/Makefile +++ b/tests/stm32h563-m33mu/Makefile @@ -143,25 +143,29 @@ $(BUILD_DIR)/lwip/%.o: $(LWIP_TOP)/%.c | check-paths @mkdir -p $(@D) $(CC) $(COMMON_FLAGS) $(THIRD_PARTY_FLAGS) -c $< -o $@ -$(BUILD_DIR)/basic/main.o: main.c | check-paths +$(BUILD_DIR)/basic/main.o: main.c | check-paths \ + $(WOLFSENTRY_BUILD)/libwolfsentry.a @mkdir -p $(@D) $(CC) $(COMMON_FLAGS) $(C89_FLAGS) -DECHO_DEBUG=LWIP_DBG_OFF \ -I$(ROOT)/examples/STM32-LWIP/Inc \ -c $< -o $@ -$(BUILD_DIR)/tls/main.o: main.c | check-paths +$(BUILD_DIR)/tls/main.o: main.c | check-paths \ + $(WOLFSENTRY_BUILD)/libwolfsentry.a @mkdir -p $(@D) $(CC) $(COMMON_FLAGS) $(TLS_C89_FLAGS) -DM33MU_EXAMPLE_TLS \ -DWOLFSSL_USER_SETTINGS -I$(ROOT)/examples/STM32-LWIP-WOLFSSL/Inc \ -I$(WOLFSSL_TOP) -c $< -o $@ -$(BUILD_DIR)/basic/%.o: $(ROOT)/examples/STM32-LWIP/Src/%.c | check-paths +$(BUILD_DIR)/basic/%.o: $(ROOT)/examples/STM32-LWIP/Src/%.c | check-paths \ + $(WOLFSENTRY_BUILD)/libwolfsentry.a @mkdir -p $(@D) $(CC) $(COMMON_FLAGS) $(C89_FLAGS) -DECHO_DEBUG=LWIP_DBG_OFF \ -I$(ROOT)/examples/STM32-LWIP/Inc \ -c $< -o $@ -$(BUILD_DIR)/tls/%.o: $(ROOT)/examples/STM32-LWIP-WOLFSSL/Src/%.c | check-paths +$(BUILD_DIR)/tls/%.o: $(ROOT)/examples/STM32-LWIP-WOLFSSL/Src/%.c | check-paths \ + $(WOLFSENTRY_BUILD)/libwolfsentry.a @mkdir -p $(@D) $(CC) $(COMMON_FLAGS) $(TLS_C89_FLAGS) -DM33MU_EXAMPLE_TLS \ -DWOLFSSL_USER_SETTINGS -I$(ROOT)/examples/STM32-LWIP-WOLFSSL/Inc \