Skip to content

Commit 1fbad55

Browse files
committed
Merged PR 7775773: Fix integer truncation issue in 32-bit Linux builds
This change fixes an incorrect implementation of the `SYMCRYPT_MUL32x32TO64` when compiling for 32-bit architectures using gcc or clang. Previously the macro cast the input parameters to `unsigned long`, which is 32 bits on some platforms and 64 bits on others. This resulted in the multiplication truncating the top half of the word. The fix is to cast to UINT64 instead. Also added 32-bit Linux unit tests to the Azure pipeline so it will be built and tested in our CI builds. Related work items: #32615192
1 parent 79031ca commit 1fbad55

File tree

7 files changed

+114
-46
lines changed

7 files changed

+114
-46
lines changed

README.md

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Like any engineering project, SymCrypt is a compromise between conflicting requi
1818
- Support FIPS 140-2 certification of products using SymCrypt.
1919
- Provide high assurance in the proper functionality of the library.
2020

21-
# Clone the Repo
21+
# Cloning the Repo
2222
In some of our Linux modules, SymCrypt uses [Jitterentropy](https://github.com/smuellerDD/jitterentropy-library)
2323
as a source of FIPS-certifiable entropy. To build these modules, you will need to ensure that the
2424
jitterentropy-library submodule is also cloned. You can do this by running
@@ -30,36 +30,56 @@ publicly, so this submodule will only be cloneable by Microsoft employees with a
3030
Azure DevOps repository. If you are external to Microsoft, you can ignore this submodule. It is only used in
3131
the unit tests and does not change the behavior of the SymCrypt product code.
3232

33-
# Build and Test
33+
# Building
34+
## Prerequisites
3435
SymCrypt can be compiled with CMake >= 3.13.0 and Visual Studio 2019 (with Windows 10 SDK version 18362) on Windows
35-
or gcc 7.4.0 or clang 10.0.0 on Linux. Note that CMake ships with Visual Studio 2019.
36+
or gcc 7.4.0 or clang 10.0.0 on Linux. Note that CMake ships with Visual Studio 2019; you can use Visual Studio's
37+
included CMake by setting `$env:PATH="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\;${env:PATH}"`.
3638

37-
Python3 is also required for translation of SymCryptAsm, and for building the SymCrypt module with integrity check.
39+
Python 3 is also required for translation of SymCryptAsm, and for building the SymCrypt module with integrity check.
3840
The integrity check additionally requires pip and pyelftools: `pip3 install -r ./scripts/requirements.txt`
3941

40-
1. Optionally use CMake from Visual Studio `$env:PATH="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\;${env:PATH}"`
41-
2. For Microsoft employees building the library internally, to include msbignum and RSA32 implementation benchmarks in the unit tests:
42+
## Supported Configurations
43+
SymCrypt has pure C implementations of all supported functionality. These "generic" implementations are designed to
44+
be portable to various architectures. However, they do not offer optimal performance because they do not take
45+
advantage of CPU-specific optimizations. To that end, we also have hand-written assembly implementations of
46+
performance-critical internal functions. Our CMake build scripts do not currently support ASM optimizations on all
47+
combinations of architectures and platforms; the Build Instructions section below lists some of the currently supported
48+
combinations, and we're working on adding support for more.
49+
50+
The ability to build SymCrypt on any particular platform or architecture, with or without CPU optimizations, does not
51+
imply that it has been tested for or is actively supported by Microsoft on that platform/architecture. While we make
52+
every effort to ensure that SymCrypt is reliable, stable and bug-free on every platform we run on, the code in this
53+
repository is provided *as is*, without warranty of any kind, express or implied, including but not limited to the
54+
warranties of merchantability, fitness for a particular purpose and noninfringement (see our [LICENSE](./LICENSE)).
55+
56+
## Build Instructions
57+
1. For Microsoft employees building the library internally, to include msbignum and RSA32 implementation benchmarks in the unit tests:
4258
1. Make sure the SymCryptDependencies submodule is initialized by following the steps above (`git submodule update --init`)
43-
2. In step 4 below, add the additional cmake argument `-DSYMCRYPT_INTERNAL_BUILD=1`
44-
3. `mkdir bin; cd bin`
45-
4. Configure CMake compilation:
46-
* For x86 Windows targets: `cmake .. -DCMAKE_TOOLCHAIN_FILE="../cmake-toolchain/WindowsUserMode-X86.cmake" -A Win32`
59+
1. In step 4 below, add the additional cmake argument `-DSYMCRYPT_INTERNAL_BUILD=1`
60+
1. `mkdir bin; cd bin`
61+
1. Use the appropriate CMake arguments to specify which architecture you want to compile for:
4762
* For x86-64 Windows targets: `cmake .. -DCMAKE_TOOLCHAIN_FILE="../cmake-toolchain/WindowsUserMode-AMD64.cmake"`
63+
* For x86 Windows targets: `cmake .. -DCMAKE_TOOLCHAIN_FILE="../cmake-toolchain/WindowsUserMode-X86.cmake" -A Win32`
4864
* For x86-64 Linux targets: `cmake .. -DCMAKE_TOOLCHAIN_FILE="../cmake-toolchain/LinuxUserMode-AMD64.cmake"`
65+
* For x86 Linux targets **no ASM optimizations**: `cmake .. -DCMAKE_TOOLCHAIN_FILE="../cmake-toolchain/LinuxUserMode-X86.cmake"`
4966
* For ARM64 Linux targets: `cmake .. -DCMAKE_TOOLCHAIN_FILE="../cmake-toolchain/LinuxUserMode-ARM64.cmake"`
50-
* For no CPU optimizations: `cmake ..`
67+
* To use the host system architecture **with no ASM optimizations**: `cmake ..`
5168
* Optionally, for a release build, specify `-DCMAKE_BUILD_TYPE=Release`
52-
5. `cmake --build .`
69+
1. `cmake --build .`
5370
* Optionally, for a release build on Windows, specify `--config Release`
5471
* Optionally specify `-jN` where N is the number of processes you wish to spawn for the build
5572

56-
If compilation succeeds, the output will be put in the `exe` subdirectory relative to where compilation occurred
57-
(i.e. `bin/exe` if you followed the instructions above).
73+
After successful compilation, the generated binaries will be placed in the following directories relative
74+
to your build directory:
75+
* `lib/\<arch\>/\<environment\>/` - static libraries
76+
* `module\<arch\>/\<environment\>/` - shared object libraries (currently only on Linux)
77+
* `exe/\<arch\>/\<environment\>/` - unit tests
5878

59-
The SymCrypt unit test is in the `unittest` directory. It runs extensive functional tests on the SymCrypt
60-
library. On Windows it also compares results against on other implementations such as the Windows APIs CNG
61-
and CAPI, and the older crypto libraries rsa32 and msbignum, if they are available. It also provides
62-
detailed performance information.
79+
# Testing
80+
The SymCrypt unit test runs extensive functional tests on the SymCrypt library. On Windows it also compares results
81+
against on other implementations such as the Windows APIs CNG and CAPI, and the older crypto libraries rsa32 and
82+
msbignum, if they are available. It also provides detailed performance information.
6383

6484
# Versioning and Servicing
6585
As of version 101.0.0, SymCrypt uses the version scheme defined by the

azure-build-template.yml

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ parameters:
5151
values:
5252
- native
5353
- qemu-aarch64
54+
- name: testInPrBuild
55+
type: boolean
56+
default: true
5457

5558
steps:
5659
- checkout: self # self represents the repo where the initial Pipelines YAML file was found
@@ -63,12 +66,17 @@ steps:
6366
python -m pip install --upgrade pip setuptools wheel
6467
pip install -r $(Build.SourcesDirectory)/scripts/requirements.txt
6568
displayName: 'Install Python requirements'
66-
- ${{ if eq(parameters.emulator, 'qemu-aarch64') }}:
67-
- script: |
68-
sudo apt-get update
69-
sudo apt-get install qemu-user binutils-aarch64-linux-gnu
70-
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
71-
displayName: 'Install arm64 cross-compilation and emulation tools'
69+
- ${{ if eq(parameters.arch, 'X86') }}:
70+
- script: |
71+
sudo apt-get update
72+
sudo apt-get install gcc-multilib g++-multilib
73+
displayName: 'Install x86 headers and libraries'
74+
- ${{ if eq(parameters.emulator, 'qemu-aarch64') }}:
75+
- script: |
76+
sudo apt-get update
77+
sudo apt-get install qemu-user binutils-aarch64-linux-gnu
78+
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
79+
displayName: 'Install arm64 cross-compilation and emulation tools'
7280
# Specify no toolchain file for generic build
7381
- ${{ if eq(parameters.env, 'Generic') }}:
7482
- task: CMake@1
@@ -98,14 +106,14 @@ steps:
98106
workingDirectory: '$(Build.SourcesDirectory)/bin'
99107
cmakeArgs: '--build . -j --config ${{parameters.buildType}}'
100108
# Execute unit tests using the inline script
101-
- ${{ if ne(parameters.env, 'Generic') }}:
109+
- ${{ if eq(parameters.testInPrBuild, true) }}:
102110
- script: |
103111
cd bin\exe\${{parameters.arch}}\${{parameters.env}}\${{parameters.buildType}}
104112
.\symcryptunittest.exe dynamic:symcrypttestmodule.dll
105113
displayName: 'Execute unit tests with SymCrypt test module'
106114
name: '${{parameters.env}}UnitTest_${{parameters.buildType}}'
107115
# Execute Generic unit tests in CI and in PRs to publish
108-
- ${{ if eq(parameters.env, 'Generic') }}:
116+
- ${{ if eq(parameters.testInPrBuild, false) }}:
109117
- script: |
110118
cd bin\exe\%PROCESSOR_ARCHITECTURE%\${{parameters.env}}\${{parameters.buildType}}
111119
.\symcryptunittest.exe dynamic:symcrypttestmodule.dll
@@ -124,7 +132,7 @@ steps:
124132
ulimit -c unlimited
125133
cp $(Build.SourcesDirectory)/.artifactignore $(Agent.WorkFolder)
126134
displayName: 'Enable core dumps & Place .artifactignore file'
127-
- ${{ if ne(parameters.env, 'Generic') }}:
135+
- ${{ if eq(parameters.testInPrBuild, true) }}:
128136
# Execute unit test using the inline script
129137
- ${{ if eq(parameters.emulator, 'native') }}:
130138
- script: |
@@ -169,19 +177,19 @@ steps:
169177
displayName: 'Execute unit tests with generic SymCrypt module'
170178
name: '${{parameters.env}}UnitTestDynamicGeneric_${{parameters.buildType}}_QEMU_AARCH64'
171179
# Execute Generic unit tests in CI and in PRs to publish
172-
- ${{ if eq(parameters.env, 'Generic') }}:
180+
- ${{ if eq(parameters.testInPrBuild, false) }}:
173181
- script: |
174182
archName=`uname -m`
175183
cd bin/exe/${archName}/${{parameters.env}}
176-
./symcryptunittest
184+
./symcryptunittest noperftests
177185
displayName: 'Execute unit tests'
178186
name: '${{parameters.env}}UnitTest_${{parameters.buildType}}'
179187
condition: or(eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/publish'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI'))
180188
# Run unit tests against the generic SymCrypt module
181189
- script: |
182190
archName=`uname -m`
183191
cd bin/exe/${archName}/${{parameters.env}}
184-
./symcryptunittest dynamic:../../../module/${archName}/${{parameters.env}}/generic/libsymcrypt.so
192+
./symcryptunittest dynamic:../../../module/${archName}/${{parameters.env}}/generic/libsymcrypt.so noperftests
185193
displayName: 'Execute unit tests with generic SymCrypt module'
186194
name: '${{parameters.env}}UnitTestDynamicGeneric_${{parameters.buildType}}'
187195
condition: or(eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/publish'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI'))

