@@ -65,3 +65,134 @@ jobs:
6565 # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
6666 run : msbuild /m /p:PlatformToolset=v142 /p:Platform=${{env.BUILD_PLATFORM}} /p:WindowsTargetPlatformVersion=${{env.TARGET_PLATFORM}} /p:Configuration=${{env.WOLFSSH_BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}}
6767
68+ # Build and run the self-contained unit tests with the MSVC AddressSanitizer.
69+ # This is the only job that executes wolfSSH tests under a sanitizer on
70+ # Windows, where the USE_WINDOWS_API console code (e.g. wolfSSH_DoOSC) is
71+ # compiled, so it guards that path against out-of-bounds reads.
72+ asan-tests :
73+ runs-on : windows-latest
74+
75+ env :
76+ # print_stats=1 emits allocator stats at exit, positive evidence that the
77+ # ASan runtime was active in-process during each test run.
78+ ASAN_OPTIONS : abort_on_error=1:print_stats=1
79+
80+ steps :
81+ - uses : actions/checkout@v2
82+ with :
83+ repository : wolfssl/wolfssl
84+ path : wolfssl
85+
86+ - uses : actions/checkout@master
87+ with :
88+ path : wolfssh
89+
90+ - name : Add MSBuild to PATH
91+ uses : microsoft/setup-msbuild@v1
92+
93+ # The pinned v142 toolset does not ship the AddressSanitizer runtime libs on
94+ # the runner. Find an installed MSVC toolset that does and build everything in
95+ # this job with it, recording its lib/bin dirs for the link and run steps.
96+ # wolfssl, wolfssh and the test projects must share one compiler version
97+ # because /GL (whole program optimization) does code generation at link time.
98+ - name : Locate MSVC AddressSanitizer runtime
99+ shell : pwsh
100+ run : |
101+ $vs = & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath
102+ $lib = Get-ChildItem "$vs\VC\Tools\MSVC\*\lib\x64\clang_rt.asan_dynamic_runtime_thunk-x86_64.lib" -ErrorAction SilentlyContinue |
103+ Sort-Object { [version]($_.FullName -replace '.*\\MSVC\\([0-9.]+)\\.*','$1') } |
104+ Select-Object -Last 1
105+ if ($null -eq $lib) { throw "MSVC AddressSanitizer runtime not found in any installed toolset" }
106+ $msvcDir = $lib.Directory.Parent.Parent.FullName
107+ $ver = [version]($msvcDir.Split('\')[-1])
108+ if ($ver.Minor -ge 30) { $toolset = "v143" } else { $toolset = "v142" }
109+ "ASAN_TOOLSET=$toolset" | Out-File $env:GITHUB_ENV -Append
110+ "ASAN_LIB_DIR=$($lib.Directory.FullName)" | Out-File $env:GITHUB_ENV -Append
111+ "ASAN_BIN_DIR=$(Join-Path $msvcDir 'bin\Hostx64\x64')" | Out-File $env:GITHUB_ENV -Append
112+ Write-Host "Using toolset $toolset (MSVC $ver)"
113+
114+ - name : Restore wolfSSL NuGet packages
115+ working-directory : wolfssl
116+ run : nuget restore ${{env.WOLFSSL_SOLUTION_FILE_PATH}}
117+
118+ # These env paths already include the wolfssh/ and wolfssl/ checkout
119+ # prefixes, so they must run from the workspace root (as the build job does).
120+ - name : updated user_settings.h for sshd and x509
121+ run : cp ${{env.USER_SETTINGS_H_NEW}} ${{env.USER_SETTINGS_H}}
122+
123+ - name : replace wolfSSL user_settings.h with wolfSSH user_settings.h
124+ run : get-content ${{env.USER_SETTINGS_H_NEW}} | %{$_ -replace "if 0","if 1"}
125+
126+ # WholeProgramOptimization=false disables /GL so the v142-independent objects
127+ # link without a cross-version code-generation requirement (C1047).
128+ - name : Build wolfssl library
129+ working-directory : wolfssl
130+ shell : pwsh
131+ run : |
132+ msbuild /m /p:PlatformToolset=$env:ASAN_TOOLSET /p:Platform=${{env.BUILD_PLATFORM}} /p:Configuration=${{env.WOLFSSL_BUILD_CONFIGURATION}} /p:WholeProgramOptimization=false /t:wolfssl ${{env.WOLFSSL_SOLUTION_FILE_PATH}}
133+ if ($LASTEXITCODE -ne 0) { throw "wolfssl build failed" }
134+
135+ - name : Restore NuGet packages
136+ working-directory : wolfssh\ide\winvs
137+ run : nuget restore ${{env.SOLUTION_FILE_PATH}}
138+
139+ # EnableASAN=true adds /fsanitize=address to each test project and to the
140+ # referenced wolfssh library project, instrumenting src/wolfterm.c. The
141+ # AddressSanitizer lib dir is added to LIB so the runtime thunk resolves.
142+ - name : Build api-test and unit-test with AddressSanitizer
143+ working-directory : wolfssh\ide\winvs
144+ shell : pwsh
145+ run : |
146+ $env:LIB = "$env:ASAN_LIB_DIR;$env:LIB"
147+ foreach ($p in @("api-test\api-test.vcxproj", "unit-test\unit-test.vcxproj")) {
148+ msbuild /m /p:PlatformToolset=$env:ASAN_TOOLSET /p:Platform=${{env.BUILD_PLATFORM}} /p:WindowsTargetPlatformVersion=${{env.TARGET_PLATFORM}} /p:Configuration=${{env.WOLFSSH_BUILD_CONFIGURATION}} /p:EnableASAN=true /p:WholeProgramOptimization=false $p
149+ if ($LASTEXITCODE -ne 0) { throw "build failed: $p" }
150+ }
151+
152+ # Positive control: compile a deliberate heap overflow with the same toolset
153+ # and confirm ASan aborts on it. This proves ASan detection actually works on
154+ # this runner, so a clean test run is meaningful rather than a silent no-op.
155+ - name : Verify AddressSanitizer detection (positive control)
156+ shell : pwsh
157+ run : |
158+ $vs = & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath
159+ Import-Module "$vs\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
160+ Enter-VsDevShell -VsInstallPath $vs -SkipAutomaticLocation -DevCmdArguments "-arch=x64" | Out-Null
161+ Set-Content canary.c 'int main(int argc, char** argv) { volatile char b[1]; (void)argv; return b[argc + 10]; }'
162+ cl /nologo /fsanitize=address /MD canary.c
163+ if ($LASTEXITCODE -ne 0) { throw "canary failed to compile" }
164+ $out = & .\canary.exe 2>&1 | Out-String
165+ $code = $LASTEXITCODE
166+ Write-Host $out
167+ if ($code -eq 0 -or $out -notmatch "AddressSanitizer") {
168+ throw "Positive control FAILED: ASan did not detect the deliberate overflow"
169+ }
170+ Write-Host "Positive control OK: ASan detected the deliberate out-of-bounds access"
171+ # canary.exe aborts with a non-zero code by design; reset so the step
172+ # itself reports success.
173+ exit 0
174+
175+ # Building a .vcxproj directly leaves $(SolutionDir) unset, so each project
176+ # writes to its own <project>\Release\x64 dir. Run from the wolfssh repo root
177+ # so the tests find keys/ and certs/, and copy the dynamic ASAN runtime next
178+ # to each binary so it loads without a full developer-prompt environment.
179+ - name : Run tests under AddressSanitizer
180+ working-directory : wolfssh
181+ shell : pwsh
182+ run : |
183+ $cfg = "${{env.WOLFSSH_BUILD_CONFIGURATION}}\${{env.BUILD_PLATFORM}}"
184+ $dll = Join-Path $env:ASAN_BIN_DIR "clang_rt.asan_dynamic-x86_64.dll"
185+ if (-not (Test-Path $dll)) { throw "ASAN runtime DLL not found: $dll" }
186+ foreach ($t in @("api-test", "unit-test")) {
187+ $dir = "ide\winvs\$t\$cfg"
188+ # Static signal: confirm the binary really imports the ASan runtime, so
189+ # we are exercising an instrumented build and not a stale one.
190+ $deps = & "$env:ASAN_BIN_DIR\dumpbin.exe" /dependents "$dir\$t.exe" | Out-String
191+ if ($deps -notmatch "clang_rt.asan") { throw "$t is not linked against the ASan runtime" }
192+ Write-Host "$t links the ASan runtime:"
193+ ($deps -split "`n" | Select-String "asan").Line.Trim() | ForEach-Object { Write-Host " $_" }
194+ Copy-Item $dll $dir
195+ & "$dir\$t.exe"
196+ if ($LASTEXITCODE -ne 0) { throw "$t failed under ASAN (exit $LASTEXITCODE)" }
197+ }
198+
0 commit comments