Commit 6525fb3
authored
Add opt-in QUIC_OPENSSL_SYMBOL_PREFIX to namespace bundled OpenSSL symbols (Linux) (#6031)
## Description
This PR adds an **opt-in** CMake cache variable,
`QUIC_OPENSSL_SYMBOL_PREFIX`, that namespace-prefixes every
globally-visible symbol in the bundled OpenSSL static archives (and
rewrites MsQuic's own undefined references to match). When
`QUIC_OPENSSL_SYMBOL_PREFIX` is left empty (the default), no new code
runs and the build is byte-for-byte identical to today.
### Motivation
When MsQuic is statically linked into a process that also pulls in
another copy of OpenSSL — for example, a system `libcrypto.so.3` brought
in transitively by an unrelated dependency (a logging library, a
database client, any C++ library that itself uses OpenSSL) — the two
OpenSSL copies share the same global C symbols (`SSL_CTX_new`, `EVP_*`,
`BN_*`, `ERR_*`, the per-module init constructors, …). The dynamic
linker resolves every reference to the **first definition loaded**, so
all callers — including MsQuic — silently end up sharing one OpenSSL's
state machine while their headers and ABI assumptions came from the
other. Typical symptoms:
- Crashes in `OPENSSL_init_crypto` / `RAND_load_file` when one OpenSSL's
per-module init runs against the other's global registries.
- Spurious SSL handshake failures when callbacks installed against one
`SSL_CTX` see the other's vtable layout.
- ABI mismatches when one OpenSSL is `3.0.x` (system `libcrypto.so.3` on
Ubuntu 22.04 / RHEL 9) and MsQuic's bundled OpenSSL is `3.5.x` (required
for `SSL_set_quic_tls_cbs`).
Note that MsQuic's bundled-OpenSSL path always links `libssl.a` /
`libcrypto.a` **statically** into MsQuic, regardless of
`QUIC_BUILD_SHARED` — `SHARED` just controls whether the result is
`libmsquic.so` or `libmsquic.a`. Building `SHARED` with
`--exclude-libs=ALL` therefore strips the (statically linked) OpenSSL
symbols from `libmsquic.so`'s dynamic export table, which is sufficient
when the consumer `dlopen`s/links against `libmsquic.so` itself. It does
**not** help:
- Static consumers that link `libmsquic.a` into a final binary — symbols
flow straight into the executable's global table.
- Consumers that bundle `libmsquic.a` into their own `.so` — same
exposure unless they also `--exclude-libs` it.
- Either case at runtime — even with exports hidden, both `libcrypto`s
coexist in one address space and OpenSSL's process-global
init/registries (`OPENSSL_init_crypto`, error/atexit tables, `RAND`
state) can still collide.
### How it works
When `QUIC_OPENSSL_SYMBOL_PREFIX=<prefix>` is passed at CMake configure
time, the build:
1. Builds the bundled OpenSSL submodule normally to produce `libssl.a`
and `libcrypto.a`.
2. Extracts every globally-defined external symbol from those archives
via `nm --defined-only --extern-only` and writes a redefine-syms file
mapping each `<sym>` to `<prefix><sym>`.
3. Produces prefixed copies via `objcopy --redefine-syms=<file>`
(touches both definitions and undefined references inside each member
object).
4. Applies the same `--redefine-syms` step as a `POST_BUILD` action on
`libmsquic_platform.a` so MsQuic's own undefined references to OpenSSL
(from `tls_openssl.c`, `tls_quictls.c`, `crypt_openssl.c`,
`selfsign_openssl.c`) get rewritten to match.
5. Routes the existing `OpenSSL` interface target at the prefixed
archives, so the rest of the build is unchanged.
The result is a `libmsquic.{a,so}` whose only externally-visible OpenSSL
symbols are the prefixed ones. The dynamic linker has no reason to
resolve them against any other OpenSSL copy present in the same process.
### Constraints
| Constraint | Why |
| --- | --- |
| Linux only (`CX_PLATFORM=linux`) | Uses GNU binutils `objcopy
--redefine-syms`. macOS would need `llvm-objcopy` >= 13 (untested);
PE/COFF lacks a flat-namespace symbol table. Rejected with `FATAL_ERROR`
on other platforms. |
| Bundled OpenSSL only | External/system OpenSSL is owned by the caller
and cannot be renamed. Rejected with `FATAL_ERROR` if combined with
`QUIC_USE_EXTERNAL_OPENSSL`, `QUIC_OPENSSL_INCLUDE_DIR`,
`QUIC_OPENSSL_LIB_DIR`, `QUIC_OPENSSL_ROOT_DIR`, or
`QUIC_USE_SYSTEM_LIBCRYPTO`. |
| Cross-compile aware | `${CMAKE_NM}` / `${CMAKE_OBJCOPY}` are forwarded
to the helper script, so `aarch64-linux-gnu-objcopy` etc. are used when
configured. |
### Files
- `cmake/openssl-prefix-rename.sh` — helper script (`gen-syms` / `apply`
modes; honors `NM` / `OBJCOPY` env vars).
- `cmake/PrefixOpenSSLArchives.cmake` — helper function
`prefix_openssl_archives(PREFIX … INPUT_TARGET … OUTPUT_TARGET …)`.
- `CMakeLists.txt` — new option + validation + plumbing in the
bundled-OpenSSL branch.
- `src/platform/CMakeLists.txt` — `POST_BUILD` rename on
`libmsquic_platform.a`.
- `docs/OpenSSLSymbolPrefix.md` — motivation, usage, caveats,
verification recipe.
### Future direction
The cleanest long-term solution is for OpenSSL itself to expose a
configure-time `--symbol-prefix=` option that compiles every public
symbol with the prefix baked in (an analog of BoringSSL's
`BSSL_NAMESPACE` or LibreSSL's recurring discussion). I plan to file
that issue upstream with this PR linked as concrete prior art
demonstrating consumer demand. Until that lands, this CMake helper
provides an equivalent at link time without requiring an OpenSSL fork.
## Testing
### Manual verification (local, this PR's branch)
Built on Linux x86_64 with `-G Ninja -DQUIC_TLS_LIB=quictls
-DQUIC_BUILD_SHARED=OFF`:
**With `-DQUIC_OPENSSL_SYMBOL_PREFIX=msqtest_`:**
```bash
# 0 unprefixed defined globals in the renamed archives:
nm --defined-only --extern-only build/openssl-prefixed/msqtest_/libssl.a \
| awk '$2 ~ /^[TDRBWVC]$/ {print $3}' | grep -vc '^msqtest_' # → 0
nm --defined-only --extern-only build/openssl-prefixed/msqtest_/libcrypto.a \
| awk '$2 ~ /^[TDRBWVC]$/ {print $3}' | grep -vc '^msqtest_' # → 0
# 0 unprefixed OpenSSL undefs in msquic_platform.a, 161 prefixed undefs:
nm -u build/obj/Release/libmsquic_platform.a | awk '$1=="U"{print $2}' \
| grep -E '^(SSL_|EVP_|BN_|ERR_|X509_|OPENSSL_|RAND_|RSA_|EC_|BIO_|ASN1_|PEM_|CRYPTO_)' \
| wc -l # → 0
nm -u build/obj/Release/libmsquic_platform.a | awk '$1=="U"{print $2}' \
| grep -c '^msqtest_' # → 161
```
**Without the option (default build):**
- 138 normal unprefixed OpenSSL undefs in `libmsquic_platform.a`.
- `build/openssl-prefixed/` directory not created.
- Build time identical to baseline (no new compilation; the rename rules
simply don't fire).
### Production validation
The same prefix-rename technique has been deployed in Microsoft's
[meru](https://github.com/microsoft/meru-common) codebase (a consumer of
MsQuic). It is currently validated across this matrix:
- `Release` x86_64
- `Release_ASAN`, `Debug_ASAN`, `Debug_UBSAN`, `Debug_TSAN` x86_64
- `arm_debug_crosscompile` (aarch64)
- `clang_tidy`
See
[microsoft/meru-common#4011](microsoft/meru-common#4011)
for the consumer-side integration that ports the same helper script +
CMake module pattern that this PR upstreams.
### MsQuic CI coverage
The default (option-empty) path is unchanged, so existing CI should be
unaffected. The option-set path is Linux-only and opt-in, so it does not
need to enter the default matrix. Happy to add a single Linux CI leg
that exercises `-DQUIC_OPENSSL_SYMBOL_PREFIX=msquic_` if maintainers
think that's worthwhile.
## Documentation
New file: `docs/OpenSSLSymbolPrefix.md` documents motivation, usage,
constraints, and a verification recipe.1 parent af14a2c commit 6525fb3
5 files changed
Lines changed: 560 additions & 4 deletions
File tree
- cmake
- docs
- src/platform
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| 44 | + | |
| 45 | + | |
44 | 46 | | |
45 | 47 | | |
46 | 48 | | |
| |||
113 | 115 | | |
114 | 116 | | |
115 | 117 | | |
| 118 | + | |
116 | 119 | | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
117 | 140 | | |
118 | 141 | | |
119 | 142 | | |
| |||
811 | 834 | | |
812 | 835 | | |
813 | 836 | | |
814 | | - | |
815 | | - | |
816 | | - | |
817 | | - | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
818 | 877 | | |
819 | 878 | | |
820 | 879 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
0 commit comments