◐ Shell
clean mode source ↗

better ssl write handling by youknowone · Pull Request #6763 · RustPython/RustPython

🧩 Analysis chain

🏁 Script executed:

# First, let's check if the file exists and view the specific lines mentioned
head -20 crates/stdlib/src/ssl/compat.rs | head -5
wc -l crates/stdlib/src/ssl/compat.rs

Repository: RustPython/RustPython

Length of output: 186


🏁 Script executed:

# Look at the specific lines mentioned (1738-1759)
sed -n '1738,1759p' crates/stdlib/src/ssl/compat.rs

Repository: RustPython/RustPython

Length of output: 186


🏁 Script executed:

# Search for PySSLSocket struct definition to see current fields
rg -n "struct PySSLSocket" crates/stdlib/src/ssl/compat.rs -A 30

Repository: RustPython/RustPython

Length of output: 186


🏁 Script executed:

# Search for write_buffered_len references to understand current usage
rg -n "write_buffered_len" crates/stdlib/src/ssl/compat.rs -B 2 -A 2

Repository: RustPython/RustPython

Length of output: 1733


🏁 Script executed:

# Search for PySSLSocket struct definition
rg -n "struct PySSLSocket" crates/stdlib/src/ssl/compat.rs -B 5 -A 50

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Also search for #[pyclass] annotations for PySSLSocket
rg -n "#\[pyclass\]" crates/stdlib/src/ssl/compat.rs -B 2 -A 50 | head -150

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Search for write_buffered_len field definition
rg -n "write_buffered_len" crates/stdlib/src/ssl/compat.rs | head -20

Repository: RustPython/RustPython

Length of output: 522


🏁 Script executed:

# Try broader search for PySSLSocket without struct keyword
rg -n "PySSLSocket" crates/stdlib/src/ssl/compat.rs | head -20

Repository: RustPython/RustPython

Length of output: 456


🏁 Script executed:

# Look for pyclass macro definition
rg -n "pyclass.*PySSLSocket" crates/stdlib/src/ssl/compat.rs -B 2 -A 100 | head -200

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Search more broadly in the file for where PySSLSocket is declared
head -500 crates/stdlib/src/ssl/compat.rs | tail -400

Repository: RustPython/RustPython

Length of output: 16044


🏁 Script executed:

# PySSLSocket is imported from parent module, let's find the _ssl module
fd "_ssl" crates/stdlib/src/ssl/ -type f

Repository: RustPython/RustPython

Length of output: 235


🏁 Script executed:

# Look for PySSLSocket struct in the _ssl module
rg -n "struct PySSLSocket" crates/stdlib/src/ssl/_ssl.rs -B 5 -A 50 | head -100

Repository: RustPython/RustPython

Length of output: 134


🏁 Script executed:

# Search for write_buffered_len field in _ssl.rs
rg -n "write_buffered_len" crates/stdlib/src/ssl/_ssl.rs

Repository: RustPython/RustPython

Length of output: 134


🏁 Script executed:

# Check what fields currently exist in PySSLSocket
rg -n "write_buffered" crates/stdlib/src/ssl/_ssl.rs -B 2 -A 2

Repository: RustPython/RustPython

Length of output: 134


🏁 Script executed:

# Find all files in the ssl directory
ls -la crates/stdlib/src/ssl/

Repository: RustPython/RustPython

Length of output: 413


🏁 Script executed:

# Search for PySSLSocket definition across the entire ssl directory
rg -n "struct PySSLSocket" crates/stdlib/src/ssl/

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Search for where write_buffered_len is first created/initialized
rg -n "write_buffered_len.*=" crates/stdlib/src/ssl/ -B 3 -A 1

Repository: RustPython/RustPython

Length of output: 1544


🏁 Script executed:

# Search for the parent module structure
ls -la crates/stdlib/src/ssl/mod.rs

Repository: RustPython/RustPython

Length of output: 140


🏁 Script executed:

# Look for PySSLSocket in the mod.rs file
rg -n "PySSLSocket" crates/stdlib/src/ssl/mod.rs -B 5 -A 50 | head -200

Repository: RustPython/RustPython

Length of output: 133


🏁 Script executed:

# Search for #[pyclass] in all ssl files to find PySSLSocket definition
rg -n "#\[pyclass\]" crates/stdlib/src/ssl/ -A 30 | grep -A 30 "PySSLSocket"

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Try to find where PySSLSocket is actually defined (might be inline in compat.rs)
rg -n "^pub.*struct PySSLSocket" crates/stdlib/src/ssl/

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Look for where PySSLSocket is defined in the entire ssl directory
rg -n "struct PySSLSocket" crates/stdlib/src/ssl/ -B 5 -A 50

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Search in compat.rs itself for PySSLSocket struct definition or pyclass
grep -n "PySSLSocket" crates/stdlib/src/ssl/compat.rs | head -20

Repository: RustPython/RustPython

Length of output: 456


🏁 Script executed:

# Look at the import line and surrounding context in compat.rs
head -50 crates/stdlib/src/ssl/compat.rs

Repository: RustPython/RustPython

Length of output: 2184


🏁 Script executed:

# Search for pyclass definition in compat.rs
rg -n "#\[pyclass\]" crates/stdlib/src/ssl/compat.rs -A 20 | head -150

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Look at the directory structure of the ssl parent
ls -la crates/stdlib/src/

Repository: RustPython/RustPython

Length of output: 3425


🏁 Script executed:

