diff options
| -rw-r--r-- | config/default_php8.rules | 2 | ||||
| -rw-r--r-- | doc/source/config.rst | 11 | ||||
| -rw-r--r-- | doc/source/features.rst | 16 | ||||
| -rw-r--r-- | src/snuffleupagus.c | 3 | ||||
| -rw-r--r-- | src/sp_config.h | 2 | ||||
| -rw-r--r-- | src/sp_config_keywords.c | 1 | ||||
| -rw-r--r-- | src/sp_wrapper.c | 135 | ||||
| -rw-r--r-- | src/tests/stream_wrapper/config/config_stream_wrapper_php.ini | 2 | ||||
| -rw-r--r-- | src/tests/stream_wrapper/stream_wrapper_php.phpt | 76 |
9 files changed, 247 insertions, 1 deletions
diff --git a/config/default_php8.rules b/config/default_php8.rules index 98cc0db..096f033 100644 --- a/config/default_php8.rules +++ b/config/default_php8.rules | |||
| @@ -26,6 +26,8 @@ sp.xxe_protection.enable(); | |||
| 26 | # PHP has a lot of wrappers, most of them aren't usually useful, you should | 26 | # PHP has a lot of wrappers, most of them aren't usually useful, you should |
| 27 | # only enable the ones you're using. | 27 | # only enable the ones you're using. |
| 28 | # sp.wrappers_whitelist.list("file,php,phar"); | 28 | # sp.wrappers_whitelist.list("file,php,phar"); |
| 29 | # The "php" wrapper can be further filtered | ||
| 30 | # sp.wrappers_whitelist.php_list("stdout,stdin,stderr"); | ||
| 29 | 31 | ||
| 30 | # Prevent sloppy comparisons. | 32 | # Prevent sloppy comparisons. |
| 31 | # sp.sloppy_comparison.enable(); | 33 | # sp.sloppy_comparison.enable(); |
diff --git a/doc/source/config.rst b/doc/source/config.rst index 9781046..75392d7 100644 --- a/doc/source/config.rst +++ b/doc/source/config.rst | |||
| @@ -395,6 +395,17 @@ to explicitly whitelist some `stream wrappers <https://secure.php.net/manual/en/ | |||
| 395 | sp.wrappers_whitelist.list("file,php,phar"); | 395 | sp.wrappers_whitelist.list("file,php,phar"); |
| 396 | 396 | ||
| 397 | 397 | ||
| 398 | Allowlist of the php stream-wrapper | ||
| 399 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 400 | |||
| 401 | :ref:`The php-stream-wrapper allowlist <php-stream-wrapper-allowlist-feature>` | ||
| 402 | allows to explicitly allow the builtin `php streams <https://www.php.net/manual/en/wrappers.php.php>`__. | ||
| 403 | |||
| 404 | :: | ||
| 405 | |||
| 406 | sp.wrappers_whitelist.php_list("stdout,stdin,stderr"); | ||
| 407 | |||
| 408 | |||
| 398 | Eval white and blacklist | 409 | Eval white and blacklist |
| 399 | ^^^^^^^^^^^^^^^^^^^^^^^^ | 410 | ^^^^^^^^^^^^^^^^^^^^^^^^ |
| 400 | 411 | ||
diff --git a/doc/source/features.rst b/doc/source/features.rst index d7f6f7f..3855f2a 100644 --- a/doc/source/features.rst +++ b/doc/source/features.rst | |||
| @@ -381,7 +381,7 @@ and using this feature to lock this up. | |||
| 381 | Whitelist of stream-wrappers | 381 | Whitelist of stream-wrappers |
| 382 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 382 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 383 | 383 | ||
| 384 | Php comes with a `lot of different <https://secure.php.net/manual/en/wrappers.php>`__ | 384 | PHP comes with a `lot of different <https://secure.php.net/manual/en/wrappers.php>`__ |
| 385 | `stream wrapper <https://secure.php.net/manual/en/intro.stream.php>`__, and most of them | 385 | `stream wrapper <https://secure.php.net/manual/en/intro.stream.php>`__, and most of them |
| 386 | are enabled by default. | 386 | are enabled by default. |
| 387 | 387 | ||
| @@ -397,6 +397,20 @@ Examples of related vulnerabilities | |||
| 397 | - `Data exfiltration via stream wrapper <https://www.idontplaydarts.com/2011/02/using-php-filter-for-local-file-inclusion/>`__ | 397 | - `Data exfiltration via stream wrapper <https://www.idontplaydarts.com/2011/02/using-php-filter-for-local-file-inclusion/>`__ |
| 398 | - `Inclusion via zip/phar <https://lightless.me/archives/include-file-from-zip-or-phar.html>`__ | 398 | - `Inclusion via zip/phar <https://lightless.me/archives/include-file-from-zip-or-phar.html>`__ |
| 399 | 399 | ||
| 400 | .. _php-stream-wrapper-allowlist-feature: | ||
| 401 | |||
| 402 | Allowlist of php stream-wrapper | ||
| 403 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 404 | |||
| 405 | The builtin `"php" stream wrapper <https://www.php.net/manual/en/wrappers.php.php>`__ | ||
| 406 | has support for common streams, like ``stdin``, ``stdout`` or ``stderr``, but | ||
| 407 | also for the dangerous ``filter`` one. | ||
| 408 | |||
| 409 | Examples of related vulnerability | ||
| 410 | """"""""""""""""""""""""""""""""" | ||
| 411 | |||
| 412 | - `CNEXT exploits <https://github.com/ambionics/cnext-exploits/>`__ | ||
| 413 | |||
| 400 | .. _eval-feature: | 414 | .. _eval-feature: |
| 401 | 415 | ||
| 402 | White and blacklist in ``eval`` | 416 | White and blacklist in ``eval`` |
diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index e549692..8c09a37 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c | |||
| @@ -113,6 +113,7 @@ static PHP_GINIT_FUNCTION(snuffleupagus) { | |||
| 113 | SP_INIT_NULL(config_eval.blacklist); | 113 | SP_INIT_NULL(config_eval.blacklist); |
| 114 | SP_INIT_NULL(config_eval.whitelist); | 114 | SP_INIT_NULL(config_eval.whitelist); |
| 115 | SP_INIT_NULL(config_wrapper.whitelist); | 115 | SP_INIT_NULL(config_wrapper.whitelist); |
| 116 | SP_INIT_NULL(config_wrapper.php_stream_allowlist); | ||
| 116 | #undef SP_INIT_NULL | 117 | #undef SP_INIT_NULL |
| 117 | } | 118 | } |
| 118 | 119 | ||
| @@ -175,6 +176,7 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { | |||
| 175 | FREE_LST(config_eval.blacklist); | 176 | FREE_LST(config_eval.blacklist); |
| 176 | FREE_LST(config_eval.whitelist); | 177 | FREE_LST(config_eval.whitelist); |
| 177 | FREE_LST(config_wrapper.whitelist); | 178 | FREE_LST(config_wrapper.whitelist); |
| 179 | FREE_LST(config_wrapper.php_stream_allowlist); | ||
| 178 | #undef FREE_LST | 180 | #undef FREE_LST |
| 179 | 181 | ||
| 180 | 182 | ||
| @@ -388,6 +390,7 @@ static void dump_config(void) { | |||
| 388 | add_assoc_bool(&arr, SP_TOKEN_SLOPPY_COMPARISON "." SP_TOKEN_ENABLE, SPCFG(sloppy).enable); | 390 | add_assoc_bool(&arr, SP_TOKEN_SLOPPY_COMPARISON "." SP_TOKEN_ENABLE, SPCFG(sloppy).enable); |
| 389 | 391 | ||
| 390 | ADD_ASSOC_SPLIST(&arr, SP_TOKEN_ALLOW_WRAPPERS "." SP_TOKEN_LIST, SPCFG(wrapper).whitelist); | 392 | ADD_ASSOC_SPLIST(&arr, SP_TOKEN_ALLOW_WRAPPERS "." SP_TOKEN_LIST, SPCFG(wrapper).whitelist); |
| 393 | ADD_ASSOC_SPLIST(&arr, SP_TOKEN_ALLOW_WRAPPERS "." SP_TOKEN_ALLOW_PHP_STREAMS, SPCFG(wrapper).php_stream_allowlist); | ||
| 391 | 394 | ||
| 392 | #undef ADD_ASSOC_SPLIST | 395 | #undef ADD_ASSOC_SPLIST |
| 393 | 396 | ||
diff --git a/src/sp_config.h b/src/sp_config.h index f245943..af227ba 100644 --- a/src/sp_config.h +++ b/src/sp_config.h | |||
| @@ -70,6 +70,7 @@ typedef struct { | |||
| 70 | 70 | ||
| 71 | typedef struct { | 71 | typedef struct { |
| 72 | sp_list_node *whitelist; | 72 | sp_list_node *whitelist; |
| 73 | sp_list_node *php_stream_allowlist; | ||
| 73 | bool enabled; | 74 | bool enabled; |
| 74 | size_t num_wrapper; // Used to verify if wrappers were added. | 75 | size_t num_wrapper; // Used to verify if wrappers were added. |
| 75 | } sp_config_wrapper; | 76 | } sp_config_wrapper; |
| @@ -214,6 +215,7 @@ typedef struct { | |||
| 214 | #define SP_TOKEN_EVAL_WHITELIST "eval_whitelist" | 215 | #define SP_TOKEN_EVAL_WHITELIST "eval_whitelist" |
| 215 | #define SP_TOKEN_SLOPPY_COMPARISON "sloppy_comparison" | 216 | #define SP_TOKEN_SLOPPY_COMPARISON "sloppy_comparison" |
| 216 | #define SP_TOKEN_ALLOW_WRAPPERS "wrappers_whitelist" | 217 | #define SP_TOKEN_ALLOW_WRAPPERS "wrappers_whitelist" |
| 218 | #define SP_TOKEN_ALLOW_PHP_STREAMS "php_list" | ||
| 217 | #define SP_TOKEN_INI_PROTECTION "ini_protection" | 219 | #define SP_TOKEN_INI_PROTECTION "ini_protection" |
| 218 | #define SP_TOKEN_INI "ini" | 220 | #define SP_TOKEN_INI "ini" |
| 219 | 221 | ||
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index bf54428..0150a1e 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c | |||
| @@ -190,6 +190,7 @@ SP_PARSE_FN(parse_wrapper_whitelist) { | |||
| 190 | 190 | ||
| 191 | sp_config_keyword config_keywords[] = { | 191 | sp_config_keyword config_keywords[] = { |
| 192 | {parse_list, SP_TOKEN_LIST, &cfg->whitelist}, | 192 | {parse_list, SP_TOKEN_LIST, &cfg->whitelist}, |
| 193 | {parse_list, SP_TOKEN_ALLOW_PHP_STREAMS, &cfg->php_stream_allowlist}, | ||
| 193 | {0, 0, 0}}; | 194 | {0, 0, 0}}; |
| 194 | 195 | ||
| 195 | SP_PROCESS_CONFIG_KEYWORDS_ERR(); | 196 | SP_PROCESS_CONFIG_KEYWORDS_ERR(); |
diff --git a/src/sp_wrapper.c b/src/sp_wrapper.c index 9eb5cbc..54a3a7a 100644 --- a/src/sp_wrapper.c +++ b/src/sp_wrapper.c | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | #include "php_snuffleupagus.h" | 1 | #include "php_snuffleupagus.h" |
| 2 | 2 | ||
| 3 | #define LOG_FEATURE "wrappers_whitelist" | ||
| 4 | |||
| 3 | static bool wrapper_is_whitelisted(const zend_string *const zs) { | 5 | static bool wrapper_is_whitelisted(const zend_string *const zs) { |
| 4 | const sp_list_node *list = SPCFG(wrapper).whitelist; | 6 | const sp_list_node *list = SPCFG(wrapper).whitelist; |
| 5 | 7 | ||
| @@ -16,6 +18,131 @@ static bool wrapper_is_whitelisted(const zend_string *const zs) { | |||
| 16 | return false; | 18 | return false; |
| 17 | } | 19 | } |
| 18 | 20 | ||
| 21 | static bool sp_php_stream_is_filtered(void) { | ||
| 22 | const sp_list_node *list = SPCFG(wrapper).php_stream_allowlist; | ||
| 23 | |||
| 24 | return list != NULL; | ||
| 25 | } | ||
| 26 | |||
| 27 | static bool sp_php_stream_is_whitelisted(const char *const kind) { | ||
| 28 | const sp_list_node *list = SPCFG(wrapper).php_stream_allowlist; | ||
| 29 | |||
| 30 | while (list) { | ||
| 31 | if (!strcasecmp(kind, ZSTR_VAL((const zend_string *)list->data))) { | ||
| 32 | return true; | ||
| 33 | } | ||
| 34 | list = list->next; | ||
| 35 | } | ||
| 36 | return false; | ||
| 37 | } | ||
| 38 | |||
| 39 | /* | ||
| 40 | * Adopted from | ||
| 41 | * https://github.com/php/php-src/blob/8896bd3200892000d8aaa01595d6c64b926a26f7/ext/standard/php_fopen_wrapper.c#L176 | ||
| 42 | */ | ||
| 43 | static php_stream * sp_php_stream_url_wrap_php(php_stream_wrapper *wrapper, | ||
| 44 | const char *path, const char *mode, | ||
| 45 | int options, zend_string **opened_path, | ||
| 46 | php_stream_context *context STREAMS_DC) { | ||
| 47 | if (!strncasecmp(path, "php://", 6)) { | ||
| 48 | path += 6; | ||
| 49 | } | ||
| 50 | |||
| 51 | if (!strncasecmp(path, "temp", 4)) { | ||
| 52 | if (!sp_php_stream_is_whitelisted("temp")) { | ||
| 53 | sp_log_warn(LOG_FEATURE, "Call to not allowed php stream type \"temp\" dropped"); | ||
| 54 | return NULL; | ||
| 55 | } | ||
| 56 | } else if (!strcasecmp(path, "memory")) { | ||
| 57 | if (!sp_php_stream_is_whitelisted("memory")) { | ||
| 58 | sp_log_warn(LOG_FEATURE, "Call to not allowed php stream type \"memory\" dropped"); | ||
| 59 | return NULL; | ||
| 60 | } | ||
| 61 | } else if (!strcasecmp(path, "output")) { | ||
| 62 | if (!sp_php_stream_is_whitelisted("output")) { | ||
| 63 | sp_log_warn(LOG_FEATURE, "Call to not allowed php stream type \"output\" dropped"); | ||
| 64 | return NULL; | ||
| 65 | } | ||
| 66 | } else if (!strcasecmp(path, "input")) { | ||
| 67 | if (!sp_php_stream_is_whitelisted("input")) { | ||
| 68 | sp_log_warn(LOG_FEATURE, "Call to not allowed php stream type \"input\" dropped"); | ||
| 69 | return NULL; | ||
| 70 | } | ||
| 71 | } else if (!strcasecmp(path, "stdin")) { | ||
| 72 | if (!sp_php_stream_is_whitelisted("stdin")) { | ||
| 73 | sp_log_warn(LOG_FEATURE, "Call to not allowed php stream type \"stdin\" dropped"); | ||
| 74 | return NULL; | ||
| 75 | } | ||
| 76 | } else if (!strcasecmp(path, "stdout")) { | ||
| 77 | if (!sp_php_stream_is_whitelisted("stdout")) { | ||
| 78 | sp_log_warn(LOG_FEATURE, "Call to not allowed php stream type \"stdout\" dropped"); | ||
| 79 | return NULL; | ||
| 80 | } | ||
| 81 | } else if (!strcasecmp(path, "stderr")) { | ||
| 82 | if (!sp_php_stream_is_whitelisted("stderr")) { | ||
| 83 | sp_log_warn(LOG_FEATURE, "Call to not allowed php stream type \"stderr\" dropped"); | ||
| 84 | return NULL; | ||
| 85 | } | ||
| 86 | } else if (!strncasecmp(path, "fd/", 3)) { | ||
| 87 | if (!sp_php_stream_is_whitelisted("fd")) { | ||
| 88 | sp_log_warn(LOG_FEATURE, "Call to not allowed php stream type \"fd\" dropped"); | ||
| 89 | return NULL; | ||
| 90 | } | ||
| 91 | } else if (!strncasecmp(path, "filter/", 7)) { | ||
| 92 | if (!sp_php_stream_is_whitelisted("filter")) { | ||
| 93 | sp_log_warn(LOG_FEATURE, "Call to not allowed php stream type \"filter\" dropped"); | ||
| 94 | return NULL; | ||
| 95 | } | ||
| 96 | } else { | ||
| 97 | sp_log_warn(LOG_FEATURE, "Call to unknown php stream type dropped"); | ||
| 98 | return NULL; | ||
| 99 | } | ||
| 100 | |||
| 101 | extern PHPAPI const php_stream_wrapper php_stream_php_wrapper; | ||
| 102 | |||
| 103 | return php_stream_php_wrapper.wops->stream_opener(wrapper, path, mode, options, opened_path, context STREAMS_DC); | ||
| 104 | } | ||
| 105 | |||
| 106 | /* | ||
| 107 | * Adopted from | ||
| 108 | * https://github.com/php/php-src/blob/8896bd3200892000d8aaa01595d6c64b926a26f7/ext/standard/php_fopen_wrapper.c#L428-L446 | ||
| 109 | */ | ||
| 110 | static const php_stream_wrapper_ops sp_php_stdio_wops = { | ||
| 111 | sp_php_stream_url_wrap_php, | ||
| 112 | NULL, /* close */ | ||
| 113 | NULL, /* fstat */ | ||
| 114 | NULL, /* stat */ | ||
| 115 | NULL, /* opendir */ | ||
| 116 | "PHP", | ||
| 117 | NULL, /* unlink */ | ||
| 118 | NULL, /* rename */ | ||
| 119 | NULL, /* mkdir */ | ||
| 120 | NULL, /* rmdir */ | ||
| 121 | NULL | ||
| 122 | }; | ||
| 123 | static const php_stream_wrapper sp_php_stream_php_wrapper = { | ||
| 124 | &sp_php_stdio_wops, | ||
| 125 | NULL, | ||
| 126 | 0, /* is_url */ | ||
| 127 | }; | ||
| 128 | |||
| 129 | static void sp_reregister_php_wrapper(void) { | ||
| 130 | if (!sp_php_stream_is_filtered()) { | ||
| 131 | return; | ||
| 132 | } | ||
| 133 | |||
| 134 | if (php_unregister_url_stream_wrapper("php") != SUCCESS) { | ||
| 135 | sp_log_warn(LOG_FEATURE, "Failed to unregister stream wrapper \"php\""); | ||
| 136 | return; | ||
| 137 | } | ||
| 138 | |||
| 139 | if (php_register_url_stream_wrapper("php", &sp_php_stream_php_wrapper) != SUCCESS) { | ||
| 140 | sp_log_warn(LOG_FEATURE, "Failed to register custom stream wrapper \"php\""); | ||
| 141 | } | ||
| 142 | |||
| 143 | sp_log_debug(LOG_FEATURE, "Stream \"php\" successfully re-registered"); | ||
| 144 | } | ||
| 145 | |||
| 19 | void sp_disable_wrapper() { | 146 | void sp_disable_wrapper() { |
| 20 | HashTable *orig = php_stream_get_url_stream_wrappers_hash(); | 147 | HashTable *orig = php_stream_get_url_stream_wrappers_hash(); |
| 21 | HashTable *orig_complete = pemalloc(sizeof(HashTable), 1); | 148 | HashTable *orig_complete = pemalloc(sizeof(HashTable), 1); |
| @@ -50,6 +177,12 @@ PHP_FUNCTION(sp_stream_wrapper_register) { | |||
| 50 | zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "S*", &protocol_name, ¶ms, ¶m_count); | 177 | zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "S*", &protocol_name, ¶ms, ¶m_count); |
| 51 | // ignore proper arguments here and just let the original handler deal with it | 178 | // ignore proper arguments here and just let the original handler deal with it |
| 52 | if (!protocol_name || wrapper_is_whitelisted(protocol_name)) { | 179 | if (!protocol_name || wrapper_is_whitelisted(protocol_name)) { |
| 180 | |||
| 181 | // reject manual loading of "php" wrapper | ||
| 182 | if (!strcasecmp(ZSTR_VAL(protocol_name), "php") && sp_php_stream_is_filtered()) { | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | |||
| 53 | orig_handler = zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), ZEND_STRL("stream_wrapper_register")); | 186 | orig_handler = zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), ZEND_STRL("stream_wrapper_register")); |
| 54 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); | 187 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); |
| 55 | } | 188 | } |
| @@ -61,5 +194,7 @@ int hook_stream_wrappers() { | |||
| 61 | HOOK_FUNCTION("stream_wrapper_register", sp_internal_functions_hook, | 194 | HOOK_FUNCTION("stream_wrapper_register", sp_internal_functions_hook, |
| 62 | PHP_FN(sp_stream_wrapper_register)); | 195 | PHP_FN(sp_stream_wrapper_register)); |
| 63 | 196 | ||
| 197 | sp_reregister_php_wrapper(); | ||
| 198 | |||
| 64 | return SUCCESS; | 199 | return SUCCESS; |
| 65 | } | 200 | } |
diff --git a/src/tests/stream_wrapper/config/config_stream_wrapper_php.ini b/src/tests/stream_wrapper/config/config_stream_wrapper_php.ini new file mode 100644 index 0000000..bec516c --- /dev/null +++ b/src/tests/stream_wrapper/config/config_stream_wrapper_php.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.wrappers_whitelist.list("php"); | ||
| 2 | sp.wrappers_whitelist.php_list("stdin,stderr,stdout"); | ||
diff --git a/src/tests/stream_wrapper/stream_wrapper_php.phpt b/src/tests/stream_wrapper/stream_wrapper_php.phpt new file mode 100644 index 0000000..c82d2f6 --- /dev/null +++ b/src/tests/stream_wrapper/stream_wrapper_php.phpt | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | --TEST-- | ||
| 2 | Stream wrapper (php) | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php | ||
| 5 | if (!extension_loaded("snuffleupagus")) print "skip snuffleupagus extension missing"; | ||
| 6 | ?> | ||
| 7 | --INI-- | ||
| 8 | sp.configuration_file={PWD}/config/config_stream_wrapper_php.ini | ||
| 9 | --FILE-- | ||
| 10 | <?php | ||
| 11 | echo file_get_contents('php://input'); | ||
| 12 | file_put_contents('php://output', "Hello from stdout\n"); | ||
| 13 | file_put_contents('php://stderr', "Hello from stderr #1\n"); | ||
| 14 | file_put_contents('php://memory', "Bye from memory\n"); | ||
| 15 | echo file_get_contents('php://memory'); | ||
| 16 | file_put_contents('php://temp', "Bye from temp\n"); | ||
| 17 | echo file_get_contents('php://temp'); | ||
| 18 | |||
| 19 | file_put_contents('php://stderr', "Hello from stderr #2\n"); | ||
| 20 | |||
| 21 | file_put_contents('php://filter/write=string.toupper/resource=output.tmp', "Hello from stdout filtered\n"); | ||
| 22 | echo file_get_contents('php://filter/read=string.toupper/resource=output.tmp'); | ||
| 23 | |||
| 24 | $foo = stream_wrapper_unregister("php"); | ||
| 25 | fwrite(STDERR, $foo); | ||
| 26 | file_put_contents('php://stderr', "Hello from stderr #3\n"); | ||
| 27 | |||
| 28 | stream_wrapper_restore("php"); | ||
| 29 | file_put_contents('php://stderr', "Hello from stderr #4\n"); | ||
| 30 | file_put_contents('php://memory', "Bye from memory\n"); | ||
| 31 | ?> | ||
| 32 | --EXPECTF-- | ||
| 33 | Warning: [snuffleupagus][0.0.0.0][wrappers_whitelist][log] Call to not allowed php stream type "input" dropped in %a/stream_wrapper_php.php on line 2 | ||
| 34 | |||
| 35 | Warning: file_get_contents(php://input): %s to open stream: operation failed in %a/stream_wrapper_php.php on line 2 | ||
| 36 | |||
| 37 | Warning: [snuffleupagus][0.0.0.0][wrappers_whitelist][log] Call to not allowed php stream type "output" dropped in %a/stream_wrapper_php.php on line 3 | ||
| 38 | |||
| 39 | Warning: file_put_contents(php://output): %s to open stream: operation failed in %a/stream_wrapper_php.php on line 3 | ||
| 40 | Hello from stderr #1 | ||
| 41 | |||
| 42 | Warning: [snuffleupagus][0.0.0.0][wrappers_whitelist][log] Call to not allowed php stream type "memory" dropped in %a/stream_wrapper_php.php on line 5 | ||
| 43 | |||
| 44 | Warning: file_put_contents(php://memory): %s to open stream: operation failed in %a/stream_wrapper_php.php on line 5 | ||
| 45 | |||
| 46 | Warning: [snuffleupagus][0.0.0.0][wrappers_whitelist][log] Call to not allowed php stream type "memory" dropped in %a/stream_wrapper_php.php on line 6 | ||
| 47 | |||
| 48 | Warning: file_get_contents(php://memory): %s to open stream: operation failed in %a/stream_wrapper_php.php on line 6 | ||
| 49 | |||
| 50 | Warning: [snuffleupagus][0.0.0.0][wrappers_whitelist][log] Call to not allowed php stream type "temp" dropped in %a/stream_wrapper_php.php on line 7 | ||
| 51 | |||
| 52 | Warning: file_put_contents(php://temp): %s to open stream: operation failed in %a/stream_wrapper_php.php on line 7 | ||
| 53 | |||
| 54 | Warning: [snuffleupagus][0.0.0.0][wrappers_whitelist][log] Call to not allowed php stream type "temp" dropped in %a/stream_wrapper_php.php on line 8 | ||
| 55 | |||
| 56 | Warning: file_get_contents(php://temp): %s to open stream: operation failed in %a/stream_wrapper_php.php on line 8 | ||
| 57 | Hello from stderr #2 | ||
| 58 | |||
| 59 | Warning: [snuffleupagus][0.0.0.0][wrappers_whitelist][log] Call to not allowed php stream type "filter" dropped in %a/stream_wrapper_php.php on line 12 | ||
| 60 | |||
| 61 | Warning: file_put_contents(php://filter/write=string.toupper/resource=output.tmp): %s to open stream: operation failed in %a/stream_wrapper_php.php on line 12 | ||
| 62 | |||
| 63 | Warning: [snuffleupagus][0.0.0.0][wrappers_whitelist][log] Call to not allowed php stream type "filter" dropped in %a/stream_wrapper_php.php on line 13 | ||
| 64 | |||
| 65 | Warning: file_get_contents(php://filter/read=string.toupper/resource=output.tmp): %s to open stream: operation failed in %a/stream_wrapper_php.php on line 13 | ||
| 66 | 1 | ||
| 67 | Warning: file_put_contents(): Unable to find the wrapper "php" - did you forget to enable it when you configured PHP? in %a/stream_wrapper_php.php on line 17 | ||
| 68 | |||
| 69 | Warning: file_put_contents(): file:// wrapper is disabled in the server configuration in %a/stream_wrapper_php.php on line 17 | ||
| 70 | |||
| 71 | Warning: file_put_contents(php://stderr): %s to open stream: no suitable wrapper could be found in %a/stream_wrapper_php.php on line 17 | ||
| 72 | Hello from stderr #4 | ||
| 73 | |||
| 74 | Warning: [snuffleupagus][0.0.0.0][wrappers_whitelist][log] Call to not allowed php stream type "memory" dropped in %a/stream_wrapper_php.php on line 21 | ||
| 75 | |||
| 76 | Warning: file_put_contents(php://memory): %s to open stream: operation failed in %a/stream_wrapper_php.php on line 21 | ||
