Skip to content

Commit f0d2a0e

Browse files
committed
Encapsulate FastCGI implementation details.
Previously fcgi_request defined in main/fastcgi.h might be treated differently in different files, because of different behavior of #ifdef TCP_NODELAY. This leaded to stack memory corruption and unpredictable crashes.
1 parent 7a01c44 commit f0d2a0e

File tree

4 files changed

+142
-132
lines changed

4 files changed

+142
-132
lines changed

main/fastcgi.c

+111-5
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,106 @@ static int is_impersonate = 0;
132132

133133
#include "fastcgi.h"
134134

135+
typedef struct _fcgi_header {
136+
unsigned char version;
137+
unsigned char type;
138+
unsigned char requestIdB1;
139+
unsigned char requestIdB0;
140+
unsigned char contentLengthB1;
141+
unsigned char contentLengthB0;
142+
unsigned char paddingLength;
143+
unsigned char reserved;
144+
} fcgi_header;
145+
146+
typedef struct _fcgi_begin_request {
147+
unsigned char roleB1;
148+
unsigned char roleB0;
149+
unsigned char flags;
150+
unsigned char reserved[5];
151+
} fcgi_begin_request;
152+
153+
typedef struct _fcgi_begin_request_rec {
154+
fcgi_header hdr;
155+
fcgi_begin_request body;
156+
} fcgi_begin_request_rec;
157+
158+
typedef struct _fcgi_end_request {
159+
unsigned char appStatusB3;
160+
unsigned char appStatusB2;
161+
unsigned char appStatusB1;
162+
unsigned char appStatusB0;
163+
unsigned char protocolStatus;
164+
unsigned char reserved[3];
165+
} fcgi_end_request;
166+
167+
typedef struct _fcgi_end_request_rec {
168+
fcgi_header hdr;
169+
fcgi_end_request body;
170+
} fcgi_end_request_rec;
171+
172+
typedef struct _fcgi_hash_bucket {
173+
unsigned int hash_value;
174+
unsigned int var_len;
175+
char *var;
176+
unsigned int val_len;
177+
char *val;
178+
struct _fcgi_hash_bucket *next;
179+
struct _fcgi_hash_bucket *list_next;
180+
} fcgi_hash_bucket;
181+
182+
typedef struct _fcgi_hash_buckets {
183+
unsigned int idx;
184+
struct _fcgi_hash_buckets *next;
185+
struct _fcgi_hash_bucket data[FCGI_HASH_TABLE_SIZE];
186+
} fcgi_hash_buckets;
187+
188+
typedef struct _fcgi_data_seg {
189+
char *pos;
190+
char *end;
191+
struct _fcgi_data_seg *next;
192+
char data[1];
193+
} fcgi_data_seg;
194+
195+
typedef struct _fcgi_hash {
196+
fcgi_hash_bucket *hash_table[FCGI_HASH_TABLE_SIZE];
197+
fcgi_hash_bucket *list;
198+
fcgi_hash_buckets *buckets;
199+
fcgi_data_seg *data;
200+
} fcgi_hash;
201+
202+
typedef struct _fcgi_req_hook fcgi_req_hook;
203+
204+
struct _fcgi_req_hook {
205+
void(*on_accept)();
206+
void(*on_read)();
207+
void(*on_close)();
208+
};
209+
210+
struct _fcgi_request {
211+
int listen_socket;
212+
int tcp;
213+
int fd;
214+
int id;
215+
int keep;
216+
#ifdef TCP_NODELAY
217+
int nodelay;
218+
#endif
219+
int closed;
220+
int in_len;
221+
int in_pad;
222+
223+
fcgi_header *out_hdr;
224+
225+
unsigned char *out_pos;
226+
unsigned char out_buf[1024*8];
227+
unsigned char reserved[sizeof(fcgi_end_request_rec)];
228+
229+
fcgi_req_hook hook;
230+
231+
int has_env;
232+
fcgi_hash env;
233+
};
234+
135235
/* maybe it's better to use weak name instead */
136236
#ifndef HAVE_ATTRIBUTE_WEAK
137237
static fcgi_logger fcgi_log;
@@ -772,9 +872,9 @@ static void fcgi_hook_dummy() {
772872
return;
773873
}
774874

