Hello community,

here is the log from the commit of package perl-Archive-Zip for 
openSUSE:Factory checked in at 2018-08-27 12:55:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/perl-Archive-Zip (Old)
 and      /work/SRC/openSUSE:Factory/.perl-Archive-Zip.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "perl-Archive-Zip"

Mon Aug 27 12:55:50 2018 rev:39 rq:631288 version:1.63

Changes:
--------
--- /work/SRC/openSUSE:Factory/perl-Archive-Zip/perl-Archive-Zip.changes        
2018-01-09 14:34:39.659946060 +0100
+++ /work/SRC/openSUSE:Factory/.perl-Archive-Zip.new/perl-Archive-Zip.changes   
2018-08-27 12:55:56.236592323 +0200
@@ -1,0 +2,17 @@
+Thu Aug 23 05:04:06 UTC 2018 - [email protected]
+
+- updated to 1.63
+   see /usr/share/doc/packages/perl-Archive-Zip/Changes
+
+  1.63 Wed 21 Aug 2018
+      - Restore missing META.yml deps (needed updated MB)
+      - Symlink traversal test fix [github/haarg]
+      - Added missing prereq Encode as suggested by CPANTS [github/manwar]
+
+-------------------------------------------------------------------
+Tue Aug 21 05:04:33 UTC 2018 - [email protected]
+
+- updated to 1.62
+   see /usr/share/doc/packages/perl-Archive-Zip/Changes
+
+-------------------------------------------------------------------

Old:
----
  Archive-Zip-1.60.tar.gz

New:
----
  Archive-Zip-1.63.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ perl-Archive-Zip.spec ++++++
--- /var/tmp/diff_new_pack.IjRJxu/_old  2018-08-27 12:55:57.308593498 +0200
+++ /var/tmp/diff_new_pack.IjRJxu/_new  2018-08-27 12:55:57.312593502 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package perl-Archive-Zip
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,11 +17,11 @@
 
 
 Name:           perl-Archive-Zip
-Version:        1.60
+Version:        1.63
 Release:        0
 %define cpan_name Archive-Zip
 Summary:        Provide an interface to ZIP archive files
-License:        Artistic-1.0 or GPL-1.0+
+License:        Artistic-1.0 OR GPL-1.0-or-later
 Group:          Development/Libraries/Perl
 Url:            http://search.cpan.org/dist/Archive-Zip/
 Source0:        
https://cpan.metacpan.org/authors/id/P/PH/PHRED/%{cpan_name}-%{version}.tar.gz

++++++ Archive-Zip-1.60.tar.gz -> Archive-Zip-1.63.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/Changes new/Archive-Zip-1.63/Changes
--- old/Archive-Zip-1.60/Changes        2017-12-19 19:41:50.000000000 +0100
+++ new/Archive-Zip-1.63/Changes        2018-08-22 17:40:12.000000000 +0200
@@ -1,5 +1,17 @@
 Revision history for Perl extension Archive-Zip
 
+1.63 Wed 21 Aug 2018
+    - Restore missing META.yml deps (needed updated MB)
+    - Symlink traversal test fix [github/haarg]
+    - Added missing prereq Encode as suggested by CPANTS [github/manwar]
+
+1.62 Sun 19 Aug 2018
+    - Add link-samename.zip to MANIFEST
+
+1.61 Sat 18 Aug 2018
+    - File::Find will not untaint [github/ThisUsedToBeAnEmail]
+    - Prevent from traversing symlinks and parent directories when extracting 
[github/ppisar]
+
 1.60 Tue 19 Dec 2017
     - RT 123913 Wrong shell bang in examples/selfex.pl
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/MANIFEST 
new/Archive-Zip-1.63/MANIFEST
--- old/Archive-Zip-1.60/MANIFEST       2017-12-19 19:43:30.000000000 +0100
+++ new/Archive-Zip-1.63/MANIFEST       2018-08-22 17:40:33.000000000 +0200
@@ -59,6 +59,7 @@
 t/22_deflated_dir.t
 t/23_closed_handle.t
 t/24_unicode_win32.t
+t/25_traversal.t
 t/badjpeg/expected.jpg
 t/badjpeg/source.zip
 t/common.pm
@@ -68,6 +69,7 @@
 t/data/crypt.zip
 t/data/def.zip
 t/data/defstr.zip
