Annotation of embedaddon/php/main/suhosin_patch.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | Suhosin Patch for PHP |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 2004-2010 Stefan Esser |
! 6: +----------------------------------------------------------------------+
! 7: | This source file is subject to version 2.02 of the PHP license, |
! 8: | that is bundled with this package in the file LICENSE, and is |
! 9: | available at through the world-wide-web at |
! 10: | http://www.php.net/license/2_02.txt. |
! 11: | If you did not receive a copy of the PHP license and are unable to |
! 12: | obtain it through the world-wide-web, please send a note to |
! 13: | license@php.net so we can mail you a copy immediately. |
! 14: +----------------------------------------------------------------------+
! 15: | Author: Stefan Esser <sesser@hardened-php.net> |
! 16: +----------------------------------------------------------------------+
! 17: */
! 18: /* $Id: suhosin_patch.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */
! 19:
! 20: #include "php.h"
! 21:
! 22: #include <stdio.h>
! 23: #include <stdlib.h>
! 24: #include <sys/mman.h>
! 25:
! 26: #if HAVE_UNISTD_H
! 27: #include <unistd.h>
! 28: #endif
! 29: #include "SAPI.h"
! 30: #include "php_globals.h"
! 31:
! 32: #if SUHOSIN_PATCH
! 33:
! 34: #ifdef HAVE_SYS_SOCKET_H
! 35: #include <sys/socket.h>
! 36: #endif
! 37:
! 38: #if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE)
! 39: #undef AF_UNIX
! 40: #endif
! 41:
! 42: #if defined(AF_UNIX)
! 43: #include <sys/un.h>
! 44: #endif
! 45:
! 46: #define SYSLOG_PATH "/dev/log"
! 47:
! 48: #ifdef PHP_WIN32
! 49: static HANDLE log_source = 0;
! 50: #endif
! 51:
! 52: #include "snprintf.h"
! 53:
! 54: #include "suhosin_patch.h"
! 55:
! 56: #ifdef ZTS
! 57: #include "suhosin_globals.h"
! 58: int suhosin_patch_globals_id;
! 59: #else
! 60: struct _suhosin_patch_globals suhosin_patch_globals;
! 61: #endif
! 62:
! 63: static char *suhosin_config = NULL;
! 64:
! 65: static zend_intptr_t SUHOSIN_POINTER_GUARD = 0;
! 66:
! 67: static void php_security_log(int loglevel, char *fmt, ...);
! 68:
! 69: static void suhosin_patch_globals_ctor(suhosin_patch_globals_struct *suhosin_patch_globals TSRMLS_DC)
! 70: {
! 71: memset(suhosin_patch_globals, 0, sizeof(*suhosin_patch_globals));
! 72: }
! 73:
! 74: ZEND_API char suhosin_get_config(int element)
! 75: {
! 76: return ((char *)SUHOSIN_MANGLE_PTR(suhosin_config))[element];
! 77: }
! 78:
! 79: static void suhosin_set_config(int element, char value)
! 80: {
! 81: ((char *)SUHOSIN_MANGLE_PTR(suhosin_config))[element] = value;
! 82: }
! 83:
! 84: static void suhosin_read_configuration_from_environment()
! 85: {
! 86: char *tmp;
! 87:
! 88: /* check if canary protection should be activated or not */
! 89: tmp = getenv("SUHOSIN_MM_USE_CANARY_PROTECTION");
! 90: /* default to activated */
! 91: suhosin_set_config(SUHOSIN_MM_USE_CANARY_PROTECTION, 1);
! 92: if (tmp) {
! 93: int flag = zend_atoi(tmp, 0);
! 94: suhosin_set_config(SUHOSIN_MM_USE_CANARY_PROTECTION, flag);
! 95: }
! 96:
! 97: /* check if free memory should be overwritten with 0xFF or not */
! 98: tmp = getenv("SUHOSIN_MM_DESTROY_FREE_MEMORY");
! 99: /* default to deactivated */
! 100: suhosin_set_config(SUHOSIN_MM_DESTROY_FREE_MEMORY, 0);
! 101: if (tmp) {
! 102: int flag = zend_atoi(tmp, 0);
! 103: suhosin_set_config(SUHOSIN_MM_DESTROY_FREE_MEMORY, flag);
! 104: }
! 105:
! 106: /* check if canary violations should be ignored */
! 107: tmp = getenv("SUHOSIN_MM_IGNORE_CANARY_VIOLATION");
! 108: /* default to NOT ignore */
! 109: suhosin_set_config(SUHOSIN_MM_IGNORE_CANARY_VIOLATION, 0);
! 110: if (tmp) {
! 111: int flag = zend_atoi(tmp, 0);
! 112: suhosin_set_config(SUHOSIN_MM_IGNORE_CANARY_VIOLATION, flag);
! 113: }
! 114:
! 115: /* check if invalid hashtable destructors should be ignored */
! 116: tmp = getenv("SUHOSIN_HT_IGNORE_INVALID_DESTRUCTOR");
! 117: /* default to NOT ignore */
! 118: suhosin_set_config(SUHOSIN_HT_IGNORE_INVALID_DESTRUCTOR, 0);
! 119: if (tmp) {
! 120: int flag = zend_atoi(tmp, 0);
! 121: suhosin_set_config(SUHOSIN_HT_IGNORE_INVALID_DESTRUCTOR, flag);
! 122: }
! 123:
! 124: /* check if invalid linkedlist destructors should be ignored */
! 125: tmp = getenv("SUHOSIN_LL_IGNORE_INVALID_DESTRUCTOR");
! 126: /* default to NOT ignore */
! 127: suhosin_set_config(SUHOSIN_LL_IGNORE_INVALID_DESTRUCTOR, 0);
! 128: if (tmp) {
! 129: int flag = zend_atoi(tmp, 0);
! 130: suhosin_set_config(SUHOSIN_LL_IGNORE_INVALID_DESTRUCTOR, flag);
! 131: }
! 132:
! 133: suhosin_set_config(SUHOSIN_CONFIG_SET, 1);
! 134: }
! 135:
! 136: static void suhosin_write_protect_configuration()
! 137: {
! 138: /* check return value of mprotect() to ensure memory is read only now */
! 139: if (mprotect(SUHOSIN_MANGLE_PTR(suhosin_config), sysconf(_SC_PAGESIZE), PROT_READ) != 0) {
! 140: perror("suhosin");
! 141: _exit(1);
! 142: }
! 143: }
! 144:
! 145: PHPAPI void suhosin_startup()
! 146: {
! 147: #ifdef ZTS
! 148: ts_allocate_id(&suhosin_patch_globals_id, sizeof(suhosin_patch_globals_struct), (ts_allocate_ctor) suhosin_patch_globals_ctor, NULL);
! 149: #else
! 150: suhosin_patch_globals_ctor(&suhosin_patch_globals TSRMLS_CC);
! 151: #endif
! 152: zend_suhosin_log = php_security_log;
! 153:
! 154: /* get the pointer guardian and ensure low 3 bits are 1 */
! 155: if (SUHOSIN_POINTER_GUARD == 0) {
! 156: zend_canary(&SUHOSIN_POINTER_GUARD, sizeof(SUHOSIN_POINTER_GUARD));
! 157: SUHOSIN_POINTER_GUARD |= 7;
! 158: }
! 159:
! 160: if (!suhosin_config) {
! 161: #ifndef MAP_ANONYMOUS
! 162: #define MAP_ANONYMOUS MAP_ANON
! 163: #endif
! 164: suhosin_config = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
! 165: if (suhosin_config == MAP_FAILED) {
! 166: perror("suhosin");
! 167: _exit(1);
! 168: }
! 169: suhosin_config = SUHOSIN_MANGLE_PTR(suhosin_config);
! 170: }
! 171: if (!SUHOSIN_CONFIG(SUHOSIN_CONFIG_SET)) {
! 172: suhosin_read_configuration_from_environment();
! 173: suhosin_write_protect_configuration();
! 174: }
! 175: }
! 176:
! 177: static char *loglevel2string(int loglevel)
! 178: {
! 179: switch (loglevel) {
! 180: case S_FILES:
! 181: return "FILES";
! 182: case S_INCLUDE:
! 183: return "INCLUDE";
! 184: case S_MEMORY:
! 185: return "MEMORY";
! 186: case S_MISC:
! 187: return "MISC";
! 188: case S_SESSION:
! 189: return "SESSION";
! 190: case S_SQL:
! 191: return "SQL";
! 192: case S_EXECUTOR:
! 193: return "EXECUTOR";
! 194: case S_VARS:
! 195: return "VARS";
! 196: default:
! 197: return "UNKNOWN";
! 198: }
! 199: }
! 200:
! 201: static void php_security_log(int loglevel, char *fmt, ...)
! 202: {
! 203: int s, r, i=0;
! 204: #if defined(AF_UNIX)
! 205: struct sockaddr_un saun;
! 206: #endif
! 207: #ifdef PHP_WIN32
! 208: LPTSTR strs[2];
! 209: unsigned short etype;
! 210: DWORD evid;
! 211: #endif
! 212: char buf[4096+64];
! 213: char error[4096+100];
! 214: char *ip_address;
! 215: char *fname;
! 216: char *alertstring;
! 217: int lineno;
! 218: va_list ap;
! 219: TSRMLS_FETCH();
! 220:
! 221: /*SDEBUG("(suhosin_log) loglevel: %d log_syslog: %u - log_sapi: %u - log_script: %u", loglevel, SPG(log_syslog), SPG(log_sapi), SPG(log_script));*/
! 222:
! 223: if (SPG(log_use_x_forwarded_for)) {
! 224: ip_address = sapi_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC);
! 225: if (ip_address == NULL) {
! 226: ip_address = "X-FORWARDED-FOR not set";
! 227: }
! 228: } else {
! 229: ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC);
! 230: if (ip_address == NULL) {
! 231: ip_address = "REMOTE_ADDR not set";
! 232: }
! 233: }
! 234:
! 235:
! 236: va_start(ap, fmt);
! 237: ap_php_vsnprintf(error, sizeof(error), fmt, ap);
! 238: va_end(ap);
! 239: while (error[i]) {
! 240: if (error[i] < 32) error[i] = '.';
! 241: i++;
! 242: }
! 243:
! 244: /* if (SPG(simulation)) {
! 245: alertstring = "ALERT-SIMULATION";
! 246: } else { */
! 247: alertstring = "ALERT";
! 248: /* }*/
! 249:
! 250: if (zend_is_executing(TSRMLS_C)) {
! 251: if (EG(current_execute_data)) {
! 252: lineno = EG(current_execute_data)->opline->lineno;
! 253: fname = EG(current_execute_data)->op_array->filename;
! 254: } else {
! 255: lineno = zend_get_executed_lineno(TSRMLS_C);
! 256: fname = zend_get_executed_filename(TSRMLS_C);
! 257: }
! 258: ap_php_snprintf(buf, sizeof(buf), "%s - %s (attacker '%s', file '%s', line %u)", alertstring, error, ip_address, fname, lineno);
! 259: } else {
! 260: fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC);
! 261: if (fname==NULL) {
! 262: fname = "unknown";
! 263: }
! 264: ap_php_snprintf(buf, sizeof(buf), "%s - %s (attacker '%s', file '%s')", alertstring, error, ip_address, fname);
! 265: }
! 266:
! 267: /* Syslog-Logging disabled? */
! 268: if (((SPG(log_syslog)|S_INTERNAL) & loglevel)==0) {
! 269: goto log_sapi;
! 270: }
! 271:
! 272: #if defined(AF_UNIX)
! 273: ap_php_snprintf(error, sizeof(error), "<%u>suhosin[%u]: %s\n", (unsigned int)(SPG(log_syslog_facility)|SPG(log_syslog_priority)),getpid(),buf);
! 274:
! 275: s = socket(AF_UNIX, SOCK_DGRAM, 0);
! 276: if (s == -1) {
! 277: goto log_sapi;
! 278: }
! 279:
! 280: memset(&saun, 0, sizeof(saun));
! 281: saun.sun_family = AF_UNIX;
! 282: strcpy(saun.sun_path, SYSLOG_PATH);
! 283: /*saun.sun_len = sizeof(saun);*/
! 284:
! 285: r = connect(s, (struct sockaddr *)&saun, sizeof(saun));
! 286: if (r) {
! 287: close(s);
! 288: s = socket(AF_UNIX, SOCK_STREAM, 0);
! 289: if (s == -1) {
! 290: goto log_sapi;
! 291: }
! 292:
! 293: memset(&saun, 0, sizeof(saun));
! 294: saun.sun_family = AF_UNIX;
! 295: strcpy(saun.sun_path, SYSLOG_PATH);
! 296: /*saun.sun_len = sizeof(saun);*/
! 297:
! 298: r = connect(s, (struct sockaddr *)&saun, sizeof(saun));
! 299: if (r) {
! 300: close(s);
! 301: goto log_sapi;
! 302: }
! 303: }
! 304: send(s, error, strlen(error), 0);
! 305:
! 306: close(s);
! 307: #endif
! 308: #ifdef PHP_WIN32
! 309: ap_php_snprintf(error, sizeof(error), "suhosin[%u]: %s", getpid(),buf);
! 310:
! 311: switch (SPG(log_syslog_priority)) { /* translate UNIX type into NT type */
! 312: case 1: /*LOG_ALERT:*/
! 313: etype = EVENTLOG_ERROR_TYPE;
! 314: break;
! 315: case 6: /*LOG_INFO:*/
! 316: etype = EVENTLOG_INFORMATION_TYPE;
! 317: break;
! 318: default:
! 319: etype = EVENTLOG_WARNING_TYPE;
! 320: }
! 321: evid = loglevel;
! 322: strs[0] = error;
! 323: /* report the event */
! 324: if (log_source == NULL) {
! 325: log_source = RegisterEventSource(NULL, "Suhosin-Patch-" SUHOSIN_PATCH_VERSION);
! 326: }
! 327: ReportEvent(log_source, etype, (unsigned short) SPG(log_syslog_priority), evid, NULL, 1, 0, strs, NULL);
! 328:
! 329: #endif
! 330: log_sapi:
! 331: /* SAPI Logging activated? */
! 332: /*SDEBUG("(suhosin_log) log_syslog: %u - log_sapi: %u - log_script: %u - log_phpscript: %u", SPG(log_syslog), SPG(log_sapi), SPG(log_script), SPG(log_phpscript));*/
! 333: if (((SPG(log_sapi)|S_INTERNAL) & loglevel)!=0) {
! 334: sapi_module.log_message(buf);
! 335: }
! 336:
! 337: /*log_script:*/
! 338: /* script logging activaed? */
! 339: if (((SPG(log_script) & loglevel)!=0) && SPG(log_scriptname)!=NULL) {
! 340: char cmd[8192], *cmdpos, *bufpos;
! 341: FILE *in;
! 342: int space;
! 343:
! 344: ap_php_snprintf(cmd, sizeof(cmd), "%s %s \'", SPG(log_scriptname), loglevel2string(loglevel));
! 345: space = sizeof(cmd) - strlen(cmd);
! 346: cmdpos = cmd + strlen(cmd);
! 347: bufpos = buf;
! 348: if (space <= 1) return;
! 349: while (space > 2 && *bufpos) {
! 350: if (*bufpos == '\'') {
! 351: if (space<=5) break;
! 352: *cmdpos++ = '\'';
! 353: *cmdpos++ = '\\';
! 354: *cmdpos++ = '\'';
! 355: *cmdpos++ = '\'';
! 356: bufpos++;
! 357: space-=4;
! 358: } else {
! 359: *cmdpos++ = *bufpos++;
! 360: space--;
! 361: }
! 362: }
! 363: *cmdpos++ = '\'';
! 364: *cmdpos = 0;
! 365:
! 366: if ((in=VCWD_POPEN(cmd, "r"))==NULL) {
! 367: php_security_log(S_INTERNAL, "Unable to execute logging shell script: %s", SPG(log_scriptname));
! 368: return;
! 369: }
! 370: /* read and forget the result */
! 371: while (1) {
! 372: int readbytes = fread(cmd, 1, sizeof(cmd), in);
! 373: if (readbytes<=0) {
! 374: break;
! 375: }
! 376: }
! 377: pclose(in);
! 378: }
! 379: /*log_phpscript:*/
! 380: if ((SPG(log_phpscript) & loglevel)!=0 && EG(in_execution) && SPG(log_phpscriptname) && SPG(log_phpscriptname)[0]) {
! 381: zend_file_handle file_handle;
! 382: zend_op_array *new_op_array;
! 383: zval *result = NULL;
! 384:
! 385: /*long orig_execution_depth = SPG(execution_depth);*/
! 386: zend_bool orig_safe_mode = PG(safe_mode);
! 387: char *orig_basedir = PG(open_basedir);
! 388:
! 389: char *phpscript = SPG(log_phpscriptname);
! 390: /*SDEBUG("scriptname %s", SPG(log_phpscriptname));`*/
! 391: #ifdef ZEND_ENGINE_2
! 392: if (zend_stream_open(phpscript, &file_handle TSRMLS_CC) == SUCCESS) {
! 393: #else
! 394: if (zend_open(phpscript, &file_handle) == SUCCESS && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) {
! 395: file_handle.filename = phpscript;
! 396: file_handle.free_filename = 0;
! 397: #endif
! 398: if (!file_handle.opened_path) {
! 399: file_handle.opened_path = estrndup(phpscript, strlen(phpscript));
! 400: }
! 401: new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
! 402: zend_destroy_file_handle(&file_handle TSRMLS_CC);
! 403: if (new_op_array) {
! 404: HashTable *active_symbol_table = EG(active_symbol_table);
! 405: zval *zerror, *zerror_class;
! 406:
! 407: if (active_symbol_table == NULL) {
! 408: active_symbol_table = &EG(symbol_table);
! 409: }
! 410: EG(return_value_ptr_ptr) = &result;
! 411: EG(active_op_array) = new_op_array;
! 412:
! 413: MAKE_STD_ZVAL(zerror);
! 414: MAKE_STD_ZVAL(zerror_class);
! 415: ZVAL_STRING(zerror, buf, 1);
! 416: ZVAL_LONG(zerror_class, loglevel);
! 417:
! 418: zend_hash_update(active_symbol_table, "SUHOSIN_ERROR", sizeof("SUHOSIN_ERROR"), (void **)&zerror, sizeof(zval *), NULL);
! 419: zend_hash_update(active_symbol_table, "SUHOSIN_ERRORCLASS", sizeof("SUHOSIN_ERRORCLASS"), (void **)&zerror_class, sizeof(zval *), NULL);
! 420:
! 421: /*SPG(execution_depth) = 0;*/
! 422: if (SPG(log_phpscript_is_safe)) {
! 423: PG(safe_mode) = 0;
! 424: PG(open_basedir) = NULL;
! 425: }
! 426:
! 427: zend_execute(new_op_array TSRMLS_CC);
! 428:
! 429: /*SPG(execution_depth) = orig_execution_depth;*/
! 430: PG(safe_mode) = orig_safe_mode;
! 431: PG(open_basedir) = orig_basedir;
! 432:
! 433: #ifdef ZEND_ENGINE_2
! 434: destroy_op_array(new_op_array TSRMLS_CC);
! 435: #else
! 436: destroy_op_array(new_op_array);
! 437: #endif
! 438: efree(new_op_array);
! 439: #ifdef ZEND_ENGINE_2
! 440: if (!EG(exception))
! 441: #endif
! 442: {
! 443: if (EG(return_value_ptr_ptr)) {
! 444: zval_ptr_dtor(EG(return_value_ptr_ptr));
! 445: EG(return_value_ptr_ptr) = NULL;
! 446: }
! 447: }
! 448: } else {
! 449: php_security_log(S_INTERNAL, "Unable to execute logging PHP script: %s", SPG(log_phpscriptname));
! 450: return;
! 451: }
! 452: } else {
! 453: php_security_log(S_INTERNAL, "Unable to execute logging PHP script: %s", SPG(log_phpscriptname));
! 454: return;
! 455: }
! 456: }
! 457:
! 458: }
! 459:
! 460:
! 461: #endif
! 462:
! 463: /*
! 464: * Local variables:
! 465: * tab-width: 4
! 466: * c-basic-offset: 4
! 467: * End:
! 468: * vim600: sw=4 ts=4 fdm=marker
! 469: * vim<600: sw=4 ts=4
! 470: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>