azure-pipelines.yml

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ pr:
3232
# The following 4 jobs only run the unit tests on CI and PRs to publish (they are always built)
3333
# 13. Windows 64b with no CPU optimizations in Release mode
3434
# 14. Windows 32b with no CPU optimizations in Release mode
35-
# 15. Linux with no CPU optimizations using GCC in Release mode
36-
# 16. Linux with no CPU optimizations using clang in Release mode
35+
# 15. Linux 64b with no CPU optimizations using GCC in Release mode
36+
# 16. Linux 64b with no CPU optimizations using clang in Release mode
37+
# 17. Linux 32b with no CPU optimizations using GCC in Release mode
3738

3839
jobs:
3940
- job: Windows_AMD64_Debug
@@ -106,7 +107,6 @@ jobs:
106107
cc: gcc
107108
cxx: g++
108109
buildType: Debug
109-
additionalCMakeArgs:
110110

111111
- job: Linux_AMD64_gcc_Sanitize
112112
pool:
@@ -120,7 +120,6 @@ jobs:
120120
cc: gcc
121121
cxx: g++
122122
buildType: Sanitize
123-
additionalCMakeArgs:
124123

125124
- job: Linux_AMD64_gcc_Release
126125
pool:
@@ -134,7 +133,6 @@ jobs:
134133
cc: gcc
135134
cxx: g++
136135
buildType: Release
137-
additionalCMakeArgs:
138136

