cURL
Haxx ad
libcurl

curl's project page on SourceForge.net

Sponsors:
Haxx

cURL > Mailing List > Monthly Index > Single Mail

curl-tracker mailing list Archives

[ curl-Bugs-1759542 ] curl writing to a wrong file descriptor causing corruption

From: SourceForge.net <noreply_at_sourceforge.net>
Date: Tue, 24 Jul 2007 05:54:14 -0700

Bugs item #1759542, was opened at 2007-07-24 18:23
Message generated for change (Settings changed) made by jayesh_a_shah
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=100976&aid=1759542&group_id=976

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: libcurl
Group: bad behaviour
Status: Open
Resolution: None
>Priority: 8
Private: No
Submitted By: Jayesh A Shah (jayesh_a_shah)
Assigned to: Daniel Stenberg (bagder)
Summary: curl writing to a wrong file descriptor causing corruption

Initial Comment:
Hi,

We are facing a issue with curl library in secure mode.

I have written down a simple program to demonstrate the issue with the curl /openssl library. This issue is seen even with latest curl library (7.16.4) and ssl (0.9.8e) libraries.

In this sample program, I do the following:

1. Initialize curl and ssl parameters
2. create a get thread
3. create a apply thread
4. wait for threads

get thread:
 
1. In the get thread, I get one file from a remote server and then notify the apply thread using global variable. To be specific, I am downloading file abc.dat to local directory as xyz.dat

In our real application, we make use of ace instead of pthreads and Ace_Message_Queue for notifying apply thread.

Apply thread:

 Wait for get thread to finish getting the data.
  open the file /root/test.dat.
  sleep for 10 secs
  close the fd for /root/test.dat

To compile this program:
  g++ -g -I<curl include path> main.cpp -lpthread -L<curl lib dir> -lcurl -L<ssl lib dir> -lssl -lcrypto -ldl -lz -o my_curl

To run this program in non secure mode:

./my_curl

To run this program in secuee mode:

./my_curl secure

When I run the program in non secure mode, there are no issues. When I run it in non secure mode, the file /root/test.dat gets corrupted.

-------------------------------------------------------Non Secure Mode:

[root_at_IMITS027 host]# ll /root/test.dat
-rw-r--r-- 1 root root 0 Jul 24 15:15 /root/test.dat
[root_at_IMITS027 host]# rm xyz.dat
rm: remove regular file `xyz.dat'? y
[root_at_IMITS027 host]# ./my_curl
Assuming non secure mode
 [root_at_IMITS027 host]# ll /root/test.dat
-rw-r--r-- 1 root root 0 Jul 24 15:15 /root/test.dat
[root_at_IMITS027 host]# ll xyz.dat
-rw-r--r-- 1 root root 595661 Jul 24 15:15 xyz.dat

Secure Mode:

[root_at_IMITS027 host]# rm xyz.dat
rm: remove regular file `xyz.dat'? y
[root_at_IMITS027 host]# rm /root/test.dat
[root_at_IMITS027 host]# touch /root/test.dat
[root_at_IMITS027 host]# ll /root/test.dat
-rw-r--r-- 1 root root 0 Jul 24 15:15 /root/test.dat
[root_at_IMITS027 host]# ./my_curl secure
running in secure mode
[root_at_IMITS027 host]# ll /root/test.dat
-rw-r--r-- 1 root root 37 Jul 24 15:16 /root/test.dat

Program code:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// File : main.cpp
//
// Description:
//

#include <pthread.h>
#include <openssl/crypto.h>
#include <curl/curl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

struct FtpFile {
  char *filename;
  FILE *stream;
};

int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
{
  struct FtpFile *out=(struct FtpFile *)stream;
  if(out && !out->stream) {
    /* open file for writing */
    out->stream=fopen(out->filename, "wb");
    if(!out->stream)
      return -1; /* failure, can't open file to write */
  }
  return fwrite(buffer, size, nmemb, out->stream);
}

bool secure = false;
volatile bool getdone = false;

#define MUTEX_TYPE pthread_mutex_t
#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
#define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
#define THREAD_ID pthread_self( )

void handle_error(const char *file, int lineno, const char *msg){
     fprintf(stderr, "** %s:%i %s\n", file, lineno, msg);
     /* exit(-1); */
 }

/* This array will store all of the mutexes available to OpenSSL. */
static MUTEX_TYPE *mutex_buf= NULL;