+t/data/dotdot-from-unexistant-path.zip
 t/data/empty.zip
 t/data/emptydef.zip
 t/data/emptydefstr.zip
@@ -75,6 +77,8 @@
 t/data/emptystorestr.zip
 t/data/good_github11.zip
 t/data/jar.zip
+t/data/link-dir.zip
+t/data/link-samename.zip
 t/data/linux.zip
 t/data/mkzip.pl
 t/data/perl.zip
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/META.json 
new/Archive-Zip-1.63/META.json
--- old/Archive-Zip-1.60/META.json      2017-12-19 19:43:30.000000000 +0100
+++ new/Archive-Zip-1.63/META.json      2018-08-22 17:40:33.000000000 +0200
@@ -4,7 +4,7 @@
       "Ned Konz <[email protected]>"
    ],
    "dynamic_config" : 0,
-   "generated_by" : "ExtUtils::MakeMaker version 7.3, CPAN::Meta::Converter 
version 2.150010",
+   "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter 
version 2.150010",
    "license" : [
       "perl_5"
    ],
@@ -33,6 +33,7 @@
       "runtime" : {
          "requires" : {
             "Compress::Raw::Zlib" : "2.017",
+            "Encode" : "0",
             "File::Basename" : "0",
             "File::Copy" : "0",
             "File::Find" : "0",
@@ -65,6 +66,6 @@
          "web" : "https://github.com/redhotpenguin/perl-Archive-Zip";
       }
    },
-   "version" : "1.60",
-   "x_serialization_backend" : "JSON::PP version 2.97000"
+   "version" : "1.63",
+   "x_serialization_backend" : "JSON::PP version 2.97001"
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/META.yml 
new/Archive-Zip-1.63/META.yml
--- old/Archive-Zip-1.60/META.yml       2017-12-19 19:43:30.000000000 +0100
+++ new/Archive-Zip-1.63/META.yml       2018-08-22 17:40:32.000000000 +0200
@@ -9,7 +9,7 @@
 configure_requires:
   ExtUtils::MakeMaker: '0'
 dynamic_config: 0
-generated_by: 'ExtUtils::MakeMaker version 7.3, CPAN::Meta::Converter version 
2.150010'
+generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 
2.150010'
 license: perl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -21,6 +21,7 @@
     - inc
 requires:
   Compress::Raw::Zlib: '2.017'
+  Encode: '0'
   File::Basename: '0'
   File::Copy: '0'
   File::Find: '0'
@@ -35,5 +36,5 @@
 resources:
   bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=Archive-Zip
   repository: https://github.com/redhotpenguin/perl-Archive-Zip.git
-version: '1.60'
+version: '1.63'
 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/Makefile.PL 
new/Archive-Zip-1.63/Makefile.PL
--- old/Archive-Zip-1.60/Makefile.PL    2017-12-19 19:39:06.000000000 +0100
+++ new/Archive-Zip-1.63/Makefile.PL    2018-08-20 21:24:52.000000000 +0200
@@ -47,6 +47,7 @@
         'IO::Handle'   => 0,
         'IO::Seekable' => 0,
         'Time::Local'  => 0,
+        'Encode'       => 0,
     },
     TEST_REQUIRES => {
         'Test::More' => '0.88',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/lib/Archive/Zip/Archive.pm 
new/Archive-Zip-1.63/lib/Archive/Zip/Archive.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip/Archive.pm     2017-12-19 
19:41:58.000000000 +0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip/Archive.pm     2018-08-22 
17:33:51.000000000 +0200
@@ -14,7 +14,7 @@
 use vars qw( $VERSION @ISA );
 
 BEGIN {
-    $VERSION = '1.60';
+    $VERSION = '1.63';
     @ISA     = qw( Archive::Zip );
 }
 
@@ -26,6 +26,7 @@
 );
 
 our $UNICODE;
+our $UNTAINT = qr/\A(.+)\z/;
 
 # Note that this returns undef on read errors, else new zip object.
 
@@ -185,6 +186,8 @@
         $dirName = File::Spec->catpath($volumeName, $dirName, '');
     } else {
         $name = $member->fileName();
+        if ((my $ret = _extractionNameIsSafe($name))
+            != AZ_OK) { return $ret; }
         ($dirName = $name) =~ s{[^/]*$}{};
         $dirName = Archive::Zip::_asLocalName($dirName);
         $name    = Archive::Zip::_asLocalName($name);
@@ -218,6 +221,8 @@
     unless ($name) {
         $name = $member->fileName();
         $name =~ s{.*/}{};    # strip off directories, if any
+        if ((my $ret = _extractionNameIsSafe($name))
+            != AZ_OK) { return $ret; }
         $name = Archive::Zip::_asLocalName($name);
     }
     my $rc = $member->extractToFileNamed($name, @_);
@@ -725,7 +730,7 @@
 # you have bigger problems than this.
 sub _untaintDir {
     my $dir = shift;
-    $dir =~ m/\A(.+)\z/s;
+    $dir =~ m/$UNTAINT/s;
     return $1;
 }
 
@@ -772,7 +777,8 @@
     if ($^O eq 'MSWin32' && $Archive::Zip::UNICODE) {
         $root = Win32::GetANSIPathName($root);
     }
-    File::Find::find($wanted, $root);
+    # File::Find will not untaint unless you explicitly pass the flag and 
regex pattern.
+    File::Find::find({ wanted => $wanted, untaint => 1, untaint_pattern => 
$UNTAINT }, $root);
 
     my $rootZipName = _asZipDirName($root, 1);    # with trailing slash
     my $pattern = $rootZipName eq './' ? '^' : "^\Q$rootZipName\E";
@@ -827,6 +833,37 @@
     return $self->addTree($root, $dest, $matcher, $compressionLevel);
 }
 