775-
fcgi_request *fcgi_init_request(fcgi_request *req, int listen_socket)
875+
fcgi_request *fcgi_init_request(int listen_socket, void(*on_accept)(), void(*on_read)(), void(*on_close)())
776876
{
777-
memset(req, 0, sizeof(fcgi_request));
877+
fcgi_request *req = calloc(1, sizeof(fcgi_request));
778878
req->listen_socket = listen_socket;
779879
req->fd = -1;
780880
req->id = -1;
@@ -794,9 +894,9 @@ fcgi_request *fcgi_init_request(fcgi_request *req, int listen_socket)
794894
795895
*/
796896
req->out_pos = req->out_buf;
797-
req->hook.on_accept = fcgi_hook_dummy;
798-
req->hook.on_read = fcgi_hook_dummy;
799-
req->hook.on_close = fcgi_hook_dummy;
897+
req->hook.on_accept = on_accept ? on_accept : fcgi_hook_dummy;
898+
req->hook.on_read = on_read ? on_read : fcgi_hook_dummy;
899+
req->hook.on_close = on_close ? on_close : fcgi_hook_dummy;
800900

801901
#ifdef _WIN32
802902
req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
@@ -809,6 +909,7 @@ fcgi_request *fcgi_init_request(fcgi_request *req, int listen_socket)
809909

810910
void fcgi_destroy_request(fcgi_request *req) {
811911
fcgi_hash_destroy(&req->env);
912+
free(req);
812913
}
813914

814915
static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
@@ -1553,6 +1654,11 @@ int fcgi_finish_request(fcgi_request *req, int force_close)
15531654
return ret;
15541655
}
15551656

