summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnatol Belski <ab@php.net>2014-01-05 19:05:04 +0100
committerAnatol Belski <ab@php.net>2014-01-05 19:05:04 +0100
commit3f7f72adb25786f51e7907e0d37f2e25bd5cf3dd (patch)
tree53a8c3c9677eea8706488c1d228be01261d56c43
parent7e8e21df0c9aa39278e994b05540b69920201b32 (diff)
downloadphp-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.c15
-rw-r--r--ext/standard/tests/file/basename_bug66395_variation2-win32.phpt36
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==