Annotation of embedaddon/php/main/suhosin_patch.c, revision 1.1.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>