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
|
#!/bin/sh
_=[[
. "${0%%/*}/regress.sh"
exec runlua "$0" "$@"
]]
require"regress".export".*"
--
-- Acquire reference to internal openssl loader so we can reinvoke to
-- trigger the bug. The bug is that ex_newstate overwrites the registry
-- index where we stored our exdata state object from a previous invocation
-- of ex_newstate, causing it to be garbage collected.
--
-- When the state object is garbage collected, it invalidates all the
-- outstanding data attached to any extant object. The state object is an
-- interpreter-scoped singleton which should persist for the lifetime of the
-- Lua interpreter. Garbage collection is supposed to signal that the Lua
-- interpreter is being destroyed, and any data belonging to that
-- interpreter and attached to OpenSSL objects is invalid. (NB: The parent
-- application and any OpenSSL objects created from the interpreter can
-- persist after our Lua interpreter. For example in a multithreaded
-- application. Likewise, there can be multiple interpreters, each of which
-- must have its own exdata state.)
--
-- Because ex_newdata is run from initall, and initall is invoked whenever
-- any openssl submodule is loaded, this bug can be triggered by loading a
-- new submodule after installing exdata. Or, as here, it can be triggered
-- by explicitly reinvoking the loader for a submodule.
--
check(package.searchpath, "package.searchpath not defined")
local file, why = package.searchpath("_openssl", package.cpath)
check(file, "module _openssl required")
local reinit = check(package.loadlib(file, "luaopen__openssl_compat"))
local function ticklebug()
reinit()
for i=1,2 do
collectgarbage"collect"
end
end
--
-- Run our test. We don't have a way to force failure with versions of the
-- openssl module that have been fixed.
--
local main = check(cqueues.new())
check(main:wrap(function ()
local alpn_attempts, alpn_issued = 0, 0
local cli_ctx, srv_ctx
cli_ctx = getsslctx("TLSv1", false, false)
check(cli_ctx.setAlpnProtos, "ALPN support not available")
cli_ctx:setAlpnProtos{ "http2.0", "http" }
srv_ctx = getsslctx("TLSv1", true)
srv_ctx:setAlpnSelect(function (ssl, list, ...)
info("onAlpnSelect: %s", table.concat(list, " "))
alpn_issued = alpn_issued + 1
return list[1]
end)
for i=1,100 do
local srv, cli = check(socket.pair(socket.SOCK_STREAM))
check(main:wrap(function ()
check(cli:starttls(cli_ctx))
end))
check(srv:starttls(srv_ctx))
alpn_attempts = alpn_attempts + 1
ticklebug()
end
info("%d ALPN callbacks issued in %d SSL connections", alpn_issued, alpn_attempts)
check(alpn_attempts == alpn_issued, "wrong number of ALPN callbacks")
end))
check(main:loop())
say"OK"
|