Skip to content

Commit ed8dfdc

Browse files
committed
Fixes issues with dynamic loading OpenSSL. Fixes #13903.
This fixes at least a couple of issues: * Procs loaded from the DLL being used even when the pointer is nil. * The actual issue (#13903) which appeared to cause stack corruption on Android 7.1.1 with OpenSSL 1.1.1f. The change that fixed this was the move to loading the procs in `sslSym`.
1 parent c835c8c commit ed8dfdc

File tree

1 file changed

+39
-19
lines changed

1 file changed

+39
-19
lines changed

lib/wrappers/openssl.nim

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ proc TLSv1_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
244244
# and support SSLv3, TLSv1, TLSv1.1 and TLSv1.2
245245
# SSLv23_method(), SSLv23_server_method(), SSLv23_client_method() are removed in 1.1.0
246246

247-
when compileOption("dynlibOverride", "ssl"):
247+
when compileOption("dynlibOverride", "ssl") or defined(noOpenSSLHacks):
248248
# Static linking
249249

250250
when defined(openssl10):
@@ -285,40 +285,59 @@ else:
285285
proc thisModule(): LibHandle {.inline.} =
286286
var thisMod {.global.}: LibHandle
287287
if thisMod.isNil: thisMod = loadLib()
288+
288289
result = thisMod
289290

290291
proc sslModule(): LibHandle {.inline.} =
291292
var sslMod {.global.}: LibHandle
292293
if sslMod.isNil: sslMod = loadLibPattern(DLLSSLName)
294+
293295
result = sslMod
294296

295-
proc sslSym(name: string): pointer =
296-
var dl = thisModule()
297-
if not dl.isNil:
298-
result = symAddr(dl, name)
297+
proc sslSymNullable(name: string, alternativeName = ""): pointer =
298+
# Load from DLL.
299+
var sslDynlib = sslModule()
300+
if not sslDynlib.isNil:
301+
result = symAddr(sslDynlib, name)
302+
if result.isNil and alternativeName.len > 0:
303+
result = symAddr(sslDynlib, alternativeName)
304+
305+
# Attempt to load from current exe.
299306
if result.isNil:
300-
dl = sslModule()
301-
if not dl.isNil:
302-
result = symAddr(dl, name)
307+
let thisDynlib = thisModule()
308+
if thisDynlib.isNil: return nil
309+
result = symAddr(thisDynlib, name)
310+
if result.isNil and alternativeName.len > 0:
311+
result = symAddr(sslDynlib, alternativeName)
312+
313+
proc sslSymThrows(name: string, alternativeName = ""): pointer =
314+
result = sslSymNullable(name, alternativeName)
315+
if result.isNil: raiseInvalidLibrary(name)
303316

304317
proc loadPSSLMethod(method1, method2: string): PSSL_METHOD =
305318
## Load <method1> from OpenSSL if available, otherwise <method2>
306-
let m1 = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym(method1))
307-
if not m1.isNil:
308-
return m1()
309-
cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym(method2))()
319+
##
320+
let methodSym = sslSymNullable(method1, method2)
321+
if methodSym.isNil:
322+
raise newException(LibraryError, "Could not load " & method1 & " nor " & method2)
323+
324+
let method2Proc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](methodSym)
325+
return method2Proc()
310326

311327
proc SSL_library_init*(): cint {.discardable.} =
312328
## Initialize SSL using OPENSSL_init_ssl for OpenSSL >= 1.1.0 otherwise
313329
## SSL_library_init
314-
let theProc = cast[proc(opts: uint64, settings: uint8): cint {.cdecl.}](sslSym("OPENSSL_init_ssl"))
315-
if not theProc.isNil:
316-
return theProc(0, 0)
317-
let olderProc = cast[proc(): cint {.cdecl.}](sslSym("SSL_library_init"))
330+
let newInitSym = sslSymNullable("OPENSSL_init_ssl")
331+
if not newInitSym.isNil:
332+
let newInitProc =
333+
cast[proc(opts: uint64, settings: uint8): cint {.cdecl.}](newInitSym)
334+
return newInitProc(0, 0)
335+
let olderProc = cast[proc(): cint {.cdecl.}](sslSymThrows("SSL_library_init"))
318336
if not olderProc.isNil: result = olderProc()
319337

320338
proc SSL_load_error_strings*() =
321-
let theProc = cast[proc() {.cdecl.}](sslSym("SSL_load_error_strings"))
339+
# TODO: Are we ignoring this on purpose? SSL GitHub CI fails otherwise.
340+
let theProc = cast[proc() {.cdecl.}](sslSymNullable("SSL_load_error_strings"))
322341
if not theProc.isNil: theProc()
323342

324343
proc SSLv23_client_method*(): PSSL_METHOD =
@@ -343,12 +362,13 @@ else:
343362
loadPSSLMethod("TLS_server_method", "SSLv23_server_method")
344363

345364
proc OpenSSL_add_all_algorithms*() =
346-
let theProc = cast[proc() {.cdecl.}](sslSym("OPENSSL_add_all_algorithms_conf"))
365+
# TODO: Are we ignoring this on purpose? SSL GitHub CI fails otherwise.
366+
let theProc = cast[proc() {.cdecl.}](sslSymNullable("OPENSSL_add_all_algorithms_conf"))
347367
if not theProc.isNil: theProc()
348368

349369
proc getOpenSSLVersion*(): culong =
350370
## Return OpenSSL version as unsigned long or 0 if not available
351-
let theProc = cast[proc(): culong {.cdecl.}](sslSym("OpenSSL_version_num"))
371+
let theProc = cast[proc(): culong {.cdecl.}](sslSymNullable("OpenSSL_version_num"))
352372
result =
353373
if theProc.isNil: 0.culong
354374
else: theProc()

0 commit comments

Comments
 (0)