Skip to content

Commit b75eda1

Browse files
authored
Build option for OpenSSF Compiler Hardening Flags (onnx#7601)
### Motivation and Context I think we should implement the OpenSSF Compiler Hardening Flags to address the following requirement for the Silver Badge (https://www.bestpractices.dev/en/projects/3313/silver#security): Hardening mechanisms SHOULD be used in the software produced by the project so that software defects are less likely to result in security vulnerabilities. [hardening] Hardening mechanisms may include HTTP headers like Content Security Policy (CSP), compiler flags to mitigate attacks (such as -fstack-protector), or compiler flags to eliminate undefined behavior. For our purposes least privilege is not considered a hardening mechanism (least privilege is important, but separate). Fixes: onnx#6834 --------- Signed-off-by: Andreas Fehlner <fehlner@arcor.de>
1 parent a9767a2 commit b75eda1

File tree

17 files changed

+162
-49
lines changed

17 files changed

+162
-49
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ jobs:
156156
DEBUG: ${{ matrix.debug_build }}
157157
ONNX_ML: ${{ matrix.onnx_ml }}
158158
ONNX_BUILD_TESTS: 1
159-
CMAKE_ARGS: "-DONNX_WERROR=ON -DONNX_USE_ASAN=${{ matrix.debug_build }} -DONNX_USE_UNITY_BUILD=${{ matrix.unity_build }}"
159+
CMAKE_ARGS: "-DONNX_WERROR=ON -DONNX_USE_ASAN=${{ matrix.debug_build }} -DONNX_USE_UNITY_BUILD=${{ matrix.unity_build }} -DONNX_HARDENING=ON"
160160

161161
- name: Build and install ONNX - MacOS
162162
if: matrix.os == 'macos-latest'
@@ -166,7 +166,7 @@ jobs:
166166
DEBUG: ${{ matrix.debug_build }}
167167
ONNX_ML: ${{ matrix.onnx_ml }}
168168
ONNX_BUILD_TESTS: 1
169-
CMAKE_ARGS: "-DONNX_WERROR=ON -DONNX_USE_UNITY_BUILD=${{ matrix.unity_build }}"
169+
CMAKE_ARGS: "-DONNX_WERROR=ON -DONNX_USE_UNITY_BUILD=${{ matrix.unity_build }} -DONNX_HARDENING=ON"
170170

171171
- name: Build and install ONNX - Windows
172172
if: startsWith(matrix.os,'windows')
@@ -176,7 +176,7 @@ jobs:
176176
DEBUG: ${{ matrix.debug_build }}
177177
ONNX_ML: ${{ matrix.onnx_ml }}
178178
ONNX_BUILD_TESTS: 1
179-
CMAKE_ARGS: "-DONNX_WERROR=ON -DONNX_USE_PROTOBUF_SHARED_LIBS=OFF -DONNX_USE_LITE_PROTO=ON -DONNX_USE_UNITY_BUILD=${{ matrix.unity_build }}"
179+
CMAKE_ARGS: "-DONNX_WERROR=ON -DONNX_USE_PROTOBUF_SHARED_LIBS=OFF -DONNX_USE_LITE_PROTO=ON -DONNX_USE_UNITY_BUILD=${{ matrix.unity_build }} -DONNX_HARDENING=ON"
180180

181181
- name: pip freeze
182182
run: |

.github/workflows/manylinux/entrypoint.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ source workflow_scripts/protobuf/build_protobuf_unix.sh "$(nproc)" "$(pwd)"/prot
4646

4747
# set ONNX build environments
4848
export ONNX_ML=1
49-
export CMAKE_ARGS="-DONNX_USE_LITE_PROTO=ON"
49+
export CMAKE_ARGS="-DONNX_USE_LITE_PROTO=ON -DONNX_HARDENING=ON"
5050

5151
$PIP_INSTALL_COMMAND -v -r requirements-release_build.txt || { echo "Installing Python requirements failed."; exit 1; }
5252

.github/workflows/release_win.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ jobs:
8989
# Build ONNX wheel
9090
echo "Install ONNX"
9191
$Env:ONNX_ML = 1
92-
$Env:CMAKE_ARGS = "-DONNX_USE_PROTOBUF_SHARED_LIBS=OFF -DONNX_USE_LITE_PROTO=ON -DONNX_WERROR=ON"
92+
$Env:CMAKE_ARGS = "-DONNX_USE_PROTOBUF_SHARED_LIBS=OFF -DONNX_USE_LITE_PROTO=ON -DONNX_WERROR=ON -DONNX_HARDENING=ON"
9393
9494
# Preview build logic (same for all arches)
9595
if ($env:BUILD_MODE -ne 'release') {

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ option(ONNX_WERROR "Build with Werror" OFF)
4848
option(ONNX_COVERAGE "Build with coverage instrumentation" OFF)
4949
option(ONNX_BUILD_TESTS "Build ONNX C++ APIs Tests" OFF)
5050
option(ONNX_USE_ASAN "Build ONNX with ASAN" OFF)
51+
option(ONNX_HARDENING "Build with compiler hardening flags (OpenSSF guidelines)" OFF)
5152
option(ONNX_USE_LITE_PROTO "Use lite protobuf instead of full." OFF)
5253
option(ONNX_DISABLE_EXCEPTIONS "Disable exception handling." OFF)
5354
option(ONNX_DISABLE_STATIC_REGISTRATION "Disable static registration for ONNX operator schemas." OFF)

cmake/Utils.cmake

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,84 @@
11
# SPDX-License-Identifier: Apache-2.0
22
#
3+
# Compiler hardening flags based on OpenSSF guidelines:
4+
# https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening-Guide-for-C-and-C++.html
5+
function(add_onnx_hardening_flags target)
6+
if(NOT ONNX_HARDENING)
7+
return()
8+
endif()
9+
10+
if(MSVC)
11+
# MSVC hardening flags
12+
target_compile_options(${target} PRIVATE
13+
/GS # Buffer security check
14+
/DYNAMICBASE # ASLR
15+
/NXCOMPAT # Data Execution Prevention
16+
/guard:cf # Control Flow Guard
17+
)
18+
target_link_options(${target} PRIVATE
19+
/DYNAMICBASE
20+
/NXCOMPAT
21+
/GUARD:CF
22+
)
23+
else()
24+
# GCC/Clang hardening compile flags
25+
target_compile_options(${target} PRIVATE
26+
-Wformat
27+
-Wformat=2
28+
-Wimplicit-fallthrough
29+
-Werror=format-security
30+
-fstack-protector-strong
31+
)
32+
33+
# _FORTIFY_SOURCE requires optimization and conflicts with sanitizers
34+
if(NOT ONNX_USE_ASAN)
35+
target_compile_options(${target} PRIVATE
36+
-U_FORTIFY_SOURCE
37+
-D_FORTIFY_SOURCE=3
38+
)
39+
endif()
40+
41+
# C++ standard library assertions
42+
target_compile_definitions(${target} PRIVATE _GLIBCXX_ASSERTIONS)
43+
44+
# Stack clash protection (Linux only - not supported on macOS)
45+
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
46+
include(CheckCXXCompilerFlag)
47+
check_cxx_compiler_flag(-fstack-clash-protection COMPILER_SUPPORTS_STACK_CLASH)
48+
if(COMPILER_SUPPORTS_STACK_CLASH)
49+
target_compile_options(${target} PRIVATE -fstack-clash-protection)
50+
endif()
51+
endif()
52+
53+
# Control-flow protection for x86_64 (Linux only - not supported on macOS)
54+
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
55+
include(CheckCXXCompilerFlag)
56+
check_cxx_compiler_flag(-fcf-protection=full COMPILER_SUPPORTS_CF_PROTECTION)
57+
if(COMPILER_SUPPORTS_CF_PROTECTION)
58+
target_compile_options(${target} PRIVATE -fcf-protection=full)
59+
endif()
60+
endif()
61+
62+
# Branch protection for AArch64 (Linux only - macOS uses different mechanism)
63+
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64")
64+
include(CheckCXXCompilerFlag)
65+
check_cxx_compiler_flag(-mbranch-protection=standard COMPILER_SUPPORTS_BRANCH_PROTECTION)
66+
if(COMPILER_SUPPORTS_BRANCH_PROTECTION)
67+
target_compile_options(${target} PRIVATE -mbranch-protection=standard)
68+
endif()
69+
endif()
70+
71+
# Linker hardening flags (Linux only, not macOS)
72+
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
73+
target_link_options(${target} PRIVATE
74+
-Wl,-z,noexecstack
75+
-Wl,-z,relro
76+
-Wl,-z,now
77+
)
78+
endif()
79+
endif()
80+
endfunction()
81+
382
# Add MSVC RunTime Flag
483
function(add_msvc_runtime_flag lib)
584
if(ONNX_USE_MSVC_STATIC_RUNTIME)
@@ -74,4 +153,7 @@ function(add_onnx_compile_options target)
74153
if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
75154
target_link_libraries(${target} PRIVATE "-lstdc++fs")
76155
endif()
156+
157+
# Apply hardening flags if enabled
158+
add_onnx_hardening_flags(${target})
77159
endfunction()

cmake/summary.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ function(onnx_print_configuration_summary)
2222
message(STATUS " ONNX_DISABLE_EXCEPTIONS : ${ONNX_DISABLE_EXCEPTIONS}")
2323
message(STATUS " ONNX_DISABLE_STATIC_REGISTRATION : ${ONNX_DISABLE_STATIC_REGISTRATION}")
2424
message(STATUS " ONNX_WERROR : ${ONNX_WERROR}")
25+
message(STATUS " ONNX_HARDENING : ${ONNX_HARDENING}")
2526
message(STATUS " ONNX_BUILD_TESTS : ${ONNX_BUILD_TESTS}")
2627
message(STATUS " ONNX_USE_UNITY_BUILD : ${ONNX_USE_UNITY_BUILD}")
2728
message(STATUS " BUILD_SHARED_LIBS : ${BUILD_SHARED_LIBS}")

onnx/common/assertions.cc

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,17 @@ std::string barf(const char* fmt, ...) {
2222

2323
va_start(args, fmt);
2424

25-
// use fixed length for buffer "msg" to avoid buffer overflow
25+
// use fixed length for buffer "msg" to avoid buffer overflow
26+
// Suppress -Wformat-nonliteral: fmt comes from the variadic parameter,
27+
// and call sites are checked via the format attribute on the declaration.
28+
#if defined(__clang__) || defined(__GNUC__)
29+
#pragma GCC diagnostic push
30+
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
31+
#endif
2632
vsnprintf(static_cast<char*>(msg.data()), msg.size() - 1, fmt, args);
33+
#if defined(__clang__) || defined(__GNUC__)
34+
#pragma GCC diagnostic pop
35+
#endif
2736

2837
// ensure null-terminated string to avoid out of bounds read
2938
msg.back() = '\0';

onnx/common/assertions.h

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ struct tensor_error : public assert_error {
2222
explicit tensor_error(const std::string& msg) : assert_error(msg) {}
2323
};
2424

25+
#if defined(__GNUC__) || defined(__clang__)
26+
__attribute__((format(printf, 1, 2)))
27+
#endif
2528
std::string barf(const char* fmt, ...);
2629

2730
[[noreturn]] void throw_assert_error(std::string& /*msg*/);
@@ -48,24 +51,19 @@ std::string barf(const char* fmt, ...);
4851
#define ONNX_EXPAND(x) x
4952

5053
// Note: msg must be a string literal
51-
#define _ONNX_ASSERTM(cond, msg, ...) \
52-
/* NOLINTNEXTLINE */ \
53-
if (_ONNX_EXPECT(!(cond), 0)) { \
54-
std::string error_msg = ::ONNX_NAMESPACE::barf( \
55-
"%s:%u: %s: Assertion `%s` failed: " msg, __FILE__, __LINE__, __func__, #cond, __VA_ARGS__); \
56-
throw_assert_error(error_msg); \
54+
// The ##__VA_ARGS__ extension removes the trailing comma when __VA_ARGS__ is empty.
55+
// This is supported by GCC, Clang, and MSVC (since VS 2019 16.6).
56+
#define ONNX_ASSERTM(cond, msg, ...) \
57+
/* NOLINTNEXTLINE */ \
58+
if (_ONNX_EXPECT(!(cond), 0)) { \
59+
std::string error_msg = ::ONNX_NAMESPACE::barf( \
60+
"%s:%u: %s: Assertion `%s` failed: " msg, __FILE__, __LINE__, __func__, #cond, ##__VA_ARGS__); \
61+
throw_assert_error(error_msg); \
5762
}
5863

59-
// The trailing ' ' argument is a hack to deal with the extra comma when ... is empty.
60-
// Another way to solve this is ##__VA_ARGS__ in _ONNX_ASSERTM, but this is a non-portable
61-
// extension we shouldn't use.
62-
#define ONNX_ASSERTM(...) ONNX_EXPAND(_ONNX_ASSERTM(__VA_ARGS__, " "))
63-
64-
#define _TENSOR_ASSERTM(cond, msg, ...) \
65-
if (_ONNX_EXPECT(!(cond), 0)) { \
66-
std::string error_msg = ::ONNX_NAMESPACE::barf( \
67-
"%s:%u: %s: Assertion `%s` failed: " msg, __FILE__, __LINE__, __func__, #cond, __VA_ARGS__); \
68-
throw_tensor_error(error_msg); \
64+
#define TENSOR_ASSERTM(cond, msg, ...) \
65+
if (_ONNX_EXPECT(!(cond), 0)) { \
66+
std::string error_msg = ::ONNX_NAMESPACE::barf( \
67+
"%s:%u: %s: Assertion `%s` failed: " msg, __FILE__, __LINE__, __func__, #cond, ##__VA_ARGS__); \
68+
throw_tensor_error(error_msg); \
6969
}
70-
71-
#define TENSOR_ASSERTM(...) ONNX_EXPAND(_TENSOR_ASSERTM(__VA_ARGS__, " "))

onnx/defs/schema.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,8 +1762,8 @@ OpName_Domain_Version_Schema_Map& OpSchemaRegistry::map() {
17621762
if (OpSchemaRegistry::Instance()->GetLoadedSchemaVersion() == 0) {
17631763
ONNX_ASSERTM(
17641764
dbg_registered_schema_count == ONNX_DBG_GET_COUNT_IN_OPSETS(),
1765-
"%u schema were exposed from operator sets and automatically placed into the static registry. "
1766-
"%u were expected based on calls to registration macros. Operator set functions may need to be updated.",
1765+
"%zu schema were exposed from operator sets and automatically placed into the static registry. "
1766+
"%zu were expected based on calls to registration macros. Operator set functions may need to be updated.",
17671767
dbg_registered_schema_count,
17681768
ONNX_DBG_GET_COUNT_IN_OPSETS());
17691769
}

onnx/defs/tensor_proto_util.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "tensor_proto_util.h"
66

7+
#include <cstring>
78
#include <string>
89
#include <vector>
910

0 commit comments

Comments
 (0)