diff options
author | Anatol Belski <ab@php.net> | 2014-01-05 19:05:04 +0100 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2014-01-05 19:05:04 +0100 |
commit | 3f7f72adb25786f51e7907e0d37f2e25bd5cf3dd (patch) | |
tree | 53a8c3c9677eea8706488c1d228be01261d56c43 | |
parent | 7e8e21df0c9aa39278e994b05540b69920201b32 (diff) | |
download | php-git-3f7f72adb25786f51e7907e0d37f2e25bd5cf3dd.tar.gz |
improved the fix for bug #66395
- fixed the traverse vulnerability in case like c:d:file.txt
- ensure paths containing NTFS streams are still worky
-rw-r--r-- | ext/standard/string.c | 15 | ||||
-rw-r--r-- | ext/standard/tests/file/basename_bug66395_variation2-win32.phpt | 36 |
2 files changed, 50 insertions, 1 deletions
diff --git a/ext/standard/string.c b/ext/standard/string.c index bf2df9a612..c4e77f2f29 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -1433,7 +1433,7 @@ PHPAPI void php_basename(const char *s, size_t len, char *suffix, size_t sufflen goto quit_loop; case 1: #if defined(PHP_WIN32) || defined(NETWARE) - if (*c == '/' || *c == '\\' || (*c == ':' && (c - s == 1))) { + if (*c == '/' || *c == '\\') { #else if (*c == '/') { #endif @@ -1441,6 +1441,19 @@ PHPAPI void php_basename(const char *s, size_t len, char *suffix, size_t sufflen state = 0; cend = c; } +#if defined(PHP_WIN32) || defined(NETWARE) + /* Catch relative paths in c:file.txt style. They're not to confuse + with the NTFS streams. This part ensures also, that no drive + letter traversing happens. */ + } else if ((*c == ':' && (c - comp == 1))) { + if (state == 0) { + comp = c; + state = 1; + } else { + cend = c; + state = 0; + } +#endif } else { if (state == 0) { comp = c; diff --git a/ext/standard/tests/file/basename_bug66395_variation2-win32.phpt b/ext/standard/tests/file/basename_bug66395_variation2-win32.phpt new file mode 100644 index 0000000000..05df79b02a --- /dev/null +++ b/ext/standard/tests/file/basename_bug66395_variation2-win32.phpt @@ -0,0 +1,36 @@ +--TEST-- +basename bug #66395 check drive traversing and NTFS streams +--SKIPIF-- +<?php if (substr(PHP_OS, 0, 3) != 'WIN') { die('skip Windows only basename tests'); } ?> +--FILE-- +<?php +echo basename("y:") . "\n"; +echo basename("y:/") . "\n"; +echo basename("notdriveletter:file.txt") . "\n"; +echo basename("a:\\b:c:d:hello.txt\\hcd:c.txt") . "\n"; +echo basename("a:b:c:d:hello.txt\\d:some.txt") . "\n"; +echo basename("a:b:c:d:hello\world\a.bmp\c:d:e:f.txt") . "\n"; +echo basename("a:\\b:\\c:d:hello\\world\\a.bmp\\d:e:f:g.txt") . "\n"; +echo basename("a:\\b:\\c:d:hello/world\\a.bmp\\d:\\e:\\f:g.txt") . "\n"; +echo basename("a:\\b:/c:d:hello\\world:somestream") . "\n"; +echo basename("a:\\b:\\c:d:hello\\world:some.stream") . "\n"; +echo basename("a:/b:\\c:d:hello\\world:some.stream:\$DATA") . "\n"; +echo basename("x:y:z:hello\world:my.stream:\$DATA") . "\n"; +echo basename("a:\\b:\\c:d:hello\\world:c:\$DATA") . "\n"; +?> +==DONE== +--EXPECTF-- +y +y +notdriveletter:file.txt +hcd:c.txt +some.txt +f.txt +g.txt +g.txt +world:somestream +world:some.stream +world:some.stream:$DATA +world:my.stream:$DATA +world:c:$DATA +==DONE== |