+# Check if one of the components of a path to the file or the file name
+# itself is an already existing symbolic link. If yes then return an
+# error. Continuing and writing to a file traversing a link posseses
+# a security threat, especially if the link was extracted from an
+# attacker-supplied archive. This would allow writing to an arbitrary
+# file. The same applies when using ".." to escape from a working
+# directory. <https://bugzilla.redhat.com/show_bug.cgi?id=1591449>
+sub _extractionNameIsSafe {
+    my $name = shift;
+    my ($volume, $directories) = File::Spec->splitpath($name, 1);
+    my @directories = File::Spec->splitdir($directories);
+    if (grep '..' eq $_, @directories) {
+        return _error(
+            "Could not extract $name safely: a parent directory is used");
+    }
+    my @path;
+    my $path;
+    for my $directory (@directories) {
+        push @path, $directory;
+        $path = File::Spec->catpath($volume, File::Spec->catdir(@path), '');
+        if (-l $path) {
+            return _error(
+                "Could not extract $name safely: $path is an existing symbolic 
link");
+        }
+        if (!-e $path) {
+            last;
+        }
+    }
+    return AZ_OK;
+}
+
 # $zip->extractTree( $root, $dest [, $volume] );
 #
 # $root and $dest are Unix-style.
@@ -861,6 +898,8 @@
         $fileName =~ s{$pattern}{$dest};       # in Unix format
                                                # convert to platform format:
         $fileName = Archive::Zip::_asLocalName($fileName, $volume);
+        if ((my $ret = _extractionNameIsSafe($fileName))
+            != AZ_OK) { return $ret; }
         my $status = $member->extractToFileNamed($fileName);
         return $status if $status != AZ_OK;
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/Archive-Zip-1.60/lib/Archive/Zip/BufferedFileHandle.pm 
new/Archive-Zip-1.63/lib/Archive/Zip/BufferedFileHandle.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip/BufferedFileHandle.pm  2017-12-19 
19:41:58.000000000 +0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip/BufferedFileHandle.pm  2018-08-22 
17:33:51.000000000 +0200
@@ -13,7 +13,7 @@
 use vars qw{$VERSION};
 
 BEGIN {
-    $VERSION = '1.60';
+    $VERSION = '1.63';
     $VERSION = eval $VERSION;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/lib/Archive/Zip/DirectoryMember.pm 
new/Archive-Zip-1.63/lib/Archive/Zip/DirectoryMember.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip/DirectoryMember.pm     2017-12-19 
19:41:59.000000000 +0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip/DirectoryMember.pm     2018-08-22 
17:33:51.000000000 +0200
@@ -6,7 +6,7 @@
 use vars qw( $VERSION @ISA );
 
 BEGIN {
-    $VERSION = '1.60';
+    $VERSION = '1.63';
     @ISA     = qw( Archive::Zip::Member );
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/lib/Archive/Zip/FileMember.pm 
new/Archive-Zip-1.63/lib/Archive/Zip/FileMember.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip/FileMember.pm  2017-12-19 
19:41:59.000000000 +0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip/FileMember.pm  2018-08-22 
17:33:51.000000000 +0200
@@ -4,7 +4,7 @@
 use vars qw( $VERSION @ISA );
 
 BEGIN {
-    $VERSION = '1.60';
+    $VERSION = '1.63';
     @ISA     = qw ( Archive::Zip::Member );
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/lib/Archive/Zip/Member.pm 
new/Archive-Zip-1.63/lib/Archive/Zip/Member.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip/Member.pm      2017-12-19 
19:41:59.000000000 +0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip/Member.pm      2018-08-22 
17:33:51.000000000 +0200
@@ -6,7 +6,7 @@
 use vars qw( $VERSION @ISA );
 
 BEGIN {
-    $VERSION = '1.60';
+    $VERSION = '1.63';
     @ISA     = qw( Archive::Zip );
 
     if ($^O eq 'MSWin32') {
@@ -34,6 +34,10 @@
 use constant DEFAULT_FILE_PERMISSIONS      => 0100666;
 use constant DIRECTORY_ATTRIB              => 040000;
 use constant FILE_ATTRIB                   => 0100000;
+use constant OS_SUPPORTS_SYMLINK           => do {
+  local $@;
+  !!eval { symlink("",""); 1 };
+};
 
 # Returns self if successful, else undef
 # Assumes that fh is positioned at beginning of central directory file header.
@@ -650,7 +654,7 @@
 
 # Note, this is not exactly UTC 1980, it's 1980 + 12 hours and 1
 # minute so that nothing timezoney can muck us up.
-my $safe_epoch = 31.606060;
+my $safe_epoch = 31.636060;
 
 # convert a unix time to DOS date/time
 # NOT AN OBJECT METHOD!
@@ -1090,7 +1094,7 @@
 
 # If symbolic link, just create one if the operating system is Linux, Unix, 
BSD or VMS
 # TODO: Add checks for other operating systems
-    if ($self->{'isSymbolicLink'} == 1 && $^O eq 'linux') {
+    if ($self->{'isSymbolicLink'} == 1 && OS_SUPPORTS_SYMLINK) {
         my $chunkSize = $Archive::Zip::ChunkSize;
         my ($outRef, $status) = $self->readChunk($chunkSize);
         symlink $$outRef, $self->{'newName'};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/lib/Archive/Zip/MemberRead.pm 
new/Archive-Zip-1.63/lib/Archive/Zip/MemberRead.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip/MemberRead.pm  2017-12-19 
19:41:59.000000000 +0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip/MemberRead.pm  2018-08-22 
17:33:51.000000000 +0200
@@ -40,7 +40,7 @@
 my $nl;
 
 BEGIN {
-    $VERSION = '1.60';
+    $VERSION = '1.63';
     $VERSION = eval $VERSION;
 
 # Requirement for newline conversion. Should check for e.g., DOS and OS/2 as 
well, but am too lazy.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/lib/Archive/Zip/MockFileHandle.pm 
new/Archive-Zip-1.63/lib/Archive/Zip/MockFileHandle.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip/MockFileHandle.pm      2017-12-19 
19:41:59.000000000 +0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip/MockFileHandle.pm      2018-08-22 
17:33:51.000000000 +0200
@@ -10,7 +10,7 @@
 use vars qw{$VERSION};
 
 BEGIN {
-    $VERSION = '1.60';
+    $VERSION = '1.63';
     $VERSION = eval $VERSION;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/lib/Archive/Zip/NewFileMember.pm 
new/Archive-Zip-1.63/lib/Archive/Zip/NewFileMember.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip/NewFileMember.pm       2017-12-19 
19:41:59.000000000 +0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip/NewFileMember.pm       2018-08-22 
17:33:51.000000000 +0200
@@ -4,7 +4,7 @@
 use vars qw( $VERSION @ISA );
 
 BEGIN {
-    $VERSION = '1.60';
+    $VERSION = '1.63';
     @ISA     = qw ( Archive::Zip::FileMember );
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/lib/Archive/Zip/StringMember.pm 
new/Archive-Zip-1.63/lib/Archive/Zip/StringMember.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip/StringMember.pm        2017-12-19 
19:41:59.000000000 +0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip/StringMember.pm        2018-08-22 
17:33:51.000000000 +0200
@@ -4,7 +4,7 @@
 use vars qw( $VERSION @ISA );
 
 BEGIN {
-    $VERSION = '1.60';
+    $VERSION = '1.63';
     @ISA     = qw( Archive::Zip::Member );
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/lib/Archive/Zip/Tree.pm 
new/Archive-Zip-1.63/lib/Archive/Zip/Tree.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip/Tree.pm        2017-12-19 
19:41:59.000000000 +0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip/Tree.pm        2018-08-22 
17:33:51.000000000 +0200
@@ -4,7 +4,7 @@
 use vars qw{$VERSION};
 
 BEGIN {
-       $VERSION = '1.60';
+       $VERSION = '1.63';
 }
 
 use Archive::Zip;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/lib/Archive/Zip/ZipFileMember.pm 
new/Archive-Zip-1.63/lib/Archive/Zip/ZipFileMember.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip/ZipFileMember.pm       2017-12-19 
19:41:59.000000000 +0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip/ZipFileMember.pm       2018-08-22 
17:33:51.000000000 +0200
@@ -4,7 +4,7 @@
 use vars qw( $VERSION @ISA );
 
 BEGIN {
-    $VERSION = '1.60';
+    $VERSION = '1.63';
     @ISA     = qw ( Archive::Zip::FileMember );
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/lib/Archive/Zip.pm 
new/Archive-Zip-1.63/lib/Archive/Zip.pm
--- old/Archive-Zip-1.60/lib/Archive/Zip.pm     2017-12-19 19:41:59.000000000 
+0100
+++ new/Archive-Zip-1.63/lib/Archive/Zip.pm     2018-08-22 17:33:51.000000000 
+0200
@@ -14,7 +14,7 @@
 use vars qw( $VERSION @ISA );
 
 BEGIN {
-    $VERSION = '1.60';
+    $VERSION = '1.63';
 
     require Exporter;
     @ISA = qw( Exporter );
@@ -1145,6 +1145,9 @@
 directory.
 If you pass C<$extractedName>, it should be in the local file
 system's format.
+If you do not pass C<$extractedName> and the internal filename traverses
+a parent directory or a symbolic link, the extraction will be aborted with
+C<AC_ERROR> for security reason.
 All necessary directories will be created. Returns C<AZ_OK>
 on success.
 
@@ -1162,6 +1165,9 @@
 the internal filename of the member (minus paths) is used as
 the name of the extracted file or directory. Returns C<AZ_OK>
 on success.
+If you do not pass C<$extractedName> and the internal filename is equalled
+to a local symbolic link, the extraction will be aborted with C<AC_ERROR> for
+security reason.
 
 =item addMember( $member )
 
@@ -1609,6 +1615,8 @@
 
 a/b/c to f:\d\e\b\c and ignore ax/d/e and d/e
 
+If the path to the extracted file traverses a parent directory or a symbolic
+link, the extraction will be aborted with C<AC_ERROR> for security reason.
 Returns an error code or AZ_OK if everything worked OK.
 
 =back
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Archive-Zip-1.60/t/25_traversal.t 
new/Archive-Zip-1.63/t/25_traversal.t
--- old/Archive-Zip-1.60/t/25_traversal.t       1970-01-01 01:00:00.000000000 
+0100
+++ new/Archive-Zip-1.63/t/25_traversal.t       2018-08-22 17:24:45.000000000 
+0200
@@ -0,0 +1,198 @@
+use strict;
+use warnings;
+
+use Archive::Zip qw( :ERROR_CODES );
+use File::Spec;
+use File::Path;
+use lib 't';
+use common;
+
+use Test::More tests => 41;
+
+# These tests check for CVE-2018-10860 vulnerabilities.
+# If an archive contains a symlink and then a file that traverses that symlink,
+# extracting the archive tree could write into an abitrary file selected by
+# the symlink value.
+# Another issue is if an archive contains a file whose path component refers
+# to a parent direcotory. Then extracting that file could write into a file
+# out of current working directory subtree.
+# These tests check extracting of these files is refuses and that they are
+# indeed not created.
+
+# Suppress croaking errors, the tests produce some.
+Archive::Zip::setErrorHandler(sub {});
+my ($existed, $ret, $zip, $allowed_file, $forbidden_file);
+
+# Change working directory to a temporary directory because some tested
+# functions operarates there and we need prepared symlinks there.
+my @data_path = (File::Spec->splitdir(File::Spec->rel2abs('.')), 't', 'data');
+ok(chdir TESTDIR, "Working directory changed");
+
+# Symlink tests make sense only if a file system supports them.
+my $symlinks_not_supported;
+{
+    my $link = 'trylink';
+    $symlinks_not_supported = !eval { symlink('.', $link) };
+    unlink $link;
+}
+
+# Case 1:
+#   link-dir -> /tmp
+#   link-dir/gotcha-linkdir
+# writes into /tmp/gotcha-linkdir file.
+SKIP: {
+    skip 'Symbolic links are not supported', 12 if $symlinks_not_supported;
+
+    # Extracting an archive tree must fail
+    $zip = Archive::Zip->new();
+    isa_ok($zip, 'Archive::Zip');
+    is($zip->read(File::Spec->catfile(@data_path, 'link-dir.zip')), AZ_OK,
+        'Archive read');
+    $existed = -e File::Spec->catfile('', 'tmp', 'gotcha-linkdir');
+    $ret = eval { $zip->extractTree() };
+    is($ret, AZ_ERROR, 'Tree extraction aborted');
+    SKIP: {
+        skip 'A canary file existed before the test', 1 if $existed;
+        ok(! -e File::Spec->catfile('link-dir', 'gotcha-linkdir'),
+            'A file was not created in a symlinked directory');
+    }
+    ok(unlink(File::Spec->catfile('link-dir')), 'link-dir removed');
+
+    # The same applies to extracting an archive member without an explicit
+    # local file name. It must abort.
+    my $link = 'link-dir';
+    ok(symlink('.', $link), 'A symlink to a directory created');
+    $forbidden_file = File::Spec->catfile($link, 'gotcha-linkdir');
+    $existed = -e $forbidden_file;
+    $ret = eval { $zip->extractMember('link-dir/gotcha-linkdir') };
+    is($ret, AZ_ERROR, 'Member extraction without a local name aborted');
+    SKIP: {
+        skip 'A canary file existed before the test', 1 if $existed;
+        ok(! -e $forbidden_file,
+            'A file was not created in a symlinked directory');
+    }
+
+    # But allow extracting an archive member into a supplied file name
+    $allowed_file = File::Spec->catfile($link, 'file');
+    $ret = eval { $zip->extractMember('link-dir/gotcha-linkdir', 
$allowed_file) };
+    is($ret, AZ_OK, 'Member extraction passed');
+    ok(-e $allowed_file, 'File created');
+    ok(unlink($allowed_file), 'File removed');
+    ok(unlink($link), 'A symlink to a directory removed');
+}
+
+# Case 2:
+#   unexisting/../../../../../tmp/gotcha-dotdot-unexistingpath
+# writes into ../../../../tmp/gotcha-dotdot-unexistingpath, that is
+# /tmp/gotcha-dotdot-unexistingpath file if CWD is not deeper than
+# 4 directories.
+$zip = Archive::Zip->new();
+isa_ok($zip, 'Archive::Zip');
+is($zip->read(File::Spec->catfile(@data_path,
+            'dotdot-from-unexistant-path.zip')), AZ_OK, 'Archive read');
+$forbidden_file = File::Spec->catfile('..', '..', '..', '..', 'tmp',
+    'gotcha-dotdot-unexistingpath');
+$existed = -e $forbidden_file;
+$ret = eval { $zip->extractTree() };
+is($ret, AZ_ERROR, 'Tree extraction aborted');
+SKIP: {
+    skip 'A canary file existed before the test', 1 if $existed;
+    ok(! -e $forbidden_file, 'A file was not created in a parent directory');
+}
+
+# The same applies to extracting an archive member without an explicit local
+# file name. It must abort.
+$existed = -e $forbidden_file;
+$ret = eval { $zip->extractMember(
+        'unexisting/../../../../../tmp/gotcha-dotdot-unexistingpath',
+    ) };
+is($ret, AZ_ERROR, 'Member extraction without a local name aborted');
+SKIP: {
+    skip 'A canary file existed before the test', 1 if $existed;
+    ok(! -e $forbidden_file, 'A file was not created in a parent directory');
+}
+
+# But allow extracting an archive member into a supplied file name
+ok(mkdir('directory'), 'Directory created');
+$allowed_file = File::Spec->catfile('directory', '..', 'file');
+$ret = eval { $zip->extractMember(
+        'unexisting/../../../../../tmp/gotcha-dotdot-unexistingpath',
+        $allowed_file
+    ) };
+is($ret, AZ_OK, 'Member extraction passed');
+ok(-e $allowed_file, 'File created');
+ok(unlink($allowed_file), 'File removed');
+
+# Case 3:
+#   link-file -> /tmp/gotcha-samename
+#   link-file
+# writes into /tmp/gotcha-samename. It must abort. (Or replace the symlink in
+# more relaxed mode in the future.)
+SKIP: {
+    skip 'Symbolic links are not supported', 18 if $symlinks_not_supported;
+
+    $zip = Archive::Zip->new();
+    isa_ok($zip, 'Archive::Zip');
+    is($zip->read(File::Spec->catfile(@data_path, 'link-samename.zip')), AZ_OK,
+        'Archive read');
+    $existed = -e File::Spec->catfile('', 'tmp', 'gotcha-samename');
+    $ret = eval { $zip->extractTree() };
+    is($ret, AZ_ERROR, 'Tree extraction aborted');
+    SKIP: {
+        skip 'A canary file existed before the test', 1 if $existed;
+        ok(! -e File::Spec->catfile('', 'tmp', 'gotcha-samename'),
+            'A file was not created through a symlinked file');
+    }
+    ok(unlink(File::Spec->catfile('link-file')), 'link-file removed');
+
+    # The same applies to extracting an archive member using extractMember()
+    # without an explicit local file name. It must abort.
+    my $link = 'link-file';
+    my $target = 'target';
+    ok(symlink($target, $link), 'A symlink to a file created');
+    $forbidden_file = File::Spec->catfile($target);
+    $existed = -e $forbidden_file;
+    # Select a member by order due to same file names.
+    my $member = ${[$zip->members]}[1];
+    ok($member, 'A member to extract selected');
+    $ret = eval { $zip->extractMember($member) };
+    is($ret, AZ_ERROR,
+        'Member extraction using extractMember() without a local name 
aborted');
+    SKIP: {
+        skip 'A canary file existed before the test', 1 if $existed;
+        ok(! -e $forbidden_file,
+            'A symlinked target file was not created');
+    }
+
+    # But allow extracting an archive member using extractMember() into
+    # a supplied file name.
+    $allowed_file = $target;
+    $ret = eval { $zip->extractMember($member, $allowed_file) };
+    is($ret, AZ_OK, 'Member extraction using extractMember() passed');
+    ok(-e $allowed_file, 'File created');
+    ok(unlink($allowed_file), 'File removed');
+
+    # The same applies to extracting an archive member using
+    # extractMemberWithoutPaths() without an explicit local file name.
+    # It must abort.
+    $existed = -e $forbidden_file;
+    # Select a member by order due to same file names.
+    $ret = eval { $zip->extractMemberWithoutPaths($member) };
+    is($ret, AZ_ERROR,
+        'Member extraction using extractMemberWithoutPaths() without a local 
name aborted');
+    SKIP: {
+        skip 'A canary file existed before the test', 1 if $existed;
+        ok(! -e $forbidden_file,
+            'A symlinked target file was not created');
+    }
+
+    # But allow extracting an archive member using extractMemberWithoutPaths()
+    # into a supplied file name.
+    $allowed_file = $target;
+    $ret = eval { $zip->extractMemberWithoutPaths($member, $allowed_file) };
+    is($ret, AZ_OK,
+        'Member extraction using extractMemberWithoutPaths() passed');
+    ok(-e $allowed_file, 'File created');
+    ok(unlink($allowed_file), 'File removed');
+    ok(unlink($link), 'A symlink to a file removed');
+}
Binary files old/Archive-Zip-1.60/t/data/dotdot-from-unexistant-path.zip and 
new/Archive-Zip-1.63/t/data/dotdot-from-unexistant-path.zip differ
Binary files old/Archive-Zip-1.60/t/data/link-dir.zip and 
new/Archive-Zip-1.63/t/data/link-dir.zip differ
Binary files old/Archive-Zip-1.60/t/data/link-samename.zip and 
new/Archive-Zip-1.63/t/data/link-samename.zip differ


Reply via email to