OpenSSL 1.1 result in error: variable has initializer but incomplete type static BIO_METHOD

Vincent Li vincent.mc.li at gmail.com
Wed Jul 1 21:07:26 UTC 2020



On Wed, 1 Jul 2020, Vincent Li wrote:

> 
> Hi,
> 
> I am running apache bench (ab) and ported it with OpenSSL 1.0 support on top of mTCP support 
> 
> https://github.com/vincentmli/mtcp/commit/642835f786aa642ea0f20fe8db9b09054639453a#diff-02f7a72f514e6e0543e832d37450c251
> 
> but it breaks after I upgraded OpenSSL 1.0 to OpenSSL 1.1, I found there 
> are quite a few projects having same problems including libevent, libevent 
> has the fix in https://github.com/libevent/libevent/commit/3e9e0a0d46e4508e8782ec3787c6d86bab63046d
> 
> so I borrowed the fix from libevent and applied the code fix below:
> 
> ```
> #include <openssl/bio.h>
> #include "openssl-compat.h"
> #define get_last_socket_error() errno
> #define clear_socket_error()    errno=0
> /* clone of openssl crypto/bio/bss_sock.c */
> 
> #ifdef HAVE_MTCP
> 
> static int mtcp_sock_write(BIO *h, const char *buf, int num);
> static int mtcp_sock_read(BIO *h, char *buf, int size);
> static int mtcp_sock_puts(BIO *h, const char *str);
> static long mtcp_sock_ctrl(BIO *h, int cmd, long arg1, void *arg2);
> static int mtcp_sock_new(BIO *h);
> static int mtcp_sock_free(BIO *data);
> int BIO_mtcp_sock_should_retry(int s);
.........SNIP.........
> 
> static long mtcp_sock_ctrl(BIO *b, int cmd, long num, void *ptr)
> {
>     long ret = 1;
>     int *ip;
> 
>     switch (cmd) {
>     case BIO_C_SET_FD:
>         mtcp_sock_free(b);
>         BIO_set_num(b, *((int *)ptr));
>         BIO_set_shutdown(b, (int)num);
>         BIO_set_init(b, 1);
>         break;
>     case BIO_C_GET_FD:
>         if (BIO_get_init(b)) {
>             ip = (int *)ptr;
>             if (ip != NULL)
>                 *ip = BIO_get_num(b);
>             ret = BIO_get_num(b);
>         } else
>             ret = -1;
>         break;
>     case BIO_CTRL_GET_CLOSE:
>         ret = BIO_get_shutdown(b);
>         break;
>     case BIO_CTRL_SET_CLOSE:
>         BIO_set_shutdown(b, (int)num);
>         break;
>     case BIO_CTRL_DUP:
>     case BIO_CTRL_FLUSH:
>         ret = 1;
>         break;
>     default:
>         ret = 0;
>         break;
>     }
>     return (ret);
> }

I found http://vega.pgw.jp/~kabe/vsd/migrate2openssl-1.1.html which says:

"bio->num (file descripter) could be set by BIO_set_fd(), but since this 
callbacks the routine set by BIO_meth_set_ctrl(biom, BioCtrl), beware of 
infinite loops. Recommend to not touch bio->num member and leave it 
alone."

so I used BIO_set/get_fd() to work with the bio->num, it compiles ok with 
some warnings, but it appears I hit the infinite loops and core dump:

root at vli-lab:/usr/src/mtcp/apps/apache_benchmark/support# cp .libs/ab .
root at vli-lab:/usr/src/mtcp/apps/apache_benchmark/support# gdb --args  ab -N 4 -c 4 -n 160 https://10.2.1.63/
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
...........SNIP............
Checking link status..done
Port 0 Link Up - speed 10000 Mbps - full-duplex
Benchmarking 10.2.1.63 (be patient)
[New Thread 0x7fdff19fb700 (LWP 1510)]
CPU0 connecting to port 443
[New Thread 0x7fdff11fa700 (LWP 1511)]
[New Thread 0x7fdff09f9700 (LWP 1512)]
CPU1 connecting to port 443
[New Thread 0x7fdfea6fe700 (LWP 1513)]
CPU2 connecting to port 443
[New Thread 0x7fdfd7fff700 (LWP 1514)]
CPU3 connecting to port 443
CPU 0: initialization finished.
[mtcp_create_context:1359] CPU 0 is now the master thread.
[CPU 0] dpdk0 flows:      0, RX:       0(pps) (err:     0),  0.00(Gbps), 
TX:       0(pps),  0.00(Gbps)
[ ALL ] dpdk0 flows:      0, RX:       0(pps) (err:     0),  0.00(Gbps), 
TX:       0(pps),  0.00(Gbps)

Thread 8 "ab" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fdff19fb700 (LWP 1510)]
0x00005555555dd3cd in mtcp_sock_ctrl (b=0x7fdfe4003dd0, cmd=105, num=0, 
ptr=0x560af680, close_flag=1443559040) at ab.c:692
692	    switch (cmd) {
(gdb) bt
#0  0x00005555555dd3cd in mtcp_sock_ctrl (b=0x7fdfe4003dd0, cmd=105, 
num=0, ptr=0x560af680, close_flag=1443559040) at ab.c:692
#1  0x00007ffff6474949 in BIO_ctrl () from 
/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
#2  0x00005555555dd3fb in mtcp_sock_ctrl (b=0x7fdfe4003dd0, cmd=<optimized 
out>, num=<optimized out>, ptr=0x560af680, 
    close_flag=1443559040) at ab.c:703
#3  0x00007ffff6474949 in BIO_ctrl () from 
/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
#4  0x00005555555dd3fb in mtcp_sock_ctrl (b=0x7fdfe4003dd0, cmd=<optimized 
out>, num=<optimized out>, ptr=0x560af680, 
    close_flag=1443559040) at ab.c:703
#5  0x00007ffff6474949 in BIO_ctrl () from 
/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
#6  0x00005555555dd3fb in mtcp_sock_ctrl (b=0x7fdfe4003dd0, cmd=<optimized 
out>, num=<optimized out>, ptr=0x560af680, 
    close_flag=1443559040) at ab.c:703
....loop continues....

How do I avoid the loops?

here is the changed code:

#ifdef USE_SSL

#ifndef OPENSSL_NO_SOCK

#include <openssl/bio.h>
#include "openssl-compat.h"
#define get_last_socket_error() errno
#define clear_socket_error()    errno=0
/* clone of openssl crypto/bio/bss_sock.c */

#ifdef HAVE_MTCP

static int mtcp_sock_write(BIO *h, const char *buf, int num, int 
close_flag);
static int mtcp_sock_read(BIO *h, char *buf, int size, int close_flag);
static int mtcp_sock_puts(BIO *h, const char *str, int close_flag);
static long mtcp_sock_ctrl(BIO *h, int cmd, long arg1, void *arg2, int 
close_flag);
static int mtcp_sock_new(BIO *h);
static int mtcp_sock_free(BIO *data, int close_flag);
int BIO_mtcp_sock_should_retry(int s);

static BIO_METHOD *mtcp_methods_sockp;

static BIO_METHOD *
BIO_mtcp_s_socket(void)
{
        if (mtcp_methods_sockp == NULL) {
                mtcp_methods_sockp = BIO_meth_new(BIO_TYPE_SOCKET, 
"socket");
                if (mtcp_methods_sockp == NULL)
                        return NULL;
                BIO_meth_set_write(mtcp_methods_sockp, mtcp_sock_write);
                BIO_meth_set_read(mtcp_methods_sockp, mtcp_sock_read);
                BIO_meth_set_puts(mtcp_methods_sockp, mtcp_sock_puts);
                BIO_meth_set_ctrl(mtcp_methods_sockp, mtcp_sock_ctrl);
                BIO_meth_set_create(mtcp_methods_sockp, mtcp_sock_new);
                BIO_meth_set_destroy(mtcp_methods_sockp, mtcp_sock_free);
        }
        return mtcp_methods_sockp;
}

BIO *BIO_mtcp_new_socket(mctx_t mctx, int fd, int close_flag)
{
    BIO *ret;

    if(!fd)
        return NULL;
    ret = BIO_new(BIO_mtcp_s_socket());
    if (ret == NULL)
        return (NULL);
    BIO_set_init(ret, 1);
    BIO_set_fd(ret, fd, close_flag);
    BIO_set_data(ret, mctx);
    return (ret);
}

static int mtcp_sock_new(BIO *bi)
{
    BIO_set_init(bi, 0);
   // BIO_set_fd(bi, fd, close_flag)
    BIO_set_data(bi, NULL);
    BIO_set_flags(bi, 0);
    return (1);
}
static int mtcp_sock_free(BIO *a, int close_flag)
{
    if (a == NULL)
        return (0);
    mctx_t mctx = (mctx_t)BIO_get_data(a);
    mtcp_close(mctx, BIO_get_fd(a, close_flag));

    return (1);
}

static int mtcp_sock_read(BIO *b, char *out, int outl, int close_flag)
{
    int ret = 0;
    mctx_t mctx = (mctx_t)BIO_get_data(b);

    if (out != NULL) {
        clear_socket_error();
        //ret = readsocket(b->num, out, outl);
        ret = mtcp_read(mctx, BIO_get_fd(b, close_flag), out, outl);
        BIO_clear_retry_flags(b);
        if (ret <= 0) {
            if (BIO_mtcp_sock_should_retry(ret))
                BIO_set_retry_read(b);
        }
    }
    return (ret);
}

static int mtcp_sock_write(BIO *b, const char *in, int inl, int 
close_flag)
{
    int ret;
    mctx_t mctx = (mctx_t)BIO_get_data(b);

    clear_socket_error();
    //ret = writesocket(b->num, in, inl);
    ret = mtcp_write(mctx, BIO_get_fd(b, close_flag), in, inl);
    BIO_clear_retry_flags(b);
    if (ret <= 0) {
        if (BIO_mtcp_sock_should_retry(ret))
            BIO_set_retry_write(b);
    }
    return (ret);
}


static long mtcp_sock_ctrl(BIO *b, int cmd, long num, void *ptr, int 
close_flag)
{
    long ret = 1;
    int *ip;

    switch (cmd) {
    case BIO_C_SET_FD:
        mtcp_sock_free(b, close_flag);
        BIO_set_fd(b, *((int *)ptr), close_flag);
        BIO_set_shutdown(b, (int)num);
        BIO_set_init(b, 1);
        break;
    case BIO_C_GET_FD:
        if (BIO_get_init(b)) {
            ip = (int *)ptr;
            if (ip != NULL)
                *ip = BIO_get_fd(b, close_flag);
            ret = BIO_get_fd(b, close_flag);
        } else
            ret = -1;
        break;
    case BIO_CTRL_GET_CLOSE:
        ret = BIO_get_shutdown(b);
        break;
    case BIO_CTRL_SET_CLOSE:
        BIO_set_shutdown(b, (int)num);
        break;
    case BIO_CTRL_DUP:
    case BIO_CTRL_FLUSH:
        ret = 1;
        break;
    default:
        ret = 0;
        break;
    }
    return (ret);
}

static int mtcp_sock_puts(BIO *bp, const char *str, int close_flag)
{
    int n, ret;

    n = strlen(str);
    ret = mtcp_sock_write(bp, str, n, close_flag);
    return (ret);
}



More information about the openssl-users mailing list