Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Libcurl (7.54.0) related stack corruption,memory leak on FreeBSD 6  #1768

@Jyoti-bdk

Description

@Jyoti-bdk

I did this

I have a multi threaded application running on Free BSD on a i386 machine out of which in the problem scenario only one thread is active which is waking up every 10 seconds and tries to do a curl_easy_perform() which fails as the DNS resolution fails (for an invalid address like https://abcd.net).
None of the other 3 threads interact with the curl library calls .

If I leave the system in this state for long time(ranging from 20 -30 hours ) ,

1- I see the one of the threads (which is supposed to be waiting in an event loop and do nothing ) gets segmentation fault .
2- Sometimes the kernel kills the process as the process overruns it's RLIMIT.

"/kernel: Process (1954,server-connect) attempted to exceed RLIMIT_DATA: attempted 131092 KB Max 131072 KB"

3 - I have also tried adding curl_global_cleanup() after curl_easy_cleanup() but result was the same .

4- The same application is running on another Octeon based platform running the same OS and there also I see the same results .

Code


static size_t
write_data_in_mem (void *buffer, size_t size, size_t nmemb, void *userp)
{
    size_t           realsize = size * nmemb;
    struct memStruct *in_mem = (struct memStruct *) userp;

    in_mem->buff = realloc(in_mem->buff, in_mem->buff_size + realsize + 1);
    if (in_mem->buff == NULL) {
	syslog(LOG_ERR, "failed to allocate %d bytes for buffer",
	       realsize+1);
	return 0;
    }

    bzero(&(in_mem->buff[in_mem->buff_size - 1]), realsize+1);
    memcpy(&(in_mem->buff[in_mem->buff_size - 1]), buffer, realsize);
    in_mem->buff_size += realsize;
    in_mem->buff[in_mem->buff_size] = 0;

    return realsize;
}

static CURL*
setup_curl_options (char *login_passwd, void *write_func,
			 void *hdrdata, void *write_data,
			 char *server_url)
{
    CURL   *curl_handle = NULL;
    object_t     *obj = get_object();
    long port = obj->curr_port;
    unsigned char *cert = obj->curr_cert;
    boolean is_https = FALSE;
    char *real_url = NULL;

    curl_handle = curl_easy_init();
    if (!curl_handle) {
	PRINT("failed to initialize curl obj");
	return NULL;
    }

    
    curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
   
    curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 10L);

  
    if (strstr(server_url, "https://") != NULL) {
	is_https = TRUE;
	curl_easy_setopt(curl_handle, CURLOPT_CAINFO, obj->ca_cert_file);
    }

    if (is_https ==TRUE) {
	/* SSL options */
	curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER , 1);
	curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST , 2);
    }

    /* providing login/passwd */
    curl_easy_setopt(curl_handle, CURLOPT_USERPWD, login_passwd);
    /* send the output to particular function */
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_func);
   /* pass structure to write function */
    curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)hdrdata);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)write_data);

  
    if (NULL != (real_url = get_complete_url_str(server_url, is_https))) {
	curl_easy_setopt(curl_handle, CURLOPT_URL, real_url);
	free(real_url);
    } else {
	curl_easy_setopt(curl_handle, CURLOPT_URL, server_url);
    }

    PRINT("Current Port:%ld", port);
    if (port) {
	curl_easy_setopt(curl_handle, CURLOPT_PORT, port);
    }

    return curl_handle;
}

int contact_server (const char* name, char *login_passwd, char * server_url )
 {
   
    CURL              *curl_handle = NULL;
    CURLcode          res = CURLE_COULDNT_CONNECT;
    struct memStruct  header = {NULL, 0};
    struct memStruct  body = {NULL, 0};
    long              resp_code = 0;
   int                 retval = -1;
   

   
    /* init buffer to save server response */
    header.buff = calloc(1, 1);
    header.buff_size = 1;
    body.buff = calloc(1, 1);
    body.buff_size = 1;

    
    curl_handle = setup_curl_options(login_passwd, write_data_in_mem,
					  (void*)&header, (void*)&body,
					  server_url);
    if (!curl_handle) {
	
	PRINT("failed to initialize curl obj");
        free(header.buff);
        free(body.buff);
	return retval;
    }

    res = curl_easy_perform(curl_handle);

    /* Check for errors */
    if (res != CURLE_OK) {
	PRINT("curl_easy_perform() failed: %s\n",
                         curl_easy_strerror(res));
        retval = -1;
        
    }
    } else {
       curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &resp_code);
       retval = 0 ;
    }  
      free(header.buff);
      free(body.buff);
      if (curl_handle) {	/* cleanup */
	curl_easy_cleanup(curl_handle);
      }
      return retval;
}



thread_main(void) 
{ 
  int retval = -1;

  while(1) 
  { 
    retval = contact_server("server1", "pwd", "https://abcd.net")
    if(retval == -1)
    {
        sleep(10);
    }
    else {
         break;
    }
  }
}

Core Analysis


(gdb) info threads
  Id   Target Id         Frame
  4    process 100149    0x4863e1e7 in sigwait () at sigwait.S:2
  3    process 100127    0x4869a57b in accept () at accept.S:2
  2    process 100128    0x486a6a73 in nanosleep () at nanosleep.S:2>>>>>>>>Uses curl 
* 1    process 100087    0xfffff078 in ?? ()>>>>>>>>>>>This one is supposed to be waiting on events which are not triggered  in the current scenario 
(gdb) bt
#0  0xfffff078 in ?? ()
#1  0x4868ad82 in res_queryN (name=0x1 <error: Cannot access memory at address 0x1>, target=<optimized out>)
    at bsd/lib/libc/net/getaddrinfo.c:2836
#2  0x48343e5a in dprintf_formatf (data=0xbf9fd1c8, stream=0x4834348e <addbyter>, format=<optimized out>,
    ap_save=0x0) at dist/curl/lib/mprintf.c:631
#3  0x482f3e60 in ?? ()
   from obj/i386/usr/lib/libcrypto.so.3
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb)
(gdb) p $sp
$23 = (void *) 0xbf9fc14c
(gdb) t 2
[Switching to thread 2 (process 100128)]
#0  0x486a6a73 in nanosleep () at nanosleep.S:2
2       nanosleep.S: No such file or directory.
(gdb) p/x $sp
$24 = 0xbf9fddfc
(gdb)
$25 = 0xbf9fddfc
(gdb) p 0xbf9fddfc - 0xbf9fc14c
$26 = 7344>>>>>>>>>>>>>>>>>>>>Clearly thread 1 has overwritten beyond it's stack limits 

I expected the following

curl/libcurl version

Curl and libcurl 7.54.0
2
3 Public curl releases: 165
4 Command line options: 207
5 curl_easy_setopt() options: 245
6 Public functions in libcurl: 61
7 Contributors: 1538
[curl -V output]

operating system

FreeBSD 6

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions