#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
+#include <limits.h>
#ifdef FPM_AUTOCONFIG_H
#include <fpm_autoconfig.h>
return pad;
}
+static inline size_t fcgi_get_params_len( int *result, unsigned char *p, unsigned char *end)
+{
+ size_t ret = 0;
+
+ if (p < end) {
+ *result = p[0];
+ if (*result < 128) {
+ ret = 1;
+ }
+ else if (p + 3 < end) {
+ *result = ((*result & 0x7f) << 24);
+ *result |= (p[1] << 16);
+ *result |= (p[2] << 8);
+ *result |= p[3];
+ ret = 4;
+ }
+ }
+ if (*result < 0) {
+ ret = 0;
+ }
+ return ret;
+}
+
+static inline int fcgi_param_get_eff_len( unsigned char *p, unsigned char *end, uint *eff_len)
+{
+ int ret = 1;
+ int zero_found = 0;
+ *eff_len = 0;
+ for (; p != end; ++p) {
+ if (*p == '\0') {
+ zero_found = 1;
+ }
+ else {
+ if (zero_found) {
+ ret = 0;
+ break;
+ }
+ if (*eff_len < ((uint)-1)) {
+ ++*eff_len;
+ }
+ else {
+ ret = 0;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
{
char buf[128];
char *tmp = buf;
- int buf_size = sizeof(buf);
+ size_t buf_size = sizeof(buf);
int name_len, val_len;
+ uint eff_name_len, eff_val_len;
char *s;
int ret = 1;
+ size_t bytes_consumed;
while (p < end) {
- name_len = *p++;
- if (name_len >= 128) {
- name_len = ((name_len & 0x7f) << 24);
- name_len |= (*p++ << 16);
- name_len |= (*p++ << 8);
- name_len |= *p++;
+ bytes_consumed = fcgi_get_params_len(&name_len, p, end);
+ if (!bytes_consumed) {
+ /* Malformated request */
+ ret = 0;
+ break;
}
- val_len = *p++;
- if (val_len >= 128) {
- val_len = ((val_len & 0x7f) << 24);
- val_len |= (*p++ << 16);
- val_len |= (*p++ << 8);
- val_len |= *p++;
+ p += bytes_consumed;
+ bytes_consumed = fcgi_get_params_len(&val_len, p, end);
+ if (!bytes_consumed) {
+ /* Malformated request */
+ ret = 0;
+ break;
}
- if (name_len + val_len < 0 ||
- name_len + val_len > end - p) {
+ p += bytes_consumed;
+ if (name_len > (INT_MAX - val_len) || /* would the addition overflow? */
+ name_len + val_len > end - p) { /* would we exceed the buffer? */
/* Malformated request */
ret = 0;
break;
}
- if (name_len+1 >= buf_size) {
- buf_size = name_len + 64;
+ if (!fcgi_param_get_eff_len(p, p+name_len, &eff_name_len) ||
+ !fcgi_param_get_eff_len(p+name_len, p+name_len+val_len, &eff_val_len)) {
+ /* Malicious request */
+ ret = 0;
+ break;
+ }
+ if (eff_name_len >= buf_size-1) {
+ if (eff_name_len > ((uint)-1)-64) {
+ ret = 0;
+ break;
+ }
+ buf_size = eff_name_len + 64;
tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
+ if (tmp == NULL) {
+ ret = 0;
+ break;
+ }
+ }
+ memcpy(tmp, p, eff_name_len);
+ tmp[eff_name_len] = 0;
+ s = estrndup((char*)p + name_len, eff_val_len);
+ if (s == NULL) {
+ ret = 0;
+ break;
}
- memcpy(tmp, p, name_len);
- tmp[name_len] = 0;
- s = estrndup((char*)p + name_len, val_len);
- zend_hash_update(req->env, tmp, name_len+1, &s, sizeof(char*), NULL);
+ zend_hash_update(req->env, tmp, eff_name_len+1, &s, sizeof(char*), NULL);
p += name_len + val_len;
}
if (tmp != buf && tmp != NULL) {