eclipse/paho.mqtt.c

Get segfaults when the network is weak in SSL_CTX_set_info_callback

penglsh opened this issue · 3 comments

I always get segfaults when the network is weak. I suspect that mqtt needs to be reconnected when the network is weak, and it starts the process of creating a context. Because the original code returns 1 when the creation fails, a segfault occurs in the function SSL_CTX_set_info_callback.

Some of my analyses are below:

  1. The call stack obtained from gdb as follows:
Program terminated with signal SIGSEGV, Segmentation fault. 
#0  0x0000000000606f80 in SSL_CTX_set_info_callback () 
#1  0x0000007f85346040 in SSLSocket_setSocketForSSL (net=0x7f60045bf0, opts=0x7f600464e8, hostname=hostname@entry=0x7f60045948 "110.73.25.17:8086", hostname_len=13) at src/SSLSocket.c:696 
#2  0x0000007f8534b1c8 in MQTTAsync_connecting (m=0x7f60045678) at src/MQTTAsync.c:4133 
#3  MQTTAsync_cycle (rc=0x7f717f99b4, timeout=<optimized out>, sock=0x7f717f99b8) at src/MQTTAsync.c:4294 
#4  MQTTAsync_receiveThread (n=<optimized out>) at src/MQTTAsync.c:2480
  1. The original codes are below, which contains my analyses:
int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts)
{
    int rc = 1; <- According to OpenSSL documentation, returning 1 means success.
    ...
    if (net->ctx == NULL) <- If the context is NULL, the function tries to instantiate one.
	{
		...
		net->ctx = SSL_CTX_new(SSLv23_client_method()); <- new a instantiate for ssl ctx
		...
        if (net->ctx == NULL) <- SSL_CTX_new failed in some unexpected situations, so net->ctx is NULL.
        {
			...
            goto exit; <- If it fails to instantiate the context, it jumps to exit, with rc is 1!
        }
		...
	}
	...
    exit:
        FUNC_EXIT_RC(rc);
        return rc; <- Here returns 1 because net->ctx is NULL above.
}

int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts,
	const char* hostname, size_t hostname_len)
{
	int rc = 1;

	FUNC_ENTRY;

	if (net->ctx != NULL || (rc = SSLSocket_createContext(net, opts)) == 1) <- when net->ctx creates failed, but rc is 1 according to the function SSLSocket_createContext, it means the codes in this if will be executed.
	{
		char *hostname_plus_null;
		int i;

		SSL_CTX_set_info_callback(net->ctx, SSL_CTX_info_callback); <- Here net->ctx is NULL and let us diving in the function SSL_CTX_set_info_callback below.
		SSL_CTX_set_msg_callback(net->ctx, SSL_CTX_msg_callback); 
		...
	}
	...
}

void SSL_CTX_set_info_callback(SSL_CTX *ctx,
                               void (*cb) (const SSL *ssl, int type, int val))
{
    ctx->info_callback = cb; <- ctx is NULL but it is called as a pointer, which causes segment fault absolutely!
}

  1. The solution that comes to mind as follows:
int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts)
{
    int rc = 1;
    ...
    if (net->ctx == NULL)
	{
		...
		net->ctx = SSL_CTX_new(SSLv23_client_method());
		...
        if (net->ctx == NULL)
        {
			...
			rc = 0;	 <- If it fails to instantiate the context, it jumps to exit, but rc will be set to 0!
            goto exit;
        }
		...
	}
    ...
    exit:
        FUNC_EXIT_RC(rc);
        return rc;
}

int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts,
	const char* hostname, size_t hostname_len)
{
	int rc = 1;

	FUNC_ENTRY;

	if (net->ctx != NULL || (rc = SSLSocket_createContext(net, opts)) == 1) <- when net->ctx creates failed, and rc is 0 according to the function SSLSocket_createContext modified, it means the codes in this if will not be executed.
	{
		char *hostname_plus_null;
		int i;

		SSL_CTX_set_info_callback(net->ctx, SSL_CTX_info_callback);
		SSL_CTX_set_msg_callback(net->ctx, SSL_CTX_msg_callback); 
		...
	}
	...
}

I hope you can respond to my analysis and solution questions, thank you very much.

What version are you using?

same problem.
v1.3.12

What version are you using?

The version is 1.3.5