diff options
author | Gustavo André dos Santos Lopes <cataphract@php.net> | 2010-11-05 01:29:08 +0000 |
---|---|---|
committer | Gustavo André dos Santos Lopes <cataphract@php.net> | 2010-11-05 01:29:08 +0000 |
commit | 0a351335249697ef3fe0b2f9441cf30ad5cb8499 (patch) | |
tree | 5263793b4f3c02dbd87e8e764a4a0326a2c78635 /main | |
parent | 6f1cfe3e7fe7ebb5f8ef733803ee50bfd4e63ad1 (diff) | |
download | php-git-0a351335249697ef3fe0b2f9441cf30ad5cb8499.tar.gz |
- Fixed bug #53241 (stream casting that relies on fdopen/fopencookie fails
with streams opened with, inter alia, the 'xb' mode).
Diffstat (limited to 'main')
-rwxr-xr-x | main/php_streams.h | 6 | ||||
-rw-r--r-- | main/streams/cast.c | 50 | ||||
-rw-r--r-- | main/streams/plain_wrapper.c | 4 |
3 files changed, 58 insertions, 2 deletions
diff --git a/main/php_streams.h b/main/php_streams.h index 99a75473f4..2ac8151b53 100755 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -462,6 +462,12 @@ END_EXTERN_C() #define PHP_STREAM_CAST_MASK (PHP_STREAM_CAST_TRY_HARD | PHP_STREAM_CAST_RELEASE | PHP_STREAM_CAST_INTERNAL) BEGIN_EXTERN_C() PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC); +/* This functions transforms the first char to 'w' if it's not 'r', 'a' or 'w' + * and strips any subsequent chars except '+' and 'b'. + * Use this to sanitize stream->mode if you call e.g. fdopen, fopencookie or + * any other function that expects standard modes and you allow non-standard + * ones. result should be a char[5]. */ +PHPAPI void php_stream_rep_nonstand_mode(php_stream *stream, char *result); END_EXTERN_C() /* use this to check if a stream can be cast into another form */ #define php_stream_can_cast(stream, as) _php_stream_cast((stream), (as), NULL, 0 TSRMLS_CC) diff --git a/main/streams/cast.c b/main/streams/cast.c index e196a005e2..89bfa0ab46 100644 --- a/main/streams/cast.c +++ b/main/streams/cast.c @@ -144,6 +144,50 @@ static COOKIE_IO_FUNCTIONS_T stream_cookie_functions = #endif /* }}} */ +/* {{{ php_stream_rep_nonstand_mode + * Result should have at least size 5, e.g. to write wbx+\0 */ +PHPAPI void php_stream_rep_nonstand_mode(php_stream *stream, char *result) +{ + /* replace modes not supported by fdopen and fopencookie, but supported + * by PHP's fread(), so that their calls won't fail */ + const char *cur_mode = stream->mode; + int has_plus = 0, + has_bin = 0, + i, + res_curs = 0; + + if (cur_mode[0] == 'r' || cur_mode[0] == 'w' || cur_mode[0] == 'a') { + result[res_curs++] = cur_mode[0]; + } else { + /* assume cur_mode[0] is 'c' or 'x'; substitute by 'w', which should not + * truncate anything in fdopen/fopencookie */ + result[res_curs++] = 'w'; + + /* x is allowed (at least by glibc & compat), but not as the 1st mode + * as in PHP and in any case is (at best) ignored by fdopen and fopencookie */ + } + + /* assume current mode has at most length 4 (e.g. wbn+) */ + for (i = 1; i < 4 && cur_mode[i] != '\0'; i++) { + if (cur_mode[i] == 'b') { + has_bin = 1; + } else if (cur_mode[i] == '+') { + has_plus = 1; + } + /* ignore 'n', 't' or other stuff */ + } + + if (has_bin) { + result[res_curs++] = 'b'; + } + if (has_plus) { + result[res_curs++] = '+'; + } + + result[res_curs] = '\0'; +} +/* }}} */ + /* {{{ php_stream_cast */ PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC) { @@ -187,7 +231,11 @@ PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show goto exit_success; } - *(FILE**)ret = fopencookie(stream, stream->mode, PHP_STREAM_COOKIE_FUNCTIONS); + { + char fixed_mode[5]; + php_stream_rep_nonstand_mode(stream, fixed_mode); + *(FILE**)ret = fopencookie(stream, fixed_mode, PHP_STREAM_COOKIE_FUNCTIONS); + } if (*ret != NULL) { off_t pos; diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index 2fc0e8989a..bc5137c01f 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -490,7 +490,9 @@ static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC) if (data->file == NULL) { /* we were opened as a plain file descriptor, so we * need fdopen now */ - data->file = fdopen(data->fd, stream->mode); + char fixed_mode[5]; + php_stream_rep_nonstand_mode(stream, fixed_mode); + data->file = fdopen(data->fd, fixed_mode); if (data->file == NULL) { return FAILURE; } |