139137
- job: Linux_AMD64_clang_Debug
140138
pool:
@@ -148,7 +146,6 @@ jobs:
148146
cc: clang
149147
cxx: clang++
150148
buildType: Debug
151-
additionalCMakeArgs:
152149

153150
- job: Linux_AMD64_clang_Sanitize
154151
pool:
@@ -162,7 +159,6 @@ jobs:
162159
cc: clang
163160
cxx: clang++
164161
buildType: Sanitize
165-
additionalCMakeArgs:
166162

167163
- job: Linux_AMD64_clang_Release
168164
pool:
@@ -176,7 +172,6 @@ jobs:
176172
cc: clang
177173
cxx: clang++
178174
buildType: Release
179-
additionalCMakeArgs:
180175

181176
- job: Linux_QEMU_ARM64_clang_Debug
182177
pool:
@@ -190,7 +185,6 @@ jobs:
190185
cc: clang
191186
cxx: clang++
192187
buildType: Debug
193-
additionalCMakeArgs:
194188
emulator: qemu-aarch64
195189

196190
- job: Linux_QEMU_ARM64_clang_Release
@@ -205,7 +199,6 @@ jobs:
205199
cc: clang
206200
cxx: clang++
207201
buildType: Release
208-
additionalCMakeArgs:
209202
emulator: qemu-aarch64
210203

