Discussion:
SSL error after fork()
anon anon
2013-03-17 22:42:14 UTC
Permalink
I'm getting an SSL error in the child process after calling fork(). I made
a short program that can reproduce it. Basically, if I make an https
request, call fork and return the parent process, and then make a second
https request, curl_easy_perform returns 35.

Contents of the error buffer:

A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem
has occurred with the token or slot.


main.cpp:

#include <curl/curl.h>
#include <string>
#include <unistd.h>
#include <iostream>

using namespace std;

void log(string str)
{ //TODO: remove
static const char logfile[] = "/home/austin/megalog";
FILE *f = fopen(logfile, "a");
fwrite(str.data(), str.size(), 1, f);
fclose(f);
cout << str;
}

int main(int argc, char *argv[])
{
string url = "https://www.google.com/";
char errBuf[1024];
CURLcode err;

curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *handle = curl_easy_init();
curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errBuf);

if ((err = curl_easy_perform(handle)))
{
log("first request failed\n");
return 1;
}
curl_easy_cleanup(handle);

if(fork())
return 0;

handle = curl_easy_init();
curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errBuf);

if ((err = curl_easy_perform(handle)))
{
log(string("curl error while sending: (") + to_string(err) +
") " + curl_easy_strerror(err) + "\n");
log(errBuf);
}
else
log("no error\n");

return 0;
}


I'm using libcurl version 7.29.0 and openssl version ___. For more details,
see my stackoverflow question:
http://stackoverflow.com/questions/15466809/libcurl-ssl-error-after-fork
Daniel Stenberg
2013-03-17 22:53:38 UTC
Permalink
I'm getting an SSL error in the child process after calling fork(). I made a
short program that can reproduce it. Basically, if I make an https request,
call fork and return the parent process, and then make a second https
request, curl_easy_perform returns 35.
Hm, what happens if you call global_init() in the parent/child after the fork
and then try the libcurl calls? It seems your problem is related to OpenSSL
and I don't know how well it handles fork() or what requirements it then puts
on the application...
I'm using libcurl version 7.29.0 and openssl version ___.
That's a strange OpenSSL version!
Please keep details on the list to get help from people on the list!
--
/ daniel.haxx.se
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
anon anon
2013-03-17 22:59:36 UTC
Permalink
I tried that (calling global_init), no change at all.
Post by anon anon
I'm getting an SSL error in the child process after calling fork(). I
made a short program that can reproduce it. Basically, if I make an https
request, call fork and return the parent process, and then make a second
https request, curl_easy_perform returns 35.
Hm, what happens if you call global_init() in the parent/child after the
fork and then try the libcurl calls? It seems your problem is related to
OpenSSL and I don't know how well it handles fork() or what requirements it
then puts on the application...
I'm using libcurl version 7.29.0 and openssl version ___.
That's a strange OpenSSL version!
Please keep details on the list to get help from people on the list!
--
/ daniel.haxx.se
------------------------------**------------------------------**-------
List admin: http://cool.haxx.se/list/**listinfo/curl-library<http://cool.haxx.se/list/listinfo/curl-library>
Etiquette: http://curl.haxx.se/mail/**etiquette.html<http://curl.haxx.se/mail/etiquette.html>
anon anon
2013-03-17 23:02:33 UTC
Permalink
oops, I pressed send too soon...

lol, I put the ___ so I wouldn't forget to put the version number after
`yum info openssl` finished loading. I guess it didn't work... Openssl
version is 1.0.1e, which is the lastest.

I'll be sure to let you guys know if anyone finds a solution to my
stackoverflow question.
Post by anon anon
I tried that (calling global_init), no change at all.
Post by anon anon
I'm getting an SSL error in the child process after calling fork(). I
made a short program that can reproduce it. Basically, if I make an https
request, call fork and return the parent process, and then make a second
https request, curl_easy_perform returns 35.
Hm, what happens if you call global_init() in the parent/child after the
fork and then try the libcurl calls? It seems your problem is related to
OpenSSL and I don't know how well it handles fork() or what requirements it
then puts on the application...
I'm using libcurl version 7.29.0 and openssl version ___.
That's a strange OpenSSL version!
Please keep details on the list to get help from people on the list!
--
/ daniel.haxx.se
------------------------------**------------------------------**-------
List admin: http://cool.haxx.se/list/**listinfo/curl-library<http://cool.haxx.se/list/listinfo/curl-library>
Etiquette: http://curl.haxx.se/mail/**etiquette.html<http://curl.haxx.se/mail/etiquette.html>
Nathan Rosenblum
2013-03-17 23:23:17 UTC
Permalink
I'm getting an SSL error in the child process after calling fork(). I made a
short program that can reproduce it. Basically, if I make an https request,
call fork and return the parent process, and then make a second https
request, curl_easy_perform returns 35.
I haven't looked deeply into your specific problem, but in general you
should be very leery of calling fork(2) without a matching exec(2),
especially if you are using libraries or frameworks whose internals
you are not intimately familiar with & which you have initialized or
used in the parent process. The fork man page for your particular
platform should have a list of some (possibly not all) of the ways
that the child process is not exactly the same as the parent process.
If any of your libraries are starting threads, doing non-trivial
signal manipulation, setting timers, etc, you are in for a world of
hurt(*).

You noted in your stackoverflow question that this arose in the
context of fuse, which as you note uses the daemon(2) call when you
don't pass a foreground fuseArg. Since daemon basically just forks,
you should be extremely careful to do the absolute minimum of work
before calling fuse_main.

Good luck!

--nate

(*) This applies doubly on OSX, where among other things Mach ports
(used for IPC) are closed across a fork.
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
anon anon
2013-03-18 00:18:50 UTC
Permalink
While I was narrowing down the source of the problem, I had a tiny
FUSE-based driver with only the init function implemented. I made a https
request in `main` before `fuse_main` was called ("return fuse_main(..." is
the last line in `main`) and a second https request in `init`, which is
called in the child process after `fork`. I checked the FUSE source and it
does call fork.

While typing this I found out that calling `curl_global_cleanup` before
`fork` and `curl_global_init` again after fork fixes it.

Loading...