From 6be6c2d62df334fb48c3245898af249a4aeee242 Mon Sep 17 00:00:00 2001 From: Christian Stocker Date: Tue, 12 Jul 2011 04:58:38 +0000 Subject: [PATCH] Added XsltProcessor::setSecurityPrefs($options) and getSecurityPrefs() to define forbidden operations within XSLT stylesheets, default is not to enable any write operations from XSLT anymore. Bug #54446 (second iteration of the code for trunk, first commit for 5.4 branch) --- NEWS | 5 +++ UPGRADING | 3 ++ ext/xsl/php_xsl.c | 8 ++++ ext/xsl/php_xsl.h | 9 ++++ ext/xsl/xsl_fe.h | 3 ++ ext/xsl/xsltprocessor.c | 92 ++++++++++++++++++++++++++++++++++++++++- 6 files changed, 119 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index ae0a795ad5..745cb80b2b 100644 --- a/NEWS +++ b/NEWS @@ -237,6 +237,11 @@ . Added SplObjectStorage::getHash() hook. (Etienne) . Added CallbackFilterIterator and RecursiveCallbackFilterIterator. (Arnaud) +- Improved XSL extension: + . Added XsltProcessor::setSecurityPrefs($options) and getSecurityPrefs() to + define forbidden operations within XSLT stylesheets, default is not to + enable any write operations from XSLT anymore. Bug #54446 + - Improved ZLIB extension: . Re-implemented non-file related functionality. (Mike) diff --git a/UPGRADING b/UPGRADING index ef879668a4..72243a6794 100755 --- a/UPGRADING +++ b/UPGRADING @@ -176,6 +176,9 @@ UPGRADE NOTES - PHP X.Y var_export(), and print_r(). - The raw data parameter in openssl_encrypt()/openssl_decrypt() is now an options integer rather than a boolean. A value of true produces the same behaviour. +- Write operations within XSLT (for example with the extension sax:output) are + disabled by default. You can define what is forbidden with the method + XsltProcess::setSecurityPrefs($options) =================================== 5. Changes made to existing methods diff --git a/ext/xsl/php_xsl.c b/ext/xsl/php_xsl.c index 90f45be280..13ed910b5d 100644 --- a/ext/xsl/php_xsl.c +++ b/ext/xsl/php_xsl.c @@ -126,6 +126,7 @@ zend_object_value xsl_objects_new(zend_class_entry *class_type TSRMLS_DC) intern->node_list = NULL; intern->doc = NULL; intern->profiling = NULL; + intern->securityPrefs = XSL_SECPREF_WRITE_FILE | XSL_SECPREF_WRITE_NETWORK | XSL_SECPREF_CREATE_DIRECTORY; zend_object_std_init(&intern->std, class_type TSRMLS_CC); object_properties_init(&intern->std, class_type); @@ -166,6 +167,13 @@ PHP_MINIT_FUNCTION(xsl) REGISTER_LONG_CONSTANT("XSL_CLONE_NEVER", -1, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("XSL_CLONE_ALWAYS", 1, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("XSL_SECPREF_NONE", XSL_SECPREF_NONE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("XSL_SECPREF_READ_FILE", XSL_SECPREF_READ_FILE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("XSL_SECPREF_WRITE_FILE", XSL_SECPREF_WRITE_FILE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("XSL_SECPREF_CREATE_DIRECTORY", XSL_SECPREF_CREATE_DIRECTORY, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("XSL_SECPREF_READ_NETWORK", XSL_SECPREF_READ_NETWORK, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("XSL_SECPREF_WRITE_NETWORK", XSL_SECPREF_WRITE_NETWORK, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("LIBXSLT_VERSION", LIBXSLT_VERSION, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("LIBXSLT_DOTTED_VERSION", LIBXSLT_DOTTED_VERSION, CONST_CS | CONST_PERSISTENT); diff --git a/ext/xsl/php_xsl.h b/ext/xsl/php_xsl.h index 5d1ffa5c3f..8782077413 100644 --- a/ext/xsl/php_xsl.h +++ b/ext/xsl/php_xsl.h @@ -32,6 +32,7 @@ extern zend_module_entry xsl_module_entry; #include #include #include +#include #if HAVE_XSL_EXSLT #include #include @@ -43,6 +44,13 @@ extern zend_module_entry xsl_module_entry; #include #include +#define XSL_SECPREF_NONE 0 +#define XSL_SECPREF_READ_FILE 2 +#define XSL_SECPREF_WRITE_FILE 4 +#define XSL_SECPREF_CREATE_DIRECTORY 8 +#define XSL_SECPREF_READ_NETWORK 16 +#define XSL_SECPREF_WRITE_NETWORK 32 + typedef struct _xsl_object { zend_object std; void *ptr; @@ -55,6 +63,7 @@ typedef struct _xsl_object { HashTable *node_list; php_libxml_node_object *doc; char *profiling; + long securityPrefs; } xsl_object; void php_xsl_set_object(zval *wrapper, void *obj TSRMLS_DC); diff --git a/ext/xsl/xsl_fe.h b/ext/xsl/xsl_fe.h index f6bc1f5ae0..a9fb16b2b2 100644 --- a/ext/xsl/xsl_fe.h +++ b/ext/xsl/xsl_fe.h @@ -34,6 +34,9 @@ PHP_FUNCTION(xsl_xsltprocessor_remove_parameter); PHP_FUNCTION(xsl_xsltprocessor_has_exslt_support); PHP_FUNCTION(xsl_xsltprocessor_register_php_functions); PHP_FUNCTION(xsl_xsltprocessor_set_profiling); +PHP_FUNCTION(xsl_xsltprocessor_set_security_prefs); +PHP_FUNCTION(xsl_xsltprocessor_get_security_prefs); + #endif /* diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c index 8cb3415167..82a223787a 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -71,6 +71,13 @@ ZEND_END_ARG_INFO(); ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_profiling, 0, 0, 1) ZEND_ARG_INFO(0, filename) ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_security_prefs, 0, 0, 1) + ZEND_ARG_INFO(0, securityPrefs) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_get_security_prefs, 0, 0, 0) +ZEND_END_ARG_INFO(); /* }}} */ /* @@ -91,6 +98,8 @@ const zend_function_entry php_xsl_xsltprocessor_class_functions[] = { PHP_FALIAS(hasExsltSupport, xsl_xsltprocessor_has_exslt_support, arginfo_xsl_xsltprocessor_has_exslt_support) PHP_FALIAS(registerPHPFunctions, xsl_xsltprocessor_register_php_functions, arginfo_xsl_xsltprocessor_register_php_functions) PHP_FALIAS(setProfiling, xsl_xsltprocessor_set_profiling, arginfo_xsl_xsltprocessor_set_profiling) + PHP_FALIAS(setSecurityPrefs, xsl_xsltprocessor_set_security_prefs, arginfo_xsl_xsltprocessor_set_security_prefs) + PHP_FALIAS(getSecurityPrefs, xsl_xsltprocessor_get_security_prefs, arginfo_xsl_xsltprocessor_get_security_prefs) {NULL, NULL, NULL} }; @@ -475,6 +484,8 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl zval *doXInclude, *member; zend_object_handlers *std_hnd; FILE *f; + int secPrefsError = 0; + xsltSecurityPrefsPtr secPrefs = NULL; node = php_libxml_import_node(docp TSRMLS_CC); @@ -531,11 +542,54 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl } efree(member); - newdocp = xsltApplyStylesheetUser(style, doc, (const char**) params, NULL, f, ctxt); + + //if securityPrefs is set to NONE, we don't have to do any checks, but otherwise... + if (intern->securityPrefs != XSL_SECPREF_NONE) { + secPrefs = xsltNewSecurityPrefs(); + if (intern->securityPrefs & XSL_SECPREF_READ_FILE ) { + if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid)) { + secPrefsError = 1; + } + } + if (intern->securityPrefs & XSL_SECPREF_WRITE_FILE ) { + if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid)) { + secPrefsError = 1; + } + } + if (intern->securityPrefs & XSL_SECPREF_CREATE_DIRECTORY ) { + if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid)) { + secPrefsError = 1; + } + } + if (intern->securityPrefs & XSL_SECPREF_READ_NETWORK) { + if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid)) { + secPrefsError = 1; + } + } + if (intern->securityPrefs & XSL_SECPREF_WRITE_NETWORK) { + if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid)) { + secPrefsError = 1; + } + } + + if (0 != xsltSetCtxtSecurityPrefs(secPrefs, ctxt)) { + secPrefsError = 1; + } + } + + if (secPrefsError == 1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't set libxslt security properties, not doing transformation for security reasons"); + } else { + newdocp = xsltApplyStylesheetUser(style, doc, (const char**) params, NULL, f, ctxt); + } if (f) { fclose(f); } + xsltFreeTransformContext(ctxt); + if (secPrefs) { + xsltFreeSecurityPrefs(secPrefs); + } if (intern->node_list != NULL) { zend_hash_destroy(intern->node_list); @@ -857,6 +911,42 @@ PHP_FUNCTION(xsl_xsltprocessor_set_profiling) } /* }}} end xsl_xsltprocessor_set_profiling */ +/* {{{ proto long xsl_xsltprocessor_set_security_prefs(long securityPrefs) */ +PHP_FUNCTION(xsl_xsltprocessor_set_security_prefs) +{ + zval *id; + xsl_object *intern; + DOM_GET_THIS(id); + long securityPrefs, oldSecurityPrefs; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &securityPrefs) == FAILURE) { + return; + } + intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); + oldSecurityPrefs = intern->securityPrefs; + intern->securityPrefs = securityPrefs; + RETURN_LONG(oldSecurityPrefs); +} +/* }}} end xsl_xsltprocessor_set_security_prefs */ + +/* {{{ proto long xsl_xsltprocessor_get_security_prefs() */ +PHP_FUNCTION(xsl_xsltprocessor_get_security_prefs) +{ + zval *id; + xsl_object *intern; + DOM_GET_THIS(id); + long securityPrefs; + + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "") == SUCCESS) { + intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); + RETURN_LONG(intern->securityPrefs); + } else { + WRONG_PARAM_COUNT; + } +} +/* }}} end xsl_xsltprocessor_get_security_prefs */ + + + /* {{{ proto bool xsl_xsltprocessor_has_exslt_support(); */ PHP_FUNCTION(xsl_xsltprocessor_has_exslt_support) -- 2.40.0