211204
- job: Generic_Windows_Win64_Release
@@ -220,7 +213,7 @@ jobs:
220213
cc: cl
221214
cxx: cl
222215
buildType: Release
223-
additionalCMakeArgs:
216+
testInPrBuild: false
224217
timeoutInMinutes: 120
225218

226219
- job: Generic_Windows_Win32_Release
@@ -236,9 +229,10 @@ jobs:
236229
cxx: cl
237230
buildType: Release
238231
additionalCMakeArgs: -A Win32
232+
testInPrBuild: false
239233
timeoutInMinutes: 120
240234

241-
- job: Generic_Linux_gcc_Release
235+
- job: Generic_Linux64_gcc_Release
242236
pool:
243237
vmImage: 'ubuntu-20.04'
244238
steps:
@@ -250,10 +244,10 @@ jobs:
250244
cc: gcc
251245
cxx: g++
252246
buildType: Release
253-
additionalCMakeArgs:
247+
testInPrBuild: false
254248
timeoutInMinutes: 120
255249

256-
- job: Generic_Linux_clang_Release
250+
- job: Generic_Linux64_clang_Release
257251
pool:
258252
vmImage: 'ubuntu-20.04'
259253
steps:
@@ -265,5 +259,20 @@ jobs:
265259
cc: clang
266260
cxx: clang++
267261
buildType: Release
268-
additionalCMakeArgs:
262+
testInPrBuild: false
269263
timeoutInMinutes: 120
264+
265+
- job: Generic_Linux32_gcc_Release
266+
pool:
267+
vmImage: 'ubuntu-20.04'
268+
steps:
269+
- template: azure-build-template.yml
270+
parameters:
271+
hostos: Linux
272+
env: LinuxUserMode # Not using Generic environment because we have to add -m32 compiler/linker options
273+
arch: X86
274+
cc: gcc
275+
cxx: g++
276+
buildType: Release
277+
testInPrBuild: false
278+
timeoutInMinutes: 120
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# This toolchain file configures CMake options for Linux User Mode X86 compilation with CPU optimizations.
2+
# To use the toolchain file, run cmake .. -DCMAKE_TOOLCHAIN_FILE="cmake-toolchain/LinuxUserMode-X86.cmake"
3+
4+
# Set CMake variables that subsequent CMake scripts can check against
5+
set(CMAKE_SYSTEM_NAME Linux)
6+
set(CMAKE_SYSTEM_PROCESSOR X86)
7+
8+
# For now this is just used for separating the output directories
9+
set(SYMCRYPT_TARGET_ENV LinuxUserMode)
10+
11+
add_compile_options("-m32")
12+
add_link_options("-m32")
13+
14+
# 32-bit ASM needs to be translated from MASM to SymCryptAsm, so we don't support ASM optimizations
15+
# on 32-bit Linux for now
16+
add_compile_options("-DSYMCRYPT_IGNORE_PLATFORM")
17+
18+
set(CMAKE_ASM_FLAGS "-x assembler-with-cpp")

