|
27 | 27 | #include <stdlib.h> |
28 | 28 | #include <string.h> |
29 | 29 | #include <assert.h> |
| 30 | +#ifdef OSCAP_THREAD_SAFE |
| 31 | +#include <pthread.h> |
| 32 | +#endif |
30 | 33 |
|
31 | 34 | #include <libxml/tree.h> |
32 | 35 | #include <libxml/xmlmemory.h> |
|
46 | 49 | #include "oscap_source_priv.h" |
47 | 50 | #include "signature_priv.h" |
48 | 51 |
|
| 52 | +#ifdef OSCAP_THREAD_SAFE |
| 53 | +static pthread_once_t xmlsec_init_once = PTHREAD_ONCE_INIT; |
| 54 | +#else |
| 55 | +static bool xmlsec_init_done = false; |
| 56 | +#endif |
| 57 | +static int xmlsec_init_result = -1; |
| 58 | + |
| 59 | +static void _xmlsec_init(void) |
| 60 | +{ |
| 61 | + if (xmlSecInit() < 0) { |
| 62 | + oscap_seterr(OSCAP_EFAMILY_XML, "Xmlsec initialization failed."); |
| 63 | + return; |
| 64 | + } |
| 65 | + if (xmlSecCheckVersion() != 1) { |
| 66 | + oscap_seterr(OSCAP_EFAMILY_XML, "Loaded xmlsec library version is not compatible."); |
| 67 | + return; |
| 68 | + } |
| 69 | + if (xmlSecCryptoAppInit(NULL) < 0) { |
| 70 | + oscap_seterr(OSCAP_EFAMILY_XML, "Crypto initialization failed."); |
| 71 | + return; |
| 72 | + } |
| 73 | + if (xmlSecCryptoInit() < 0) { |
| 74 | + oscap_seterr(OSCAP_EFAMILY_XML, "Xmlsec-crypto initialization failed."); |
| 75 | + return; |
| 76 | + } |
| 77 | + xmlsec_init_result = 0; |
| 78 | +} |
| 79 | + |
| 80 | +static int _xmlsec_ensure_init(void) |
| 81 | +{ |
| 82 | +#ifdef OSCAP_THREAD_SAFE |
| 83 | + pthread_once(&xmlsec_init_once, _xmlsec_init); |
| 84 | +#else |
| 85 | + if (!xmlsec_init_done) { |
| 86 | + xmlsec_init_done = true; |
| 87 | + _xmlsec_init(); |
| 88 | + } |
| 89 | +#endif |
| 90 | + return xmlsec_init_result; |
| 91 | +} |
| 92 | + |
49 | 93 | struct oscap_signature_ctx { |
50 | 94 | const char *pubkey_pem; // path to the public key file in PEM format |
51 | 95 | const char *pubkey_cert_pem; // path to the public key certificate file in PEM format |
@@ -131,28 +175,20 @@ static int _oscap_signature_validate_doc(xmlDocPtr doc, oscap_document_type_t sc |
131 | 175 | xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid); |
132 | 176 | xsltSetDefaultSecurityPrefs(xsltSecPrefs); |
133 | 177 |
|
134 | | - /* Init xmlsec library */ |
135 | | - if (xmlSecInit() < 0) { |
136 | | - oscap_seterr(OSCAP_EFAMILY_XML, "Xmlsec initialization failed."); |
137 | | - return(-1); |
138 | | - } |
139 | | - |
140 | | - /* Check loaded library version */ |
141 | | - if (xmlSecCheckVersion() != 1) { |
142 | | - oscap_seterr(OSCAP_EFAMILY_XML, "Loaded xmlsec library version is not compatible."); |
143 | | - return(-1); |
144 | | - } |
145 | | - |
146 | | - /* Init crypto library */ |
147 | | - if (xmlSecCryptoAppInit(NULL) < 0) { |
148 | | - oscap_seterr(OSCAP_EFAMILY_XML, "Crypto initialization failed."); |
149 | | - return(-1); |
150 | | - } |
151 | | - |
152 | | - /* Init xmlsec-crypto library */ |
153 | | - if (xmlSecCryptoInit() < 0) { |
154 | | - oscap_seterr(OSCAP_EFAMILY_XML, "Xmlsec-crypto initialization failed."); |
155 | | - return(-1); |
| 178 | + /* Initialize xmlsec and crypto libraries once per process. |
| 179 | + * |
| 180 | + * xmlSecCryptoAppShutdown() calls OPENSSL_cleanup() which is |
| 181 | + * irreversible and destroys all process-global OpenSSL state |
| 182 | + * including threading locks. Other libraries in the same process |
| 183 | + * (e.g. librpm) continue to use OpenSSL after signature validation |
| 184 | + * completes. Calling OPENSSL_cleanup() while they are active causes |
| 185 | + * a segfault in CRYPTO_THREAD_write_lock. |
| 186 | + * |
| 187 | + * The xmlsec/OpenSSL libraries are designed to be initialized once |
| 188 | + * and remain active for the process lifetime. Treat them as such. |
| 189 | + */ |
| 190 | + if (_xmlsec_ensure_init() < 0) { |
| 191 | + goto cleanup; |
156 | 192 | } |
157 | 193 |
|
158 | 194 | /* find Signature node */ |
@@ -261,22 +297,18 @@ static int _oscap_signature_validate_doc(xmlDocPtr doc, oscap_document_type_t sc |
261 | 297 | } |
262 | 298 |
|
263 | 299 | cleanup: |
264 | | - /* cleanup */ |
| 300 | + /* cleanup per-validation resources only */ |
265 | 301 | if (dsigCtx != NULL) |
266 | 302 | xmlSecDSigCtxDestroy(dsigCtx); |
267 | 303 |
|
268 | | - /* destroy keys manager */ |
269 | 304 | if (mngr != NULL) |
270 | 305 | xmlSecKeysMngrDestroy(mngr); |
271 | 306 |
|
272 | | - /* Shutdown xmlsec-crypto library */ |
273 | | - xmlSecCryptoShutdown(); |
274 | | - |
275 | | - /* Shutdown crypto library */ |
276 | | - xmlSecCryptoAppShutdown(); |
277 | | - |
278 | | - /* Shutdown xmlsec library */ |
279 | | - xmlSecShutdown(); |
| 307 | + /* Do NOT call xmlSecCryptoShutdown(), xmlSecCryptoAppShutdown(), |
| 308 | + * or xmlSecShutdown() here. These destroy process-global state |
| 309 | + * (including OPENSSL_cleanup()) that other libraries rely on. |
| 310 | + * The resources are cleaned up at process exit. |
| 311 | + */ |
280 | 312 |
|
281 | 313 | /* Shutdown libxslt/libxml */ |
282 | 314 | xsltFreeSecurityPrefs(xsltSecPrefs); |
|
0 commit comments