Properly fix SIGBUS crash issue (#358)

* Fix SIGBUS crash.

* Workaround annoying and buggy style checker.

* Fix revealed SIGSEGV error.

* Add comments.
This commit is contained in:
Eugene Kabanov 2023-02-09 07:15:22 +02:00 committed by GitHub
parent b9fcf9962d
commit 5d3da66e56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 42 additions and 22 deletions

View File

@ -35,7 +35,7 @@ type
RSA, EC
TLSResult {.pure.} = enum
Success, Error, EOF
Success, Error, Stopped, WriteEof, ReadEof
TLSPrivateKey* = ref object
case kind: TLSKeyType
@ -126,6 +126,9 @@ template newTLSStreamProtocolImpl[T](message: T): ref TLSStreamProtocolError =
err.errCode = code
err
template newTLSUnexpectedProtocolError(): ref TLSStreamProtocolError =
newException(TLSStreamProtocolError, "Unexpected internal error")
proc newTLSStreamProtocolError[T](message: T): ref TLSStreamProtocolError =
newTLSStreamProtocolImpl(message)
@ -142,12 +145,14 @@ proc tlsWriteRec(engine: ptr SslEngineContext,
sslEngineSendrecAck(engine[], length)
return TLSResult.Success
except AsyncStreamError as exc:
if writer.state == AsyncStreamState.Running:
writer.state = AsyncStreamState.Error
writer.error = exc
writer.state = AsyncStreamState.Error
writer.error = exc
return TLSResult.Error
except CancelledError:
if writer.state == AsyncStreamState.Running:
writer.state = AsyncStreamState.Stopped
return TLSResult.Stopped
return TLSResult.Error
proc tlsWriteApp(engine: ptr SslEngineContext,
@ -157,6 +162,13 @@ proc tlsWriteApp(engine: ptr SslEngineContext,
if item.size > 0:
var length = 0'u
var buf = sslEngineSendappBuf(engine[], length)
if isNil(buf) or (length == 0):
# This situation could happen when connection is closing, no
# application data can be sent, but some can still be received
# (and discarded).
writer.state = AsyncStreamState.Finished
return TLSResult.WriteEof
let toWrite = min(int(length), item.size)
copyOut(buf, item, toWrite)
if int(length) >= item.size:
@ -180,6 +192,8 @@ proc tlsWriteApp(engine: ptr SslEngineContext,
except CancelledError:
if writer.state == AsyncStreamState.Running:
writer.state = AsyncStreamState.Stopped
return TLSResult.Stopped
return TLSResult.Error
proc tlsReadRec(engine: ptr SslEngineContext,
@ -191,17 +205,18 @@ proc tlsReadRec(engine: ptr SslEngineContext,
sslEngineRecvrecAck(engine[], uint(res))
if res == 0:
sslEngineClose(engine[])
return TLSResult.EOF
return TLSResult.ReadEof
else:
return TLSResult.Success
except AsyncStreamError as exc:
reader.state = AsyncStreamState.Error
reader.error = exc
return TLSResult.Error
except CancelledError:
if reader.state == AsyncStreamState.Running:
reader.state = AsyncStreamState.Stopped
except AsyncStreamError as exc:
if reader.state == AsyncStreamState.Running:
reader.state = AsyncStreamState.Error
reader.error = exc
return TLSResult.Stopped
return TLSResult.Error
proc tlsReadApp(engine: ptr SslEngineContext,
@ -215,13 +230,15 @@ proc tlsReadApp(engine: ptr SslEngineContext,
except CancelledError:
if reader.state == AsyncStreamState.Running:
reader.state = AsyncStreamState.Stopped
return TLSResult.Stopped
return TLSResult.Error
template readAndReset(fut: untyped) =
if fut.finished():
let res = fut.read()
case res
of TLSResult.Success:
of TLSResult.Success, TLSResult.WriteEof, TLSResult.Stopped:
fut = nil
continue
of TLSResult.Error:
@ -229,7 +246,7 @@ template readAndReset(fut: untyped) =
if loopState == AsyncStreamState.Running:
loopState = AsyncStreamState.Error
break
of TLSResult.EOF:
of TLSResult.ReadEof:
fut = nil
if loopState == AsyncStreamState.Running:
loopState = AsyncStreamState.Finished
@ -301,14 +318,14 @@ proc tlsLoop*(stream: TLSAsyncStream) {.async.} =
if isNil(sendAppFut):
if (state and SSL_SENDAPP) == SSL_SENDAPP:
# Application data can be sent over stream.
if not(stream.writer.handshaked):
stream.reader.handshaked = true
stream.writer.handshaked = true
if not(isNil(stream.writer.handshakeFut)):
stream.writer.handshakeFut.complete()
sendAppFut = tlsWriteApp(engine, stream.writer)
if stream.writer.state == AsyncStreamState.Running:
# Application data can be sent over stream.
if not(stream.writer.handshaked):
stream.reader.handshaked = true
stream.writer.handshaked = true
if not(isNil(stream.writer.handshakeFut)):
stream.writer.handshakeFut.complete()
sendAppFut = tlsWriteApp(engine, stream.writer)
else:
sendAppFut.readAndReset()
@ -353,8 +370,10 @@ proc tlsLoop*(stream: TLSAsyncStream) {.async.} =
of AsyncStreamState.Error:
if not(isNil(stream.writer.error)):
stream.writer.error
else:
elif not(isNil(stream.reader.error)):
newTLSStreamWriteError(stream.reader.error)
else:
newTLSUnexpectedProtocolError()
of AsyncStreamState.Finished:
let err = engine[].sslEngineLastError()
if err != 0:
@ -389,7 +408,8 @@ proc tlsLoop*(stream: TLSAsyncStream) {.async.} =
if not(isNil(stream.writer.handshakeFut)):
if not(stream.writer.handshakeFut.finished()):
stream.writer.handshakeFut.fail(
newTLSStreamProtocolError("Connection with remote peer lost")
newTLSStreamProtocolError(
"Connection to the remote peer has been lost")
)
# Completing readers