While doing some customization of mod_ssl I checked for memory leaks on
Solaris using libumem and found 5 allocations that happen for each
handshake and do not seem to get freed.

Versions: httpd 2.4 head plus OpenSSL 1.0.1g

> ::findleaks
...
000b9688      85 002779c8 mod_ssl.so`default_malloc_ex+0x20
000b8788      85 00185d10 mod_ssl.so`default_malloc_ex+0x20
000bea08      84 00178690 mod_ssl.so`default_malloc_ex+0x20
000b8288      84 00131ab8 mod_ssl.so`default_malloc_ex+0x20
000b8788      84 00185d88 mod_ssl.so`default_malloc_ex+0x20

...

The number 84/85 is the number of connections handled.

The five allocation stacks always point to ssl_callback_TmpDH, at
offsets 0x12c, 0xec and 0x140:

> 002779c8::bufctl_audit
            ADDR          BUFADDR        TIMESTAMP           THREAD
                            CACHE          LASTLOG         CONTENTS
          2779c8           275c78   277d6c5029c999                1
                            b9688            a5b58                0
                 libumem.so.1`umem_cache_alloc+0x210
                 libumem.so.1`umem_alloc+0x60
                 libumem.so.1`malloc+0x28
                 mod_ssl.so`default_malloc_ex+0x20
                 mod_ssl.so`CRYPTO_malloc+0x88
                 mod_ssl.so`DH_new_method+0x24
                 mod_ssl.so`ssl_callback_TmpDH+0x12c
                 mod_ssl.so`ssl3_send_server_key_exchange+0xad8

> 00185d88::bufctl_audit
            ADDR          BUFADDR        TIMESTAMP           THREAD
                            CACHE          LASTLOG         CONTENTS
          185d88           180ed8   277d6c502a3e23                1
                            b8788            a5e14                0
                 libumem.so.1`umem_cache_alloc+0x13c
                 libumem.so.1`umem_alloc+0x60
                 libumem.so.1`malloc+0x28
                 mod_ssl.so`default_malloc_ex+0x20
                 mod_ssl.so`CRYPTO_malloc+0x88
                 mod_ssl.so`BN_new+0x24
                 mod_ssl.so`BN_dec2bn+0x220
                 mod_ssl.so`ssl_callback_TmpDH+0xec
                 mod_ssl.so`ssl3_send_server_key_exchange+0xad8

> 00131ab8::bufctl_audit
            ADDR          BUFADDR        TIMESTAMP           THREAD
                            CACHE          LASTLOG         CONTENTS
          131ab8           12b620   277d6c502a483a                1
                            b8288            a5e78                0
                 libumem.so.1`umem_cache_alloc+0x210
                 libumem.so.1`umem_alloc+0x60
                 libumem.so.1`malloc+0x28
                 mod_ssl.so`default_malloc_ex+0x20
                 mod_ssl.so`CRYPTO_malloc+0x88
                 mod_ssl.so`bn_expand_internal+0x44
                 mod_ssl.so`bn_expand2+0x20
                 mod_ssl.so`BN_dec2bn+0x1bc
                 mod_ssl.so`ssl_callback_TmpDH+0xec
                 mod_ssl.so`ssl3_send_server_key_exchange+0xad8

> 00185d10::bufctl_audit
            ADDR          BUFADDR        TIMESTAMP           THREAD
                            CACHE          LASTLOG         CONTENTS
          185d10           180f08   277d6c502a0e49                1
                            b8788            a5d4c                0
                 libumem.so.1`umem_cache_alloc+0x13c
                 libumem.so.1`umem_alloc+0x60
                 libumem.so.1`malloc+0x28
                 mod_ssl.so`default_malloc_ex+0x20
                 mod_ssl.so`CRYPTO_malloc+0x88
                 mod_ssl.so`BN_new+0x24
                 mod_ssl.so`BN_bin2bn+0x11c
                 mod_ssl.so`ssl_callback_TmpDH+0x140
                 mod_ssl.so`ssl3_send_server_key_exchange+0xad8

> 00178690::bufctl_audit
            ADDR          BUFADDR        TIMESTAMP           THREAD
                            CACHE          LASTLOG         CONTENTS
          178690           17f3c0   277d6c502a23c5                1
                            bea08            a5db0                0
                 libumem.so.1`umem_cache_alloc+0x13c
                 libumem.so.1`umem_alloc+0x60
                 libumem.so.1`malloc+0x28
                 mod_ssl.so`default_malloc_ex+0x20
                 mod_ssl.so`CRYPTO_malloc+0x88
                 mod_ssl.so`bn_expand_internal+0x44
                 mod_ssl.so`bn_expand2+0x20
                 mod_ssl.so`BN_bin2bn+0xf0
                 mod_ssl.so`ssl_callback_TmpDH+0x140
                 mod_ssl.so`ssl3_send_server_key_exchange+0xad8

ssl_callback_TmpDH is in modules/ssl/ssl_engine_kernel.c.

I think this is due to the changes in modules/ssl/ssl_engine_init.c
applied by the backported r1542327.

Function ssl_callback_TmpDH calls functions get_dh4096() or get_dh3072()
or get_dh2048() or get_dh1024(), which are defined by macro make_get_dh
and include code:

    DH *dh;
    if (!(dh = DH_new())) {
               ^^^^^^
        return NULL;
    }
    dh->p = get_##rfc##_prime_##size(NULL);
    BN_dec2bn(&dh->g, #gen);
    ^^^^^^^^^
    if (!dh->p || !dh->g) {
        DH_free(dh);
        return NULL;
    }
    return dh;

So the first three leaks come from here. For the leak with BN_bin2bn it
is hidden in get_##rfc##_prime_##size, e.g. get_rfc3526_prime_4096()
contains the line

return BN_bin2bn(RFC3526_PRIME_4096,sizeof(RFC3526_PRIME_4096),bn);

It seems to me that a single call to DH_free(dh) would suffice to free
all 5 allocations.

So the question is, where can those allocations be best freed? Is it the
application (mod_ssl) responsibility, or should OpenSSL free it after it
no longer uses the callback set via SSL_CTX_set_tmp_dh_callback? If the
returned DH is only used for a single connection, we could try to free
during connection shutdown.

I would prefer if someone with a better knowledge of mod_ssl would look
further into it. We have to pass around the DH to be able to free it
later and find the right place to free it.

Regards,

Rainer

Reply via email to