diff options
| author | Stefan Esser | 2015-12-17 16:35:34 +0100 |
|---|---|---|
| committer | Stefan Esser | 2015-12-17 16:35:34 +0100 |
| commit | c4c9192839ba7842f5da58f5fd525056c77cfe54 (patch) | |
| tree | 810854ddb53e03d7320570ec8d634390a849d6b2 /ifilter.c | |
| parent | aee7faf18880573b60606756a61faea32a1bb89a (diff) | |
Continue the actual porting work on GitHub
Diffstat (limited to 'ifilter.c')
| -rw-r--r-- | ifilter.c | 726 |
1 files changed, 726 insertions, 0 deletions
diff --git a/ifilter.c b/ifilter.c new file mode 100644 index 0000000..7160f10 --- /dev/null +++ b/ifilter.c | |||
| @@ -0,0 +1,726 @@ | |||
| 1 | /* | ||
| 2 | +----------------------------------------------------------------------+ | ||
| 3 | | Suhosin Version 1 | | ||
| 4 | +----------------------------------------------------------------------+ | ||
| 5 | | Copyright (c) 2006-2007 The Hardened-PHP Project | | ||
| 6 | | Copyright (c) 2007-2015 SektionEins GmbH | | ||
| 7 | +----------------------------------------------------------------------+ | ||
| 8 | | This source file is subject to version 3.01 of the PHP license, | | ||
| 9 | | that is bundled with this package in the file LICENSE, and is | | ||
| 10 | | available through the world-wide-web at the following url: | | ||
| 11 | | http://www.php.net/license/3_01.txt | | ||
| 12 | | If you did not receive a copy of the PHP license and are unable to | | ||
| 13 | | obtain it through the world-wide-web, please send a note to | | ||
| 14 | | license@php.net so we can mail you a copy immediately. | | ||
| 15 | +----------------------------------------------------------------------+ | ||
| 16 | | Author: Stefan Esser <sesser@sektioneins.de> | | ||
| 17 | +----------------------------------------------------------------------+ | ||
| 18 | */ | ||
| 19 | /* | ||
| 20 | $Id: ifilter.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifdef HAVE_CONFIG_H | ||
| 24 | #include "config.h" | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #include "php.h" | ||
| 28 | #include "php_ini.h" | ||
| 29 | #include "ext/standard/info.h" | ||
| 30 | #include "php_suhosin7.h" | ||
| 31 | #include "php_variables.h" | ||
| 32 | #include "ext/standard/php_var.h" | ||
| 33 | |||
| 34 | |||
| 35 | static void (*orig_register_server_variables)(zval *track_vars_array TSRMLS_DC) = NULL; | ||
| 36 | |||
| 37 | #if !HAVE_STRNLEN | ||
| 38 | static size_t strnlen(const char *s, size_t maxlen) { | ||
| 39 | char *r = memchr(s, '\0', maxlen); | ||
| 40 | return r ? r-s : maxlen; | ||
| 41 | } | ||
| 42 | #endif | ||
| 43 | |||
| 44 | size_t suhosin_strnspn(const char *input, size_t n, const char *accept) | ||
| 45 | { | ||
| 46 | size_t count = 0; | ||
| 47 | for (; *input != '\0' && count < n; input++, count++) { | ||
| 48 | if (strchr(accept, *input) == NULL) | ||
| 49 | break; | ||
| 50 | } | ||
| 51 | return count; | ||
| 52 | } | ||
| 53 | |||
| 54 | size_t suhosin_strncspn(const char *input, size_t n, const char *reject) | ||
| 55 | { | ||
| 56 | size_t count = 0; | ||
| 57 | for (; *input != '\0' && count < n; input++, count++) { | ||
| 58 | if (strchr(reject, *input) != NULL) | ||
| 59 | break; | ||
| 60 | } | ||
| 61 | return count; | ||
| 62 | } | ||
| 63 | |||
| 64 | |||
| 65 | /* {{{ normalize_varname | ||
| 66 | */ | ||
| 67 | void normalize_varname(char *varname) | ||
| 68 | { | ||
| 69 | char *s=varname, *index=NULL, *indexend=NULL, *p; | ||
| 70 | |||
| 71 | /* overjump leading space */ | ||
| 72 | while (*s == ' ') { | ||
| 73 | s++; | ||
| 74 | } | ||
| 75 | |||
| 76 | /* and remove it */ | ||
| 77 | if (s != varname) { | ||
| 78 | memmove(varname, s, strlen(s)+1); | ||
| 79 | } | ||
| 80 | |||
| 81 | for (p=varname; *p && *p != '['; p++) { | ||
| 82 | switch(*p) { | ||
| 83 | case ' ': | ||
| 84 | case '.': | ||
| 85 | *p='_'; | ||
| 86 | break; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | /* find index */ | ||
| 91 | index = strchr(varname, '['); | ||
| 92 | if (index) { | ||
| 93 | index++; | ||
| 94 | s=index; | ||
| 95 | } else { | ||
| 96 | return; | ||
| 97 | } | ||
| 98 | |||
| 99 | /* done? */ | ||
| 100 | while (index) { | ||
| 101 | |||
| 102 | while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') { | ||
| 103 | index++; | ||
| 104 | } | ||
| 105 | indexend = strchr(index, ']'); | ||
| 106 | indexend = indexend ? indexend + 1 : index + strlen(index); | ||
| 107 | |||
| 108 | if (s != index) { | ||
| 109 | memmove(s, index, strlen(index)+1); | ||
| 110 | s += indexend-index; | ||
| 111 | } else { | ||
| 112 | s = indexend; | ||
| 113 | } | ||
| 114 | |||
| 115 | if (*s == '[') { | ||
| 116 | s++; | ||
| 117 | index = s; | ||
| 118 | } else { | ||
| 119 | index = NULL; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | *s++='\0'; | ||
| 123 | } | ||
| 124 | /* }}} */ | ||
| 125 | |||
| 126 | static unsigned char suhosin_hexchars[] = "0123456789ABCDEF"; | ||
| 127 | |||
| 128 | static const char suhosin_is_dangerous_char[256] = { | ||
| 129 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, | ||
| 130 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 131 | 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 132 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, | ||
| 133 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 134 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 135 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 136 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 137 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 138 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 139 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 140 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 141 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 142 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 143 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 144 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
| 145 | }; | ||
| 146 | |||
| 147 | /* {{{ suhosin_server_encode | ||
| 148 | */ | ||
| 149 | static void suhosin_server_strip(HashTable *arr, char *key, int klen) | ||
| 150 | { | ||
| 151 | zval **tzval; | ||
| 152 | unsigned char *s, *t; | ||
| 153 | |||
| 154 | if (zend_hash_find(arr, key, klen, (void **) &tzval) == SUCCESS && | ||
| 155 | Z_TYPE_PP(tzval) == IS_STRING) { | ||
| 156 | |||
| 157 | s = t = (unsigned char *)Z_STRVAL_PP(tzval); | ||
| 158 | for (; *t; t++) { | ||
| 159 | if (suhosin_is_dangerous_char[*t]) { | ||
| 160 | *t = '?'; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | Z_STRLEN_PP(tzval) = t-s; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | /* }}} */ | ||
| 167 | |||
| 168 | /* {{{ suhosin_server_encode | ||
| 169 | */ | ||
| 170 | static void suhosin_server_encode(HashTable *arr, char *key, int klen) | ||
| 171 | { | ||
| 172 | zval **tzval; | ||
| 173 | unsigned char *temp = NULL, *t, *newv, *n; | ||
| 174 | int extra = 0; | ||
| 175 | |||
| 176 | if (zend_hash_find(arr, key, klen, (void **) &tzval) == SUCCESS && | ||
| 177 | Z_TYPE_PP(tzval) == IS_STRING) { | ||
| 178 | |||
| 179 | temp = (unsigned char *)Z_STRVAL_PP(tzval); | ||
| 180 | |||
| 181 | for (t = temp; *t; t++) { | ||
| 182 | if (suhosin_is_dangerous_char[*t]) { | ||
| 183 | extra += 2; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | /* no extra bytes required */ | ||
| 188 | if (extra == 0) { | ||
| 189 | return; | ||
| 190 | } | ||
| 191 | |||
| 192 | n = newv = emalloc(t - temp + 1 + extra); | ||
| 193 | t = temp; | ||
| 194 | for (t = temp; *t; t++, n++) { | ||
| 195 | if (suhosin_is_dangerous_char[*t]) { | ||
| 196 | *n++ = '%'; | ||
| 197 | *n++ = suhosin_hexchars[*t >> 4]; | ||
| 198 | *n = suhosin_hexchars[*t & 15]; | ||
| 199 | } else { | ||
| 200 | *n = *t; | ||
| 201 | } | ||
| 202 | } | ||
| 203 | *n = 0; | ||
| 204 | |||
| 205 | /* XXX: we leak memory here, but only for the duration of the request */ | ||
| 206 | Z_STRVAL_PP(tzval) = (char *)newv; | ||
| 207 | Z_STRLEN_PP(tzval) = n-newv; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | /* }}} */ | ||
| 211 | |||
| 212 | /* {{{ suhosin_register_server_variables | ||
| 213 | */ | ||
| 214 | void suhosin_register_server_variables(zval *track_vars_array TSRMLS_DC) | ||
| 215 | { | ||
| 216 | HashTable *svars; | ||
| 217 | int retval = 0, failure = 0; | ||
| 218 | |||
| 219 | orig_register_server_variables(track_vars_array TSRMLS_CC); | ||
| 220 | |||
| 221 | svars = Z_ARRVAL_P(track_vars_array); | ||
| 222 | if (!SUHOSIN_G(simulation)) { | ||
| 223 | retval = zend_hash_del(svars, "HTTP_GET_VARS", sizeof("HTTP_GET_VARS")); | ||
| 224 | if (retval == SUCCESS) failure = 1; | ||
| 225 | retval = zend_hash_del(svars, "HTTP_POST_VARS", sizeof("HTTP_POST_VARS")); | ||
| 226 | if (retval == SUCCESS) failure = 1; | ||
| 227 | retval = zend_hash_del(svars, "HTTP_COOKIE_VARS", sizeof("HTTP_COOKIE_VARS")); | ||
| 228 | if (retval == SUCCESS) failure = 1; | ||
| 229 | retval = zend_hash_del(svars, "HTTP_ENV_VARS", sizeof("HTTP_ENV_VARS")); | ||
| 230 | if (retval == SUCCESS) failure = 1; | ||
| 231 | retval = zend_hash_del(svars, "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS")); | ||
| 232 | if (retval == SUCCESS) failure = 1; | ||
| 233 | retval = zend_hash_del(svars, "HTTP_SESSION_VARS", sizeof("HTTP_SESSION_VARS")); | ||
| 234 | if (retval == SUCCESS) failure = 1; | ||
| 235 | retval = zend_hash_del(svars, "HTTP_POST_FILES", sizeof("HTTP_POST_FILES")); | ||
| 236 | if (retval == SUCCESS) failure = 1; | ||
| 237 | retval = zend_hash_del(svars, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA")); | ||
| 238 | if (retval == SUCCESS) failure = 1; | ||
| 239 | } else { | ||
| 240 | retval = zend_hash_exists(svars, "HTTP_GET_VARS", sizeof("HTTP_GET_VARS")); | ||
| 241 | retval+= zend_hash_exists(svars, "HTTP_POST_VARS", sizeof("HTTP_POST_VARS")); | ||
| 242 | retval+= zend_hash_exists(svars, "HTTP_COOKIE_VARS", sizeof("HTTP_COOKIE_VARS")); | ||
| 243 | retval+= zend_hash_exists(svars, "HTTP_ENV_VARS", sizeof("HTTP_ENV_VARS")); | ||
| 244 | retval+= zend_hash_exists(svars, "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS")); | ||
| 245 | retval+= zend_hash_exists(svars, "HTTP_SESSION_VARS", sizeof("HTTP_SESSION_VARS")); | ||
| 246 | retval+= zend_hash_exists(svars, "HTTP_POST_FILES", sizeof("HTTP_POST_FILES")); | ||
| 247 | retval+= zend_hash_exists(svars, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA")); | ||
| 248 | if (retval > 0) failure = 1; | ||
| 249 | } | ||
| 250 | |||
| 251 | if (failure) { | ||
| 252 | suhosin_log(S_VARS, "Attacker tried to overwrite a superglobal through a HTTP header"); | ||
| 253 | } | ||
| 254 | |||
| 255 | if (SUHOSIN_G(raw_cookie)) { | ||
| 256 | zval *z; | ||
| 257 | MAKE_STD_ZVAL(z); | ||
| 258 | ZVAL_STRING(z, SUHOSIN_G(raw_cookie), 1); | ||
| 259 | zend_hash_add(svars, "RAW_HTTP_COOKIE", sizeof("RAW_HTTP_COOKIE"), (void **)&z, sizeof(zval *), NULL); | ||
| 260 | } | ||
| 261 | if (SUHOSIN_G(decrypted_cookie)) { | ||
| 262 | zval *z; | ||
| 263 | MAKE_STD_ZVAL(z); | ||
| 264 | ZVAL_STRING(z, SUHOSIN_G(decrypted_cookie), 0); | ||
| 265 | zend_hash_update(svars, "HTTP_COOKIE", sizeof("HTTP_COOKIE"), (void **)&z, sizeof(zval *), NULL); | ||
| 266 | SUHOSIN_G(decrypted_cookie) = NULL; | ||
| 267 | } | ||
| 268 | |||
| 269 | if (SUHOSIN_G(server_encode)) { | ||
| 270 | /* suhosin_server_encode(svars, "argv", sizeof("argv")); */ | ||
| 271 | suhosin_server_encode(svars, "REQUEST_URI", sizeof("REQUEST_URI")); | ||
| 272 | suhosin_server_encode(svars, "QUERY_STRING", sizeof("QUERY_STRING")); | ||
| 273 | } | ||
| 274 | if (SUHOSIN_G(server_strip)) { | ||
| 275 | suhosin_server_strip(svars, "PHP_SELF", sizeof("PHP_SELF")); | ||
| 276 | suhosin_server_strip(svars, "PATH_INFO", sizeof("PATH_INFO")); | ||
| 277 | suhosin_server_strip(svars, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED")); | ||
| 278 | suhosin_server_strip(svars, "HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT")); | ||
| 279 | } | ||
| 280 | } | ||
| 281 | /* }}} */ | ||
| 282 | |||
| 283 | |||
| 284 | /* Old Input filter */ | ||
| 285 | unsigned int (*old_input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) = NULL; | ||
| 286 | |||
| 287 | /* {{{ suhosin_input_filter_wrapper | ||
| 288 | */ | ||
| 289 | unsigned int suhosin_input_filter_wrapper(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) | ||
| 290 | { | ||
| 291 | zend_bool already_scanned = SUHOSIN_G(already_scanned); | ||
| 292 | SUHOSIN_G(already_scanned) = 0; | ||
| 293 | |||
| 294 | if (SUHOSIN_G(do_not_scan)) { | ||
| 295 | if (new_val_len) { | ||
| 296 | *new_val_len = val_len; | ||
| 297 | } | ||
| 298 | return 1; | ||
| 299 | } | ||
| 300 | |||
| 301 | if (!already_scanned) { | ||
| 302 | if (suhosin_input_filter(arg, var, val, val_len, new_val_len TSRMLS_CC)==0) { | ||
| 303 | SUHOSIN_G(abort_request)=1; | ||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | if (new_val_len) { | ||
| 307 | val_len = *new_val_len; | ||
| 308 | } | ||
| 309 | } | ||
| 310 | if (old_input_filter) { | ||
| 311 | return old_input_filter(arg, var, val, val_len, new_val_len TSRMLS_CC); | ||
| 312 | } else { | ||
| 313 | return 1; | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | /* {{{ suhosin_input_filter | ||
| 318 | */ | ||
| 319 | unsigned int suhosin_input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) | ||
| 320 | { | ||
| 321 | char *index, *prev_index = NULL; | ||
| 322 | unsigned int var_len, total_len, depth = 0; | ||
| 323 | |||
| 324 | /* Mark that we were called */ | ||
| 325 | SUHOSIN_G(already_scanned) = 1; | ||
| 326 | |||
| 327 | if (new_val_len) { | ||
| 328 | *new_val_len = 0; | ||
| 329 | } | ||
| 330 | |||
| 331 | /* Drop this variable if the limit was reached */ | ||
| 332 | switch (arg) { | ||
| 333 | case PARSE_GET: | ||
| 334 | SUHOSIN_G(att_get_vars)++; | ||
| 335 | SUHOSIN_G(att_request_variables)++; | ||
| 336 | if (SUHOSIN_G(no_more_get_variables)) { | ||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | break; | ||
| 340 | case PARSE_POST: | ||
| 341 | SUHOSIN_G(att_post_vars)++; | ||
| 342 | SUHOSIN_G(att_request_variables)++; | ||
| 343 | if (SUHOSIN_G(no_more_post_variables)) { | ||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | break; | ||
| 347 | case PARSE_COOKIE: | ||
| 348 | SUHOSIN_G(att_cookie_vars)++; | ||
| 349 | SUHOSIN_G(att_request_variables)++; | ||
| 350 | if (SUHOSIN_G(no_more_cookie_variables)) { | ||
| 351 | return 0; | ||
| 352 | } | ||
| 353 | break; | ||
| 354 | default: /* we do not want to protect parse_str() and friends */ | ||
| 355 | if (new_val_len) { | ||
| 356 | *new_val_len = val_len; | ||
| 357 | } | ||
| 358 | return 1; | ||
| 359 | } | ||
| 360 | |||
| 361 | /* Drop this variable if the limit is now reached */ | ||
| 362 | switch (arg) { | ||
| 363 | case PARSE_GET: | ||
| 364 | if (SUHOSIN_G(max_get_vars) && SUHOSIN_G(max_get_vars) <= SUHOSIN_G(cur_get_vars)) { | ||
| 365 | suhosin_log(S_VARS, "configured GET variable limit exceeded - dropped variable '%s' - all further GET variables are dropped", var); | ||
| 366 | if (!SUHOSIN_G(simulation)) { | ||
| 367 | SUHOSIN_G(no_more_get_variables) = 1; | ||
| 368 | return 0; | ||
| 369 | } | ||
| 370 | } | ||
| 371 | break; | ||
| 372 | case PARSE_COOKIE: | ||
| 373 | if (SUHOSIN_G(max_cookie_vars) && SUHOSIN_G(max_cookie_vars) <= SUHOSIN_G(cur_cookie_vars)) { | ||
| 374 | suhosin_log(S_VARS, "configured COOKIE variable limit exceeded - dropped variable '%s' - all further COOKIE variables are dropped", var); | ||
| 375 | if (!SUHOSIN_G(simulation)) { | ||
| 376 | SUHOSIN_G(no_more_cookie_variables) = 1; | ||
| 377 | return 0; | ||
| 378 | } | ||
| 379 | } | ||
| 380 | break; | ||
| 381 | case PARSE_POST: | ||
| 382 | if (SUHOSIN_G(max_post_vars) && SUHOSIN_G(max_post_vars) <= SUHOSIN_G(cur_post_vars)) { | ||
| 383 | suhosin_log(S_VARS, "configured POST variable limit exceeded - dropped variable '%s' - all further POST variables are dropped", var); | ||
| 384 | if (!SUHOSIN_G(simulation)) { | ||
| 385 | SUHOSIN_G(no_more_post_variables) = 1; | ||
| 386 | return 0; | ||
| 387 | } | ||
| 388 | } | ||
| 389 | break; | ||
| 390 | } | ||
| 391 | |||
| 392 | /* Drop this variable if it begins with whitespace which is disallowed */ | ||
| 393 | if (isspace(*var)) { | ||
| 394 | if (SUHOSIN_G(disallow_ws)) { | ||
| 395 | suhosin_log(S_VARS, "request variable name begins with disallowed whitespace - dropped variable '%s'", var); | ||
| 396 | if (!SUHOSIN_G(simulation)) { | ||
| 397 | return 0; | ||
| 398 | } | ||
| 399 | } | ||
| 400 | switch (arg) { | ||
| 401 | case PARSE_GET: | ||
| 402 | if (SUHOSIN_G(disallow_get_ws)) { | ||
| 403 | suhosin_log(S_VARS, "GET variable name begins with disallowed whitespace - dropped variable '%s'", var); | ||
| 404 | if (!SUHOSIN_G(simulation)) { | ||
| 405 | return 0; | ||
| 406 | } | ||
| 407 | } | ||
| 408 | break; | ||
| 409 | case PARSE_POST: | ||
| 410 | if (SUHOSIN_G(disallow_post_ws)) { | ||
| 411 | suhosin_log(S_VARS, "POST variable name begins with disallowed whitespace - dropped variable '%s'", var); | ||
| 412 | if (!SUHOSIN_G(simulation)) { | ||
| 413 | return 0; | ||
| 414 | } | ||
| 415 | } | ||
| 416 | break; | ||
| 417 | case PARSE_COOKIE: | ||
| 418 | if (SUHOSIN_G(disallow_cookie_ws)) { | ||
| 419 | suhosin_log(S_VARS, "COOKIE variable name begins with disallowed whitespace - dropped variable '%s'", var); | ||
| 420 | if (!SUHOSIN_G(simulation)) { | ||
| 421 | return 0; | ||
| 422 | } | ||
| 423 | } | ||
| 424 | break; | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | /* Drop this variable if it exceeds the value length limit */ | ||
| 429 | if (SUHOSIN_G(max_value_length) && SUHOSIN_G(max_value_length) < val_len) { | ||
| 430 | suhosin_log(S_VARS, "configured request variable value length limit exceeded - dropped variable '%s'", var); | ||
| 431 | if (!SUHOSIN_G(simulation)) { | ||
| 432 | return 0; | ||
| 433 | } | ||
| 434 | } | ||
| 435 | switch (arg) { | ||
| 436 | case PARSE_GET: | ||
| 437 | if (SUHOSIN_G(max_get_value_length) && SUHOSIN_G(max_get_value_length) < val_len) { | ||
| 438 | suhosin_log(S_VARS, "configured GET variable value length limit exceeded - dropped variable '%s'", var); | ||
| 439 | if (!SUHOSIN_G(simulation)) { | ||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | } | ||
| 443 | break; | ||
| 444 | case PARSE_COOKIE: | ||
| 445 | if (SUHOSIN_G(max_cookie_value_length) && SUHOSIN_G(max_cookie_value_length) < val_len) { | ||
| 446 | suhosin_log(S_VARS, "configured COOKIE variable value length limit exceeded - dropped variable '%s'", var); | ||
| 447 | if (!SUHOSIN_G(simulation)) { | ||
| 448 | return 0; | ||
| 449 | } | ||
| 450 | } | ||
| 451 | break; | ||
| 452 | case PARSE_POST: | ||
| 453 | if (SUHOSIN_G(max_post_value_length) && SUHOSIN_G(max_post_value_length) < val_len) { | ||
| 454 | suhosin_log(S_VARS, "configured POST variable value length limit exceeded - dropped variable '%s'", var); | ||
| 455 | if (!SUHOSIN_G(simulation)) { | ||
| 456 | return 0; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | break; | ||
| 460 | } | ||
| 461 | |||
| 462 | /* Normalize the variable name */ | ||
| 463 | normalize_varname(var); | ||
| 464 | |||
| 465 | /* Find length of variable name */ | ||
| 466 | index = strchr(var, '['); | ||
| 467 | total_len = strlen(var); | ||
| 468 | var_len = index ? index-var : total_len; | ||
| 469 | |||
| 470 | /* Drop this variable if it exceeds the varname/total length limit */ | ||
| 471 | if (SUHOSIN_G(max_varname_length) && SUHOSIN_G(max_varname_length) < var_len) { | ||
| 472 | suhosin_log(S_VARS, "configured request variable name length limit exceeded - dropped variable '%s'", var); | ||
| 473 | if (!SUHOSIN_G(simulation)) { | ||
| 474 | return 0; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | if (SUHOSIN_G(max_totalname_length) && SUHOSIN_G(max_totalname_length) < total_len) { | ||
| 478 | suhosin_log(S_VARS, "configured request variable total name length limit exceeded - dropped variable '%s'", var); | ||
| 479 | if (!SUHOSIN_G(simulation)) { | ||
| 480 | return 0; | ||
| 481 | } | ||
| 482 | } | ||
| 483 | switch (arg) { | ||
| 484 | case PARSE_GET: | ||
| 485 | if (SUHOSIN_G(max_get_name_length) && SUHOSIN_G(max_get_name_length) < var_len) { | ||
| 486 | suhosin_log(S_VARS, "configured GET variable name length limit exceeded - dropped variable '%s'", var); | ||
| 487 | if (!SUHOSIN_G(simulation)) { | ||
| 488 | return 0; | ||
| 489 | } | ||
| 490 | } | ||
| 491 | if (SUHOSIN_G(max_get_totalname_length) && SUHOSIN_G(max_get_totalname_length) < total_len) { | ||
| 492 | suhosin_log(S_VARS, "configured GET variable total name length limit exceeded - dropped variable '%s'", var); | ||
| 493 | if (!SUHOSIN_G(simulation)) { | ||
| 494 | return 0; | ||
| 495 | } | ||
| 496 | } | ||
| 497 | break; | ||
| 498 | case PARSE_COOKIE: | ||
| 499 | if (SUHOSIN_G(max_cookie_name_length) && SUHOSIN_G(max_cookie_name_length) < var_len) { | ||
| 500 | suhosin_log(S_VARS, "configured COOKIE variable name length limit exceeded - dropped variable '%s'", var); | ||
| 501 | if (!SUHOSIN_G(simulation)) { | ||
| 502 | return 0; | ||
| 503 | } | ||
| 504 | } | ||
| 505 | if (SUHOSIN_G(max_cookie_totalname_length) && SUHOSIN_G(max_cookie_totalname_length) < total_len) { | ||
| 506 | suhosin_log(S_VARS, "configured COOKIE variable total name length limit exceeded - dropped variable '%s'", var); | ||
| 507 | if (!SUHOSIN_G(simulation)) { | ||
| 508 | return 0; | ||
| 509 | } | ||
| 510 | } | ||
| 511 | break; | ||
| 512 | case PARSE_POST: | ||
| 513 | if (SUHOSIN_G(max_post_name_length) && SUHOSIN_G(max_post_name_length) < var_len) { | ||
| 514 | suhosin_log(S_VARS, "configured POST variable name length limit exceeded - dropped variable '%s'", var); | ||
| 515 | if (!SUHOSIN_G(simulation)) { | ||
| 516 | return 0; | ||
| 517 | } | ||
| 518 | } | ||
| 519 | if (SUHOSIN_G(max_post_totalname_length) && SUHOSIN_G(max_post_totalname_length) < total_len) { | ||
| 520 | suhosin_log(S_VARS, "configured POST variable total name length limit exceeded - dropped variable '%s'", var); | ||
| 521 | if (!SUHOSIN_G(simulation)) { | ||
| 522 | return 0; | ||
| 523 | } | ||
| 524 | } | ||
| 525 | break; | ||
| 526 | } | ||
| 527 | |||
| 528 | /* Find out array depth */ | ||
| 529 | while (index) { | ||
| 530 | char *index_end; | ||
| 531 | unsigned int index_length; | ||
| 532 | |||
| 533 | /* overjump '[' */ | ||
| 534 | index++; | ||
| 535 | |||
| 536 | /* increase array depth */ | ||
| 537 | depth++; | ||
| 538 | |||
| 539 | index_end = strchr(index, ']'); | ||
| 540 | if (index_end == NULL) { | ||
| 541 | index_end = index+strlen(index); | ||
| 542 | } | ||
| 543 | |||
| 544 | index_length = index_end - index; | ||
| 545 | |||
| 546 | /* max. array index length */ | ||
| 547 | if (SUHOSIN_G(max_array_index_length) && SUHOSIN_G(max_array_index_length) < index_length) { | ||
| 548 | suhosin_log(S_VARS, "configured request variable array index length limit exceeded - dropped variable '%s'", var); | ||
| 549 | if (!SUHOSIN_G(simulation)) { | ||
| 550 | return 0; | ||
| 551 | } | ||
| 552 | } | ||
| 553 | switch (arg) { | ||
| 554 | case PARSE_GET: | ||
| 555 | if (SUHOSIN_G(max_get_array_index_length) && SUHOSIN_G(max_get_array_index_length) < index_length) { | ||
| 556 | suhosin_log(S_VARS, "configured GET variable array index length limit exceeded - dropped variable '%s'", var); | ||
| 557 | if (!SUHOSIN_G(simulation)) { | ||
| 558 | return 0; | ||
| 559 | } | ||
| 560 | } | ||
| 561 | break; | ||
| 562 | case PARSE_COOKIE: | ||
| 563 | if (SUHOSIN_G(max_cookie_array_index_length) && SUHOSIN_G(max_cookie_array_index_length) < index_length) { | ||
| 564 | suhosin_log(S_VARS, "configured COOKIE variable array index length limit exceeded - dropped variable '%s'", var); | ||
| 565 | if (!SUHOSIN_G(simulation)) { | ||
| 566 | return 0; | ||
| 567 | } | ||
| 568 | } | ||
| 569 | break; | ||
| 570 | case PARSE_POST: | ||
| 571 | if (SUHOSIN_G(max_post_array_index_length) && SUHOSIN_G(max_post_array_index_length) < index_length) { | ||
| 572 | suhosin_log(S_VARS, "configured POST variable array index length limit exceeded - dropped variable '%s'", var); | ||
| 573 | if (!SUHOSIN_G(simulation)) { | ||
| 574 | return 0; | ||
| 575 | } | ||
| 576 | } | ||
| 577 | break; | ||
| 578 | } | ||
| 579 | |||
| 580 | /* index whitelist/blacklist */ | ||
| 581 | if (SUHOSIN_G(array_index_whitelist) && *(SUHOSIN_G(array_index_whitelist))) { | ||
| 582 | if (suhosin_strnspn(index, index_length, SUHOSIN_G(array_index_whitelist)) != index_length) { | ||
| 583 | suhosin_log(S_VARS, "array index contains not whitelisted characters - dropped variable '%s'", var); | ||
| 584 | if (!SUHOSIN_G(simulation)) { | ||
| 585 | return 0; | ||
| 586 | } | ||
| 587 | } | ||
| 588 | } else if (SUHOSIN_G(array_index_blacklist) && *(SUHOSIN_G(array_index_blacklist))) { | ||
| 589 | if (suhosin_strncspn(index, index_length, SUHOSIN_G(array_index_blacklist)) != index_length) { | ||
| 590 | suhosin_log(S_VARS, "array index contains blacklisted characters - dropped variable '%s'", var); | ||
| 591 | if (!SUHOSIN_G(simulation)) { | ||
| 592 | return 0; | ||
| 593 | } | ||
| 594 | } | ||
| 595 | } | ||
| 596 | |||
| 597 | index = strchr(index, '['); | ||
| 598 | } | ||
| 599 | |||
| 600 | /* Drop this variable if it exceeds the array depth limit */ | ||
| 601 | if (SUHOSIN_G(max_array_depth) && SUHOSIN_G(max_array_depth) < depth) { | ||
| 602 | suhosin_log(S_VARS, "configured request variable array depth limit exceeded - dropped variable '%s'", var); | ||
| 603 | if (!SUHOSIN_G(simulation)) { | ||
| 604 | return 0; | ||
| 605 | } | ||
| 606 | } | ||
| 607 | switch (arg) { | ||
| 608 | case PARSE_GET: | ||
| 609 | if (SUHOSIN_G(max_get_array_depth) && SUHOSIN_G(max_get_array_depth) < depth) { | ||
| 610 | suhosin_log(S_VARS, "configured GET variable array depth limit exceeded - dropped variable '%s'", var); | ||
| 611 | if (!SUHOSIN_G(simulation)) { | ||
| 612 | return 0; | ||
| 613 | } | ||
| 614 | } | ||
| 615 | break; | ||
| 616 | case PARSE_COOKIE: | ||
| 617 | if (SUHOSIN_G(max_cookie_array_depth) && SUHOSIN_G(max_cookie_array_depth) < depth) { | ||
| 618 | suhosin_log(S_VARS, "configured COOKIE variable array depth limit exceeded - dropped variable '%s'", var); | ||
| 619 | if (!SUHOSIN_G(simulation)) { | ||
| 620 | return 0; | ||
| 621 | } | ||
| 622 | } | ||
| 623 | break; | ||
| 624 | case PARSE_POST: | ||
| 625 | if (SUHOSIN_G(max_post_array_depth) && SUHOSIN_G(max_post_array_depth) < depth) { | ||
| 626 | suhosin_log(S_VARS, "configured POST variable array depth limit exceeded - dropped variable '%s'", var); | ||
| 627 | if (!SUHOSIN_G(simulation)) { | ||
| 628 | return 0; | ||
| 629 | } | ||
| 630 | } | ||
| 631 | break; | ||
| 632 | } | ||
| 633 | |||
| 634 | /* Check if variable value is truncated by a \0 */ | ||
| 635 | |||
| 636 | if (val && *val && val_len != strnlen(*val, val_len)) { | ||
| 637 | |||
| 638 | if (SUHOSIN_G(disallow_nul)) { | ||
| 639 | suhosin_log(S_VARS, "ASCII-NUL chars not allowed within request variables - dropped variable '%s'", var); | ||
| 640 | if (!SUHOSIN_G(simulation)) { | ||
| 641 | return 0; | ||
| 642 | } | ||
| 643 | } | ||
| 644 | switch (arg) { | ||
| 645 | case PARSE_GET: | ||
| 646 | if (SUHOSIN_G(disallow_get_nul)) { | ||
| 647 | suhosin_log(S_VARS, "ASCII-NUL chars not allowed within GET variables - dropped variable '%s'", var); | ||
| 648 | if (!SUHOSIN_G(simulation)) { | ||
| 649 | return 0; | ||
| 650 | } | ||
| 651 | } | ||
| 652 | break; | ||
| 653 | case PARSE_COOKIE: | ||
| 654 | if (SUHOSIN_G(disallow_cookie_nul)) { | ||
| 655 | suhosin_log(S_VARS, "ASCII-NUL chars not allowed within COOKIE variables - dropped variable '%s'", var); | ||
| 656 | if (!SUHOSIN_G(simulation)) { | ||
| 657 | return 0; | ||
| 658 | } | ||
| 659 | } | ||
| 660 | break; | ||
| 661 | case PARSE_POST: | ||
| 662 | if (SUHOSIN_G(disallow_post_nul)) { | ||
| 663 | suhosin_log(S_VARS, "ASCII-NUL chars not allowed within POST variables - dropped variable '%s'", var); | ||
| 664 | if (!SUHOSIN_G(simulation)) { | ||
| 665 | return 0; | ||
| 666 | } | ||
| 667 | } | ||
| 668 | break; | ||
| 669 | } | ||
| 670 | } | ||
| 671 | |||
| 672 | /* Drop this variable if it is one of GLOBALS, _GET, _POST, ... */ | ||
| 673 | /* This is to protect several silly scripts that do globalizing themself */ | ||
| 674 | if (suhosin_is_protected_varname(var, var_len)) { | ||
| 675 | suhosin_log(S_VARS, "tried to register forbidden variable '%s' through %s variables", var, arg == PARSE_GET ? "GET" : arg == PARSE_POST ? "POST" : "COOKIE"); | ||
| 676 | if (!SUHOSIN_G(simulation)) { | ||
| 677 | return 0; | ||
| 678 | } | ||
| 679 | } | ||
| 680 | |||
| 681 | /* Okay let PHP register this variable */ | ||
| 682 | SUHOSIN_G(cur_request_variables)++; | ||
| 683 | switch (arg) { | ||
| 684 | case PARSE_GET: | ||
| 685 | SUHOSIN_G(cur_get_vars)++; | ||
| 686 | break; | ||
| 687 | case PARSE_COOKIE: | ||
| 688 | SUHOSIN_G(cur_cookie_vars)++; | ||
| 689 | break; | ||
| 690 | case PARSE_POST: | ||
| 691 | SUHOSIN_G(cur_post_vars)++; | ||
| 692 | break; | ||
| 693 | } | ||
| 694 | |||
| 695 | if (new_val_len) { | ||
| 696 | *new_val_len = val_len; | ||
| 697 | } | ||
| 698 | |||
| 699 | return 1; | ||
| 700 | } | ||
| 701 | /* }}} */ | ||
| 702 | |||
| 703 | |||
| 704 | |||
| 705 | /* {{{ suhosin_hook_register_server_variables | ||
| 706 | */ | ||
| 707 | void suhosin_hook_register_server_variables() | ||
| 708 | { | ||
| 709 | if (sapi_module.register_server_variables) { | ||
| 710 | orig_register_server_variables = sapi_module.register_server_variables; | ||
| 711 | sapi_module.register_server_variables = suhosin_register_server_variables; | ||
| 712 | } | ||
| 713 | } | ||
| 714 | /* }}} */ | ||
| 715 | |||
| 716 | |||
| 717 | /* | ||
| 718 | * Local variables: | ||
| 719 | * tab-width: 4 | ||
| 720 | * c-basic-offset: 4 | ||
| 721 | * End: | ||
| 722 | * vim600: noet sw=4 ts=4 fdm=marker | ||
| 723 | * vim<600: noet sw=4 ts=4 | ||
| 724 | */ | ||
| 725 | |||
| 726 | |||
