summaryrefslogtreecommitdiff
path: root/dev-perl/Archive-Zip
diff options
context:
space:
mode:
authorV3n3RiX <venerix@redcorelinux.org>2018-07-14 21:03:06 +0100
committerV3n3RiX <venerix@redcorelinux.org>2018-07-14 21:03:06 +0100
commit8376ef56580626e9c0f796d5b85b53a0a1c7d5f5 (patch)
tree7681bbd4e8b05407772df40a4bf04cbbc8afc3fa /dev-perl/Archive-Zip
parent30a9caf154332f12ca60756e1b75d2f0e3e1822d (diff)
gentoo resync : 14.07.2018
Diffstat (limited to 'dev-perl/Archive-Zip')
-rw-r--r--dev-perl/Archive-Zip/Archive-Zip-1.600.0-r1.ebuild35
-rw-r--r--dev-perl/Archive-Zip/Archive-Zip-1.600.0.ebuild31
-rw-r--r--dev-perl/Archive-Zip/Manifest5
-rw-r--r--dev-perl/Archive-Zip/files/Archive-Zip-1.60-CVE-2018-10860.patch395
-rw-r--r--dev-perl/Archive-Zip/metadata.xml23
5 files changed, 489 insertions, 0 deletions
diff --git a/dev-perl/Archive-Zip/Archive-Zip-1.600.0-r1.ebuild b/dev-perl/Archive-Zip/Archive-Zip-1.600.0-r1.ebuild
new file mode 100644
index 000000000000..2b727f01eb34
--- /dev/null
+++ b/dev-perl/Archive-Zip/Archive-Zip-1.600.0-r1.ebuild
@@ -0,0 +1,35 @@
+# Copyright 1999-2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=6
+
+DIST_AUTHOR=PHRED
+DIST_VERSION=1.60
+DIST_EXAMPLES=("examples/*")
+inherit perl-module
+
+DESCRIPTION="A wrapper that lets you read Zip archive members as if they were files"
+
+SLOT="0"
+KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~ppc ~ppc64 ~sparc ~x86 ~x86-fbsd ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~sparc-solaris ~x64-solaris ~x86-solaris"
+IUSE="test"
+
+RDEPEND="
+ >=virtual/perl-Compress-Raw-Zlib-2.17.0
+ virtual/perl-File-Path
+ >=virtual/perl-File-Spec-0.800.0
+ virtual/perl-File-Temp
+ virtual/perl-IO
+ virtual/perl-Time-Local
+"
+DEPEND="${RDEPEND}
+ virtual/perl-ExtUtils-MakeMaker
+ test? (
+ dev-perl/Test-MockModule
+ >=virtual/perl-Test-Simple-0.880.0
+ )
+"
+
+PATCHES=(
+ "${FILESDIR}/${PN}-1.60-CVE-2018-10860.patch"
+)
diff --git a/dev-perl/Archive-Zip/Archive-Zip-1.600.0.ebuild b/dev-perl/Archive-Zip/Archive-Zip-1.600.0.ebuild
new file mode 100644
index 000000000000..600c7bfe0884
--- /dev/null
+++ b/dev-perl/Archive-Zip/Archive-Zip-1.600.0.ebuild
@@ -0,0 +1,31 @@
+# Copyright 1999-2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=6
+
+DIST_AUTHOR=PHRED
+DIST_VERSION=1.60
+DIST_EXAMPLES=("examples/*")
+inherit perl-module
+
+DESCRIPTION="A wrapper that lets you read Zip archive members as if they were files"
+
+SLOT="0"
+KEYWORDS="alpha amd64 arm ~arm64 hppa ia64 ppc ppc64 sparc x86 ~x86-fbsd ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~sparc-solaris ~x64-solaris ~x86-solaris"
+IUSE="test"
+
+RDEPEND="
+ >=virtual/perl-Compress-Raw-Zlib-2.17.0
+ virtual/perl-File-Path
+ >=virtual/perl-File-Spec-0.800.0
+ virtual/perl-File-Temp
+ virtual/perl-IO
+ virtual/perl-Time-Local
+"
+DEPEND="${RDEPEND}
+ virtual/perl-ExtUtils-MakeMaker
+ test? (
+ dev-perl/Test-MockModule
+ >=virtual/perl-Test-Simple-0.880.0
+ )
+"
diff --git a/dev-perl/Archive-Zip/Manifest b/dev-perl/Archive-Zip/Manifest
new file mode 100644
index 000000000000..6d97a8c17018
--- /dev/null
+++ b/dev-perl/Archive-Zip/Manifest
@@ -0,0 +1,5 @@
+AUX Archive-Zip-1.60-CVE-2018-10860.patch 15820 BLAKE2B f4d9081f147dc123214c1048b2c916ce654278c35282bea4a470c2a5eae01b380da3f052dfd36c056097e969b1926674ec1eb4be928356b7426f316138c321ec SHA512 87a49c07463cfbc370d3afbf534cc600ec253abc5d03119da60431807af37edda68efa179a5add1ab06798f921a5ce91ed6172aac8aa1f8f83f67f52401e6fc0
+DIST Archive-Zip-1.60.tar.gz 191318 BLAKE2B 97b66b360c55ba864e9e78e74ab5bbeec145859cd551efe5a248a4ad9af7ddbdbd32ad61dd8f30bbfb7e9bb583d0463b657bbe6d67464105fd536adc6a0bd660 SHA512 5af85e1717e7026b5ebe9533b0dd57290b35099d166ee400ca648cb558a37529a3ec290fb9a44679c16cf955a2de9b75328c2fa88d3e87e51c10cac80247852f
+EBUILD Archive-Zip-1.600.0-r1.ebuild 858 BLAKE2B aed29a2225cfd651137f8dd811d13090d12214863fb69fc27c22d1d38ec30430fcda0013eb610eccb590f83b551a5bdc505e33d806b4ba4ab048656569b7f006 SHA512 d313e158eb633046c818971af88b5079d2956200bc96cdd09b12b6cece2b543082e7a72babfbc65cad2bbba584907e6d2786348008e8fe1230e02711977048d8
+EBUILD Archive-Zip-1.600.0.ebuild 789 BLAKE2B cff5d1ed7d2da83405e03bb6043354bb20e13228e62d7ab6dec4d5d2aedebc6bf2ec268d308e965b4282d9fe03db22ab667c06df876f8f89fe4ba3f4e639bb48 SHA512 8fae5015313e935b90209f988dc6a115602268845e3bb07da68a7891bf12aea775ee004c86b441df53bf07936b4b08bea49a8dd73553bdff50108e2a3c95fb1d
+MISC metadata.xml 1187 BLAKE2B 93311e721bebc19566b1108db3e9ec72034db4aaacbbb3abba77d35c5c53ad87a8c57ab7a3778a9062ac452983a0bbefdf7fd11b49c23df07e043974f8922acc SHA512 cab4eed19897f888eb2ff9cc094ba567053eeb115610b0dd4093db37cb8a24488454bfda9b75668f57d37d46e64e3cec5fa300b4227fe40b437c167fb38b690f
diff --git a/dev-perl/Archive-Zip/files/Archive-Zip-1.60-CVE-2018-10860.patch b/dev-perl/Archive-Zip/files/Archive-Zip-1.60-CVE-2018-10860.patch
new file mode 100644
index 000000000000..94ade1abdfb4
--- /dev/null
+++ b/dev-perl/Archive-Zip/files/Archive-Zip-1.60-CVE-2018-10860.patch
@@ -0,0 +1,395 @@
+From 4c200ada6595c0add0de2c450cc44cebd1dbb609 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
+Date: Fri, 15 Jun 2018 14:49:47 +0200
+Subject: Prevent from traversing symlinks and parent directories when
+ extracting
+
+If an attacker-supplied archive contains symbolic links and files that
+referes to the symbolic links in their path components, the user can
+be tricked into overwriting any arbitrary file.
+
+The same issue is with archives whose members refer to a parent
+directory (..) in their path components.
+
+This patch fixes it by aborting an extraction (extractTree(),
+extractMember(), extractMemberWithoutPaths()) in those cases by not
+traversing the dangerous paths and returning AZ_ERORR instead.
+
+However, if a user supplies a local file name, the security checks are
+not performed. This is based on the assumption that a user knows
+what's on his local file system.
+
+CVE-2018-10860
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1591449
+Bug: https://bugs.gentoo.org/660466
+Bug: https://github.com/redhotpenguin/perl-Archive-Zip/pull/33
+---
+ MANIFEST | 3 +
+ lib/Archive/Zip.pm | 8 ++
+ lib/Archive/Zip/Archive.pm | 37 +++++
+ t/25_traversal.t | 189 +++++++++++++++++++++++++
+ t/data/dotdot-from-unexistant-path.zip | Bin 0 -> 245 bytes
+ t/data/link-dir.zip | Bin 0 -> 260 bytes
+ t/data/link-samename.zip | Bin 0 -> 257 bytes
+ 7 files changed, 237 insertions(+)
+ create mode 100644 t/25_traversal.t
+ create mode 100644 t/data/dotdot-from-unexistant-path.zip
+ create mode 100644 t/data/link-dir.zip
+ create mode 100644 t/data/link-samename.zip
+
+diff --git a/MANIFEST b/MANIFEST
+index 37d8b8d..dd9675a 100644
+--- a/MANIFEST
++++ b/MANIFEST
+@@ -59,6 +59,7 @@ t/21_zip64.t
+ 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/crypcomp.zip
+ 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,7 @@ t/data/emptystore.zip
+ t/data/emptystorestr.zip
+ t/data/good_github11.zip
+ t/data/jar.zip
++t/data/link-dir.zip
+ t/data/linux.zip
+ t/data/mkzip.pl
+ t/data/perl.zip
+diff --git a/lib/Archive/Zip.pm b/lib/Archive/Zip.pm
+index ca82e31..907808b 100644
+--- a/lib/Archive/Zip.pm
++++ b/lib/Archive/Zip.pm
+@@ -1145,6 +1145,9 @@ member is used as the name of the extracted file or
+ 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 @@ extracted member (its paths will be deleted too). Otherwise,
+ 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/x to f:\d\e\x
+
+ 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 --git a/lib/Archive/Zip/Archive.pm b/lib/Archive/Zip/Archive.pm
+index 48f0d1a..b0d3e46 100644
+--- a/lib/Archive/Zip/Archive.pm
++++ b/lib/Archive/Zip/Archive.pm
+@@ -185,6 +185,8 @@ sub extractMember {
+ $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 +220,8 @@ sub extractMemberWithoutPaths {
+ 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, @_);
+@@ -827,6 +831,37 @@ sub addTreeMatching {
+ 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 +896,8 @@ sub extractTree {
+ $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 --git a/t/25_traversal.t b/t/25_traversal.t
+new file mode 100644
+index 0000000..d03dede
+--- /dev/null
++++ b/t/25_traversal.t
+@@ -0,0 +1,189 @@
++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");
++
++# Case 1:
++# link-dir -> /tmp
++# link-dir/gotcha-linkdir
++# writes into /tmp/gotcha-linkdir file.
++SKIP: {
++ # Symlink tests make sense only if a file system supports them.
++ my $link = 'trylink';
++ $ret = eval { symlink('.', $link)};
++ skip 'Symbolic links are not supported', 12 if $@;
++ unlink $link;
++
++ # 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.
++ $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.)
++$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');
+diff --git a/t/data/dotdot-from-unexistant-path.zip b/t/data/dotdot-from-unexistant-path.zip
+new file mode 100644
+index 0000000..faaa5bb
+--- /dev/null
++++ b/t/data/dotdot-from-unexistant-path.zip
+@@ -0,0 +1 @@
++PK
+\ No newline at end of file
+diff --git a/t/data/link-dir.zip b/t/data/link-dir.zip
+new file mode 100644
+index 0000000..99fbb43
+--- /dev/null
++++ b/t/data/link-dir.zip
+@@ -0,0 +1,4 @@
++PK
++
++PK
++
+\ No newline at end of file
+diff --git a/t/data/link-samename.zip b/t/data/link-samename.zip
+new file mode 100644
+index 0000000..e9036c0
+--- /dev/null
++++ b/t/data/link-samename.zip
+@@ -0,0 +1,2 @@
++PK
++PK
+\ No newline at end of file
+--
+2.17.1
+
diff --git a/dev-perl/Archive-Zip/metadata.xml b/dev-perl/Archive-Zip/metadata.xml
new file mode 100644
index 000000000000..1751c7ecd7ee
--- /dev/null
+++ b/dev-perl/Archive-Zip/metadata.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+ <maintainer type="project">
+ <email>perl@gentoo.org</email>
+ <name>Gentoo Perl Project</name>
+ </maintainer>
+ <upstream>
+ <remote-id type="cpan">Archive-Zip</remote-id>
+ <remote-id type="cpan-module">Archive::Zip</remote-id>
+ <remote-id type="cpan-module">Archive::Zip::Archive</remote-id>
+ <remote-id type="cpan-module">Archive::Zip::BufferedFileHandle</remote-id>
+ <remote-id type="cpan-module">Archive::Zip::DirectoryMember</remote-id>
+ <remote-id type="cpan-module">Archive::Zip::FileMember</remote-id>
+ <remote-id type="cpan-module">Archive::Zip::Member</remote-id>
+ <remote-id type="cpan-module">Archive::Zip::MemberRead</remote-id>
+ <remote-id type="cpan-module">Archive::Zip::MockFileHandle</remote-id>
+ <remote-id type="cpan-module">Archive::Zip::NewFileMember</remote-id>
+ <remote-id type="cpan-module">Archive::Zip::StringMember</remote-id>
+ <remote-id type="cpan-module">Archive::Zip::Tree</remote-id>
+ <remote-id type="cpan-module">Archive::Zip::ZipFileMember</remote-id>
+ </upstream>
+</pkgmetadata>