1 Star 0 Fork 0

Dean/taint

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
taint.c 56.40 KB
一键复制 编辑 原始数据 按行查看 历史
惠新宸 提交于 2020-03-27 12:47 +08:00 . Should not conflics anymore
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005
/*
+----------------------------------------------------------------------+
| Taint |
+----------------------------------------------------------------------+
| Copyright (c) 2012-2015 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Xinchen Hui <laruence@php.net> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "SAPI.h"
#include "zend_compile.h"
#include "zend_execute.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_taint.h"
static void *origin_opcode_handler[255];
ZEND_DECLARE_MODULE_GLOBALS(taint)
/* {{{ TAINT_ARG_INFO
*/
ZEND_BEGIN_ARG_INFO_EX(taint_arginfo, 0, 0, 1)
ZEND_ARG_INFO(1, string)
ZEND_ARG_INFO(1, ...)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(untaint_arginfo, 0, 0, 1)
ZEND_ARG_INFO(1, string)
ZEND_ARG_INFO(1, ...)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(is_tainted_arginfo, 0, 0, 1)
ZEND_ARG_INFO(0, string)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ taint_functions[]
*/
zend_function_entry taint_functions[] = {
PHP_FE(taint, taint_arginfo)
PHP_FE(untaint, untaint_arginfo)
PHP_FE(is_tainted, is_tainted_arginfo)
{NULL, NULL, NULL}
};
/* }}} */
/** {{{ module depends
*/
zend_module_dep taint_deps[] = {
/* ZEND_MOD_CONFLICTS("xdebug") */
{NULL, NULL, NULL}
};
/* }}} */
/* {{{ taint_module_entry
*/
zend_module_entry taint_module_entry = {
STANDARD_MODULE_HEADER_EX, NULL,
taint_deps,
"taint",
taint_functions,
PHP_MINIT(taint),
PHP_MSHUTDOWN(taint),
PHP_RINIT(taint),
PHP_RSHUTDOWN(taint),
PHP_MINFO(taint),
PHP_TAINT_VERSION,
PHP_MODULE_GLOBALS(taint),
NULL,
NULL,
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */
static struct taint_overridden_fucs /* {{{ */ {
php_func strval;
php_func sprintf;
php_func vsprintf;
php_func explode;
php_func implode;
php_func trim;
php_func rtrim;
php_func ltrim;
php_func strstr;
php_func str_pad;
php_func str_replace;
php_func str_ireplace;
php_func substr;
php_func strtolower;
php_func strtoupper;
php_func dirname;
php_func basename;
php_func pathinfo;
} taint_origin_funcs;
#define TAINT_O_FUNC(m) (taint_origin_funcs.m)
/* }}} */
/* These are most copied from zend_execute.c: zend_fetch_dimension_address */
static int php_taint_make_real_object(zval *object) /* {{{ */ {
if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
if (EXPECTED(Z_TYPE_P(object) <= IS_FALSE)) {
/* nothing to destroy */
} else if (EXPECTED((Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0))) {
zval_ptr_dtor_nogc(object);
} else {
return 0;
}
object_init(object);
zend_error(E_WARNING, "Creating default object from empty value");
}
return 1;
}
/* }}} */
static zend_long php_taint_check_string_offset(zval *dim, int type) /* {{{ */ {
zend_long offset;
try_again:
if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
switch(Z_TYPE_P(dim)) {
case IS_STRING:
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
break;
}
if (type != BP_VAR_UNSET) {
zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
}
break;
case IS_DOUBLE:
case IS_NULL:
case IS_FALSE:
case IS_TRUE:
zend_error(E_NOTICE, "String offset cast occurred");
break;
case IS_REFERENCE:
dim = Z_REFVAL_P(dim);
goto try_again;
default:
zend_error(E_WARNING, "Illegal offset type");
break;
}
offset = zval_get_long(dim);
} else {
offset = Z_LVAL_P(dim);
}
return offset;
}
/* }}} */
static zval *php_taint_fetch_dimension_address_inner(HashTable *ht, const zval *dim, int dim_type, int type) /* {{{ */ {
zval *retval;
zend_string *offset_key;
zend_ulong hval;
try_again:
if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) {
hval = Z_LVAL_P(dim);
num_index:
retval = zend_hash_index_find(ht, hval);
if (retval == NULL) {
switch (type) {
case BP_VAR_R:
zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
/* break missing intentionally */
case BP_VAR_UNSET:
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
/* break missing intentionally */
case BP_VAR_W:
retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
break;
}
}
} else if (EXPECTED(Z_TYPE_P(dim) == IS_STRING)) {
offset_key = Z_STR_P(dim);
if (dim_type != IS_CONST) {
if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
goto num_index;
}
}
str_index:
retval = zend_hash_find(ht, offset_key);
if (retval) {
/* support for $GLOBALS[...] */
if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
retval = Z_INDIRECT_P(retval);
if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
switch (type) {
case BP_VAR_R:
zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset_key));
/* break missing intentionally */
case BP_VAR_UNSET:
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
zend_error(E_NOTICE,"Undefined index: %s", ZSTR_VAL(offset_key));
/* break missing intentionally */
case BP_VAR_W:
ZVAL_NULL(retval);
break;
}
}
}
} else {
switch (type) {
case BP_VAR_R:
zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset_key));
/* break missing intentionally */
case BP_VAR_UNSET:
case BP_VAR_IS:
retval = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
zend_error(E_NOTICE,"Undefined index: %s", ZSTR_VAL(offset_key));
/* break missing intentionally */
case BP_VAR_W:
retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval));
break;
}
}
} else {
switch (Z_TYPE_P(dim)) {
case IS_NULL:
offset_key = ZSTR_EMPTY_ALLOC();
goto str_index;
case IS_DOUBLE:
hval = zend_dval_to_lval(Z_DVAL_P(dim));
goto num_index;
case IS_RESOURCE:
zend_error(E_NOTICE, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
hval = Z_RES_HANDLE_P(dim);
goto num_index;
case IS_FALSE:
hval = 0;
goto num_index;
case IS_TRUE:
hval = 1;
goto num_index;
case IS_REFERENCE:
dim = Z_REFVAL_P(dim);
goto try_again;
default:
zend_error(E_WARNING, "Illegal offset type");
retval = (type == BP_VAR_W || type == BP_VAR_RW) ?
#if PHP_VERSION_ID < 70100
&EG(error_zval)
#else
NULL
#endif
: &EG(uninitialized_zval);
}
}
return retval;
}
/* }}} */
static void php_taint_fetch_dimension_address(zval *result, zval *container, zval *dim, int dim_type, int type) /* {{{ */ {
zval *retval;
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
try_array:
SEPARATE_ARRAY(container);
fetch_from_array:
if (dim == NULL) {
retval = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
if (UNEXPECTED(retval == NULL)) {
zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
#if PHP_VERSION_ID < 70100
retval = &EG(error_zval);
#else
ZVAL_ERROR(result);
return;
#endif
}
} else {
retval = php_taint_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type);
}
ZVAL_INDIRECT(result, retval);
return;
} else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
container = Z_REFVAL_P(container);
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
goto try_array;
}
}
if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
if (type != BP_VAR_UNSET && UNEXPECTED(Z_STRLEN_P(container) == 0)) {
zval_ptr_dtor_nogc(container);
convert_to_array:
ZVAL_NEW_ARR(container);
zend_hash_init(Z_ARRVAL_P(container), 8, NULL, ZVAL_PTR_DTOR, 0);
goto fetch_from_array;
}
if (dim == NULL) {
zend_throw_error(NULL, "[] operator not supported for strings");
#if PHP_VERSION_ID < 70100
ZVAL_INDIRECT(result, &EG(error_zval));
#else
ZVAL_ERROR(result);
#endif
} else {
php_taint_check_string_offset(dim, type);
#if PHP_VERSION_ID < 70100
ZVAL_INDIRECT(result, NULL); /* wrong string offset */
#else
ZVAL_ERROR(result);
#endif
}
} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
if (!Z_OBJ_HT_P(container)->read_dimension) {
zend_throw_error(NULL, "Cannot use object as array");
#if PHP_VERSION_ID < 70100
retval = &EG(error_zval);
#else
ZVAL_ERROR(result);
#endif
} else {
retval = Z_OBJ_HT_P(container)->read_dimension(container, dim, type, result);
if (UNEXPECTED(retval == &EG(uninitialized_zval))) {
zend_class_entry *ce = Z_OBJCE_P(container);
ZVAL_NULL(result);
zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
} else if (EXPECTED(retval && Z_TYPE_P(retval) != IS_UNDEF)) {
if (!Z_ISREF_P(retval)) {
if (Z_REFCOUNTED_P(retval) &&
Z_REFCOUNT_P(retval) > 1) {
if (Z_TYPE_P(retval) != IS_OBJECT) {
Z_DELREF_P(retval);
ZVAL_DUP(result, retval);
retval = result;
} else {
ZVAL_COPY_VALUE(result, retval);
retval = result;
}
}
if (Z_TYPE_P(retval) != IS_OBJECT) {
zend_class_entry *ce = Z_OBJCE_P(container);
zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
}
} else if (UNEXPECTED(Z_REFCOUNT_P(retval) == 1)) {
ZVAL_UNREF(retval);
}
if (result != retval) {
ZVAL_INDIRECT(result, retval);
}
} else {
#if PHP_VERSION_ID < 70100
ZVAL_INDIRECT(result, &EG(error_zval));
#else
ZVAL_ERROR(result);
#endif
}
}
} else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) {
if (UNEXPECTED(TAINT_ISERR(container))) {
#if PHP_VERSION_ID < 70100
ZVAL_INDIRECT(result, &EG(error_zval));
#else
ZVAL_ERROR(result);
#endif
} else if (type != BP_VAR_UNSET) {
goto convert_to_array;
} else {
/* for read-mode only */
ZVAL_NULL(result);
}
} else {
if (type == BP_VAR_UNSET) {
zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
ZVAL_NULL(result);
} else {
zend_error(E_WARNING, "Cannot use a scalar value as an array");
#if PHP_VERSION_ID < 70100
ZVAL_INDIRECT(result, &EG(error_zval));
#else
ZVAL_ERROR(result);
#endif
}
}
}
/* }}} */
static void php_taint_assign_op_overloaded_property(zval *object, zval *property, void **cache_slot, zval *value, binary_op_type binary_op, zval *result) /* {{{ */ {
zval *z;
zval rv, obj;
zval *zptr;
int tainted = 0;
ZVAL_OBJ(&obj, Z_OBJ_P(object));
Z_ADDREF(obj);
if (Z_OBJ_HT(obj)->read_property &&
(z = Z_OBJ_HT(obj)->read_property(&obj, property, BP_VAR_R, cache_slot, &rv)) != NULL) {
if (EG(exception)) {
OBJ_RELEASE(Z_OBJ(obj));
return;
}
if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) {
zval rv2;
zval *value = Z_OBJ_HT_P(z)->get(z, &rv2);
if (z == &rv) {
zval_ptr_dtor(&rv);
}
ZVAL_COPY_VALUE(z, value);
}
zptr = z;
ZVAL_DEREF(z);
SEPARATE_ZVAL_NOREF(z);
if (Z_TYPE_P(z) == IS_STRING && TAINT_POSSIBLE(Z_STR_P(z))) {
tainted = 1;
} else if (Z_TYPE_P(value) == IS_STRING && TAINT_POSSIBLE(Z_STR_P(value))) {
tainted = 1;
}
binary_op(z, z, value);
Z_OBJ_HT(obj)->write_property(&obj, property, z, cache_slot);
if (result) {
ZVAL_COPY(result, z);
}
if (tainted && Z_TYPE_P(z) == IS_STRING && Z_STRLEN_P(z)) {
TAINT_MARK(Z_STR_P(z));
}
zval_ptr_dtor(zptr);
} else {
zend_error(E_WARNING, "Attempt to assign property of non-object");
if (result) {
ZVAL_NULL(result);
}
}
OBJ_RELEASE(Z_OBJ(obj));
}
/* }}} */
static void php_taint_binary_assign_op_obj_dim(zval *object, zval *property, zval *value, zval *retval, binary_op_type binary_op) /* {{{ */ {
zval *z;
zval rv, res;
int tainted = 0;
if (Z_OBJ_HT_P(object)->read_dimension &&
(z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv)) != NULL) {
if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) {
zval rv2;
zval *value = Z_OBJ_HT_P(z)->get(z, &rv2);
if (z == &rv) {
zval_ptr_dtor(&rv);
}
ZVAL_COPY_VALUE(z, value);
}
if ((Z_TYPE_P(z) == IS_STRING && TAINT_POSSIBLE(Z_STR_P(z))) ||
(Z_TYPE_P(z) == IS_REFERENCE && IS_STRING == Z_TYPE_P(Z_REFVAL_P(z)) &&
TAINT_POSSIBLE(Z_STR_P(Z_REFVAL_P(z))))) {
tainted = 1;
} else if (Z_TYPE_P(value) == IS_STRING && TAINT_POSSIBLE(Z_STR_P(value))) {
tainted = 1;
}
binary_op(&res, Z_ISREF_P(z) ? Z_REFVAL_P(z) : z, value);
Z_OBJ_HT_P(object)->write_dimension(object, property, &res);
if (z == &rv) {
zval_ptr_dtor(&rv);
}
if (retval) {
ZVAL_COPY(retval, &res);
}
if (tainted && Z_TYPE(res) == IS_STRING && Z_STRLEN(res)) {
TAINT_MARK(Z_STR(res));
}
zval_ptr_dtor(&res);
} else {
zend_error(E_WARNING, "Attempt to assign property of non-object");
if (retval) {
ZVAL_NULL(retval);
}
}
}
/* }}} */
/* Copied codes end */
static void php_taint_mark_strings(zend_array *symbol_table) /* {{{ */ {
zval *val;
ZEND_HASH_FOREACH_VAL(symbol_table, val) {
ZVAL_DEREF(val);
if (Z_TYPE_P(val) == IS_ARRAY) {
php_taint_mark_strings(Z_ARRVAL_P(val));
} else if (IS_STRING == Z_TYPE_P(val) && Z_STRLEN_P(val)) {
TAINT_MARK(Z_STR_P(val));
}
} ZEND_HASH_FOREACH_END();
} /* }}} */
static zval *php_taint_get_zval_ptr_tmpvar(zend_execute_data *execute_data, uint32_t var, zend_free_op *should_free) /* {{{ */ {
zval *ret = EX_VAR(var);
if (should_free) {
*should_free = ret;
}
ZVAL_DEREF(ret);
return ret;
}
/* }}} */
#ifndef CV_DEF_OF
#define CV_DEF_OF(i) (EX(func)->op_array.vars[i])
#endif
static zval *php_taint_get_zval_ptr_cv(zend_execute_data *execute_data, uint32_t var, int type, int force_ret) /* {{{ */ {
zval *ret = EX_VAR(var);
if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
if (force_ret) {
switch (type) {
case BP_VAR_R:
case BP_VAR_UNSET:
zend_error(E_NOTICE, "Undefined variable: %s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(var))));
case BP_VAR_IS:
ret = &EG(uninitialized_zval);
break;
case BP_VAR_RW:
zend_error(E_NOTICE, "Undefined variable: %s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(var))));
case BP_VAR_W:
ZVAL_NULL(ret);
break;
}
} else {
return NULL;
}
} else {
ZVAL_DEREF(ret);
}
return ret;
}
/* }}} */
static zval *php_taint_get_zval_ptr(zend_execute_data *execute_data, int op_type, znode_op op, taint_free_op *should_free, int type, int force_ret) /* {{{ */ {
if (op_type & (IS_TMP_VAR|IS_VAR)) {
return php_taint_get_zval_ptr_tmpvar(execute_data, op.var, should_free);
} else {
*should_free = NULL;
if (op_type == IS_CONST) {
return EX_CONSTANT(op);
} else if (op_type == IS_CV) {
return php_taint_get_zval_ptr_cv(execute_data, op.var, type, force_ret);
} else {
return NULL;
}
}
}
/* }}} */
static zval *php_taint_get_zval_ptr_ptr_var(zend_execute_data *execute_data, uint32_t var, zend_free_op *should_free) /* {{{ */ {
zval *ret = EX_VAR(var);
if (EXPECTED(Z_TYPE_P(ret) == IS_INDIRECT)) {
*should_free = NULL;
ret = Z_INDIRECT_P(ret);
} else {
*should_free = ret;
}
return ret;
}
/* }}} */
static zval *php_taint_get_zval_ptr_ptr(zend_execute_data *execute_data, int op_type, znode_op op, taint_free_op *should_free, int type) /* {{{ */ {
if (op_type == IS_CV) {
*should_free = NULL;
return php_taint_get_zval_ptr_cv(execute_data, op.var, type, 1);
} else if (op_type == IS_VAR) {
ZEND_ASSERT(op_type == IS_VAR);
return php_taint_get_zval_ptr_ptr_var(execute_data, op.var, should_free);
} else if (op_type == IS_UNUSED) {
*should_free = NULL;
return &EX(This);
} else {
ZEND_ASSERT(0);
}
}
/* }}} */
static void php_taint_error(const char *fname, const char *format, ...) /* {{{ */ {
char *buffer, *msg;
va_list args;
va_start(args, format);
vspprintf(&buffer, 0, format, args);
spprintf(&msg, 0, "%s() [%s]: %s", get_active_function_name(), fname, buffer);
efree(buffer);
zend_error(TAINT_G(error_level), "%s", msg);
efree(msg);
va_end(args);
} /* }}} */
#define CALL_ORIGIN_HANDLER() do { \
if (origin_opcode_handler[opline->opcode]) { \
return ((user_opcode_handler_t)(origin_opcode_handler[opline->opcode]))(execute_data); \
} \
} while (0)
static int php_taint_echo_handler(zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
taint_free_op free_op1;
zval *op1;
op1 = php_taint_get_zval_ptr(execute_data, opline->op1_type, opline->op1, &free_op1, BP_VAR_R, 0);
if (op1 && IS_STRING == Z_TYPE_P(op1) && TAINT_POSSIBLE(Z_STR_P(op1))) {
if (opline->extended_value) {
php_taint_error("print", "Attempt to print a string that might be tainted");
} else {
php_taint_error("echo", "Attempt to echo a string that might be tainted");
}
}
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
static int php_taint_exit_handler(zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
taint_free_op free_op1;
zval *op1;
op1 = php_taint_get_zval_ptr(execute_data, opline->op1_type, opline->op1, &free_op1, BP_VAR_R, 0);
if (op1 && IS_STRING == Z_TYPE_P(op1) && TAINT_POSSIBLE(Z_STR_P(op1))) {
php_taint_error("exit", "Attempt to output a string that might be tainted");
}
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
static int php_taint_init_dynamic_fcall_handler(zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
taint_free_op free_op2;
zval *op2;
op2 = php_taint_get_zval_ptr(execute_data, opline->op2_type, opline->op2, &free_op2, BP_VAR_R, 0);
if (op2) {
if (IS_STRING == Z_TYPE_P(op2)) {
if (TAINT_POSSIBLE(Z_STR_P(op2))) {
php_taint_error("fcall", "Attempt to call a function which name might be tainted");
}
} else if (IS_ARRAY == Z_TYPE_P(op2)) {
zval *cname = zend_hash_index_find(Z_ARRVAL_P(op2), 0);
zval *mname = zend_hash_index_find(Z_ARRVAL_P(op2), 1);
if (cname && IS_STRING == Z_TYPE_P(cname) && TAINT_POSSIBLE(Z_STR_P(cname))) {
php_taint_error("fcall", "Attempt to call a method of a class which name might be tainted");
} else if (mname && IS_STRING == Z_TYPE_P(mname) && TAINT_POSSIBLE(Z_STR_P(mname))) {
php_taint_error("fcall", "Attempt to call a method which name might be tainted");
}
}
}
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
static int php_taint_include_or_eval_handler(zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
taint_free_op free_op1;
zval *op1;
op1 = php_taint_get_zval_ptr(execute_data, opline->op1_type, opline->op1, &free_op1, BP_VAR_R, 0);
if ((op1 && IS_STRING == Z_TYPE_P(op1) && TAINT_POSSIBLE(Z_STR_P(op1))))
switch (opline->extended_value) {
case ZEND_INCLUDE_ONCE:
php_taint_error("include_once", "File path contains data that might be tainted");
break;
case ZEND_REQUIRE_ONCE:
php_taint_error("require_once", "File path contains data that might be tainted");
break;
case ZEND_INCLUDE:
php_taint_error("include", "File path contains data that might be tainted");
break;
case ZEND_REQUIRE:
php_taint_error("require", "File path contains data that might be tainted");
break;
case ZEND_EVAL:
php_taint_error("eval", "Code contains data that might be tainted");
break;
}
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
static int php_taint_rope_handler(zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
zval *op2, *result;
taint_free_op free_op2;
zend_string **rope;
char *target;
int i, tainted = 0;
size_t len = 0;
rope = (zend_string **)EX_VAR(opline->op1.var);
op2 = php_taint_get_zval_ptr(execute_data, opline->op2_type, opline->op2, &free_op2, BP_VAR_R, 1);
result = EX_VAR(opline->result.var);
rope[opline->extended_value] = zval_get_string(op2);
for (i = 0; i <= opline->extended_value; i++) {
if (TAINT_POSSIBLE(rope[i])) {
tainted = 1;
}
len += ZSTR_LEN(rope[i]);
}
ZVAL_STR(result, zend_string_alloc(len, 0));
target = Z_STRVAL_P(result);
for (i = 0; i <= opline->extended_value; i++) {
memcpy(target, ZSTR_VAL(rope[i]), ZSTR_LEN(rope[i]));
target += ZSTR_LEN(rope[i]);
zend_string_release(rope[i]);
}
*target = '\0';
if (tainted) {
TAINT_MARK(Z_STR_P(result));
}
CALL_ORIGIN_HANDLER();
execute_data->opline++;
return ZEND_USER_OPCODE_CONTINUE;
} /* }}} */
static int php_taint_concat_handler(zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
zval *op1, *op2, *result;
taint_free_op free_op1, free_op2;
int tainted = 0;
op1 = php_taint_get_zval_ptr(execute_data, opline->op1_type, opline->op1, &free_op1, BP_VAR_R, 1);
op2 = php_taint_get_zval_ptr(execute_data, opline->op2_type, opline->op2, &free_op2, BP_VAR_R, 1);
result = EX_VAR(opline->result.var);
if ((op1 && IS_STRING == Z_TYPE_P(op1) && TAINT_POSSIBLE(Z_STR_P(op1)))
|| (op2 && IS_STRING == Z_TYPE_P(op2) && TAINT_POSSIBLE(Z_STR_P(op2)))) {
tainted = 1;
}
concat_function(result, op1, op2);
if (tainted && IS_STRING == Z_TYPE_P(result) && Z_STRLEN_P(result)) {
TAINT_MARK(Z_STR_P(result));
}
if ((TAINT_OP1_TYPE(opline) & (IS_VAR|IS_TMP_VAR)) && free_op1) {
zval_ptr_dtor_nogc(free_op1);
}
if ((TAINT_OP2_TYPE(opline) & (IS_VAR|IS_TMP_VAR)) && free_op2) {
zval_ptr_dtor_nogc(free_op2);
}
CALL_ORIGIN_HANDLER();
execute_data->opline++;
return ZEND_USER_OPCODE_CONTINUE;
} /* }}} */
static int php_taint_binary_assign_op_helper(binary_op_type binary_op, zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
zval *var_ptr, *value;
taint_free_op free_op1, free_op2;
int tainted = 0;
value = php_taint_get_zval_ptr(execute_data, opline->op2_type, opline->op2, &free_op2, BP_VAR_R, 1);
var_ptr = php_taint_get_zval_ptr_ptr(execute_data, opline->op1_type, opline->op1, &free_op1, BP_VAR_RW);
if (opline->op1_type == IS_VAR) {
if (var_ptr == NULL || TAINT_ISERR(var_ptr)) {
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
}
}
if ((var_ptr && IS_STRING == Z_TYPE_P(var_ptr) && TAINT_POSSIBLE(Z_STR_P(var_ptr)))
|| (value && IS_STRING == Z_TYPE_P(value) && TAINT_POSSIBLE(Z_STR_P(value)))) {
tainted = 1;
}
SEPARATE_ZVAL_NOREF(var_ptr);
binary_op(var_ptr, var_ptr, value);
if (tainted && IS_STRING == Z_TYPE_P(var_ptr) && Z_STRLEN_P(var_ptr)) {
TAINT_MARK(Z_STR_P(var_ptr));
}
if (TAINT_RET_USED(opline)) {
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
}
if ((TAINT_OP1_TYPE(opline) & (IS_VAR|IS_TMP_VAR)) && free_op1) {
zval_ptr_dtor_nogc(free_op1);
}
if ((TAINT_OP2_TYPE(opline) & (IS_VAR|IS_TMP_VAR)) && free_op2) {
zval_ptr_dtor_nogc(free_op2);
}
CALL_ORIGIN_HANDLER();
execute_data->opline++;
return ZEND_USER_OPCODE_CONTINUE;
} /* }}} */
static int php_taint_binary_assign_op_obj_helper(binary_op_type binary_op, zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
zval *object, *property, *var_ptr, *value;
taint_free_op free_op1, free_op2, free_op_data;
int tainted = 0;
object = php_taint_get_zval_ptr_ptr(execute_data, opline->op1_type, opline->op1, &free_op1, BP_VAR_RW);
if (opline->op1_type == IS_UNUSED && Z_OBJ_P(object) == NULL) {
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
}
if (opline->op1_type == IS_VAR && object == NULL) {
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
}
property = php_taint_get_zval_ptr(execute_data, opline->op2_type, opline->op2, &free_op2, BP_VAR_R, 1);
do {
if (opline->op1_type == IS_UNUSED || Z_TYPE_P(object) != IS_OBJECT) {
if (!php_taint_make_real_object(object)) {
zend_error(E_WARNING, "Attempt to assign property of non-object");
if (TAINT_RET_USED(opline)) {
ZVAL_NULL(EX_VAR(opline->result.var));
}
break;
}
}
value = php_taint_get_zval_ptr(execute_data, (opline + 1)->op1_type, (opline + 1)->op1, &free_op_data, BP_VAR_R, 1);
if (Z_OBJ_HT_P(object)->get_property_ptr_ptr
&& (var_ptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, NULL)) != NULL) {
ZVAL_DEREF(var_ptr);
SEPARATE_ZVAL_NOREF(var_ptr);
if (Z_TYPE_P(var_ptr) == IS_STRING && TAINT_POSSIBLE(Z_STR_P(var_ptr))) {
tainted = 1;
} else if (Z_TYPE_P(value) == IS_STRING && TAINT_POSSIBLE(Z_STR_P(value))) {
tainted = 1;
}
binary_op(var_ptr, var_ptr, value);
if (TAINT_RET_USED(opline)) {
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
}
if (tainted && Z_TYPE_P(var_ptr) == IS_STRING && Z_STRLEN_P(var_ptr)) {
TAINT_MARK(Z_STR_P(var_ptr));
}
} else {
php_taint_assign_op_overloaded_property(object, property, NULL, value, binary_op, EX_VAR(opline->result.var));
if (!TAINT_RET_USED(opline)) {
zval_ptr_dtor_nogc(EX_VAR(opline->result.var));
}
}
} while (0);
if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && free_op2) {
zval_ptr_dtor_nogc(free_op2);
}
if (((opline + 1)->op1_type & (IS_VAR|IS_TMP_VAR)) && free_op_data) {
zval_ptr_dtor_nogc(free_op_data);
}
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && free_op1) {
zval_ptr_dtor_nogc(free_op1);
}
CALL_ORIGIN_HANDLER();
execute_data->opline += 2;
return ZEND_USER_OPCODE_CONTINUE;
}
/* }}} */
static int php_taint_binary_assign_op_dim_helper(binary_op_type binary_op, zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
zval *container, *dim, *var_ptr, *value, rv;
taint_free_op free_op1, free_op2, free_op_data;
int tainted = 0;
container = php_taint_get_zval_ptr_ptr(execute_data, opline->op1_type, opline->op1, &free_op1, BP_VAR_RW);
if (opline->op1_type == IS_UNUSED && Z_OBJ_P(container) == NULL) {
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
}
if (opline->op1_type == IS_VAR && container == NULL) {
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
}
dim = php_taint_get_zval_ptr(execute_data, opline->op2_type, opline->op2, &free_op2, BP_VAR_R, 1);
do {
if (opline->op1_type == IS_UNUSED || Z_TYPE_P(container) == IS_OBJECT) {
value = php_taint_get_zval_ptr(execute_data, (opline + 1)->op1_type, (opline + 1)->op1, &free_op_data, BP_VAR_R, 1);
php_taint_binary_assign_op_obj_dim(container, dim, value, EX_VAR(opline->result.var), binary_op);
if (!TAINT_RET_USED(opline)) {
zval_ptr_dtor_nogc(EX_VAR(opline->result.var));
}
break;
}
php_taint_fetch_dimension_address(&rv, container, dim, opline->op2_type, BP_VAR_RW);
value = php_taint_get_zval_ptr(execute_data, (opline + 1)->op1_type, (opline + 1)->op1, &free_op_data, BP_VAR_R, 1);
ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT);
var_ptr = Z_INDIRECT(rv);
if (var_ptr == NULL) {
zend_throw_error(NULL, "Cannot use assign-op operators with overloaded objects nor string offsets");
if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && free_op2) {
zval_ptr_dtor_nogc(free_op2);
}
if (((opline + 1)->op1_type & (IS_VAR|IS_TMP_VAR)) && free_op_data) {
zval_ptr_dtor_nogc(free_op_data);
}
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && free_op1) {
zval_ptr_dtor_nogc(free_op1);
}
CALL_ORIGIN_HANDLER();
execute_data->opline += 2;
return ZEND_USER_OPCODE_CONTINUE;
}
if (TAINT_ISERR(var_ptr)) {
if (TAINT_RET_USED(opline)) {
ZVAL_NULL(EX_VAR(opline->result.var));
}
} else {
ZVAL_DEREF(var_ptr);
SEPARATE_ZVAL_NOREF(var_ptr);
if (Z_TYPE_P(var_ptr) == IS_STRING && TAINT_POSSIBLE(Z_STR_P(var_ptr))) {
tainted = 1;
} else if (Z_TYPE_P(value) == IS_STRING && TAINT_POSSIBLE(Z_STR_P(value))) {
tainted = 1;
}
binary_op(var_ptr, var_ptr, value);
if (TAINT_RET_USED(opline)) {
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
}
if (tainted && Z_TYPE_P(var_ptr) == IS_STRING && Z_STRLEN_P(var_ptr)) {
TAINT_MARK(Z_STR_P(var_ptr));
}
}
} while (0);
if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && free_op2) {
zval_ptr_dtor_nogc(free_op2);
}
if (((opline + 1)->op1_type & (IS_VAR|IS_TMP_VAR)) && free_op_data) {
zval_ptr_dtor_nogc(free_op_data);
}
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && free_op1) {
zval_ptr_dtor_nogc(free_op1);
}
CALL_ORIGIN_HANDLER();
execute_data->opline += 2;
return ZEND_USER_OPCODE_CONTINUE;
}
/* }}} */
static int php_taint_assign_concat_handler(zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
if (EXPECTED(opline->extended_value == 0)) {
return php_taint_binary_assign_op_helper(concat_function, execute_data);
} else if (EXPECTED(opline->extended_value == ZEND_ASSIGN_DIM)) {
return php_taint_binary_assign_op_dim_helper(concat_function, execute_data);
} else {
return php_taint_binary_assign_op_obj_helper(concat_function, execute_data);
}
} /* }}} */
#if PHP_VERSION_ID >= 70400
static int php_taint_assign_op_handler(zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
if (UNEXPECTED(opline->extended_value == ZEND_CONCAT)) {
return php_taint_binary_assign_op_helper(concat_function, execute_data);
}
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
static int php_taint_assign_dim_op_handler(zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
if (UNEXPECTED(opline->extended_value == ZEND_CONCAT)) {
return php_taint_binary_assign_op_dim_helper(concat_function, execute_data);
}
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
static int php_taint_assign_obj_op_handler(zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
if (UNEXPECTED(opline->extended_value == ZEND_CONCAT)) {
return php_taint_binary_assign_op_obj_helper(concat_function, execute_data);
}
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
#endif
static void php_taint_fcall_check(zend_execute_data *ex, const zend_op *opline, zend_function *fbc) /* {{{ */ {
int arg_count = ZEND_CALL_NUM_ARGS(ex);
if (!arg_count) {
return;
}
if (fbc->common.scope == NULL) {
zend_string *fname = fbc->common.function_name;
if (zend_string_equals_literal(fname, "print_r")) {
zval *p = ZEND_CALL_ARG(ex, 1);
if (p && IS_STRING == Z_TYPE_P(p) && TAINT_POSSIBLE(Z_STR_P(p))) {
php_taint_error(ZSTR_VAL(fname), "Attempt to print_r data that might be tainted");
}
} else if (zend_string_equals_literal(fname, "fopen")) {
zval *p = ZEND_CALL_ARG(ex, 1);
if (p && IS_STRING == Z_TYPE_P(p) && TAINT_POSSIBLE(Z_STR_P(p))) {
php_taint_error(ZSTR_VAL(fname), "Attempt to open a file which path might be tainted");
}
} else if (zend_string_equals_literal(fname, "unlink")) {
zval *p = ZEND_CALL_ARG(ex, 1);
if (p && IS_STRING == Z_TYPE_P(p) && TAINT_POSSIBLE(Z_STR_P(p))) {
php_taint_error(ZSTR_VAL(fname), "Attempt to unlink a file which path might be tainted");
}
} else if (zend_string_equals_literal(fname, "file") ||
zend_string_equals_literal(fname, "readfile") ||
zend_string_equals_literal(fname, "file_get_contents")) {
zval *p = ZEND_CALL_ARG(ex, 1);
if (p && IS_STRING == Z_TYPE_P(p) && TAINT_POSSIBLE(Z_STR_P(p))) {
php_taint_error(ZSTR_VAL(fname), "Attempt to read a file which path might be tainted");
}
} else if (zend_string_equals_literal(fname, "opendir")) {
zval *p = ZEND_CALL_ARG(ex, 1);
if (p && IS_STRING == Z_TYPE_P(p) && TAINT_POSSIBLE(Z_STR_P(p))) {
php_taint_error(ZSTR_VAL(fname), "Attempt to open a directory which path might be tainted");
}
} else if (zend_string_equals_literal(fname, "printf")) {
if (arg_count > 1) {
uint32_t i;
for (i = 0; i < arg_count; i++) {
zval *p = ZEND_CALL_ARG(ex, i + 1);
if (p && IS_STRING == Z_TYPE_P(p) && TAINT_POSSIBLE(Z_STR_P(p))) {
php_taint_error(ZSTR_VAL(fname), "%dth argument contains data that might be tainted", i + 1);
break;
}
}
}
} else if (zend_string_equals_literal(fname, "vprintf")) {
if (arg_count > 1) {
zend_string *key;
zend_long idx;
zval *val, *p = ZEND_CALL_ARG(ex, 1);
if (IS_ARRAY == Z_TYPE_P(p)) {
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(p), idx, key, val) {
if (IS_STRING == Z_TYPE_P(val) && TAINT_POSSIBLE(Z_STR_P(val))) {
if (key) {
php_taint_error(ZSTR_VAL(fname), "Second argument contains data(index:%s) that might be tainted", ZSTR_VAL(key));
} else {
php_taint_error(ZSTR_VAL(fname), "Second argument contains data(index:%ld) that might be tainted", idx);
}
break;
}
} ZEND_HASH_FOREACH_END();
}
}
} else if (zend_string_equals_literal(fname, "file_put_contents") ||
zend_string_equals_literal(fname, "fwrite")) {
if (arg_count > 1) {
zval *fp, *str;
fp = ZEND_CALL_ARG(ex, 1);
str = ZEND_CALL_ARG(ex, 2);
if (IS_STRING == Z_TYPE_P(fp)) {
if (zend_string_equals_literal(Z_STR_P(fp), "php://output")) {
if (IS_STRING == Z_TYPE_P(str) && TAINT_POSSIBLE(Z_STR_P(str))) {
php_taint_error(ZSTR_VAL(fname), "Attempt to output data that might be tainted");
}
}
} else if (Z_TYPE_P(fp) == IS_RESOURCE) {
}
}
} else if (zend_string_equals_literal(fname, "header")) {
zval *header = ZEND_CALL_ARG(ex, 1);
if (IS_STRING == Z_TYPE_P(header) && TAINT_POSSIBLE(Z_STR_P(header))) {
php_taint_error(ZSTR_VAL(fname), "Attempt to send a header that might be tainted");
}
} else if (zend_string_equals_literal(fname, "unserialize")) {
/* TODO: allow_classes? */
zval *str = ZEND_CALL_ARG(ex, 1);
if (IS_STRING == Z_TYPE_P(str) && TAINT_POSSIBLE(Z_STR_P(str))) {
php_taint_error(ZSTR_VAL(fname), "Attempt to unserialize a string that might be tainted");
}
} else if (zend_string_equals_literal(fname, "mysqli_query") ||
zend_string_equals_literal(fname, "mysqli_prepare") ||
zend_string_equals_literal(fname, "mysql_query") ||
zend_string_equals_literal(fname, "sqlite_query") ||
zend_string_equals_literal(fname, "sqlite_single_query")) {
zval *query = ZEND_CALL_ARG(ex, arg_count);
if (IS_STRING == Z_TYPE_P(query) && TAINT_POSSIBLE(Z_STR_P(query))) {
php_taint_error(ZSTR_VAL(fname), "SQL statement contains data that might be tainted");
}
} else if (zend_string_equals_literal(fname, "oci_parse")) {
if (arg_count > 1) {
zval *sql = ZEND_CALL_ARG(ex, 2);
if (IS_STRING == Z_TYPE_P(sql) && TAINT_POSSIBLE(Z_STR_P(sql))) {
php_taint_error(ZSTR_VAL(fname), "SQL statement contains data that might be tainted");
}
}
} else if (zend_string_equals_literal(fname, "preg_replace_callback")) {
if (arg_count > 1) {
zval *callback = ZEND_CALL_ARG(ex, 2);
if (IS_STRING == Z_TYPE_P(callback)) {
if (TAINT_POSSIBLE(Z_STR_P(callback))) {
php_taint_error(ZSTR_VAL(fname), "Callback name contains data that might be tainted");
}
} else if (IS_ARRAY == Z_TYPE_P(callback)) {
zval *cname = zend_hash_index_find(Z_ARRVAL_P(callback), 0);
zval *mname = zend_hash_index_find(Z_ARRVAL_P(callback), 1);
if (cname && IS_STRING == Z_TYPE_P(cname) && TAINT_POSSIBLE(Z_STR_P(cname))) {
php_taint_error(ZSTR_VAL(fname), "Callback class name contains data that might be tainted");
} else if (mname && IS_STRING == Z_TYPE_P(mname) && TAINT_POSSIBLE(Z_STR_P(mname))) {
php_taint_error(ZSTR_VAL(fname), "Callback method name contains data that might be tainted");
}
}
}
} else if (zend_string_equals_literal(fname, "passthru") ||
zend_string_equals_literal(fname, "system") ||
zend_string_equals_literal(fname, "exec") ||
zend_string_equals_literal(fname, "shell_exec") ||
zend_string_equals_literal(fname, "proc_open") ||
zend_string_equals_literal(fname, "popen")) {
zval *cmd = ZEND_CALL_ARG(ex, arg_count);
if (IS_STRING == Z_TYPE_P(cmd) && TAINT_POSSIBLE(Z_STR_P(cmd))) {
php_taint_error(ZSTR_VAL(fname), "CMD statement contains data that might be tainted");
}
}
} else {
char mname[64];
zend_string *class_name = fbc->common.scope->name;
zend_string *fname = fbc->common.function_name;
if (zend_string_equals_literal(class_name, "mysqli")) {
if (zend_string_equals_literal(fname, "query") ||
zend_string_equals_literal(fname, "prepare")) {
zval *sql = ZEND_CALL_ARG(ex, 1);
if (IS_STRING == Z_TYPE_P(sql) && TAINT_POSSIBLE(Z_STR_P(sql))) {
snprintf(mname, sizeof(mname), "%s::%s", "mysqli", ZSTR_VAL(fname));
php_taint_error(mname, "SQL statement contains data that might be tainted");
}
}
} else if (zend_string_equals_literal(class_name, "PDO")) {
if (zend_string_equals_literal(fname, "query") ||
zend_string_equals_literal(fname, "prepare")) {
zval *sql = ZEND_CALL_ARG(ex, arg_count);
if (IS_STRING == Z_TYPE_P(sql) && TAINT_POSSIBLE(Z_STR_P(sql))) {
snprintf(mname, sizeof(mname), "%s::%s", "PDO", ZSTR_VAL(fname));
php_taint_error(mname, "SQL statement contains data that might be tainted");
}
}
} else if (zend_string_equals_literal(class_name, "SQLite3")) {
if (zend_string_equals_literal(fname, "query") ||
zend_string_equals_literal(fname, "prepare")) {
zval *sql = ZEND_CALL_ARG(ex, arg_count);
if (IS_STRING == Z_TYPE_P(sql) && TAINT_POSSIBLE(Z_STR_P(sql))) {
snprintf(mname, sizeof(mname), "%s::%s", "SQLite3", ZSTR_VAL(fname));
php_taint_error(mname, "SQL statement contains data that might be tainted");
}
}
} else if (zend_string_equals_literal(class_name, "sqlitedatabase")) {
if (zend_string_equals_literal(fname, "query") ||
zend_string_equals_literal(fname, "singlequery")) {
zval *sql = ZEND_CALL_ARG(ex, arg_count);
if (IS_STRING == Z_TYPE_P(sql) && TAINT_POSSIBLE(Z_STR_P(sql))) {
snprintf(mname, sizeof(mname), "%s::%s", "sqlitedatabase", ZSTR_VAL(fname));
php_taint_error(mname, "SQL statement contains data that might be tainted");
}
}
}
}
} /* }}} */
static int php_taint_fcall_handler(zend_execute_data *execute_data) /* {{{ */ {
const zend_op *opline = execute_data->opline;
zend_execute_data *call = execute_data->call;
zend_function *fbc = call->func;
if (fbc->type == ZEND_INTERNAL_FUNCTION) {
php_taint_fcall_check(call, opline, fbc);
}
CALL_ORIGIN_HANDLER();
return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
/* Taint custom opcode handlers {{{ */
typedef struct {
zend_uchar opcode;
void *handler;
} taint_custom_handler;
static const taint_custom_handler override_opcode_handlers[] = {
{ ZEND_ECHO, php_taint_echo_handler },
{ ZEND_EXIT, php_taint_exit_handler },
{ ZEND_INIT_USER_CALL, php_taint_init_dynamic_fcall_handler },
{ ZEND_INIT_DYNAMIC_CALL, php_taint_init_dynamic_fcall_handler },
{ ZEND_INCLUDE_OR_EVAL, php_taint_include_or_eval_handler },
{ ZEND_CONCAT, php_taint_concat_handler },
{ ZEND_FAST_CONCAT, php_taint_concat_handler },
#if PHP_VERSION_ID < 70400
{ ZEND_ASSIGN_CONCAT, php_taint_assign_concat_handler },
#else
{ ZEND_ASSIGN_OP, php_taint_assign_op_handler },
{ ZEND_ASSIGN_DIM_OP, php_taint_assign_dim_op_handler },
{ ZEND_ASSIGN_OBJ_OP, php_taint_assign_obj_op_handler },
#endif
{ ZEND_ROPE_END, php_taint_rope_handler },
{ ZEND_DO_FCALL, php_taint_fcall_handler },
{ ZEND_DO_ICALL, php_taint_fcall_handler },
{ ZEND_DO_FCALL_BY_NAME, php_taint_fcall_handler }
};
/* }}} */
static void php_taint_register_handlers() /* {{{ */ {
int idx;
for (idx = 0; idx < sizeof(override_opcode_handlers)/sizeof(taint_custom_handler); idx++) {
origin_opcode_handler[idx] = (void*)zend_get_user_opcode_handler(override_opcode_handlers[idx].opcode);
}
for (idx = 0; idx < sizeof(override_opcode_handlers)/sizeof(taint_custom_handler); idx++) {
zend_set_user_opcode_handler(override_opcode_handlers[idx].opcode, (user_opcode_handler_t)override_opcode_handlers[idx].handler);
}
return;
} /* }}} */
static void php_taint_override_func(const char *name, php_func handler, php_func *stash) /* {{{ */ {
zend_function *func;
if ((func = zend_hash_str_find_ptr(CG(function_table), name, strlen(name))) != NULL) {
if (stash) {
*stash = func->internal_function.handler;
}
func->internal_function.handler = handler;
}
} /* }}} */
static void php_taint_override_functions() /* {{{ */ {
const char *f_join = "join";
const char *f_trim = "trim";
const char *f_split = "split";
const char *f_rtrim = "rtrim";
const char *f_ltrim = "ltrim";
const char *f_strval = "strval";
const char *f_strstr = "strstr";
const char *f_substr = "substr";
const char *f_sprintf = "sprintf";
const char *f_explode = "explode";
const char *f_implode = "implode";
const char *f_str_pad = "str_pad";
const char *f_vsprintf = "vsprintf";
const char *f_str_replace = "str_replace";
const char *f_str_ireplace = "str_ireplace";
const char *f_strtolower = "strtolower";
const char *f_strtoupper = "strtoupper";
const char *f_dirname = "dirname";
const char *f_basename = "basename";
const char *f_pathinfo = "pathinfo";
php_taint_override_func(f_strval, PHP_FN(taint_strval), &TAINT_O_FUNC(strval));
php_taint_override_func(f_sprintf, PHP_FN(taint_sprintf), &TAINT_O_FUNC(sprintf));
php_taint_override_func(f_vsprintf, PHP_FN(taint_vsprintf), &TAINT_O_FUNC(vsprintf));
php_taint_override_func(f_explode, PHP_FN(taint_explode), &TAINT_O_FUNC(explode));
php_taint_override_func(f_split, PHP_FN(taint_explode), NULL);
php_taint_override_func(f_implode, PHP_FN(taint_implode), &TAINT_O_FUNC(implode));
php_taint_override_func(f_join, PHP_FN(taint_implode), NULL);
php_taint_override_func(f_trim, PHP_FN(taint_trim), &TAINT_O_FUNC(trim));
php_taint_override_func(f_rtrim, PHP_FN(taint_rtrim), &TAINT_O_FUNC(rtrim));
php_taint_override_func(f_ltrim, PHP_FN(taint_ltrim), &TAINT_O_FUNC(ltrim));
php_taint_override_func(f_str_replace, PHP_FN(taint_str_replace), &TAINT_O_FUNC(str_replace));
php_taint_override_func(f_str_ireplace, PHP_FN(taint_str_ireplace), &TAINT_O_FUNC(str_ireplace));
php_taint_override_func(f_str_pad, PHP_FN(taint_str_pad), &TAINT_O_FUNC(str_pad));
php_taint_override_func(f_strstr, PHP_FN(taint_strstr), &TAINT_O_FUNC(strstr));
php_taint_override_func(f_strtolower, PHP_FN(taint_strtolower), &TAINT_O_FUNC(strtolower));
php_taint_override_func(f_strtoupper, PHP_FN(taint_strtoupper), &TAINT_O_FUNC(strtoupper));
php_taint_override_func(f_substr, PHP_FN(taint_substr), &TAINT_O_FUNC(substr));
php_taint_override_func(f_dirname, PHP_FN(taint_dirname), &TAINT_O_FUNC(dirname));
php_taint_override_func(f_basename, PHP_FN(taint_basename), &TAINT_O_FUNC(basename));
php_taint_override_func(f_pathinfo, PHP_FN(taint_pathinfo), &TAINT_O_FUNC(pathinfo));
} /* }}} */
#ifdef COMPILE_DL_TAINT
ZEND_GET_MODULE(taint)
#endif
/* {{{ proto string strval(mixed $value)
*/
PHP_FUNCTION(taint_strval) {
zval *num;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &num) == FAILURE) {
return;
}
if (Z_TYPE_P(num) == IS_STRING && TAINT_POSSIBLE(Z_STR_P(num))) {
tainted = 1;
}
TAINT_O_FUNC(strval)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value)
&& Z_STR_P(return_value) != Z_STR_P(num) && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string sprintf(string $format, ...)
*/
PHP_FUNCTION(taint_sprintf) {
zval *args;
int i, argc, tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
RETURN_FALSE;
}
for (i = 0; i < argc; i++) {
if (IS_STRING == Z_TYPE(args[i]) && TAINT_POSSIBLE(Z_STR(args[i]))) {
tainted = 1;
break;
}
}
TAINT_O_FUNC(sprintf)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string vsprintf(string $format, ...)
*/
PHP_FUNCTION(taint_vsprintf) {
zval *args;
zend_string *format;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa", &format, &args) == FAILURE) {
RETURN_FALSE;
}
do {
zval *val;
if (TAINT_POSSIBLE(format)) {
tainted = 1;
break;
}
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), val) {
ZVAL_DEREF(val);
if (IS_STRING == Z_TYPE_P(val) && TAINT_POSSIBLE(Z_STR_P(val))) {
tainted = 1;
break;
}
} ZEND_HASH_FOREACH_END();
} while (0);
TAINT_O_FUNC(vsprintf)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto array explode(string $separator, string $str[, int $limit])
*/
PHP_FUNCTION(taint_explode) {
zend_string *str, *delim;
zend_long limit = ZEND_LONG_MAX;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &delim, &str, &limit) == FAILURE) {
return;
}
if (TAINT_POSSIBLE(str)) {
tainted = 1;
}
TAINT_O_FUNC(explode)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_ARRAY == Z_TYPE_P(return_value) && zend_hash_num_elements(Z_ARRVAL_P(return_value))) {
php_taint_mark_strings(Z_ARRVAL_P(return_value));
}
}
/* }}} */
/* {{{ proto string implode(string $separator[, array $args])
*/
PHP_FUNCTION(taint_implode) {
zval *op1, *op2 = NULL;
zval *target = NULL;
int tainted = 0;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_ZVAL(op1)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL(op2)
ZEND_PARSE_PARAMETERS_END();
if (op2 == NULL) {
target = op1;
} else {
target = op2;
}
if (Z_TYPE_P(target) == IS_ARRAY) {
zval *val;
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(target), val) {
ZVAL_DEREF(val);
if (IS_STRING == Z_TYPE_P(val) && Z_STRLEN_P(val) && TAINT_POSSIBLE(Z_STR_P(val))) {
tainted = 1;
break;
}
} ZEND_HASH_FOREACH_END();
}
TAINT_O_FUNC(implode)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string trim(string $str)
*/
PHP_FUNCTION(taint_trim)
{
zend_string *str, *what;
int tainted = 0;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(str)
Z_PARAM_OPTIONAL
Z_PARAM_STR(what)
ZEND_PARSE_PARAMETERS_END();
if (TAINT_POSSIBLE(str)) {
tainted = 1;
}
TAINT_O_FUNC(trim)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) &&
Z_STR_P(return_value) != str && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string rtrim(string $str)
*/
PHP_FUNCTION(taint_rtrim)
{
zend_string *str, *what;
int tainted = 0;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(str)
Z_PARAM_OPTIONAL
Z_PARAM_STR(what)
ZEND_PARSE_PARAMETERS_END();
if (TAINT_POSSIBLE(str)) {
tainted = 1;
}
TAINT_O_FUNC(rtrim)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) &&
Z_STR_P(return_value) != str && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string ltrim(string $str)
*/
PHP_FUNCTION(taint_ltrim)
{
zend_string *str, *what;
int tainted = 0;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(str)
Z_PARAM_OPTIONAL
Z_PARAM_STR(what)
ZEND_PARSE_PARAMETERS_END();
if (TAINT_POSSIBLE(str)) {
tainted = 1;
}
TAINT_O_FUNC(ltrim)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) &&
Z_STR_P(return_value) != str && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string str_replace(mixed $search, mixed $replace, mixed $subject [, int &$count])
*/
PHP_FUNCTION(taint_str_replace)
{
zval *str, *from, *len, *repl;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz|z", &str, &repl, &from, &len) == FAILURE) {
return;
}
if (IS_STRING == Z_TYPE_P(repl) && TAINT_POSSIBLE(Z_STR_P(repl))) {
tainted = 1;
} else if (IS_STRING == Z_TYPE_P(from) && TAINT_POSSIBLE(Z_STR_P(from))) {
tainted = 1;
}
TAINT_O_FUNC(str_replace)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string str_ireplace(mixed $search, mixed $replace, mixed $subject [, int &$count])
*/
PHP_FUNCTION(taint_str_ireplace)
{
zval *str, *from, *len, *repl;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz|z", &str, &repl, &from, &len) == FAILURE) {
return;
}
if (IS_STRING == Z_TYPE_P(repl) && TAINT_POSSIBLE(Z_STR_P(repl))) {
tainted = 1;
} else if (IS_STRING == Z_TYPE_P(from) && TAINT_POSSIBLE(Z_STR_P(from))) {
tainted = 1;
}
TAINT_O_FUNC(str_ireplace)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string str_pad(string $input, int $pad_length[, string $pad_string = " "[, int $pad_type = STR_PAD_RIGHT]])
*/
PHP_FUNCTION(taint_str_pad)
{
zend_string *input;
zend_long pad_length;
zend_string *pad_str = NULL;
zend_long pad_type_val = 1;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|Sl", &input, &pad_length, &pad_str, &pad_type_val) == FAILURE) {
return;
}
if (TAINT_POSSIBLE(input)) {
tainted = 1;
} else if (pad_str && TAINT_POSSIBLE(pad_str)) {
tainted = 1;
}
TAINT_O_FUNC(str_pad)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string strstr(string $haystack, mixed $needle[, bool $part = false])
*/
PHP_FUNCTION(taint_strstr)
{
zval *needle;
zend_string *haystack;
zend_bool part = 0;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|b", &haystack, &needle, &part) == FAILURE) {
return;
}
if (TAINT_POSSIBLE(haystack)) {
tainted = 1;
}
TAINT_O_FUNC(strstr)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) &&
Z_STR_P(return_value) != haystack && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string substr(string $string, int $start[, int $length])
*/
PHP_FUNCTION(taint_substr)
{
zend_string *str;
zend_long l = 0, f;
int tainted = 0;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(str)
Z_PARAM_LONG(f)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(l)
ZEND_PARSE_PARAMETERS_END();
if (TAINT_POSSIBLE(str)) {
tainted = 1;
}
TAINT_O_FUNC(substr)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) &&
Z_STR_P(return_value) != str && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string strtolower(string $string)
*/
PHP_FUNCTION(taint_strtolower)
{
zend_string *str;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
return;
}
if (TAINT_POSSIBLE(str)) {
tainted = 1;
}
TAINT_O_FUNC(strtolower)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) &&
Z_STR_P(return_value) != str && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string strtoupper(string $string)
*/
PHP_FUNCTION(taint_strtoupper)
{
zend_string *str;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
return;
}
if (TAINT_POSSIBLE(str)) {
tainted = 1;
}
TAINT_O_FUNC(strtoupper)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value) &&
Z_STR_P(return_value) != str && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string dirname(string $path, int level)
*/
PHP_FUNCTION(taint_dirname) {
zend_string *str;
zend_long levels = 1;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &str, &levels) == FAILURE) {
return;
}
if (TAINT_POSSIBLE(str)) {
tainted = 1;
}
TAINT_O_FUNC(dirname)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value)
&& Z_STR_P(return_value) != str && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string basename(string $path[, string $suffix])
*/
PHP_FUNCTION(taint_basename) {
zend_string *string, *suffix = NULL;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|S", &string, &suffix) == FAILURE) {
return;
}
if (TAINT_POSSIBLE(string)) {
tainted = 1;
}
TAINT_O_FUNC(basename)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted && IS_STRING == Z_TYPE_P(return_value)
&& Z_STR_P(return_value) != string && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
}
/* }}} */
/* {{{ proto string pathinfo(string $path[, int $options])
*/
PHP_FUNCTION(taint_pathinfo) {
zend_string *path;
zend_long opt;
int tainted = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &path, &opt) == FAILURE) {
return;
}
if (TAINT_POSSIBLE(path)) {
tainted = 1;
}
TAINT_O_FUNC(pathinfo)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (tainted) {
if (IS_STRING == Z_TYPE_P(return_value)) {
if (Z_STR_P(return_value) != path && Z_STRLEN_P(return_value)) {
TAINT_MARK(Z_STR_P(return_value));
}
} else if (IS_ARRAY == Z_TYPE_P(return_value)) {
php_taint_mark_strings(Z_ARRVAL_P(return_value));
}
}
}
/* }}} */
static PHP_INI_MH(OnUpdateErrorLevel) /* {{{ */ {
if (!new_value) {
TAINT_G(error_level) = E_USER_WARNING;
} else {
TAINT_G(error_level) = (int)atoi(ZSTR_VAL(new_value));
}
return SUCCESS;
} /* }}} */
/* {{{ PHP_INI
*/
PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN("taint.enable", "0", PHP_INI_SYSTEM, OnUpdateBool, enable, zend_taint_globals, taint_globals)
STD_PHP_INI_ENTRY("taint.error_level", "512", PHP_INI_ALL, OnUpdateErrorLevel, error_level, zend_taint_globals, taint_globals)
PHP_INI_END()
/* }}} */
/* {{{ proto bool taint(string $str[, string ...])
*/
PHP_FUNCTION(taint)
{
zval *args;
int argc;
int i;
if (!TAINT_G(enable)) {
RETURN_TRUE;
}
if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
return;
}
for (i = 0; i < argc; i++) {
zval *el = &args[i];
ZVAL_DEREF(el);
if (IS_STRING == Z_TYPE_P(el) && Z_STRLEN_P(el) && !TAINT_POSSIBLE(Z_STR_P(el))) {
/* string might be in shared memory */
zend_string *str = zend_string_init(Z_STRVAL_P(el), Z_STRLEN_P(el), 0);
zend_string_release(Z_STR_P(el));
TAINT_MARK(str);
ZVAL_STR(el, str);
}
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool untaint(string $str[, string ...])
*/
PHP_FUNCTION(untaint)
{
zval *args;
int argc;
int i;
if (!TAINT_G(enable)) {
RETURN_TRUE;
}
if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
return;
}
for (i = 0; i < argc; i++) {
zval *el = &args[i];
ZVAL_DEREF(el);
if (IS_STRING == Z_TYPE_P(el) && TAINT_POSSIBLE(Z_STR_P(el))) {
TAINT_CLEAN(Z_STR_P(el));
}
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool is_tainted(string $str)
*/
PHP_FUNCTION(is_tainted)
{
zval *arg;
if (!TAINT_G(enable)) {
RETURN_FALSE;
}
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) {
return;
}
ZVAL_DEREF(arg);
if (IS_STRING == Z_TYPE_P(arg) && TAINT_POSSIBLE(Z_STR_P(arg))) {
RETURN_TRUE;
}
RETURN_FALSE;
}
/* }}} */
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(taint)
{
REGISTER_INI_ENTRIES();
if (!TAINT_G(enable)) {
return SUCCESS;
}
php_taint_register_handlers();
php_taint_override_functions();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION(taint)
{
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RINIT_FUNCTION
*/
PHP_RINIT_FUNCTION(taint)
{
if (SG(sapi_started) || !TAINT_G(enable)) {
return SUCCESS;
}
if (Z_TYPE(PG(http_globals)[TRACK_VARS_POST]) == IS_ARRAY) {
php_taint_mark_strings(Z_ARRVAL(PG(http_globals)[TRACK_VARS_POST]));
}
if (Z_TYPE(PG(http_globals)[TRACK_VARS_GET]) == IS_ARRAY) {
php_taint_mark_strings(Z_ARRVAL(PG(http_globals)[TRACK_VARS_GET]));
}
if (Z_TYPE(PG(http_globals)[TRACK_VARS_COOKIE]) == IS_ARRAY) {
php_taint_mark_strings(Z_ARRVAL(PG(http_globals)[TRACK_VARS_COOKIE]));
}
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RSHUTDOWN_FUNCTION
*/
PHP_RSHUTDOWN_FUNCTION(taint)
{
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(taint)
{
php_info_print_table_start();
php_info_print_table_header(2, "taint support", "enabled");
php_info_print_table_row(2, "Version", PHP_TAINT_VERSION);
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/lujunjian/taint.git
git@gitee.com:lujunjian/taint.git
lujunjian
taint
taint
master

搜索帮助