diff options
author | Tony Cook <tony@develop-help.com> | 2015-12-23 14:58:26 +1100 |
---|---|---|
committer | Ricardo Signes <rjbs@cpan.org> | 2016-01-11 08:25:45 -0500 |
commit | 43db0843f0ee392f73efdeb31f58b713707b7227 (patch) | |
tree | cdb8b01bdd14d43576ce1c3104727e12d39ecf58 | |
parent | 2db25f5c06609690db1209783f0ff18d20999665 (diff) | |
download | perl-43db0843f0ee392f73efdeb31f58b713707b7227.tar.gz |
avoid invalid memory access in MapPath[AW]
This issue was assigned CVE-2015-8608. [perl #126755]
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | ext/XS-APItest/APItest.pm | 2 | ||||
-rw-r--r-- | ext/XS-APItest/APItest.xs | 10 | ||||
-rw-r--r-- | ext/XS-APItest/t/win32.t | 39 | ||||
-rw-r--r-- | ext/XS-APItest/typemap | 12 | ||||
-rw-r--r-- | win32/vdir.h | 23 |
6 files changed, 79 insertions, 8 deletions
@@ -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); } |