Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Requests v2.32.0-v2.32.3 caused a segmentation fault with multiple simultaneous requests with a certificate. #6872

Open
alloni opened this issue Jan 16, 2025 · 0 comments

Comments

@alloni
Copy link

alloni commented Jan 16, 2025

We are having intermittent segmentation faults on requests (using requests v2.32.0-v2.32.3, urllib3 v1.26.19). On investigation with faulthandler, they occur when a certificate is passed in, and two separate threads are trying to access the same ssl_context at the same time - one updating it with the given cert, one reading:

Current thread 0x00007f46c114d700 (most recent call first):
  File "<library path>/site-packages/urllib3/util/ssl_.py", line 418 in ssl_wrap_socket
  File "<library path>/site-packages/urllib3/connection.py", line 419 in connect
  File "<library path>/site-packages/urllib3/connectionpool.py", line 1060 in _validate_conn
  File "<library path>/site-packages/urllib3/connectionpool.py", line 404 in _make_request
  File "<library path>/site-packages/urllib3/connectionpool.py", line 715 in urlopen
  File "<library path>/site-packages/requests/adapters.py", line 667 in send
  File "<library path>/site-packages/requests/sessions.py", line 703 in send
  File "<library path>/site-packages/requests/sessions.py", line 589 in request
  File "<library path>/site-packages/requests/sessions.py", line 602 in get
  ...

Thread 0x00007f469e7fc700 (most recent call first):
  File "/usr/ssl.py", line 1382 in do_handshake
  File "/usr/ssl.py", line 1104 in _create
  File "/usr/ssl.py", line 517 in wrap_socket
  File "<library path>/site-packages/urllib3/util/ssl_.py", line 493 in _ssl_wrap_socket_impl
  File "<library path>/site-packages/urllib3/util/ssl_.py", line 449 in ssl_wrap_socket
  File "<library path>/site-packages/urllib3/connection.py", line 419 in connect
  File "<library path>/site-packages/urllib3/connectionpool.py", line 1060 in _validate_conn
  File "<library path>/site-packages/urllib3/connectionpool.py", line 404 in _make_request
  File "<library path>/site-packages/urllib3/connectionpool.py", line 715 in urlopen
  File "<library path>/site-packages/requests/adapters.py", line 667 in send
  File "<library path>/site-packages/requests/sessions.py", line 703 in send
  File "<library path>/site-packages/requests/sessions.py", line 589 in request
  File "<library path>/site-packages/requests/sessions.py", line 602 in get
  ...

This seems to happen because requests v2.32 switched from having a request without an SSL context create a new one to using the same preloaded SSL context across multiple requests. (This is #6745 with more information as to what exactly is going on - opening a new issue as the original issue creator has left the company.)

Expected Result

No segmentation faults.

Actual Result

Got intermittent segmentation faults.

Reproduction Steps

As per the original issue - and note that it only crashes if a generated certificate is passed in - openssl req -x509 -newkey rsa:4096 -keyout client.key -out client.crt -days 365 -nodes:

import concurrent.futures
import random
import uuid
from threading import Thread
from time import time

import requests


def do_request():
    start = time()
    random_id = uuid.uuid4()
    delay = random.randint(1, 5)
    print("start {} delay {} seconds".format(random_id, delay))
    endpoints = []
    endpoints.append('https://httpbin.org/delay/' + str(delay))
    delay = str(random.randint(1, 5)) + 's'
    endpoints.append('https://run.mocky.io/v3/0432e9f0-674f-45bd-9c18-628b861c2258?mocky-delay=' + str(delay))
    random.shuffle(endpoints)
    response = None
    for endpoint in endpoints:
        try:
            print("start {} delay {} seconds".format(random_id, endpoint))
            if 'run' in endpoint:
                cert = './client.crt', './client.key'
                response = requests.get(endpoint, timeout=random.randint(1, 5), cert=cert)
            else:
                response = requests.get(endpoint, timeout=random.randint(1, 5))
        except Exception as e:
            print(e)
    end = time()


    print("finished {} in {} seconds".format(random_id, end - start))
    return response


def measure():
    cnt = 20
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        futures = []
        for server in range(1, cnt):
            futures.append(executor.submit(do_request))
        for future in concurrent.futures.as_completed(futures):
            pass


for i in range(1, 500):
    threads = [Thread(target=measure, args=()) for _ in range(5)]

    for t in threads: t.start()
    for t in threads: t.join()

System Information

{
  "chardet": {
    "version": null
  },
  "charset_normalizer": {
    "version": "3.4.1"
  },
  "cryptography": {
    "version": "43.0.1"
  },
  "idna": {
    "version": "3.10"
  },
  "implementation": {
    "name": "CPython",
    "version": "3.11.11"
  },
  "platform": {
    "release": "4.18.0-553.34.1.el8_10.x86_64",
    "system": "Linux"
  },
  "pyOpenSSL": {
    "openssl_version": "30300020",
    "version": "24.2.1"
  },
  "requests": {
    "version": "2.32.3"
  },
  "system_ssl": {
    "version": "101010bf"
  },
  "urllib3": {
    "version": "1.26.19"
  },
  "using_charset_normalizer": true,
  "using_pyopenssl": true
}

(Attempted with requests v2.32.0, v2.32.2, v2.32.3, urllib3 v1.26.18, v1.26.19.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant