|
|
c3be86 |
diff -up yum-utils-1.1.31/docs/reposync.1.orig yum-utils-1.1.31/docs/reposync.1
|
|
|
c3be86 |
--- yum-utils-1.1.31/docs/reposync.1.orig 2018-07-20 11:01:16.789747160 +0200
|
|
|
c3be86 |
+++ yum-utils-1.1.31/docs/reposync.1 2018-07-20 11:01:21.765700655 +0200
|
|
|
c3be86 |
@@ -47,6 +47,16 @@ Download all the non-default metadata.
|
|
|
c3be86 |
Download only newest packages per-repo.
|
|
|
c3be86 |
.IP "\fB\-q, \-\-quiet\fP"
|
|
|
c3be86 |
Output as little information as possible.
|
|
|
c3be86 |
+.IP "\fB\-\-allow-path-traversal\fP"
|
|
|
c3be86 |
+Allow packages stored outside their repo directory to be synced.
|
|
|
c3be86 |
+These are packages that are referenced in metadata by using absolute paths or
|
|
|
c3be86 |
+up-level ".." symbols, and are normally skipped by \fBreposync\fR for security
|
|
|
c3be86 |
+reasons.
|
|
|
c3be86 |
+
|
|
|
c3be86 |
+\fBCAUTION:\fR Using this option has potential security implications since, by
|
|
|
c3be86 |
+providing malicious repodata, an attacker could make \fBreposync\fR write to
|
|
|
c3be86 |
+arbitrary locations on the file system that are accessible by the user running
|
|
|
c3be86 |
+it.
|
|
|
c3be86 |
.SH "EXAMPLES"
|
|
|
c3be86 |
.IP "Sync all packages from the 'updates' repo to the current directory:"
|
|
|
c3be86 |
\fB reposync \-\-repoid=updates\fP
|
|
|
c3be86 |
diff -up yum-utils-1.1.31/reposync.py.orig yum-utils-1.1.31/reposync.py
|
|
|
c3be86 |
--- yum-utils-1.1.31/reposync.py.orig 2018-07-20 11:01:16.752747506 +0200
|
|
|
c3be86 |
+++ yum-utils-1.1.31/reposync.py 2018-07-20 11:01:54.717392693 +0200
|
|
|
c3be86 |
@@ -84,6 +84,12 @@ def localpkgs(directory):
|
|
|
c3be86 |
cache[name] = { 'path': fn, 'size': st.st_size, 'device': st.st_dev }
|
|
|
c3be86 |
return cache
|
|
|
c3be86 |
|
|
|
c3be86 |
+def is_subpath(path, root):
|
|
|
c3be86 |
+ root = os.path.realpath(root)
|
|
|
c3be86 |
+ path = os.path.realpath(os.path.join(root, path))
|
|
|
c3be86 |
+ # join() is used below to ensure root ends with a slash
|
|
|
c3be86 |
+ return path.startswith(os.path.join(root, ''))
|
|
|
c3be86 |
+
|
|
|
c3be86 |
def parseArgs():
|
|
|
c3be86 |
usage = """
|
|
|
c3be86 |
Reposync is used to synchronize a remote yum repository to a local
|
|
|
c3be86 |
@@ -126,6 +132,10 @@ def parseArgs():
|
|
|
c3be86 |
parser.add_option("","--download-metadata", dest="downloadmd",
|
|
|
c3be86 |
default=False, action="store_true",
|
|
|
c3be86 |
help="download all the non-default metadata")
|
|
|
c3be86 |
+ parser.add_option("", "--allow-path-traversal", default=False,
|
|
|
c3be86 |
+ action="store_true",
|
|
|
c3be86 |
+ help="Allow packages stored outside their repo directory to be synced "
|
|
|
c3be86 |
+ "(UNSAFE, USE WITH CAUTION!)")
|
|
|
c3be86 |
(opts, args) = parser.parse_args()
|
|
|
c3be86 |
return (opts, args)
|
|
|
c3be86 |
|
|
|
c3be86 |
@@ -226,13 +236,36 @@ def main():
|
|
|
c3be86 |
else:
|
|
|
c3be86 |
local_repo_path = opts.destdir + '/' + repo.id
|
|
|
c3be86 |
|
|
|
c3be86 |
+ # Ensure we don't traverse out of local_repo_path by dropping any
|
|
|
c3be86 |
+ # packages whose remote_path is absolute or contains up-level
|
|
|
c3be86 |
+ # references (unless explicitly allowed).
|
|
|
c3be86 |
+ # See RHBZ#1600221 for details.
|
|
|
c3be86 |
+ if not opts.allow_path_traversal:
|
|
|
c3be86 |
+ newlist = []
|
|
|
c3be86 |
+ skipped = False
|
|
|
c3be86 |
+ for pkg in download_list:
|
|
|
c3be86 |
+ if is_subpath(pkg.remote_path, local_repo_path):
|
|
|
c3be86 |
+ newlist.append(pkg)
|
|
|
c3be86 |
+ continue
|
|
|
c3be86 |
+ my.logger.warning(
|
|
|
c3be86 |
+ 'WARNING: skipping package %s: remote path "%s" not '
|
|
|
c3be86 |
+ 'within repodir, unsafe to mirror locally'
|
|
|
c3be86 |
+ % (pkg, pkg.remote_path)
|
|
|
c3be86 |
+ )
|
|
|
c3be86 |
+ skipped = True
|
|
|
c3be86 |
+ if skipped:
|
|
|
c3be86 |
+ my.logger.info(
|
|
|
c3be86 |
+ 'You can enable unsafe remote paths by using '
|
|
|
c3be86 |
+ '--allow-path-traversal (see reposync(1) for details)'
|
|
|
c3be86 |
+ )
|
|
|
c3be86 |
+ download_list = newlist
|
|
|
c3be86 |
+
|
|
|
c3be86 |
if opts.delete and os.path.exists(local_repo_path):
|
|
|
c3be86 |
current_pkgs = localpkgs(local_repo_path)
|
|
|
c3be86 |
|
|
|
c3be86 |
download_set = {}
|
|
|
c3be86 |
for pkg in download_list:
|
|
|
c3be86 |
- remote = pkg.returnSimple('relativepath')
|
|
|
c3be86 |
- rpmname = os.path.basename(remote)
|
|
|
c3be86 |
+ rpmname = os.path.basename(pkg.remote_path)
|
|
|
c3be86 |
download_set[rpmname] = 1
|
|
|
c3be86 |
|
|
|
c3be86 |
for pkg in current_pkgs:
|
|
|
c3be86 |
@@ -280,8 +313,7 @@ def main():
|
|
|
c3be86 |
local_size = 0
|
|
|
c3be86 |
if not opts.urls:
|
|
|
c3be86 |
for pkg in download_list:
|
|
|
c3be86 |
- remote = pkg.returnSimple('relativepath')
|
|
|
c3be86 |
- local = local_repo_path + '/' + remote
|
|
|
c3be86 |
+ local = os.path.join(local_repo_path, pkg.remote_path)
|
|
|
c3be86 |
sz = int(pkg.returnSimple('packagesize'))
|
|
|
c3be86 |
if os.path.exists(local) and os.path.getsize(local) == sz:
|
|
|
c3be86 |
continue
|
|
|
c3be86 |
@@ -293,10 +325,9 @@ def main():
|
|
|
c3be86 |
download_list.sort(sortPkgObj)
|
|
|
c3be86 |
if opts.urls:
|
|
|
c3be86 |
for pkg in download_list:
|
|
|
c3be86 |
- remote = pkg.returnSimple('relativepath')
|
|
|
c3be86 |
- local = os.path.join(local_repo_path, remote)
|
|
|
c3be86 |
+ local = os.path.join(local_repo_path, pkg.remote_path)
|
|
|
c3be86 |
if not (os.path.exists(local) and my.verifyPkg(local, pkg, False)):
|
|
|
c3be86 |
- print urljoin(pkg.repo.urls[0], pkg.relativepath)
|
|
|
c3be86 |
+ print urljoin(pkg.repo.urls[0], pkg.remote_path)
|
|
|
c3be86 |
continue
|
|
|
c3be86 |
|
|
|
c3be86 |
# create dest dir
|
|
|
c3be86 |
@@ -305,8 +336,7 @@ def main():
|
|
|
c3be86 |
|
|
|
c3be86 |
# set localpaths
|
|
|
c3be86 |
for pkg in download_list:
|
|
|
c3be86 |
- rpmfn = pkg.remote_path
|
|
|
c3be86 |
- pkg.localpath = os.path.join(local_repo_path, rpmfn)
|
|
|
c3be86 |
+ pkg.localpath = os.path.join(local_repo_path, pkg.remote_path)
|
|
|
c3be86 |
pkg.repo.copy_local = True
|
|
|
c3be86 |
pkg.repo.cache = 0
|
|
|
c3be86 |
localdir = os.path.dirname(pkg.localpath)
|