1657+
int fcgi_has_env(fcgi_request *req)
1658+
{
1659+
return req && req->has_env;
1660+
}
1661+
15561662
char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
15571663
{
15581664
unsigned int val_len;

main/fastcgi.h

+3-101
Original file line numberDiff line numberDiff line change
@@ -77,43 +77,6 @@ typedef enum _fcgi_protocol_status {
7777
FCGI_UNKNOWN_ROLE = 3
7878
} dcgi_protocol_status;
7979

80-
typedef struct _fcgi_header {
81-
unsigned char version;
82-
unsigned char type;
83-
unsigned char requestIdB1;
84-
unsigned char requestIdB0;
85-
unsigned char contentLengthB1;
86-
unsigned char contentLengthB0;
87-
unsigned char paddingLength;
88-
unsigned char reserved;
89-
} fcgi_header;
90-
91-
typedef struct _fcgi_begin_request {
92-
unsigned char roleB1;
93-
unsigned char roleB0;
94-
unsigned char flags;
95-
unsigned char reserved[5];
96-
} fcgi_begin_request;
97-
98-
typedef struct _fcgi_begin_request_rec {
99-
fcgi_header hdr;
100-
fcgi_begin_request body;
101-
} fcgi_begin_request_rec;
102-
103-
typedef struct _fcgi_end_request {
104-
unsigned char appStatusB3;
105-
unsigned char appStatusB2;
106-
unsigned char appStatusB1;
107-
unsigned char appStatusB0;
108-
unsigned char protocolStatus;
109-
unsigned char reserved[3];
110-
} fcgi_end_request;
111-
112-
typedef struct _fcgi_end_request_rec {
113-
fcgi_header hdr;
114-
fcgi_end_request body;
115-
} fcgi_end_request_rec;
116-
11780
/* FastCGI client API */
11881

11982
typedef void (*fcgi_apply_func)(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg);
@@ -122,69 +85,7 @@ typedef void (*fcgi_apply_func)(char *var, unsigned int var_len, char *val, unsi
12285
#define FCGI_HASH_TABLE_MASK (FCGI_HASH_TABLE_SIZE - 1)
12386
#define FCGI_HASH_SEG_SIZE 4096
12487

125-
typedef struct _fcgi_hash_bucket {
126-
unsigned int hash_value;
127-
unsigned int var_len;
128-
char *var;
129-
unsigned int val_len;
130-
char *val;
131-
struct _fcgi_hash_bucket *next;
132-
struct _fcgi_hash_bucket *list_next;
133-
} fcgi_hash_bucket;
134-
135-
typedef struct _fcgi_hash_buckets {
136-
unsigned int idx;
137-
struct _fcgi_hash_buckets *next;
138-
struct _fcgi_hash_bucket data[FCGI_HASH_TABLE_SIZE];
139-
} fcgi_hash_buckets;
140-
141-
typedef struct _fcgi_data_seg {
142-
char *pos;
143-
char *end;
144-
struct _fcgi_data_seg *next;
145-
char data[1];
146-
} fcgi_data_seg;
147-
148-
typedef struct _fcgi_hash {
149-
fcgi_hash_bucket *hash_table[FCGI_HASH_TABLE_SIZE];
150-
fcgi_hash_bucket *list;
151-
fcgi_hash_buckets *buckets;
152-
fcgi_data_seg *data;
153-
} fcgi_hash;
154-
155-
typedef struct _fcgi_request fcgi_request;
156-
typedef struct _fcgi_req_hook fcgi_req_hook;
157-
158-
struct _fcgi_req_hook {
159-
void(*on_accept)();
160-
void(*on_read)();
161-
void(*on_close)();
162-
};
163-
164-
struct _fcgi_request {
165-
int listen_socket;
166-
int tcp;
167-
int fd;
168-
int id;
169-
int keep;
170-
#ifdef TCP_NODELAY
171-
int nodelay;
172-
#endif
173-
int closed;
174-
int in_len;
175-
int in_pad;
176-
177-
fcgi_header *out_hdr;
178-
179-
unsigned char *out_pos;
180-
unsigned char out_buf[1024*8];
181-
unsigned char reserved[sizeof(fcgi_end_request_rec)];
182-
183-
fcgi_req_hook hook;
184-
185-
int has_env;
186-
fcgi_hash env;
187-
};
88+
typedef struct _fcgi_request fcgi_request;
18889

18990
int fcgi_init(void);
19091
void fcgi_shutdown(void);
@@ -194,7 +95,7 @@ void fcgi_close(fcgi_request *req, int force, int destroy);
19495
int fcgi_in_shutdown(void);
19596
void fcgi_terminate(void);
19697
int fcgi_listen(const char *path, int backlog);
197-
fcgi_request* fcgi_init_request(fcgi_request *request, int listen_socket);
98+
fcgi_request* fcgi_init_request(int listen_socket, void(*on_accept)(), void(*on_read)(), void(*on_close)());
19899
void fcgi_destroy_request(fcgi_request *req);
199100
void fcgi_set_allowed_clients(char *ip);
200101
int fcgi_accept_request(fcgi_request *req);
@@ -207,6 +108,7 @@ typedef void (*fcgi_logger)(int type, const char *fmt, ...);
207108
void fcgi_set_logger(fcgi_logger lg);
208109
#endif
209110

111+
int fcgi_has_env(fcgi_request *req);
210112
char* fcgi_getenv(fcgi_request *req, const char* var, int var_len);
211113
char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val);
212114
char* fcgi_quick_getenv(fcgi_request *req, const char* var, int var_len, unsigned int hash_value);

sapi/cgi/cgi_main.c

+14-13
Original file line numberDiff line numberDiff line change
@@ -1036,12 +1036,12 @@ static int is_valid_path(const char *path)
10361036
/* }}} */
10371037

10381038
#define CGI_GETENV(name) \
1039-
((request->has_env) ? \
1039+
((has_env) ? \
10401040
FCGI_GETENV(request, name) : \
10411041
getenv(name))
10421042

10431043
#define CGI_PUTENV(name, value) \
1044-
((request->has_env) ? \
1044+
((has_env) ? \
10451045
FCGI_PUTENV(request, name, value) : \
10461046
_sapi_cgi_putenv(name, sizeof(name)-1, value))
10471047

@@ -1113,6 +1113,7 @@ static int is_valid_path(const char *path)
11131113
*/
11141114
static void init_request_info(fcgi_request *request)
11151115
{
1116+
int has_env = fcgi_has_env(request);
11161117
char *env_script_filename = CGI_GETENV("SCRIPT_FILENAME");
11171118
char *env_path_translated = CGI_GETENV("PATH_TRANSLATED");
11181119
char *script_path_translated = env_script_filename;
@@ -1734,7 +1735,7 @@ int main(int argc, char *argv[])
17341735
int fastcgi;
17351736
char *bindpath = NULL;
17361737
int fcgi_fd = 0;
1737-
fcgi_request request = {0};
1738+
fcgi_request *request = NULL;
17381739
int warmup_repeats = 0;
17391740
int repeats = 1;
17401741
int benchmark = 0;
@@ -1972,7 +1973,7 @@ consult the installation file that came with this distribution, or visit \n\
19721973
php_import_environment_variables = cgi_php_import_environment_variables;
19731974

19741975
/* library is already initialized, now init our request */
1975-
fcgi_init_request(&request, fcgi_fd);
1976+
request = fcgi_init_request(fcgi_fd, NULL, NULL, NULL);
19761977

19771978
#ifndef PHP_WIN32
19781979
/* Pre-fork, if required */
@@ -2101,8 +2102,8 @@ consult the installation file that came with this distribution, or visit \n\
21012102
break;
21022103
case 'h':
21032104
case '?':
2104-
if (request.listen_socket) {
2105-
fcgi_destroy_request(&request);
2105+
if (request) {
2106+
fcgi_destroy_request(request);
21062107
}
21072108
fcgi_shutdown();
21082109
no_headers = 1;
@@ -2125,9 +2126,9 @@ consult the installation file that came with this distribution, or visit \n\
21252126
fcgi_impersonate();
21262127
}
21272128
#endif
2128-
while (!fastcgi || fcgi_accept_request(&request) >= 0) {
2129-
SG(server_context) = fastcgi ? (void *)&request : (void *) 1;
2130-
init_request_info(&request);
2129+
while (!fastcgi || fcgi_accept_request(request) >= 0) {
2130+
SG(server_context) = fastcgi ? (void *)request : (void *) 1;
2131+
init_request_info(request);
21312132

21322133
if (!cgi && !fastcgi) {
21332134
while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
@@ -2312,7 +2313,7 @@ consult the installation file that came with this distribution, or visit \n\
23122313
* get path_translated */
23132314
if (php_request_startup() == FAILURE) {
23142315
if (fastcgi) {
2315-
fcgi_finish_request(&request, 1);
2316+
fcgi_finish_request(request, 1);
23162317
}
23172318
SG(server_context) = NULL;
23182319
php_module_shutdown();
@@ -2523,7 +2524,7 @@ consult the installation file that came with this distribution, or visit \n\
25232524
/* only fastcgi will get here */
25242525
requests++;
25252526
if (max_requests && (requests == max_requests)) {
2526-
fcgi_finish_request(&request, 1);
2527+
fcgi_finish_request(request, 1);
25272528
if (bindpath) {
25282529
free(bindpath);
25292530
}
@@ -2536,8 +2537,8 @@ consult the installation file that came with this distribution, or visit \n\
25362537
/* end of fastcgi loop */
25372538
}
25382539

2539-
if (request.listen_socket) {
2540-
fcgi_destroy_request(&request);
2540+
if (request) {
2541+
fcgi_destroy_request(request);
25412542
}
25422543
fcgi_shutdown();
25432544

0 commit comments

Comments
 (0)