8000 00462: Fix PySSL_SetError handling SSL_ERROR_SYSCALL · fedora-python/cpython@10918b4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 10918b4

Browse files
keepworkingserhiy-storchakaencukou
authored andcommitted
00462: Fix PySSL_SetError handling SSL_ERROR_SYSCALL
Python 3.10 changed from using SSL_write() and SSL_read() to SSL_write_ex() and SSL_read_ex(), but did not update handling of the return value. Change error handling so that the return value is not examined. OSError (not EOF) is now returned when retval is 0. This resolves the issue of failing tests when a system is stressed on OpenSSL 3.5. Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Petr Viktorin <encukou@gmail.com>
1 parent 8a54d09 commit 10918b4

File tree

3 files changed

+38
-53
lines changed

3 files changed

+38
-53
lines changed

Lib/test/test_ssl.py

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,16 +2605,18 @@ def run(self):
26052605
self.write(msg.lower())
26062606
except OSError as e:
26072607
# handles SSLError and socket errors
2608+
if isinstance(e, ConnectionError):
2609+
# OpenSSL 1.1.1 sometimes raises
2610+
# ConnectionResetError when connection is not
2611+
# shut down gracefully.
2612+
if self.server.chatty and support.verbose:
2613+
print(f" Connection reset by peer: {self.addr}")
2614+
2615+
self.close()
2616+
self.running = False
2617+
return
26082618
if self.server.chatty and support.verbose:
2609-
if isinstance(e, ConnectionError):
2610-
# OpenSSL 1.1.1 sometimes raises
2611-
# ConnectionResetError when connection is not
2612-
# shut down gracefully.
2613-
print(
2614-
f" Connection reset by peer: {self.addr}"
2615-
)
2616-
else:
2617-
handle_error("Test server failure:\n")
2619+
handle_error("Test server failure:\n")
26182620
try:
26192621
self.write(b"ERROR\n")
26202622
except OSError:
@@ -3296,23 +3298,16 @@ def test_wrong_cert_tls13(self):
32963298
client_context.wrap_socket(socket.socket(),
32973299
server_hostname=hostname,
32983300
suppress_ragged_eofs=False) as s:
3299-
# TLS 1.3 perform client cert exchange after handshake
33003301
s.connect((HOST, server.port))
3301-
try:
3302+
with self.assertRaisesRegex(
3303+
OSError,
3304+
'alert unknown ca|EOF occurred|TLSV1_ALERT_UNKNOWN_CA|closed by the remote host|Connection reset by peer'
3305+
):
3306+
# TLS 1.3 perform client cert exchange after handshake
33023307
s.write(b'data')
33033308
s.read(1000)
33043309
s.write(b'should have failed already')
33053310
s.read(1000)
3306-
except ssl.SSLError as e:
3307-
if support.verbose:
3308-
sys.stdout.write("\nSSLError is %r\n" % e)
3309-
except OSError as e:
3310-
if e.errno != errno.ECONNRESET:
3311-
raise
3312-
if support.verbose:
3313-
sys.stdout.write("\nsocket.error is %r\n" % e)
3314-
else:
3315-
self.fail("Use of invalid cert should have failed!")
33163311

33173312
def test_rude_shutdown(self):
33183313
"""A brutal shutdown of an SSL server should raise an OSError
@@ -4558,8 +4553,8 @@ def msg_cb(conn, direction, version, content_type, msg_type, data):
45584553
# test sometimes fails with EOF error. Test passes as long as
45594554
# server aborts connection with an error.
45604555
with self.assertRaisesRegex(
4561-
ssl.SSLError,
4562-
'(certificate required|EOF occurred)'
4556+
OSError,
4557+
'certificate required|EOF occurred|closed by the remote host|Connection reset by peer'
45634558
):
45644559
# receive CertificateRequest
45654560
data = s.recv(1024)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix the :mod:`ssl` module error handling of connection terminate by peer.
2+
It now throws an OSError with the appropriate error code instead of an EOFError.

Modules/_ssl.c

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ PySSL_ChainExceptions(PySSLSocket *sslsock) {
582582
}
583583

584584
static PyObject *
585-
PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno)
585+
PySSL_SetError(PySSLSocket *sslsock, const char *filename, int lineno)
586586
{
587587
PyObject *type;
588588
char *errstr = NULL;
@@ -595,7 +595,6 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno)
595595
_sslmodulestate *state = get_state_sock(sslsock);
596596
type = state->PySSLErrorObject;
597597

598-
assert(ret <= 0);
599598
e = ERR_peek_last_error();
600599

601600
if (sslsock->ssl != NULL) {
@@ -628,32 +627,21 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno)
628627
case SSL_ERROR_SYSCALL:
629628
{
630629
if (e == 0) {
631-
PySocketSockObject *s = GET_SOCKET(sslsock);
632-
if (ret == 0 || (((PyObject *)s) == Py_None)) {
630+
/* underlying BIO reported an I/O error */
631+
ERR_clear_error();
632+
#ifdef MS_WINDOWS
633+
if (err.ws) {
634+
return PyErr_SetFromWindowsErr(err.ws);
635+
}
636+
#endif
637+
if (err.c) {
638+
errno = err.c;
639+
return PyErr_SetFromErrno(PyExc_OSError);
640+
}
641+
else {
633642
p = PY_SSL_ERROR_EOF;
634643
type = state->PySSLEOFErrorObject;
635644
errstr = "EOF occurred in violation of protocol";
636-
} else if (s && ret == -1) {
637-
/* underlying BIO reported an I/O error */
638-
ERR_clear_error();
639-
#ifdef MS_WINDOWS
640-
if (err.ws) {
641-
return PyErr_SetFromWindowsErr(err.ws);
642-
}
643-
#endif
644-
if (err.c) {
645-
errno = err.c;
646-
return PyErr_SetFromErrno(PyExc_OSError);
647-
}
648-
else {
649-
p = PY_SSL_ERROR_EOF;
650-
type = state->PySSLEOFErrorObject;
651-
errstr = "EOF occurred in violation of protocol";
652-
}
653-
} else { /* possible? */
654-
p = PY_SSL_ERROR_SYSCALL;
655-
type = state->PySSLSyscallErrorObject;
656-
errstr = "Some I/O error occurred";
657645
}
658646
} else {
659647
if (ERR_GET_LIB(e) == ERR_LIB_SYS) {
@@ -1014,7 +1002,7 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
10141002
err.ssl == SSL_ERROR_WANT_WRITE);
10151003
Py_XDECREF(sock);
10161004
if (ret < 1)
1017-
return PySSL_SetError(self, ret, __FILE__, __LINE__);
1005+
return PySSL_SetError(self, __FILE__, __LINE__);
10181006
if (PySSL_ChainExceptions(self) < 0)
10191007
return NULL;
10201008
Py_RETURN_NONE;
@@ -2433,7 +2421,7 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
24332421

24342422
Py_XDECREF(sock);
24352423
if (retval == 0)
2436-
return PySSL_SetError(self, retval, __FILE__, __LINE__);
2424+
return PySSL_SetError(self, __FILE__, __LINE__);
24372425
if (PySSL_ChainExceptions(self) < 0)
24382426
return NULL;
24392427
return PyLong_FromSize_t(count);
@@ -2463,7 +2451,7 @@ _ssl__SSLSocket_pending_impl(PySSLSocket *self)
24632451
self->err = err;
24642452

24652453
if (count < 0)
2466-
return PySSL_SetError(self, count, __FILE__, __LINE__);
2454+
return PySSL_SetError(self, __FILE__, __LINE__);
24672455
else
24682456
return PyLong_FromLong(count);
24692457
}
@@ -2585,7 +2573,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len,
25852573
err.ssl == SSL_ERROR_WANT_WRITE);
25862574

25872575
if (retval == 0) {
2588-
PySSL_SetError(self, retval, __FILE__, __LINE__);
2576+
PySSL_SetError(self, __FILE__, __LINE__);
25892577
goto error;
25902578
}
25912579
if (self->exc_type != NULL)
@@ -2709,7 +2697,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
27092697
}
27102698
if (ret < 0) {
27112699
Py_XDECREF(sock);
2712-
PySSL_SetError(self, ret, __FILE__, __LINE__);
2700+
PySSL_SetError(self, __FILE__, __LINE__);
27132701
return NULL;
27142702
}
27152703
if (self->exc_type != NULL)

0 commit comments

Comments
 (0)
0