lib/env_linuxUserMode.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ SymCryptInitEnvLinuxUsermode( UINT32 version )
5151
// without PLT
5252
void __stack_chk_fail();
5353

54+
// On X86, __stack_chk_fail_local is used as a wrapper for __stack_chk_fail. The compiler should
55+
// generate it for us, but for some reason it is not doing so on gcc 9.4.0.
56+
void __stack_chk_fail_local()
57+
{
58+
__stack_chk_fail();
59+
}
60+
5461
_Analysis_noreturn_
5562
VOID
5663
SYMCRYPT_CALL

lib/sc_lib.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1610,7 +1610,7 @@ extern const BYTE SymCryptSha512KATAnswer[64];
16101610
#if SYMCRYPT_MS_VC
16111611
#define SYMCRYPT_MUL32x32TO64( _a, _b ) UInt32x32To64( (_a), (_b) )
16121612
#elif SYMCRYPT_GNUC
1613-
#define SYMCRYPT_MUL32x32TO64( _a, _b ) ( (unsigned long)(_a)*(unsigned long)(_b) )
1613+
#define SYMCRYPT_MUL32x32TO64( _a, _b ) ( (UINT64)(_a)*(UINT64)(_b) )
16141614
#else
16151615
#error Unknown compiler
16161616
#endif

modules_linux/common/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ add_library(symcrypt_module_linux_common STATIC ${SOURCES})
88

99
set(jitter_cflags "${CMAKE_C_FLAGS} -fwrapv -fvisibility=hidden")
1010
set(jitter_ldflags "")
11+
12+
if(CMAKE_SYSTEM_PROCESSOR MATCHES X86)
13+
set(jitter_cflags "${jitter_cflags} -m32")
14+
set(jitter_ldflags "-m32")
15+
endif()
16+
1117
if (CMAKE_C_COMPILER_ID MATCHES "Clang" AND DEFINED CMAKE_C_COMPILER_TARGET)
1218
set(jitter_cflags "--target=${CMAKE_C_COMPILER_TARGET} --sysroot=${CMAKE_SYSROOT_COMPILE} ${jitter_cflags}")
1319
set(jitter_ldflags "--target=${CMAKE_C_COMPILER_TARGET}")

0 commit comments

Comments
 (0)