Search code examples
clinuxapachecgilibc

Remote C-based CGI Script Crashing In __libc_start_main()


I have a CGI script written in C. I know this is unorthodox in this day and age, but I have my reasons. Also, it's compiled with -static, so I don't have to worry about shared libraries on my web provider. The script has been working fine for over a year now but it recently broke. It's also notoriously difficult to debug the problem because the script is crashing on my web provider's service and I don't get much visibility. But I do get core dumps.

The problem I'm seeing is: On the remote server, the CGI script crashes and the error apparently comes from the startup code, i.e., the stuff that's executed before my main() function is ever reached (__libc_start_main()).

I have created an SSCCE that illustrates the problem, named hey.c:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  printf("Content-type: text/plain\n\n");
  printf("Hey, is this thing on?\n");
  printf("query string: '%s'\n", getenv("REQUEST_URI"));
  return 0;
}

Compiled on 64-bit Linux with gcc:

gcc -g -Wall hey.c -o hey.cgi -static

Runs fine from a prompt:

$ REQUEST_URI="q=querystring" ./hey.cgi
Content-type: text/plain

Hey, is this thing on?
query string: 'q=querystring'

When I run it locally on an Apache installation (e.g., http://localserver/cgi-bin/hey.cgi?q=query), the web page shows:

Hey, is this thing on?
query string: '/cgi-bin/hey.cgi?q=query'

However, when I put this binary onto my web provider's Apache cgi-bin directory, I get a 500 Internal Server Error. The server leaves behind numbered core dumps in the wake of the crash, which I then download and inspect with gdb:

Core was generated by `hey.cgi'.
Program terminated with signal 11, Segmentation fault.
#0  0x000000000041b763 in __syscall_error ()
(gdb) bt
#0  0x000000000041b763 in __syscall_error ()
#1  0x0000000000402569 in __libc_message ()
#2  0x000000000040283c in __libc_fatal ()
#3  0x0000000000401355 in __libc_start_main ()
#4  0x0000000000401081 in _start ()

Lots of low-level details, I know, but hopefully the problem is obvious to someone out there on Stack Overflow. Thanks.

More details, pursuant to comments: I verified with a simple Python CGI script (and os.environ[]) that REQUEST_URI is defined. I think that's core to the CGI protocol, but I'm not an expert.

file reports x86-64 statically linked binary; ldd reports 'not a dynamic executable'. Libtool never comes into play-- I use a single gcc command invocation to build the entire script.

It would be ideal to compile the script on the server. If I had that kind of access, I probably would have had enough flexibility to obviate this approach. I'm not worried about protecting source; this was just the best solution I could find to my problem. The program in question is a custom search engine for my site that consists of about 20 lines of C to interface with a library called SWISH-E. My web provider does not provide too many facilities but I was able to make this work.

Other solutions include: transferring to different hosting (a lot of trouble); finding a pure PHP-based solution that would be supported on my host (I'm investigating this via mnoGoSearch).


Solution

  • I found a solution and I wanted to post it since these Stack Overflow questions have a way of finding themselves in top Google results.

    Eventually, I plan to solve this by moving this bit of functionality to a different server or platform into which I have better debugging visibility. In the meantime, I decided that since the problem seemed to be a manifestation of compiling with -static, and because I couldn't install the necessary shared library onto the shared hosting system into the standard lib directory, instead I would take a dynamic approach. I uploaded the necessary shared object into the same directory as my compiled script and reworked my C-based CGI script to use dlopen/dlsym to dynamically open the shared object, fetch the required function pointers, and call those pointers.

    This approach works (though I'm keeping my fingers crossed that it doesn't mysteriously break again), while I research other solutions. If someone else encounters this weird combination of issues, maybe this will help.