static void locking_function(int mode, int n, const char * file, int line)
{
  if (mode & CRYPTO_LOCK)
    MUTEX_LOCK(mutex_buf[n]);
  else
    MUTEX_UNLOCK(mutex_buf[n]);
}

static unsigned long id_function(void)
{
  return ((unsigned long)THREAD_ID);
}

int thread_setup(void)
{
  int i;

  curl_global_init(CURL_GLOBAL_ALL);
  mutex_buf = (MUTEX_TYPE *)malloc(CRYPTO_num_locks( ) * sizeof(MUTEX_TYPE));
  if (!mutex_buf)
    return 0;
  for (i = 0; i < CRYPTO_num_locks( ); i++)
    MUTEX_SETUP(mutex_buf[i]);
  CRYPTO_set_id_callback(id_function);
  CRYPTO_set_locking_callback(locking_function);
  return 1;
}

int thread_cleanup(void)
{
  int i;

  curl_global_cleanup();
  if (!mutex_buf)
    return 0;
  CRYPTO_set_id_callback(NULL);
  CRYPTO_set_locking_callback(NULL);
  for (i = 0; i < CRYPTO_num_locks( ); i++)
    MUTEX_CLEANUP(mutex_buf[i]);
  free(mutex_buf);
  mutex_buf = NULL;
  return 1;
}

void * applydata(void * in)
{
        while(!getdone);
        int fd = open("/root/test.dat", O_RDWR);
        sleep(10);
        close(fd);
        return 0;
}

void * getdata(void * in)
{

    CURL *curl;
    CURLcode res;
    struct FtpFile ftpfile={
        "xyz.dat", /* name to store the file as if succesful */
        NULL
   };

   curl = curl_easy_init();
   curl_easy_setopt(curl, CURLOPT_USERPWD, "jayesh:passwd") ;
   curl_easy_setopt(curl, CURLOPT_PORT, 0) ;
   curl_easy_setopt(curl,CURLOPT_URL, "ftp://10.0.1.27//home/jayesh/abc.dat");
 
   if(secure)
   {
    // Setting SSL for both the data and control channels
    curl_easy_setopt(curl, CURLOPT_FTP_SSL, CURLFTPSSL_ALL);

    curl_easy_setopt(curl, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_DEFAULT);

    //set the ssl version
    curl_easy_setopt(curl,CURLOPT_SSLVERSION,CURL_SSLVERSION_SSLv3);

    // Set up using the default engine
    curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);

    // Don't perform peer or host verification
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);

    curl_easy_setopt(curl, CURLOPT_SSLKEY, "passwd2");
    }

    /* Define our callback to get called when there's data to be written */
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
    /* Set a pointer to our struct to pass to the callback */
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);

    /* Switch on full protocol/debug output ?*/
    curl_easy_setopt(curl, CURLOPT_VERBOSE, true);

    res = curl_easy_perform(curl);
    if(CURLE_OK != res)
    {
      /* we failed */
      fprintf(stderr, "curl told us %d\n", res);
    }
        
    // this is only for test, we would send postmsg
    // only on success in out app
    getdone = true;

    sleep(1);
    /* always cleanup */
    curl_easy_cleanup(curl);

   if(ftpfile.stream)
    fclose(ftpfile.stream); /* close the local file */

   return 0;
}

int main(int argc, char ** argv)
{

   if(argc != 2 )
   {
        printf("Assuming non secure mode\n");
        secure = false;
   } else
   {
     if(!strcmp(argv[1], "secure"))
     {
        printf("running in secure mode\n");
        secure = true;
     } else
     {
        printf("running in non secure mode\n");
        secure = false;
     }
   }

    thread_setup();
    /* create two threads with message queue */

    pthread_t tid[2];
    pthread_create(&tid[0], NULL, getdata, NULL);
    pthread_create(&tid[1], NULL, applydata, NULL);
   

  /* now wait for all threads to terminate */
  for(int i=0; i< 2; i++) {
    pthread_join(tid[i], NULL);
    fprintf(stderr, "Thread %d terminated\n", i);
  }

  thread_cleanup();

  return 0;
}

---------------------------------------------------

----------------------------------------------------------------------

You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=100976&aid=1759542&group_id=976
Received on 2007-07-24

These mail archives are generated by hypermail.

donate! Page updated November 12, 2010.
web site info

File upload with ASP.NET