# Search for all Python SSL-related files
find crates/stdlib/src -name "*ssl*" -o -name "*_ssl*"

Repository: RustPython/RustPython

Length of output: 291


🏁 Script executed:

# Look for PySSLSocket definition more broadly
rg -n "PySSLSocket" crates/stdlib/src/ --type rust -B 5 | grep -A 10 "struct PySSLSocket\|#\[pyclass\].*PySSLSocket" | head -100

Repository: RustPython/RustPython

Length of output: 637


🏁 Script executed:

# Now let's look at the PySSLSocket struct definition in ssl.rs
sed -n '2302,2370p' crates/stdlib/src/ssl.rs

Repository: RustPython/RustPython

Length of output: 3244


🏁 Script executed:

# Search for write_buffered_len field specifically
rg -n "write_buffered_len" crates/stdlib/src/ssl.rs -B 2 -A 2

Repository: RustPython/RustPython

Length of output: 1012


🏁 Script executed:

# Get more context around the struct definition
sed -n '2300,2380p' crates/stdlib/src/ssl.rs

Repository: RustPython/RustPython

Length of output: 3734


🏁 Script executed:

# Now let's see how the function uses this in context - look at the full function
sed -n '1700,1830p' crates/stdlib/src/ssl/compat.rs

Repository: RustPython/RustPython

Length of output: 4509


🏁 Script executed:

# Search for test cases related to write_buffered_len or SSL_write
rg -n "test.*write\|write.*test" crates/stdlib/src/ssl/ -i | head -20

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Check if there are any tests in the ssl.rs file
rg -n "#\[test\]" crates/stdlib/src/ssl.rs | head -10

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Look for how CPython or OpenSSL handles this scenario
rg -n "bad write retry\|write retry" crates/stdlib/src/ssl/ -B 3 -A 3

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Check how the code currently handles data - is there any copy of the data?
sed -n '1712,1830p' crates/stdlib/src/ssl/compat.rs | grep -A 5 -B 5 "data\|write_all"

Repository: RustPython/RustPython

Length of output: 3631


🏁 Script executed:

# Look for similar patterns in the codebase where data is stored/compared
rg -n "hash.*=.*new\|DefaultHasher\|Hash.*Hasher" crates/stdlib/src/ssl/ | head -10

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Check if DefaultHasher is already used anywhere in the ssl module
rg -n "use std::hash" crates/stdlib/src/ssl.rs

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Let's check the broader context of how write operations are handled
rg -n "fn ssl_write" crates/stdlib/src/ssl/compat.rs -A 5

Repository: RustPython/RustPython

Length of output: 486


🏁 Script executed:

# Check if there are any benchmarks or tests that would demonstrate the vulnerability
rg -n "SSL_write\|ssl_write" crates/stdlib/src/ssl.rs -B 2 -A 2 | head -50

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Let's verify the actual vulnerability - check how write data flows through rustls
# Look at the comment about "internal buffer write"
sed -n '1745,1760p' crates/stdlib/src/ssl/compat.rs

Repository: RustPython/RustPython

Length of output: 767


🏁 Script executed:

# Check if rustls::Writer::write_all stores data internally
# Look for any documentation or comments about rustls buffering
rg -n "rustls.*buffer\|buffer.*rustls\|writer.*buffer" crates/stdlib/src/ssl/compat.rs | head -20

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# See if there's any example or comment about the retry logic
rg -n "WantWrite\|WantRead" crates/stdlib/src/ssl/compat.rs -B 3 -A 3 | head -80

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Verify the vulnerability is real by understanding rustls buffering
# Look for how rustls Writer works in the broader context
rg -n "conn.writer()" crates/stdlib/src/ssl/compat.rs -B 2 -A 5 | head -40

Repository: RustPython/RustPython

Length of output: 738


🏁 Script executed:

# Check if there's any comment about the hash approach feasibility
rg -n "hash\|Hash\|Hasher" crates/stdlib/src/ssl.rs | head -20

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Check what imports are already in ssl.rs for hashing
head -100 crates/stdlib/src/ssl.rs | grep -i "use.*hash\|use std"

Repository: RustPython/RustPython

Length of output: 119


🏁 Script executed:

# Verify the suggested fix would pass cargo clippy by checking similar patterns
rg -n "DefaultHasher\|std::hash" crates/stdlib/src/ | head -10

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Verify that hash-based approach is standard by checking similar uses
rg -n "use std::hash::" crates/ | head -10

Repository: RustPython/RustPython

Length of output: 47


🏁 Script executed:

# Confirm the suggested fix would work with current types
# Check if PyMutex<Option<u64>> is already used elsewhere
rg -n "PyMutex<Option<" crates/stdlib/src/ssl.rs | head -10

Repository: RustPython/RustPython

Length of output: 181


🏁 Script executed:

# Review the full context one more time - look at initialization pattern
sed -n '1900,1910p' crates/stdlib/src/ssl.rs

Repository: RustPython/RustPython

Length of output: 582


🏁 Script executed:

# Verify there are no other places where write_buffered_len is manipulated incorrectly
rg -n "write_buffered_len" crates/stdlib/src/ssl.rs

Repository: RustPython/RustPython

Length of output: 240


Detect "bad write retry" when content changes but length matches.

The retry guard only checks if already_buffered != data.len(). If the caller retries with different data of the same length, the code silently proceeds with the old buffered plaintext rather than raising "bad write retry," which deviates from OpenSSL behavior and risks sending corrupted application data. Add a hash-based check to validate that retry data matches the originally buffered content.