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>