Skip to content

Instantly share code, notes, and snippets.

@ice799
Last active August 29, 2015 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ice799/abc2522397b1605a5d7f to your computer and use it in GitHub Desktop.
Save ice799/abc2522397b1605a5d7f to your computer and use it in GitHub Desktop.
Proof of concept instructions:
NOTE: I've gotten segfaults and tested the fixed package on the following systems:
Debian 7
Ubuntu 12.04
CentOS 7
The patch (which is the same on all OSes) fixed the issue in the above systems.
1.) install nginx, spawn-fcgi, libfcgi, libfcgi-dev, and ab. Package names might
drift from this depending on Linux version. In particular: ab (apachebench)
might be named: http-utils, or apache2-utils, or something else.
2.) increase your max files to some large amount, say 1048576. To do this, you
can add these lines to your /etc/security/limits.conf:
* soft nofile 1048576
* hard nofile 1048576
You may need to reboot after modifying /etc/security/limits.conf for changes to
take effect.
3.) Start nginx giving full path to the nginx.conf from this gist: sudo nginx -c `pwd`/nginx_cgi.conf
4.) Build the threaded.c example in this gist: gcc threaded.c -o threaded -lfcgi -lpthread
5.) Start the fcgi process: spawn-fcgi -p 8000 -n threaded
6.) Run apache bench to generate a lot of connections: ab -n 8192 -c 2048 http://127.0.0.1:8081/
On my tests, I get a segfault and you probably will too. It is possible that instead
you just get data corruption and don't see a segfault. If so, increase the number of -n
to ab and sooner or later the corruption will catch up to you and you will segfault.
Once you install an fcgi with the patch, the segfault stops.
events {
worker_connections 8192;
}
http {
server {
listen 8081;
server_name localhost;
location / {
fastcgi_pass 127.0.0.1:8000;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
}
}
}
/*
* threaded.c -- A simple multi-threaded FastCGI application.
*/
#ifndef lint
static const char rcsid[] = "$Id: threaded.c,v 1.9 2001/11/20 03:23:21 robs Exp $";
#endif /* not lint */
#include "fcgi_config.h"
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "fcgiapp.h"
#define THREAD_COUNT 2048
static int counts[THREAD_COUNT];
static void *doit(void *a)
{
int rc, i, thread_id = (int)a;
pid_t pid = getpid();
FCGX_Request request;
char *server_name;
FCGX_InitRequest(&request, 0, 0);
for (;;)
{
static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t counts_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Some platforms require accept() serialization, some don't.. */
pthread_mutex_lock(&accept_mutex);
rc = FCGX_Accept_r(&request);
pthread_mutex_unlock(&accept_mutex);
if (rc < 0) {
printf("bye!\n");
break;
}
server_name = FCGX_GetParam("SERVER_NAME", request.envp);
FCGX_FPrintF(request.out,
"Content-type: text/html\r\n"
"\r\n"
"<title>FastCGI Hello! (multi-threaded C, fcgiapp library)</title>"
"<h1>FastCGI Hello! (multi-threaded C, fcgiapp library)</h1>"
"Thread %d, Process %ld<p>"
"Request counts for %d threads running on host <i>%s</i><p><code>",
thread_id, pid, THREAD_COUNT, server_name ? server_name : "?");
sleep(2);
pthread_mutex_lock(&counts_mutex);
++counts[thread_id];
for (i = 0; i < THREAD_COUNT; i++)
FCGX_FPrintF(request.out, "%5d " , counts[i]);
pthread_mutex_unlock(&counts_mutex);
FCGX_Finish_r(&request);
}
return NULL;
}
int main(void)
{
int i;
pthread_t id[THREAD_COUNT];
FCGX_Init();
for (i = 1; i < THREAD_COUNT; i++)
pthread_create(&id[i], NULL, doit, (void*)i);
doit(0);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment