summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Cook <tony@develop-help.com>2015-12-23 14:58:26 +1100
committerRicardo Signes <rjbs@cpan.org>2016-01-11 08:25:45 -0500
commit43db0843f0ee392f73efdeb31f58b713707b7227 (patch)
treecdb8b01bdd14d43576ce1c3104727e12d39ecf58
parent2db25f5c06609690db1209783f0ff18d20999665 (diff)
downloadperl-43db0843f0ee392f73efdeb31f58b713707b7227.tar.gz
avoid invalid memory access in MapPath[AW]
This issue was assigned CVE-2015-8608. [perl #126755]
-rw-r--r--MANIFEST1
-rw-r--r--ext/XS-APItest/APItest.pm2
-rw-r--r--ext/XS-APItest/APItest.xs10
-rw-r--r--ext/XS-APItest/t/win32.t39
-rw-r--r--ext/XS-APItest/typemap12
-rw-r--r--win32/vdir.h23
6 files changed, 79 insertions, 8 deletions
diff --git a/MANIFEST b/MANIFEST
index da8a493c63..2fbc0fcc8f 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -4000,6 +4000,7 @@ ext/XS-APItest/t/underscore_length.t Test find_rundefsv()
ext/XS-APItest/t/utf16_to_utf8.t Test behaviour of utf16_to_utf8{,reversed}
ext/XS-APItest/t/utf8.t Tests for code in utf8.c
ext/XS-APItest/t/whichsig.t XS::APItest: tests for whichsig() and variants
+ext/XS-APItest/t/win32.t Test Win32 specific APIs
ext/XS-APItest/t/xs_special_subs_require.t for require too
ext/XS-APItest/t/xs_special_subs.t Test that XS BEGIN/CHECK/INIT/END work
ext/XS-APItest/t/xsub_h.t Tests for XSUB.h
diff --git a/ext/XS-APItest/APItest.pm b/ext/XS-APItest/APItest.pm
index 63ea85831a..ec8bc9e3de 100644
--- a/ext/XS-APItest/APItest.pm
+++ b/ext/XS-APItest/APItest.pm
@@ -5,7 +5,7 @@ use strict;
use warnings;
use Carp;
-our $VERSION = '0.60_01';
+our $VERSION = '0.60_02';
require XSLoader;
diff --git a/ext/XS-APItest/APItest.xs b/ext/XS-APItest/APItest.xs
index 8e78736af7..79c2264c8c 100644
--- a/ext/XS-APItest/APItest.xs
+++ b/ext/XS-APItest/APItest.xs
@@ -4792,3 +4792,13 @@ test_toTITLE_utf8(SV * p)
RETVAL = av;
OUTPUT:
RETVAL
+
+#if defined(WIN32) && defined(PERL_IMPLICIT_SYS)
+
+const char *
+PerlDir_mapA(const char *path)
+
+const WCHAR *
+PerlDir_mapW(const WCHAR *wpath)
+
+#endif
diff --git a/ext/XS-APItest/t/win32.t b/ext/XS-APItest/t/win32.t
new file mode 100644
index 0000000000..a8905c2549
--- /dev/null
+++ b/ext/XS-APItest/t/win32.t
@@ -0,0 +1,39 @@
+#!perl -w
+use strict;
+use Test::More;
+use XS::APItest;
+use Config;
+
+plan skip_all => "Tests only apply on MSWin32"
+ unless $^O eq "MSWin32";
+
+SKIP:
+{
+ # [perl #126755] previous the bad drive tests would crash
+ $Config{ccflags} =~ /(?:\A|\s)-DPERL_IMPLICIT_SYS\b/
+ or skip "need implicit_sys for this test", 1;
+ eval "use Encode; 1"
+ or skip "Can't load Encode", 1;
+ for my $letter ("A" .. "Z", "a" .. "z") {
+ my $good_drive = $letter . ":";
+ my $result = PerlDir_mapA($good_drive);
+ like($result, qr/^$letter:\\/i, "check good drive $letter");
+
+ my $wgood_drive = encode("UTF-16LE", $good_drive . "\0");
+ $result = PerlDir_mapW($wgood_drive);
+ like(decode("UTF16-LE", $result), qr/^$letter:\\/i,
+ "check a good drive (wide)");
+ }
+ for my $bad ('@', '[', '!', '~', '`', '{') {
+ my $bad_drive = "$bad:";
+ my $result = PerlDir_mapA($bad_drive);
+ is($result, $bad_drive, "check bad drive $bad:");
+
+ my $wbad_drive = encode("UTF-16LE", $bad_drive . "\0");
+ $result = PerlDir_mapW($wbad_drive);
+ is(decode("UTF16-LE", $result), "$bad_drive\0",
+ "check bad drive $bad: (wide)");
+ }
+}
+
+done_testing();
diff --git a/ext/XS-APItest/typemap b/ext/XS-APItest/typemap
index 035f882a6b..ed86a374f1 100644
--- a/ext/XS-APItest/typemap
+++ b/ext/XS-APItest/typemap
@@ -1 +1,13 @@
XS::APItest::PtrTable T_PTROBJ
+
+const WCHAR * WPV
+
+INPUT
+
+WPV
+ $var = ($type)SvPV_nolen($arg);
+
+OUTPUT
+
+WPV
+ sv_setpvn($arg, (const char *)($var), sizeof(WCHAR) * (1+wcslen($var)));
diff --git a/win32/vdir.h b/win32/vdir.h
index a4186a1ad9..b922130b8f 100644
--- a/win32/vdir.h
+++ b/win32/vdir.h
@@ -15,6 +15,7 @@
* and one additional slot for a UNC name
*/
const int driveCount = ('Z'-'A')+1+1;
+const int driveLetterCount = ('Z'-'A')+1;
class VDir
{
@@ -383,6 +384,7 @@ char *VDir::MapPathA(const char *pInName)
* possiblities -- relative path or absolute path with or without drive letter
* OR UNC name
*/
+ int driveIndex;
char szBuffer[(MAX_PATH+1)*2];
char szlBuf[MAX_PATH+1];
int length = strlen(pInName);
@@ -402,15 +404,18 @@ char *VDir::MapPathA(const char *pInName)
}
/* strlen(pInName) is now <= MAX_PATH */
- if (pInName[1] == ':') {
+ if (length > 1 && pInName[1] == ':') {
/* has drive letter */
- if (IsPathSep(pInName[2])) {
+ if (length > 2 && IsPathSep(pInName[2])) {
/* absolute with drive letter */
DoGetFullPathNameA((char*)pInName, sizeof(szLocalBufferA), szLocalBufferA);
}
else {
/* relative path with drive letter */
- strcpy(szBuffer, GetDirA(DriveIndex(*pInName)));
+ driveIndex = DriveIndex(*pInName);
+ if (driveIndex < 0 || driveIndex >= driveLetterCount)
+ return (char *)pInName;
+ strcpy(szBuffer, GetDirA(driveIndex));
strcat(szBuffer, &pInName[2]);
if(strlen(szBuffer) > MAX_PATH)
szBuffer[MAX_PATH] = '\0';
@@ -420,7 +425,7 @@ char *VDir::MapPathA(const char *pInName)
}
else {
/* no drive letter */
- if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
+ if (length > 1 && IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
/* UNC name */
DoGetFullPathNameA((char*)pInName, sizeof(szLocalBufferA), szLocalBufferA);
}
@@ -611,6 +616,7 @@ WCHAR* VDir::MapPathW(const WCHAR *pInName)
* possiblities -- relative path or absolute path with or without drive letter
* OR UNC name
*/
+ int driveIndex;
WCHAR szBuffer[(MAX_PATH+1)*2];
WCHAR szlBuf[MAX_PATH+1];
int length = wcslen(pInName);
@@ -630,7 +636,7 @@ WCHAR* VDir::MapPathW(const WCHAR *pInName)
}
/* strlen(pInName) is now <= MAX_PATH */
- if (pInName[1] == ':') {
+ if (length > 1 && pInName[1] == ':') {
/* has drive letter */
if (IsPathSep(pInName[2])) {
/* absolute with drive letter */
@@ -638,7 +644,10 @@ WCHAR* VDir::MapPathW(const WCHAR *pInName)
}
else {
/* relative path with drive letter */
- wcscpy(szBuffer, GetDirW(DriveIndex((char)*pInName)));
+ driveIndex = DriveIndex(*pInName);
+ if (driveIndex < 0 || driveIndex >= driveLetterCount)
+ return (WCHAR *)pInName;
+ wcscpy(szBuffer, GetDirW(driveIndex));
wcscat(szBuffer, &pInName[2]);
if(wcslen(szBuffer) > MAX_PATH)
szBuffer[MAX_PATH] = '\0';
@@ -648,7 +657,7 @@ WCHAR* VDir::MapPathW(const WCHAR *pInName)
}
else {
/* no drive letter */
- if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
+ if (length > 1 && IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
/* UNC name */
DoGetFullPathNameW((WCHAR*)pInName, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW);
}