You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@serf.apache.org by Alexandr Miloslavskiy <al...@syntevo.com> on 2021/10/08 01:08:37 UTC

[BUG] Segfault when connection failed

I'm trying serf from branch 1.4.x.
I couldn't use 1.3.9 because I also need to use OpenSSL 1.1.

I have encountered a segfault and debugged. To my understanding, the 
crashing code comes from this commit:
r1712776 by Bert Huijben, 2015-11-05 17:05:02

Hard to say if the commit introduced the problem or merely shuffled the 
code around. At any rate, the crash is not reproducible with serf 1.3.9.

I have debugged, see analysis below. However, without knowledge of serf, 
I can't quickly figure how to fix.

Hopefully Bert could do that?

Analysis:
---------
1) I'm trying to connect SVN to an HTTPS server using a client cert.

2) I'm using a wrong password for the certificate.

3) In `ssl_decrypt()`
    It detects error in `SSL_read()` and propagates error.
    Stack:
      libsvn_ra_1!ssl_decrypt
      libsvn_ra_1!common_databuf_prep
      libsvn_ra_1!serf_databuf_peek
      libsvn_ra_1!read_from_connection
      libsvn_ra_1!process_connection
      libsvn_ra_1!serf__process_connection
      libsvn_ra_1!serf_context_run
      libsvn_ra_1!svn_ra_serf__context_run_wait
      libsvn_ra_1!svn_ra_serf__exchange_capabilities
      libsvn_ra_1!svn_ra_serf__open
      libsvn_ra_1!svn_ra_open5
      libsvn_client_1!svn_client__open_ra_session_internal
      libsvn_client_1!svn_client__ra_session_from_path2
      libsvn_client_1!svn_client_info4

4) In `svn_ra_open5()`
    calls `svn_pool_destroy(sesspool)`

5) In `svn_pool_destroy()`
    calls the registered `clean_resp()`

6) In `clean_resp()`
    Sets `request->respool` to NULL.
    (request->writing == SERF_WRITING_STARTED)
    calls `serf__connection_pre_cleanup()`

7) In `serf__connection_pre_cleanup()`
    It has loop for `conn->done_reqs`.
    loop handles exactly one request, the one already in `clean_resp()`
    loop sets `rq->writing` to `SERF_WRITING_FINISHED`
    loop calls `serf__destroy_request()`

8) In `serf__destroy_request()`
    `rq->writing` is already `SERF_WRITING_FINISHED` (see #7)
    Therefore, it's time to clean things.
    `request->respool` is null (see #6).
    `request` is freed via `serf_bucket_mem_free()`.

9) Back to `clean_resp()`
    Segfaults on `if (request->resp_bkt)`.

Re: [BUG] Segfault when connection failed

Posted by Alexandr Miloslavskiy <al...@syntevo.com>.
CC += Bert Huijben, probably he knows the area best

On 08.10.2021 4:08, Alexandr Miloslavskiy wrote:
> I'm trying serf from branch 1.4.x.
> I couldn't use 1.3.9 because I also need to use OpenSSL 1.1.
> 
> I have encountered a segfault and debugged. To my understanding, the 
> crashing code comes from this commit:
> r1712776 by Bert Huijben, 2015-11-05 17:05:02
> 
> Hard to say if the commit introduced the problem or merely shuffled the 
> code around. At any rate, the crash is not reproducible with serf 1.3.9.
> 
> I have debugged, see analysis below. However, without knowledge of serf, 
> I can't quickly figure how to fix.
> 
> Hopefully Bert could do that?
> 
> Analysis:
> ---------
> 1) I'm trying to connect SVN to an HTTPS server using a client cert.
> 
> 2) I'm using a wrong password for the certificate.
> 
> 3) In `ssl_decrypt()`
>     It detects error in `SSL_read()` and propagates error.
>     Stack:
>       libsvn_ra_1!ssl_decrypt
>       libsvn_ra_1!common_databuf_prep
>       libsvn_ra_1!serf_databuf_peek
>       libsvn_ra_1!read_from_connection
>       libsvn_ra_1!process_connection
>       libsvn_ra_1!serf__process_connection
>       libsvn_ra_1!serf_context_run
>       libsvn_ra_1!svn_ra_serf__context_run_wait
>       libsvn_ra_1!svn_ra_serf__exchange_capabilities
>       libsvn_ra_1!svn_ra_serf__open
>       libsvn_ra_1!svn_ra_open5
>       libsvn_client_1!svn_client__open_ra_session_internal
>       libsvn_client_1!svn_client__ra_session_from_path2
>       libsvn_client_1!svn_client_info4
> 
> 4) In `svn_ra_open5()`
>     calls `svn_pool_destroy(sesspool)`
> 
> 5) In `svn_pool_destroy()`
>     calls the registered `clean_resp()`
> 
> 6) In `clean_resp()`
>     Sets `request->respool` to NULL.
>     (request->writing == SERF_WRITING_STARTED)
>     calls `serf__connection_pre_cleanup()`
> 
> 7) In `serf__connection_pre_cleanup()`
>     It has loop for `conn->done_reqs`.
>     loop handles exactly one request, the one already in `clean_resp()`
>     loop sets `rq->writing` to `SERF_WRITING_FINISHED`
>     loop calls `serf__destroy_request()`
> 
> 8) In `serf__destroy_request()`
>     `rq->writing` is already `SERF_WRITING_FINISHED` (see #7)
>     Therefore, it's time to clean things.
>     `request->respool` is null (see #6).
>     `request` is freed via `serf_bucket_mem_free()`.
> 
> 9) Back to `clean_resp()`
>     Segfaults on `if (request->resp_bkt)`.
>