New issue 2578: Behavioral discrepancy between CPython and PyPy ssl modules
https://bitbucket.org/pypy/pypy/issues/2578/behavioral-discrepancy-between-cpython-and

Nathaniel Smith:

Here's a weird edge case where the CPython and PyPy ssl modules behave 
differently. I'm not entirely sure whether it's a bug or not, and it's easy 
enough for me to work around, but I found the PyPy behavior surprising and who 
knows it might point to some deeper issue, so I wanted to make a formal note.

Scenario:
* Client and server negotiate a TLS connection
* Client sends `close_notify` then immediately closes socket 
* Server receives `close_notify` then attempts to send `close_notify` back

In this scenario, on CPython the server gets a `BrokenPipeError`, which makes 
sense – this is the usual error for trying to send data on a socket that the 
other side already closed. On PyPy, the server gets a `SSLEOFError: EOF 
occurred in violation of protocol`. This is (a) different, and (b) the text is 
not true, the EOF was totally legal.

(Quoth RFC 5246: "Unless some other fatal alert has been transmitted, each 
party is required to send a close_notify alert before closing the write side of 
the connection.  The other party MUST respond with a close_notify alert of its 
own and close down the connection immediately, discarding any pending writes.  
It is not required for the initiator of the close to wait for the responding 
close_notify alert before closing the read side of the connection.")

Weirdly, running under strace I can see PyPy getting `EPIPE` before raising 
`SSLEOFError`, and then the next syscall it makes is to start looking up python 
files so it can print the traceback:

```
[pid 17390] write(4, 
"\25\3\3\0\32\211\327\250b\301+o\373$\363\32\t\r\231\261\256\322\f\230\362\205vr\224VD",
 31) = -1 EPIPE (Broken pipe)
[pid 17390] --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=17387, 
si_uid=1000} ---
[pid 17390] 
stat("/home/njs/pypy/pypy3.5-5.8-beta-linux_x86_64-portable/lib-python/3/threading.py",
 {st_mode=S_IFREG|0644, st_size=48919, ...}) = 0
```

And looking at the definition of `pyssl_error` in 
lib_pypy/_cffi_ssl/_stdssl/error.py, it looks like the difference between 
raising `SSLEOFError` and an `OSError` like `BrokenPipeError` is the setting of 
a "did the BIO indicate an error" flag. If that flag is broken in general then 
that's definitely worrisome.

Sample code here:
https://gist.github.com/njsmith/7cf06383adca0392c862cfa22cb70804

CC: @alex_gaynor


_______________________________________________
pypy-issue mailing list
pypy-issue@python.org
https://mail.python.org/mailman/listinfo/pypy-issue

Reply via email to